291 changes: 12 additions & 279 deletions pkg/server/test/expand.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ func TestExpandQuery(t *testing.T, datastore storage.OpenFGADatastore) {
Id: ulid.Make().String(),
SchemaVersion: typesystem.SchemaVersion1_1,
TypeDefinitions: []*openfgapb.TypeDefinition{
{
Type: "user",
},
{
Type: "repo",
Relations: map[string]*openfgapb.Userset{
Expand Down Expand Up @@ -811,6 +814,9 @@ func TestExpandQuery(t *testing.T, datastore storage.OpenFGADatastore) {
Id: ulid.Make().String(),
SchemaVersion: typesystem.SchemaVersion1_1,
TypeDefinitions: []*openfgapb.TypeDefinition{
{
Type: "user",
},
{
Type: "document",
Relations: map[string]*openfgapb.Userset{
Expand All @@ -824,57 +830,8 @@ func TestExpandQuery(t *testing.T, datastore storage.OpenFGADatastore) {
typesystem.DirectRelationReference("document", "editor"),
},
},
},
},
},
},
},
tuples: []*openfgapb.TupleKey{
tuple.NewTupleKey("document:1", "parent", "document:2#editor"),
},
request: &openfgapb.ExpandRequest{
TupleKey: tuple.NewTupleKey("document:1", "parent", ""),
},
expected: &openfgapb.ExpandResponse{
Tree: &openfgapb.UsersetTree{
Root: &openfgapb.UsersetTree_Node{
Name: "document:1#parent",
Value: &openfgapb.UsersetTree_Node_Leaf{
Leaf: &openfgapb.UsersetTree_Leaf{
Value: &openfgapb.UsersetTree_Leaf_Users{
Users: &openfgapb.UsersetTree_Users{
Users: []string{"document:2#editor"},
},
},
},
},
},
},
},
},
{
name: "1.1_TupleToUserset_involving_wildcard_is_skipped",
model: &openfgapb.AuthorizationModel{
Id: ulid.Make().String(),
SchemaVersion: typesystem.SchemaVersion1_1,
TypeDefinitions: []*openfgapb.TypeDefinition{
{
Type: "user",
},
{
Type: "document",
Relations: map[string]*openfgapb.Userset{
"parent": typesystem.This(),
"viewer": typesystem.Union(
typesystem.This(),
typesystem.TupleToUserset("parent", "viewer"),
),
},
Metadata: &openfgapb.Metadata{
Relations: map[string]*openfgapb.RelationMetadata{
"parent": {
"editor": {
DirectlyRelatedUserTypes: []*openfgapb.RelationReference{
typesystem.WildcardRelationReference("user"),
{
Type: "user",
},
Expand All @@ -885,245 +842,21 @@ func TestExpandQuery(t *testing.T, datastore storage.OpenFGADatastore) {
},
},
},
tuples: []*openfgapb.TupleKey{
tuple.NewTupleKey("document:1", "parent", "user:*"),
tuple.NewTupleKey("document:X", "viewer", "user:jon"),
},
request: &openfgapb.ExpandRequest{
TupleKey: tuple.NewTupleKey("document:1", "viewer", ""),
},
expected: &openfgapb.ExpandResponse{
Tree: &openfgapb.UsersetTree{
Root: &openfgapb.UsersetTree_Node{
Name: "document:1#viewer",
Value: &openfgapb.UsersetTree_Node_Union{
Union: &openfgapb.UsersetTree_Nodes{
Nodes: []*openfgapb.UsersetTree_Node{
{
Name: "document:1#viewer",
Value: &openfgapb.UsersetTree_Node_Leaf{
Leaf: &openfgapb.UsersetTree_Leaf{
Value: &openfgapb.UsersetTree_Leaf_Users{},
},
},
},
{
Name: "document:1#viewer",
Value: &openfgapb.UsersetTree_Node_Leaf{
Leaf: &openfgapb.UsersetTree_Leaf{
Value: &openfgapb.UsersetTree_Leaf_TupleToUserset{
TupleToUserset: &openfgapb.UsersetTree_TupleToUserset{
Tupleset: "document:1#parent",
},
},
},
},
},
},
},
},
},
},
},
},
{
name: "1.1_Tuple_involving_userset_skipped_if_it_is_referenced_in_a_TTU_rewrite",
model: &openfgapb.AuthorizationModel{
Id: ulid.Make().String(),
SchemaVersion: typesystem.SchemaVersion1_1,
TypeDefinitions: []*openfgapb.TypeDefinition{
{
Type: "folder",
Relations: map[string]*openfgapb.Userset{
"viewer": typesystem.This(),
},
},
{
Type: "document",
Relations: map[string]*openfgapb.Userset{
"parent": typesystem.This(),
"editor": typesystem.This(),
"viewer": typesystem.TupleToUserset("parent", "viewer"),
},
Metadata: &openfgapb.Metadata{
Relations: map[string]*openfgapb.RelationMetadata{
"parent": {
DirectlyRelatedUserTypes: []*openfgapb.RelationReference{
typesystem.DirectRelationReference("document", "editor"),
},
},
},
},
},
},
},
tuples: []*openfgapb.TupleKey{
tuple.NewTupleKey("document:1", "parent", "document:2#editor"),
},
request: &openfgapb.ExpandRequest{
TupleKey: tuple.NewTupleKey("document:1", "viewer", ""),
TupleKey: tuple.NewTupleKey("document:1", "parent", ""),
},
expected: &openfgapb.ExpandResponse{
Tree: &openfgapb.UsersetTree{
Root: &openfgapb.UsersetTree_Node{
Name: "document:1#viewer",
Name: "document:1#parent",
Value: &openfgapb.UsersetTree_Node_Leaf{
Leaf: &openfgapb.UsersetTree_Leaf{
Value: &openfgapb.UsersetTree_Leaf_TupleToUserset{
TupleToUserset: &openfgapb.UsersetTree_TupleToUserset{
Tupleset: "document:1#parent",
},
},
},
},
},
},
},
},
{
name: "1.1_Tuple_involving_userset_skipped_if_same_ComputedUserset_involved_in_TTU_rewrite",
model: &openfgapb.AuthorizationModel{
Id: ulid.Make().String(),
SchemaVersion: typesystem.SchemaVersion1_1,
TypeDefinitions: []*openfgapb.TypeDefinition{
{
Type: "user",
},
{
Type: "document",
Relations: map[string]*openfgapb.Userset{
"parent": typesystem.This(),
"viewer": typesystem.Union(
typesystem.This(),
typesystem.TupleToUserset("parent", "viewer"),
),
},
Metadata: &openfgapb.Metadata{
Relations: map[string]*openfgapb.RelationMetadata{
"viewer": {
DirectlyRelatedUserTypes: []*openfgapb.RelationReference{
{Type: "user"},
},
},
"parent": {
DirectlyRelatedUserTypes: []*openfgapb.RelationReference{
typesystem.DirectRelationReference("document", "viewer"),
},
},
},
},
},
},
},
tuples: []*openfgapb.TupleKey{
tuple.NewTupleKey("document:1", "parent", "document:2#viewer"),
tuple.NewTupleKey("document:2", "viewer", "user:jon"),
},
request: &openfgapb.ExpandRequest{
TupleKey: tuple.NewTupleKey("document:1", "viewer", ""),
},
expected: &openfgapb.ExpandResponse{
Tree: &openfgapb.UsersetTree{
Root: &openfgapb.UsersetTree_Node{
Name: "document:1#viewer",
Value: &openfgapb.UsersetTree_Node_Union{
Union: &openfgapb.UsersetTree_Nodes{
Nodes: []*openfgapb.UsersetTree_Node{
{
Name: "document:1#viewer",
Value: &openfgapb.UsersetTree_Node_Leaf{
Leaf: &openfgapb.UsersetTree_Leaf{
Value: &openfgapb.UsersetTree_Leaf_Users{},
},
},
},
{
Name: "document:1#viewer",
Value: &openfgapb.UsersetTree_Node_Leaf{
Leaf: &openfgapb.UsersetTree_Leaf{
Value: &openfgapb.UsersetTree_Leaf_TupleToUserset{
TupleToUserset: &openfgapb.UsersetTree_TupleToUserset{
Tupleset: "document:1#parent",
},
},
},
},
},
},
},
},
},
},
},
},
{
name: "1.1_Tupleset_relation_involving_rewrite_skipped",
model: &openfgapb.AuthorizationModel{
Id: ulid.Make().String(),
SchemaVersion: typesystem.SchemaVersion1_1,
TypeDefinitions: []*openfgapb.TypeDefinition{
{
Type: "user",
},
{
Type: "document",
Relations: map[string]*openfgapb.Userset{
"parent": typesystem.ComputedUserset("editor"),
"editor": typesystem.This(),
"viewer": typesystem.Union(
typesystem.This(), typesystem.TupleToUserset("parent", "viewer"),
),
},
Metadata: &openfgapb.Metadata{
Relations: map[string]*openfgapb.RelationMetadata{
"editor": {
DirectlyRelatedUserTypes: []*openfgapb.RelationReference{
{Type: "document"},
},
},
"viewer": {
DirectlyRelatedUserTypes: []*openfgapb.RelationReference{
{Type: "user"},
},
},
},
},
},
},
},
tuples: []*openfgapb.TupleKey{
tuple.NewTupleKey("document:1", "editor", "document:2"),
tuple.NewTupleKey("document:2", "viewer", "user:jon"),
},
request: &openfgapb.ExpandRequest{
TupleKey: tuple.NewTupleKey("document:1", "viewer", ""),
},
expected: &openfgapb.ExpandResponse{
Tree: &openfgapb.UsersetTree{
Root: &openfgapb.UsersetTree_Node{
Name: "document:1#viewer",
Value: &openfgapb.UsersetTree_Node_Union{
Union: &openfgapb.UsersetTree_Nodes{
Nodes: []*openfgapb.UsersetTree_Node{
{
Name: "document:1#viewer",
Value: &openfgapb.UsersetTree_Node_Leaf{
Leaf: &openfgapb.UsersetTree_Leaf{
Value: &openfgapb.UsersetTree_Leaf_Users{},
},
},
},
{
Name: "document:1#viewer",
Value: &openfgapb.UsersetTree_Node_Leaf{
Leaf: &openfgapb.UsersetTree_Leaf{
Value: &openfgapb.UsersetTree_Leaf_TupleToUserset{
TupleToUserset: &openfgapb.UsersetTree_TupleToUserset{
Tupleset: "document:1#parent",
},
},
},
},
Value: &openfgapb.UsersetTree_Leaf_Users{
Users: &openfgapb.UsersetTree_Users{
Users: []string{"document:2#editor"},
},
},
},
Expand Down
6 changes: 3 additions & 3 deletions pkg/server/test/list_objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ func TestListObjectsRespectsMaxResults(t *testing.T, ds storage.OpenFGADatastore
Logger: logger.NewNoopLogger(),
ListObjectsDeadline: listObjectsDeadline,
ListObjectsMaxResults: test.maxResults,
ResolveNodeLimit: defaultResolveNodeLimit,
ResolveNodeLimit: DefaultResolveNodeLimit,
}
typesys := typesystem.New(model)
ctx = typesystem.ContextWithTypesystem(ctx, typesys)
Expand Down Expand Up @@ -313,7 +313,7 @@ func BenchmarkListObjectsWithReverseExpand(b *testing.B, ds storage.OpenFGADatas
listObjectsQuery := commands.ListObjectsQuery{
Datastore: ds,
Logger: logger.NewNoopLogger(),
ResolveNodeLimit: defaultResolveNodeLimit,
ResolveNodeLimit: DefaultResolveNodeLimit,
}

var r *openfgapb.ListObjectsResponse
Expand Down Expand Up @@ -379,7 +379,7 @@ func BenchmarkListObjectsWithConcurrentChecks(b *testing.B, ds storage.OpenFGADa
listObjectsQuery := commands.ListObjectsQuery{
Datastore: ds,
Logger: logger.NewNoopLogger(),
ResolveNodeLimit: defaultResolveNodeLimit,
ResolveNodeLimit: DefaultResolveNodeLimit,
}

var r *openfgapb.ListObjectsResponse
Expand Down
3 changes: 1 addition & 2 deletions pkg/server/test/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

const (
defaultResolveNodeLimit = 25
DefaultResolveNodeLimit = 25
)

func RunAllTests(t *testing.T, ds storage.OpenFGADatastore) {
Expand All @@ -19,7 +19,6 @@ func RunQueryTests(t *testing.T, ds storage.OpenFGADatastore) {
t.Run("TestReadAuthorizationModelQueryErrors", func(t *testing.T) { TestReadAuthorizationModelQueryErrors(t, ds) })
t.Run("TestSuccessfulReadAuthorizationModelQuery", func(t *testing.T) { TestSuccessfulReadAuthorizationModelQuery(t, ds) })
t.Run("TestReadAuthorizationModel", func(t *testing.T) { ReadAuthorizationModelTest(t, ds) })

t.Run("TestExpandQuery", func(t *testing.T) { TestExpandQuery(t, ds) })
t.Run("TestExpandQueryErrors", func(t *testing.T) { TestExpandQueryErrors(t, ds) })

Expand Down
293 changes: 293 additions & 0 deletions pkg/server/test/write_authzmodel.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"testing"

parser "github.com/craigpastro/openfga-dsl-parser/v2"
"github.com/oklog/ulid/v2"
"github.com/openfga/openfga/pkg/logger"
"github.com/openfga/openfga/pkg/server/commands"
Expand Down Expand Up @@ -135,6 +136,298 @@ func WriteAuthorizationModelTest(t *testing.T, datastore storage.OpenFGADatastor
},
},
},
{
name: "self_referencing_type_restriction_with_entrypoint",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: parser.MustParse(`
type user
type document
relations
define editor: [user] as self
define viewer: [document#viewer] as self or editor
`),
SchemaVersion: typesystem.SchemaVersion1_1,
},
},
{
name: "self_referencing_type_restriction_without_entrypoint_1",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: parser.MustParse(`
type user
type document
relations
define viewer: [document#viewer] as self
`),
SchemaVersion: typesystem.SchemaVersion1_1,
},
err: serverErrors.InvalidAuthorizationModelInput(&typesystem.InvalidRelationError{
ObjectType: "document",
Relation: "viewer",
Cause: typesystem.ErrCycle,
}),
},
{
name: "self_referencing_type_restriction_without_entrypoint_2",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: parser.MustParse(`
type user
type document
relations
define editor: [user] as self
define viewer: [document#viewer] as self and editor
`),
SchemaVersion: typesystem.SchemaVersion1_1,
},
err: serverErrors.InvalidAuthorizationModelInput(&typesystem.InvalidRelationError{
ObjectType: "document",
Relation: "viewer",
Cause: typesystem.ErrNoEntrypoints,
}),
},
{
name: "self_referencing_type_restriction_without_entrypoint_3",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: parser.MustParse(`
type user
type document
relations
define restricted: [user] as self
define viewer: [document#viewer] as self but not restricted
`),
SchemaVersion: typesystem.SchemaVersion1_1,
},
err: serverErrors.InvalidAuthorizationModelInput(&typesystem.InvalidRelationError{
ObjectType: "document",
Relation: "viewer",
Cause: typesystem.ErrCycle,
}),
},
{
name: "rewritten_relation_in_intersection_unresolvable",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: parser.MustParse(`
type user
type document
relations
define admin: [user] as self
define action1 as admin and action2 and action3
define action2 as admin and action1 and action3
define action3 as admin and action1 and action2
`),
SchemaVersion: typesystem.SchemaVersion1_1,
},
err: serverErrors.InvalidAuthorizationModelInput(&typesystem.InvalidRelationError{
ObjectType: "document",
Relation: "action1",
Cause: typesystem.ErrNoEntrypoints,
}),
},
{
name: "direct_relationship_with_entrypoint",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: parser.MustParse(`
type user
type document
relations
define viewer: [user] as self
`),
},
},
{
name: "computed_relationship_with_entrypoint",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: parser.MustParse(`
type user
type document
relations
define editor: [user] as self
define viewer as editor
`),
},
},

{
name: "rewritten_relation_in_exclusion_unresolvable",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: parser.MustParse(`
type user
type document
relations
define admin: [user] as self
define action1 as admin but not action2
define action2 as admin but not action3
define action3 as admin but not action1
`),
},
err: serverErrors.InvalidAuthorizationModelInput(&typesystem.InvalidRelationError{
ObjectType: "document",
Relation: "action1",
Cause: typesystem.ErrNoEntrypoints,
}),
},
{
name: "no_entrypoint_3a",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: parser.MustParse(`
type user
type document
relations
define viewer: [document#viewer] as self and editor
define editor: [user] as self
`),
},
err: serverErrors.InvalidAuthorizationModelInput(&typesystem.InvalidRelationError{
ObjectType: "document",
Relation: "viewer",
Cause: typesystem.ErrNoEntrypoints,
}),
},

{
name: "no_entrypoint_3b",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: parser.MustParse(`
type user
type document
relations
define viewer: [document#viewer] as self but not editor
define editor: [user] as self
`),
},
err: serverErrors.InvalidAuthorizationModelInput(&typesystem.InvalidRelationError{
ObjectType: "document",
Relation: "viewer",
Cause: typesystem.ErrNoEntrypoints,
}),
},
{
name: "no_entrypoint_4",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: parser.MustParse(`
type user
type folder
relations
define parent: [document] as self
define viewer as editor from parent
type document
relations
define parent: [folder] as self
define editor as viewer
define viewer as editor from parent
`),
},
err: serverErrors.InvalidAuthorizationModelInput(&typesystem.InvalidRelationError{
ObjectType: "document",
Relation: "editor",
Cause: typesystem.ErrNoEntrypoints,
}),
},
{
name: "self_referencing_type_restriction_with_entrypoint_1",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: parser.MustParse(`
type user
type document
relations
define restricted: [user] as self
define editor: [user] as self
define viewer: [document#viewer] as self or editor
define can_view as viewer but not restricted
define can_view_actual as can_view
`),
},
},
{
name: "self_referencing_type_restriction_with_entrypoint_2",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: parser.MustParse(`
type user
type document
relations
define editor: [user] as self
define viewer: [document#viewer] as self or editor
`),
},
},
{
name: "relation_with_union_of_ttu_rewrites",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: parser.MustParse(`
type user
type org
relations
define admin: [user] as self
define member: [user] as self
type group
relations
define member: [user] as self
type feature
relations
define accessible as admin from subscriber_org or member from subscriber_group
define subscriber_group: [group] as self
define subscriber_org: [org] as self
`),
},
},
{
name: "type_name_is_empty_string",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: []*openfgapb.TypeDefinition{
{
Type: "",
},
},
},
err: serverErrors.InvalidAuthorizationModelInput(
fmt.Errorf("the type name of a type definition cannot be an empty string"),
),
},
{
name: "relation_name_is_empty_string",
request: &openfgapb.WriteAuthorizationModelRequest{
StoreId: storeID,
TypeDefinitions: []*openfgapb.TypeDefinition{
{
Type: "user",
Relations: map[string]*openfgapb.Userset{
"": typesystem.This(),
},
},
{
Type: "other",
},
},
},
err: serverErrors.InvalidAuthorizationModelInput(
fmt.Errorf("type 'user' defines a relation with an empty string for a name"),
),
},
}

ctx := context.Background()
Expand Down
328 changes: 278 additions & 50 deletions pkg/typesystem/typesystem.go

Large diffs are not rendered by default.

187 changes: 182 additions & 5 deletions pkg/typesystem/typesystem_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,150 @@
package typesystem

import (
"context"
"testing"

parser "github.com/craigpastro/openfga-dsl-parser/v2"
"github.com/stretchr/testify/require"
openfgapb "go.buf.build/openfga/go/openfga/api/openfga/v1"
)

func TestNewAndValidate(t *testing.T) {

tests := []struct {
name string
model string
expectedError error
}{
{
name: "direct_relationship_with_entrypoint",
model: `
type user
type document
relations
define viewer: [user] as self
`,
},
{
name: "computed_relationship_with_entrypoint",
model: `
type user
type document
relations
define editor: [user] as self
define viewer as editor
`,
},
{
name: "no_entrypoint_1",
model: `
type user
type document
relations
define admin: [user] as self
define action1 as admin and action2 and action3
define action2 as admin and action1 and action3
define action3 as admin and action1 and action2
`,
expectedError: ErrNoEntrypoints,
},
{
name: "no_entrypoint_2",
model: `
type user
type document
relations
define admin: [user] as self
define action1 as admin but not action2
define action2 as admin but not action3
define action3 as admin but not action1
`,
expectedError: ErrNoEntrypoints,
},
{
name: "no_entrypoint_3a",
model: `
type user
type document
relations
define viewer: [document#viewer] as self and editor
define editor: [user] as self
`,
expectedError: ErrNoEntrypoints,
},
{
name: "no_entrypoint_3b",
model: `
type user
type document
relations
define viewer: [document#viewer] as self but not editor
define editor: [user] as self
`,
expectedError: ErrNoEntrypoints,
},
{
name: "no_entrypoint_4",
model: `
type user
type folder
relations
define parent: [document] as self
define viewer as editor from parent
type document
relations
define parent: [folder] as self
define editor as viewer
define viewer as editor from parent
`,
expectedError: ErrNoEntrypoints,
},
{
name: "self_referencing_type_restriction_with_entrypoint_1",
model: `
type user
type document
relations
define restricted: [user] as self
define editor: [user] as self
define viewer: [document#viewer] as self or editor
define can_view as viewer but not restricted
define can_view_actual as can_view
`,
},
{
name: "self_referencing_type_restriction_with_entrypoint_2",
model: `
type user
type document
relations
define editor: [user] as self
define viewer: [document#viewer] as self or editor
`,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_, err := NewAndValidate(context.Background(), &openfgapb.AuthorizationModel{
SchemaVersion: SchemaVersion1_1,
TypeDefinitions: parser.MustParse(test.model),
})
require.ErrorIs(t, err, test.expectedError)
})
}
}

func TestSuccessfulRewriteValidations(t *testing.T) {
var tests = []struct {
name string
Expand Down Expand Up @@ -36,11 +173,51 @@ func TestSuccessfulRewriteValidations(t *testing.T) {
},
},
},
{
name: "self_referencing_type_restriction_with_entrypoint",
model: &openfgapb.AuthorizationModel{
TypeDefinitions: parser.MustParse(`
type user
type document
relations
define editor: [user] as self
define viewer: [document#viewer] as self or editor
`),
SchemaVersion: SchemaVersion1_1,
},
},
{
name: "intersection_may_contain_repeated_relations",
model: &openfgapb.AuthorizationModel{
TypeDefinitions: parser.MustParse(`
type user
type document
relations
define editor: [user] as self
define viewer as editor and editor
`),
SchemaVersion: SchemaVersion1_1,
},
},
{
name: "exclusion_may_contain_repeated_relations",
model: &openfgapb.AuthorizationModel{
TypeDefinitions: parser.MustParse(`
type user
type document
relations
define editor: [user] as self
define viewer as editor but not editor
`),
SchemaVersion: SchemaVersion1_1,
},
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_, err := NewAndValidate(test.model)
_, err := NewAndValidate(context.Background(), test.model)
require.NoError(t, err)
})
}
Expand Down Expand Up @@ -471,13 +648,13 @@ func TestInvalidRewriteValidations(t *testing.T) {
define viewer as viewer from parent
`),
},
err: ErrCycle,
err: ErrNoEntrypoints,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_, err := NewAndValidate(test.model)
_, err := NewAndValidate(context.Background(), test.model)
require.ErrorIs(t, err, test.err)
})
}
Expand Down Expand Up @@ -578,7 +755,7 @@ func TestSuccessfulRelationTypeRestrictionsValidations(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_, err := NewAndValidate(test.model)
_, err := NewAndValidate(context.Background(), test.model)
require.NoError(t, err)
})
}
Expand Down Expand Up @@ -1052,7 +1229,7 @@ func TestInvalidRelationTypeRestrictionsValidations(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
_, err := NewAndValidate(test.model)
_, err := NewAndValidate(context.Background(), test.model)
require.EqualError(t, err, test.err.Error())
})
}
Expand Down