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
132 lines
3.5 KiB
Go
132 lines
3.5 KiB
Go
// Copyright © 2023 Ory Corp
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package expand_test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"testing"
|
|
|
|
"github.com/ory/x/httprouterx"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/ory/keto/internal/driver"
|
|
"github.com/ory/keto/internal/expand"
|
|
"github.com/ory/keto/internal/namespace"
|
|
"github.com/ory/keto/internal/testhelpers"
|
|
"github.com/ory/keto/ketoapi"
|
|
)
|
|
|
|
func TestRESTHandler(t *testing.T) {
|
|
nspace := &namespace.Namespace{
|
|
Name: "expand handler",
|
|
}
|
|
|
|
reg := driver.NewSqliteTestRegistry(t, driver.WithNamespaces([]*namespace.Namespace{nspace}))
|
|
h := expand.NewHandler(reg)
|
|
r := httprouterx.NewRouterPublic()
|
|
h.RegisterReadRoutes(r)
|
|
ts := httptest.NewServer(r)
|
|
defer ts.Close()
|
|
|
|
t.Run("case=returns bad request on malformed int", func(t *testing.T) {
|
|
resp, err := ts.Client().Get(ts.URL + expand.RouteBase + "?max-depth=foo")
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, http.StatusBadRequest, resp.StatusCode)
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
assert.Contains(t, string(body), "invalid syntax")
|
|
})
|
|
|
|
t.Run("case=returns not found on unknown namespace", func(t *testing.T) {
|
|
resp, err := ts.Client().Get(ts.URL + expand.RouteBase + "?" + url.Values{
|
|
"max-depth": {"10"},
|
|
"namespace": {"not " + nspace.Name},
|
|
}.Encode())
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
assert.Contains(t, string(body), "Unknown namespace")
|
|
})
|
|
|
|
t.Run("case=returns not found on unknown namespace", func(t *testing.T) {
|
|
resp, err := ts.Client().Get(ts.URL + expand.RouteBase + "?" + url.Values{
|
|
"max-depth": {"10"},
|
|
"namespace": {"not " + nspace.Name},
|
|
}.Encode())
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
assert.Contains(t, string(body), "Unknown namespace")
|
|
})
|
|
|
|
t.Run("case=returns expand tree", func(t *testing.T) {
|
|
rootSub := &ketoapi.SubjectSet{
|
|
Namespace: nspace.Name,
|
|
Object: "root",
|
|
Relation: "parent of",
|
|
}
|
|
expectedTree := &ketoapi.Tree[*ketoapi.RelationTuple]{
|
|
Type: ketoapi.TreeNodeUnion,
|
|
Tuple: &ketoapi.RelationTuple{
|
|
SubjectSet: rootSub,
|
|
},
|
|
Children: []*ketoapi.Tree[*ketoapi.RelationTuple]{
|
|
{
|
|
Type: ketoapi.TreeNodeLeaf,
|
|
Tuple: &ketoapi.RelationTuple{
|
|
SubjectID: new("child0"),
|
|
},
|
|
},
|
|
{
|
|
Type: ketoapi.TreeNodeLeaf,
|
|
Tuple: &ketoapi.RelationTuple{
|
|
SubjectID: new("child1"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
testhelpers.MapAndInsertTuples(t, reg,
|
|
&ketoapi.RelationTuple{
|
|
Namespace: nspace.Name,
|
|
Object: rootSub.Object,
|
|
Relation: rootSub.Relation,
|
|
SubjectID: expectedTree.Children[0].Tuple.SubjectID,
|
|
},
|
|
&ketoapi.RelationTuple{
|
|
Namespace: nspace.Name,
|
|
Object: rootSub.Object,
|
|
Relation: rootSub.Relation,
|
|
SubjectID: expectedTree.Children[1].Tuple.SubjectID,
|
|
},
|
|
)
|
|
|
|
qs := rootSub.ToURLQuery()
|
|
qs.Set("max-depth", "2")
|
|
resp, err := ts.Client().Get(ts.URL + expand.RouteBase + "?" + qs.Encode())
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
actualTree := ketoapi.Tree[*ketoapi.RelationTuple]{}
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
t.Logf("body: %s", string(body))
|
|
require.NoError(t, json.NewDecoder(bytes.NewBuffer(body)).Decode(&actualTree))
|
|
expand.AssertExternalTreesAreEqual(t, expectedTree, &actualTree)
|
|
})
|
|
}
|