Files
upstream-ory-keto/internal/e2e/full_suit_test.go
upstream-mirror 9456a4e922
Some checks failed
CI / Run lints and checks (push) Failing after 47s
CI / Run tests (push) Failing after 1s
CI / Run race tests (push) Failing after 5s
CI / Build CLI docs (push) Has been skipped
CI / Run buf actions (push) Failing after 5s
CodeQL / Analyze (go) (push) Failing after 3s
CodeQL / Analyze (javascript) (push) Failing after 2s
Docker Image Scanners / scanners (push) Failing after 3s
Format / format (push) Failing after 3s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Draft newsletter (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
snapshot of https://github.com/ory/keto.git (master, 2026-09-16; blobs > 131072B omitted)
2026-09-16 01:08:34 +05:00

161 lines
4.9 KiB
Go

// Copyright © 2023 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package e2e
import (
"fmt"
"io"
"net/http"
"testing"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/ory/herodot"
"github.com/ory/x/cmdx"
prometheus "github.com/ory/x/prometheusx"
"github.com/ory/keto/cmd"
cliclient "github.com/ory/keto/cmd/client"
"github.com/ory/keto/internal/relationtuple"
"github.com/ory/keto/internal/x/dbx"
"github.com/ory/keto/ketoapi"
)
type (
transactClient interface {
client
transactTuples(t testing.TB, ins []*ketoapi.RelationTuple, del []*ketoapi.RelationTuple)
}
client interface {
createTuple(t testing.TB, r *ketoapi.RelationTuple)
deleteTuple(t testing.TB, r *ketoapi.RelationTuple)
deleteAllTuples(t testing.TB, q *ketoapi.RelationQuery)
queryTuple(t testing.TB, q *ketoapi.RelationQuery, opts ...paginationOptionSetter) *ketoapi.GetResponse
queryTupleErr(t testing.TB, expected *herodot.DefaultError, q *ketoapi.RelationQuery, opts ...paginationOptionSetter)
check(t testing.TB, r *ketoapi.RelationTuple) bool
batchCheck(t testing.TB, r []*ketoapi.RelationTuple) []checkResponse
batchCheckErr(t testing.TB, requestTuples []*ketoapi.RelationTuple, expected *herodot.DefaultError)
expand(t testing.TB, r *ketoapi.SubjectSet, depth int) *ketoapi.Tree[*ketoapi.RelationTuple]
oplCheckSyntax(t testing.TB, content []byte) []*ketoapi.ParseError
waitUntilLive(t testing.TB)
queryNamespaces(t testing.TB) ketoapi.GetNamespacesResponse
}
)
const (
promLogLine = "promhttp_metric_handler_requests_total"
)
func Test(t *testing.T) {
t.Parallel()
for _, dsn := range dbx.GetDSNs(t) {
t.Run(fmt.Sprintf("dsn=%s", dsn.Name), func(t *testing.T) {
t.Parallel()
ctx, reg, namespaceTestMgr, getAddr := newInitializedReg(t, dsn, nil)
closeServer := startServer(ctx, t, reg)
t.Cleanup(closeServer)
_, _, readAddr := getAddr(t, "read")
_, _, writeAddr := getAddr(t, "write")
_, _, oplAddr := getAddr(t, "opl")
_, _, metricsAddr := getAddr(t, "metrics")
// The test cases start here
// We execute every test with all clients available
for _, cl := range []client{
newGrpcClient(t, ctx,
readAddr,
writeAddr,
oplAddr,
),
&restClient{
readURL: "http://" + readAddr,
writeURL: "http://" + writeAddr,
oplSyntaxURL: "http://" + oplAddr,
},
&cliClient{c: &cmdx.CommandExecuter{
New: func() *cobra.Command {
return cmd.NewRootCmd(nil)
},
Ctx: ctx,
PersistentArgs: []string{
"--" + cliclient.FlagReadRemote, readAddr,
"--" + cliclient.FlagWriteRemote, writeAddr,
"--insecure-disable-transport-security=true",
"--" + cmdx.FlagFormat, string(cmdx.FormatJSON),
},
}},
&sdkClient{
readRemote: readAddr,
writeRemote: writeAddr,
syntaxRemote: oplAddr,
},
} {
t.Run(fmt.Sprintf("client=%T", cl), runCases(cl, namespaceTestMgr))
if tc, ok := cl.(transactClient); ok {
t.Run(fmt.Sprintf("transactClient=%T", cl), runTransactionCases(tc, namespaceTestMgr))
}
}
t.Run("case=metrics are served", func(t *testing.T) {
t.Parallel()
newGrpcClient(t, ctx,
readAddr,
writeAddr,
oplAddr,
).waitUntilLive(t)
t.Run("case=on "+prometheus.MetricsPrometheusPath, func(t *testing.T) {
t.Parallel()
resp, err := http.Get(fmt.Sprintf("http://%s%s", metricsAddr, prometheus.MetricsPrometheusPath))
require.NoError(t, err)
require.Equal(t, resp.StatusCode, http.StatusOK)
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.Contains(t, string(body), promLogLine)
})
t.Run("case=not on /", func(t *testing.T) {
t.Parallel()
resp, err := http.Get(fmt.Sprintf("http://%s", metricsAddr))
require.NoError(t, err)
require.Equal(t, resp.StatusCode, http.StatusNotFound)
})
})
})
}
}
func TestServeCORS(t *testing.T) {
t.Parallel()
ctx, reg, _, getAddr := newInitializedReg(t, dbx.GetSqlite(t), map[string]any{
"serve.read.cors.enabled": true,
"serve.read.cors.debug": true,
"serve.read.cors.allowed_methods": []string{http.MethodGet},
"serve.read.cors.allowed_origins": []string{"https://ory.sh"},
})
closeServer := startServer(ctx, t, reg)
t.Cleanup(closeServer)
_, _, readAddr := getAddr(t, "read")
waitUntilLive(t, "http://"+readAddr)
t.Log("Health check is ready")
req, err := http.NewRequest(http.MethodOptions, "http://"+readAddr+relationtuple.ReadRouteBase, nil)
require.NoError(t, err)
req.Header.Set("Origin", "https://ory.sh")
req.Header.Set("Access-Control-Request-Method", "GET")
resp, err := http.DefaultClient.Do(req) //nolint:gosec // Test code with controlled URL.
require.NoError(t, err)
require.Equal(t, http.StatusNoContent, resp.StatusCode)
assert.Equalf(t, "https://ory.sh", resp.Header.Get("Access-Control-Allow-Origin"), "%+v", resp.Header)
}