github.com/openfga/openfga@v1.5.4-rc1/pkg/storage/test/storage.go (about) 1 package test 2 3 import ( 4 "context" 5 "testing" 6 7 "github.com/google/go-cmp/cmp" 8 "github.com/oklog/ulid/v2" 9 openfgav1 "github.com/openfga/api/proto/openfga/v1" 10 "github.com/stretchr/testify/require" 11 "google.golang.org/protobuf/protoadapt" 12 "google.golang.org/protobuf/testing/protocmp" 13 14 "github.com/openfga/openfga/pkg/tuple" 15 16 "github.com/openfga/openfga/pkg/storage" 17 "github.com/openfga/openfga/pkg/testutils" 18 ) 19 20 var ( 21 cmpOpts = []cmp.Option{ 22 protocmp.IgnoreFields(protoadapt.MessageV2Of(&openfgav1.Tuple{}), "timestamp"), 23 protocmp.IgnoreFields(protoadapt.MessageV2Of(&openfgav1.TupleChange{}), "timestamp"), 24 testutils.TupleKeyCmpTransformer, 25 protocmp.Transform(), 26 } 27 ) 28 29 func RunAllTests(t *testing.T, ds storage.OpenFGADatastore) { 30 t.Run("TestDatastoreIsReady", func(t *testing.T) { 31 status, err := ds.IsReady(context.Background()) 32 require.NoError(t, err) 33 require.True(t, status.IsReady) 34 }) 35 // Tuples. 36 t.Run("TestTupleWriteAndRead", func(t *testing.T) { TupleWritingAndReadingTest(t, ds) }) 37 t.Run("TestReadChanges", func(t *testing.T) { ReadChangesTest(t, ds) }) 38 t.Run("TestReadStartingWithUser", func(t *testing.T) { ReadStartingWithUserTest(t, ds) }) 39 40 // TODO I suspect there is overlap in test scenarios. Consolidate them into one 41 t.Run("ReadPageTestCorrectnessOfContinuationTokens", func(t *testing.T) { ReadPageTestCorrectnessOfContinuationTokens(t, ds) }) 42 t.Run("ReadPageTestCorrectnessOfContinuationTokensV2", func(t *testing.T) { ReadPageTestCorrectnessOfContinuationTokensV2(t, ds) }) 43 44 // TODO Consolidate them into one, since both Read and ReadPage should respect the same set of filters 45 t.Run("ReadTestCorrectnessOfTuples", func(t *testing.T) { ReadTestCorrectnessOfTuples(t, ds) }) 46 t.Run("ReadPageTestCorrectnessOfTuples", func(t *testing.T) { ReadPageTestCorrectnessOfTuples(t, ds) }) 47 48 // Authorization models. 49 t.Run("TestWriteAndReadAuthorizationModel", func(t *testing.T) { WriteAndReadAuthorizationModelTest(t, ds) }) 50 t.Run("TestReadAuthorizationModels", func(t *testing.T) { ReadAuthorizationModelsTest(t, ds) }) 51 t.Run("TestFindLatestAuthorizationModel", func(t *testing.T) { FindLatestAuthorizationModelTest(t, ds) }) 52 53 // Assertions. 54 t.Run("TestWriteAndReadAssertions", func(t *testing.T) { AssertionsTest(t, ds) }) 55 56 // Stores. 57 t.Run("TestStore", func(t *testing.T) { StoreTest(t, ds) }) 58 } 59 60 // BootstrapFGAStore is a utility to write an FGA model and relationship tuples to a datastore. 61 // It doesn't validate the model. It validates the format of the tuples, but not the types within them. 62 // It returns the store_id and FGA AuthorizationModel, respectively. 63 func BootstrapFGAStore( 64 t require.TestingT, 65 ds storage.OpenFGADatastore, 66 model string, 67 tupleStrs []string, 68 ) (string, *openfgav1.AuthorizationModel) { 69 storeID := ulid.Make().String() 70 71 fgaModel := testutils.MustTransformDSLToProtoWithID(model) 72 err := ds.WriteAuthorizationModel(context.Background(), storeID, fgaModel) 73 require.NoError(t, err) 74 75 tuples := tuple.MustParseTupleStrings(tupleStrs...) 76 77 batchSize := ds.MaxTuplesPerWrite() 78 for batch := 0; batch < len(tuples); batch += batchSize { 79 batchEnd := min(batch+batchSize, len(tuples)) 80 81 err := ds.Write(context.Background(), storeID, nil, tuples[batch:batchEnd]) 82 require.NoError(t, err) 83 } 84 85 return storeID, fgaModel 86 }