github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/validationfile/loader_test.go (about) 1 package validationfile 2 3 import ( 4 "context" 5 "sort" 6 "testing" 7 8 "github.com/authzed/spicedb/internal/datastore/memdb" 9 "github.com/authzed/spicedb/internal/datastore/proxy/proxy_test" 10 "github.com/authzed/spicedb/pkg/datastore" 11 "github.com/authzed/spicedb/pkg/datastore/options" 12 "github.com/authzed/spicedb/pkg/tuple" 13 14 "github.com/stretchr/testify/require" 15 ) 16 17 func TestPopulateFromFiles(t *testing.T) { 18 tests := []struct { 19 name string 20 filePaths []string 21 want []string 22 expectedError string 23 }{ 24 { 25 name: "no comment", 26 filePaths: []string{"testdata/loader_no_comment.yaml"}, 27 want: []string{ 28 "example/project:pied_piper#owner@example/user:milburga", 29 "example/project:pied_piper#reader@example/user:tarben", 30 "example/project:pied_piper#writer@example/user:freyja", 31 }, 32 expectedError: "", 33 }, 34 { 35 name: "with comment", 36 filePaths: []string{"testdata/loader_with_comment.yaml"}, 37 want: []string{ 38 "example/project:pied_piper#owner@example/user:milburga", 39 "example/project:pied_piper#reader@example/user:tarben", 40 "example/project:pied_piper#writer@example/user:freyja", 41 }, 42 expectedError: "", 43 }, 44 { 45 name: "multiple files", 46 filePaths: []string{"testdata/initial_schema_and_rels.yaml", "testdata/just_rels.yaml"}, 47 want: []string{ 48 "example/project:pied_piper#owner@example/user:milburga", 49 "example/project:pied_piper#reader@example/user:tarben", 50 "example/project:pied_piper#writer@example/user:freyja", 51 "example/project:pied_piper#owner@example/user:fred", 52 "example/project:pied_piper#reader@example/user:tom", 53 "example/project:pied_piper#writer@example/user:sarah", 54 }, 55 expectedError: "", 56 }, 57 { 58 name: "multiple files", 59 filePaths: []string{"testdata/initial_schema_and_rels.yaml", "testdata/just_rels.yaml"}, 60 want: []string{ 61 "example/project:pied_piper#owner@example/user:milburga", 62 "example/project:pied_piper#reader@example/user:tarben", 63 "example/project:pied_piper#writer@example/user:freyja", 64 "example/project:pied_piper#owner@example/user:fred", 65 "example/project:pied_piper#reader@example/user:tom", 66 "example/project:pied_piper#writer@example/user:sarah", 67 }, 68 expectedError: "", 69 }, 70 { 71 name: "missing schema", 72 filePaths: []string{"testdata/just_rels.yaml"}, 73 want: nil, 74 expectedError: "object definition `example/project` not found", 75 }, 76 { 77 name: "legacy file", 78 filePaths: []string{"testdata/legacy.yaml"}, 79 want: nil, 80 expectedError: "relationships must be specified in `relationships`", 81 }, 82 { 83 name: "basic caveats", 84 filePaths: []string{"testdata/basic_caveats.yaml"}, 85 want: []string{ 86 "resource:first#reader@user:sarah[some_caveat:{\"somecondition\":42}]", 87 "resource:first#reader@user:tom[some_caveat]", 88 }, 89 expectedError: "", 90 }, 91 { 92 name: "invalid caveat", 93 filePaths: []string{"testdata/invalid_caveat.yaml"}, 94 want: nil, 95 expectedError: "could not lookup caveat `some_caveat` for relation `reader`: caveat with name `some_caveat` not found", 96 }, 97 { 98 name: "invalid caveated relationship", 99 filePaths: []string{"testdata/invalid_caveated_rel.yaml"}, 100 want: nil, 101 expectedError: "subjects of type `user with some_caveat` are not allowed on relation `resource#reader`", 102 }, 103 { 104 name: "invalid caveated relationship syntax", 105 filePaths: []string{"testdata/invalid_caveated_rel_syntax.yaml"}, 106 want: nil, 107 expectedError: "error parsing relationship", 108 }, 109 { 110 name: "repeated relationship", 111 filePaths: []string{"testdata/repeated_relationship.yaml"}, 112 want: nil, 113 expectedError: "found repeated relationship `resource:first#reader@user:tom`", 114 }, 115 } 116 117 for _, tt := range tests { 118 tt := tt 119 t.Run(tt.name, func(t *testing.T) { 120 require := require.New(t) 121 ds, err := memdb.NewMemdbDatastore(0, 0, 0) 122 require.NoError(err) 123 124 parsed, _, err := PopulateFromFiles(context.Background(), ds, tt.filePaths) 125 if tt.expectedError == "" { 126 require.NoError(err) 127 128 foundRelationships := make([]string, 0, len(parsed.Tuples)) 129 for _, tpl := range parsed.Tuples { 130 foundRelationships = append(foundRelationships, tuple.MustString(tpl)) 131 } 132 133 sort.Strings(tt.want) 134 sort.Strings(foundRelationships) 135 require.Equal(tt.want, foundRelationships) 136 } else { 137 require.NotNil(err) 138 require.Contains(err.Error(), tt.expectedError) 139 } 140 }) 141 } 142 } 143 144 func TestPopulationChunking(t *testing.T) { 145 require := require.New(t) 146 147 ds, err := memdb.NewMemdbDatastore(0, 0, 0) 148 require.NoError(err) 149 150 cs := txCountingDatastore{delegate: ds} 151 _, _, err = PopulateFromFiles(context.Background(), &cs, []string{"testdata/requires_chunking.yaml"}) 152 require.NoError(err) 153 require.Equal(3, cs.count) 154 } 155 156 type txCountingDatastore struct { 157 proxy_test.MockDatastore 158 count int 159 delegate datastore.Datastore 160 } 161 162 func (c *txCountingDatastore) ReadWriteTx(ctx context.Context, userFunc datastore.TxUserFunc, option ...options.RWTOptionsOption) (datastore.Revision, error) { 163 c.count++ 164 return c.delegate.ReadWriteTx(ctx, userFunc, option...) 165 }