diff --git a/cmd/store/import.go b/cmd/store/import.go index 62b41d53..5124057c 100644 --- a/cmd/store/import.go +++ b/cmd/store/import.go @@ -44,6 +44,7 @@ const ( progressBarSleepDelay = 10 // time.Millisecond progressBarThrottleValue = 65 progressBarUpdateDelay = 5 * time.Millisecond + maxAssertionsPerWrite = 100 ) // createStore creates a new store with the given client configuration and store data. @@ -226,9 +227,15 @@ func importAssertions( StoreId: &storeID, } + if len(assertions) > maxAssertionsPerWrite { + fmt.Fprintf(os.Stderr, "Warning: %d test assertions found, but only the first %d will be written\n", + len(assertions), maxAssertionsPerWrite) + assertions = assertions[:maxAssertionsPerWrite] + } + _, err := fgaClient.WriteAssertions(ctx).Body(assertions).Options(writeOptions).Execute() if err != nil { - return fmt.Errorf("failed to import assertions: %w", err) + return fmt.Errorf("failed to import test assertions: %w", err) } } diff --git a/cmd/store/import_test.go b/cmd/store/import_test.go index edb0e031..c65b20af 100644 --- a/cmd/store/import_test.go +++ b/cmd/store/import_test.go @@ -12,6 +12,11 @@ import ( "github.com/openfga/cli/internal/storetest" ) +const ( + testModelID = "model-1" + testStoreID = "store-1" +) + func TestImportStore(t *testing.T) { t.Parallel() @@ -51,7 +56,7 @@ func TestImportStore(t *testing.T) { Expectation: true, }, } - modelID, storeID := "model-1", "store-1" + modelID, storeID := testModelID, testStoreID expectedOptions := client.ClientWriteAssertionsOptions{AuthorizationModelId: &modelID, StoreId: &storeID} importStoreTests := []struct { @@ -215,6 +220,64 @@ func TestImportStore(t *testing.T) { } } +func TestImportStoreWithTruncatedAssertions(t *testing.T) { + t.Parallel() + + modelID, storeID := testModelID, testStoreID + expectedOptions := client.ClientWriteAssertionsOptions{AuthorizationModelId: &modelID, StoreId: &storeID} + + // Generate 150 users to create 150 assertions (exceeding 100 limit) + users := make([]string, 150) + for i := range 150 { + users[i] = "user:" + string(rune('a'+i/26)) + string(rune('a'+i%26)) + } + + // Only the first 100 assertions should be written + first100Assertions := make([]client.ClientAssertion, 100) + for i := range 100 { + first100Assertions[i] = client.ClientAssertion{ + User: users[i], + Relation: "reader", + Object: "document:doc1", + Expectation: true, + } + } + + mockCtrl := gomock.NewController(t) + mockFgaClient := mockclient.NewMockSdkClient(mockCtrl) + + defer mockCtrl.Finish() + + // Only expect a single write with the first 100 assertions + setupWriteAssertionsMock(mockCtrl, mockFgaClient, first100Assertions, expectedOptions) + setupWriteModelMock(mockCtrl, mockFgaClient, modelID) + setupCreateStoreMock(mockCtrl, mockFgaClient, storeID) + + testStore := storetest.StoreData{ + Model: `type user + type document + relations + define reader: [user]`, + Tests: []storetest.ModelTest{ + { + Name: "Test", + Check: []storetest.ModelTestCheck{ + { + Users: users, + Object: "document:doc1", + Assertions: map[string]bool{"reader": true}, + }, + }, + }, + }, + } + + _, err := importStore(t.Context(), &fga.ClientConfig{}, mockFgaClient, &testStore, "", "", 10, 1, "") + if err != nil { + t.Errorf("expected no error, got %v", err) + } +} + func TestUpdateStore(t *testing.T) { t.Parallel() @@ -225,8 +288,8 @@ func TestUpdateStore(t *testing.T) { Expectation: true, }} - modelID := "model-1" - storeID := "store-1" + modelID := testModelID + storeID := testStoreID sampleTime := time.Now() expectedOptions := client.ClientWriteAssertionsOptions{ AuthorizationModelId: &modelID, diff --git a/internal/storetest/remotetest.go b/internal/storetest/remotetest.go index b80330f0..906b53c6 100644 --- a/internal/storetest/remotetest.go +++ b/internal/storetest/remotetest.go @@ -140,6 +140,7 @@ func RunRemoteListUsersTest( results := make([]ModelTestListUsersSingleResult, 0, len(listUsersTest.Assertions)) object, _ := convertStoreObjectToObject(listUsersTest.Object) + for relation, expectation := range listUsersTest.Assertions { result := RunSingleRemoteListUsersTest(ctx, fgaClient, client.ClientListUsersRequest{