From 5d945c60783750aacd1b70a093b39a61706e3806 Mon Sep 17 00:00:00 2001 From: Edwin Marrima Date: Wed, 1 May 2024 20:24:19 +0200 Subject: [PATCH 1/3] feat: store import return store_id, model_id and tuple import result (failure/success) --- .../failed-store-import-001.fga.yaml | 23 +++ cmd/store/create.go | 4 +- cmd/store/import.go | 54 +++--- cmd/store/import_test.go | 158 ++++++++++++++++++ cmd/tuple/import.go | 18 +- 5 files changed, 227 insertions(+), 30 deletions(-) create mode 100644 cmd/store/.test-data/failed-store-import-001.fga.yaml create mode 100644 cmd/store/import_test.go diff --git a/cmd/store/.test-data/failed-store-import-001.fga.yaml b/cmd/store/.test-data/failed-store-import-001.fga.yaml new file mode 100644 index 00000000..c69cda5b --- /dev/null +++ b/cmd/store/.test-data/failed-store-import-001.fga.yaml @@ -0,0 +1,23 @@ +name: FGA Demo Store +model: |+ + model + schema 1.1 + + type user + + type doc + relations + define owner: [user] + define reader: [user] + define writer: [user] + +tuples: + - user: user:Kross + relation: writer + object: doc:dev-docs + - user: user:Modric + relation: owner + object: document:wrong-type +tests: + - name: Tests + check: [] \ No newline at end of file diff --git a/cmd/store/create.go b/cmd/store/create.go index 4e0b0cae..4bb7acc9 100644 --- a/cmd/store/create.go +++ b/cmd/store/create.go @@ -32,7 +32,7 @@ import ( ) type CreateStoreAndModelResponse struct { - Store client.ClientCreateStoreResponse `json:"store"` + Store *client.ClientCreateStoreResponse `json:"store"` Model *client.ClientWriteAuthorizationModelResponse `json:"model,omitempty"` } @@ -69,7 +69,7 @@ func CreateStoreWithModel( return nil, err } - response.Store = *createStoreResponse + response.Store = createStoreResponse fgaClient.SetStoreId(response.Store.Id) if inputModel != "" { diff --git a/cmd/store/import.go b/cmd/store/import.go index c415bd97..33457d18 100644 --- a/cmd/store/import.go +++ b/cmd/store/import.go @@ -33,20 +33,34 @@ import ( "github.com/openfga/cli/internal/storetest" ) +type importStoreIODependencies struct { + createStoreWithModel func(clientConfig fga.ClientConfig, storeName string, inputModel string, inputFormat authorizationmodel.ModelFormat) (*CreateStoreAndModelResponse, error) + importTuples func(fgaClient client.SdkClient, body client.ClientWriteRequest, maxTuplesPerWrite int, maxParallelRequests int) (*tuple.ImportResponse, error) + modelWrite func(fgaClient client.SdkClient, inputModel authorizationmodel.AuthzModel) (*client.ClientWriteAuthorizationModelResponse, error) +} + +type ImportStoreResponse struct { + *CreateStoreAndModelResponse + Tuple *tuple.ImportResponse `json:"tuple"` +} + func importStore( clientConfig fga.ClientConfig, - fgaClient client.SdkClient, storeData *storetest.StoreData, format authorizationmodel.ModelFormat, storeID string, maxTuplesPerWrite int, maxParallelRequests int, -) (*CreateStoreAndModelResponse, error) { + ioAggregator importStoreIODependencies, +) (*ImportStoreResponse, error) { var err error - var response *CreateStoreAndModelResponse //nolint:wsl - if storeID == "" { //nolint:wsl - createStoreAndModelResponse, err := CreateStoreWithModel(clientConfig, storeData.Name, storeData.Model, format) - response = createStoreAndModelResponse + var fgaClient client.SdkClient + response := &ImportStoreResponse{ + CreateStoreAndModelResponse: &CreateStoreAndModelResponse{}, + } //nolint:wsl + if storeID == "" { //nolint:wsl + createStoreAndModelResponse, err := ioAggregator.createStoreWithModel(clientConfig, storeData.Name, storeData.Model, format) + response.CreateStoreAndModelResponse = createStoreAndModelResponse if err != nil { //nolint:wsl return nil, err } @@ -59,27 +73,29 @@ func importStore( if err != nil { return nil, err //nolint:wrapcheck } - - _, err := model.Write(fgaClient, authModel) + fgaClient, err = clientConfig.GetFgaClient() + if err != nil { + return nil, fmt.Errorf("failed to initialize FGA Client due to %w", err) + } + authorizationModelResponse, err := ioAggregator.modelWrite(fgaClient, authModel) if err != nil { return nil, fmt.Errorf("failed to write model due to %w", err) } + response.Model = authorizationModelResponse } - fgaClient, err = clientConfig.GetFgaClient() if err != nil { return nil, fmt.Errorf("failed to initialize FGA Client due to %w", err) } - writeRequest := client.ClientWriteRequest{ Writes: storeData.Tuples, } - _, err = tuple.ImportTuples(fgaClient, writeRequest, maxTuplesPerWrite, maxParallelRequests) + importTupleResponse, err := ioAggregator.importTuples(fgaClient, writeRequest, maxTuplesPerWrite, maxParallelRequests) if err != nil { return nil, err //nolint:wrapcheck } - + response.Tuple = importTupleResponse return response, nil } @@ -90,7 +106,7 @@ var importCmd = &cobra.Command{ Long: `Import a store: updating the name, model and appending the global tuples`, Example: "fga store import --file=model.fga.yaml", RunE: func(cmd *cobra.Command, _ []string) error { - var createStoreAndModelResponse *CreateStoreAndModelResponse + var createStoreAndModelResponse *ImportStoreResponse clientConfig := cmdutils.GetClientConfig(cmd) storeID, err := cmd.Flags().GetString("store-id") @@ -118,13 +134,13 @@ var importCmd = &cobra.Command{ return err //nolint:wrapcheck } - fgaClient, err := clientConfig.GetFgaClient() - if err != nil { - return fmt.Errorf("failed to initialize FGA Client due to %w", err) + ioAggregator := importStoreIODependencies{ + createStoreWithModel: CreateStoreWithModel, + importTuples: tuple.ImportTuples, + modelWrite: model.Write, } - - createStoreAndModelResponse, err = importStore(clientConfig, fgaClient, storeData, format, - storeID, maxTuplesPerWrite, maxParallelRequests) + createStoreAndModelResponse, err = importStore(clientConfig, storeData, format, + storeID, maxTuplesPerWrite, maxParallelRequests, ioAggregator) if err != nil { return err } diff --git a/cmd/store/import_test.go b/cmd/store/import_test.go new file mode 100644 index 00000000..8c42dafa --- /dev/null +++ b/cmd/store/import_test.go @@ -0,0 +1,158 @@ +package store + +import ( + "fmt" + "github.com/openfga/cli/cmd/tuple" + "github.com/openfga/cli/internal/authorizationmodel" + "github.com/openfga/cli/internal/fga" + "github.com/openfga/cli/internal/storetest" + "github.com/openfga/go-sdk/client" + "path" + "reflect" + "testing" + "time" +) + +func TestImportStore(t *testing.T) { + t.Run("Must create store and modelID when there's no store configured", func(t *testing.T) { + // Arrange + clientConfig := fga.ClientConfig{ApiUrl: "https://localhost:8080"} + storeData := &storetest.StoreData{} + authorizationModelID := "01HWJGBQQNNQATBQ661SH6585Y" + storeID := "Test-001" + + ioAggregator := importStoreIODependencies{ + importTuples: func(fgaClient client.SdkClient, body client.ClientWriteRequest, maxTuplesPerWrite, maxParallelRequests int) (*tuple.ImportResponse, error) { + return nil, nil + }, + createStoreWithModel: func(clientConfig fga.ClientConfig, storeName, inputModel string, inputFormat authorizationmodel.ModelFormat) (*CreateStoreAndModelResponse, error) { + return &CreateStoreAndModelResponse{ + Store: &client.ClientCreateStoreResponse{ + Id: "01HWJGBQQHZZJHQEQZ6MCBC3B0", + Name: storeID, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + }, + Model: &client.ClientWriteAuthorizationModelResponse{ + AuthorizationModelId: authorizationModelID, + }, + }, nil + }, + } + + // Act + response, err := importStore(clientConfig, storeData, "", "", 2, 2, ioAggregator) + + // Assert + if err != nil { + t.Error(err) + } + if response.Model.AuthorizationModelId != authorizationModelID { + t.Fatalf("expected: %s\nreturned: %s", authorizationModelID, response.Model.AuthorizationModelId) + } + if response.Store.Name != storeID { + t.Fatalf("expected: %s\nreturned: %s", storeID, response.Store.Name) + } + }) + + t.Run("Must return the Model ID and an empty Store when importing into an existing store", func(t *testing.T) { + clientConfig := fga.ClientConfig{ApiUrl: "https://localhost:8080"} + storeData := &storetest.StoreData{} + authorizationModelID := "01HWJGBQQNNQATBQ661SH6585Y" + + ioAggregator := importStoreIODependencies{ + importTuples: func(fgaClient client.SdkClient, body client.ClientWriteRequest, maxTuplesPerWrite, maxParallelRequests int) (*tuple.ImportResponse, error) { + return nil, nil + }, + modelWrite: func(fgaClient client.SdkClient, inputModel authorizationmodel.AuthzModel) (*client.ClientWriteAuthorizationModelResponse, error) { + return &client.ClientWriteAuthorizationModelResponse{ + AuthorizationModelId: authorizationModelID, + }, nil + }, + createStoreWithModel: func(clientConfig fga.ClientConfig, storeName, inputModel string, inputFormat authorizationmodel.ModelFormat) (*CreateStoreAndModelResponse, error) { + return &CreateStoreAndModelResponse{ + Model: &client.ClientWriteAuthorizationModelResponse{ + AuthorizationModelId: authorizationModelID, + }, + }, nil + }, + } + + // Act + response, err := importStore(clientConfig, storeData, "", "01HWJGBQQHZZJHQEQZ6MCBC3B0", 2, 2, ioAggregator) + + // Assert + if err != nil { + t.Error(err) + } + if response.Store != nil { + t.Fatalf("Expected: null\nReturn: %v", response.Store) + } + if response.Model.AuthorizationModelId != authorizationModelID { + t.Fatalf("expected: %s\nreturned: %s", authorizationModelID, response.Model.AuthorizationModelId) + } + }) + + t.Run("Must returns the modelID, a null store object, and a list of failed/successfully imported tuples when tuples containing unregistered types are provided as input", func(t *testing.T) { + clientConfig := fga.ClientConfig{ApiUrl: "https://localhost:8080"} + fileName := "./.test-data/failed-store-import-001.fga.yaml" + format, storeData, err := storetest.ReadFromFile(fileName, path.Dir(fileName)) + authorizationModelID := "01HWJGBQQNNQATBQ661SH6585Y" + + successfulTupleImport := storeData.Tuples[0] + failedTupleImport := storeData.Tuples[1] + failureReason := fmt.Sprintf("error message: Invalid tuple '%s#%s@%s'. Reason: type 'document' not found", + failedTupleImport.Object, + failedTupleImport.Relation, + failedTupleImport.User, + ) + ioAggregator := importStoreIODependencies{ + importTuples: func(fgaClient client.SdkClient, body client.ClientWriteRequest, maxTuplesPerWrite, maxParallelRequests int) (*tuple.ImportResponse, error) { + return &tuple.ImportResponse{ + Successful: []client.ClientTupleKey{ + successfulTupleImport, + }, + Failed: []tuple.FailedWriteResponse{ + { + TupleKey: failedTupleImport, + Reason: failureReason, + }, + }, + }, nil + }, + modelWrite: func(fgaClient client.SdkClient, inputModel authorizationmodel.AuthzModel) (*client.ClientWriteAuthorizationModelResponse, error) { + return &client.ClientWriteAuthorizationModelResponse{ + AuthorizationModelId: authorizationModelID, + }, nil + }, + createStoreWithModel: func(clientConfig fga.ClientConfig, storeName, inputModel string, inputFormat authorizationmodel.ModelFormat) (*CreateStoreAndModelResponse, error) { + return &CreateStoreAndModelResponse{ + Model: &client.ClientWriteAuthorizationModelResponse{ + AuthorizationModelId: authorizationModelID, + }, + }, nil + }, + } + + // Act + importResponse, err := importStore(clientConfig, storeData, format, "01HWJGBQQHZZJHQEQZ6MCBC3B0", 2, 2, ioAggregator) + if err != nil { + t.Error(err) + } + if len(importResponse.Tuple.Successful) != 1 { + t.Fatalf("expected: %d\nreturned: %d", 1, len(importResponse.Tuple.Successful)) + } + if len(importResponse.Tuple.Failed) != 1 { + t.Fatalf("expected: %d\nreturned: %d", 1, len(importResponse.Tuple.Failed)) + } + if !reflect.DeepEqual(importResponse.Tuple.Successful[0], successfulTupleImport) { + t.Fatalf("expected: %v\nreturned: %v", successfulTupleImport, importResponse.Tuple.Successful[0]) + } + if !reflect.DeepEqual(importResponse.Tuple.Failed[0].TupleKey, failedTupleImport) { + t.Fatalf("expected: %v\nreturned: %v", failedTupleImport, importResponse.Tuple.Failed[0]) + } + if failureReason != importResponse.Tuple.Failed[0].Reason { + t.Fatalf("expected: %s\nreturned: %s", failureReason, importResponse.Tuple.Failed[0].Reason) + } + }) +} diff --git a/cmd/tuple/import.go b/cmd/tuple/import.go index 890ad24e..67bfae77 100644 --- a/cmd/tuple/import.go +++ b/cmd/tuple/import.go @@ -37,14 +37,14 @@ var MaxTuplesPerWrite = 1 // MaxParallelRequests Limit the parallel writes to the API. var MaxParallelRequests = 10 -type failedWriteResponse struct { +type FailedWriteResponse struct { TupleKey client.ClientTupleKey `json:"tuple_key"` Reason string `json:"reason"` } type ImportResponse struct { - Successful []client.ClientTupleKey `json:"successful"` - Failed []failedWriteResponse `json:"failed"` + Successful []client.ClientTupleKey `json:"successful,omitemptys"` + Failed []FailedWriteResponse `json:"failed,omitempty"` } // ImportTuples receives a client.ClientWriteRequest and imports the tuples to the store. It can be used to import @@ -98,10 +98,10 @@ func extractErrMssg(err error) string { func processWrites( writes []client.ClientWriteRequestWriteResponse, -) ([]client.ClientTupleKey, []failedWriteResponse) { +) ([]client.ClientTupleKey, []FailedWriteResponse) { var ( successfulWrites []client.ClientTupleKey - failedWrites []failedWriteResponse + failedWrites []FailedWriteResponse ) for _, write := range writes { @@ -109,7 +109,7 @@ func processWrites( successfulWrites = append(successfulWrites, write.TupleKey) } else { reason := extractErrMssg(write.Error) - failedWrites = append(failedWrites, failedWriteResponse{ + failedWrites = append(failedWrites, FailedWriteResponse{ TupleKey: write.TupleKey, Reason: reason, }) @@ -121,10 +121,10 @@ func processWrites( func processDeletes( deletes []client.ClientWriteRequestDeleteResponse, -) ([]client.ClientTupleKey, []failedWriteResponse) { +) ([]client.ClientTupleKey, []FailedWriteResponse) { var ( successfulDeletes []client.ClientTupleKey - failedDeletes []failedWriteResponse + failedDeletes []FailedWriteResponse ) for _, delete := range deletes { @@ -138,7 +138,7 @@ func processDeletes( successfulDeletes = append(successfulDeletes, deletedTupleKey) } else { reason := extractErrMssg(delete.Error) - failedDeletes = append(failedDeletes, failedWriteResponse{ + failedDeletes = append(failedDeletes, FailedWriteResponse{ TupleKey: deletedTupleKey, Reason: reason, }) From 0b9774574a9c1a13d4aa055dde49234db1fdaf45 Mon Sep 17 00:00:00 2001 From: Edwin Marrima Date: Wed, 1 May 2024 20:58:55 +0200 Subject: [PATCH 2/3] fix: lint detected issues --- cmd/store/import.go | 39 +++++++++++++--- cmd/store/import_test.go | 98 ++++++++++++++++++++++++++++++---------- cmd/tuple/import.go | 2 +- 3 files changed, 107 insertions(+), 32 deletions(-) diff --git a/cmd/store/import.go b/cmd/store/import.go index 33457d18..417e9ec6 100644 --- a/cmd/store/import.go +++ b/cmd/store/import.go @@ -34,9 +34,22 @@ import ( ) type importStoreIODependencies struct { - createStoreWithModel func(clientConfig fga.ClientConfig, storeName string, inputModel string, inputFormat authorizationmodel.ModelFormat) (*CreateStoreAndModelResponse, error) - importTuples func(fgaClient client.SdkClient, body client.ClientWriteRequest, maxTuplesPerWrite int, maxParallelRequests int) (*tuple.ImportResponse, error) - modelWrite func(fgaClient client.SdkClient, inputModel authorizationmodel.AuthzModel) (*client.ClientWriteAuthorizationModelResponse, error) + createStoreWithModel func( + clientConfig fga.ClientConfig, + storeName string, + inputModel string, + inputFormat authorizationmodel.ModelFormat, + ) (*CreateStoreAndModelResponse, error) + importTuples func( + fgaClient client.SdkClient, + body client.ClientWriteRequest, + maxTuplesPerWrite int, + maxParallelRequests int, + ) (*tuple.ImportResponse, error) + modelWrite func( + fgaClient client.SdkClient, + inputModel authorizationmodel.AuthzModel, + ) (*client.ClientWriteAuthorizationModelResponse, error) } type ImportStoreResponse struct { @@ -54,12 +67,19 @@ func importStore( ioAggregator importStoreIODependencies, ) (*ImportStoreResponse, error) { var err error + var fgaClient client.SdkClient + response := &ImportStoreResponse{ CreateStoreAndModelResponse: &CreateStoreAndModelResponse{}, - } //nolint:wsl + } if storeID == "" { //nolint:wsl - createStoreAndModelResponse, err := ioAggregator.createStoreWithModel(clientConfig, storeData.Name, storeData.Model, format) + createStoreAndModelResponse, err := ioAggregator.createStoreWithModel( + clientConfig, + storeData.Name, + storeData.Model, + format, + ) response.CreateStoreAndModelResponse = createStoreAndModelResponse if err != nil { //nolint:wsl return nil, err @@ -73,29 +93,36 @@ func importStore( if err != nil { return nil, err //nolint:wrapcheck } + fgaClient, err = clientConfig.GetFgaClient() if err != nil { return nil, fmt.Errorf("failed to initialize FGA Client due to %w", err) } + authorizationModelResponse, err := ioAggregator.modelWrite(fgaClient, authModel) if err != nil { return nil, fmt.Errorf("failed to write model due to %w", err) } + response.Model = authorizationModelResponse } + fgaClient, err = clientConfig.GetFgaClient() if err != nil { return nil, fmt.Errorf("failed to initialize FGA Client due to %w", err) } + writeRequest := client.ClientWriteRequest{ Writes: storeData.Tuples, } importTupleResponse, err := ioAggregator.importTuples(fgaClient, writeRequest, maxTuplesPerWrite, maxParallelRequests) if err != nil { - return nil, err //nolint:wrapcheck + return nil, err } + response.Tuple = importTupleResponse + return response, nil } diff --git a/cmd/store/import_test.go b/cmd/store/import_test.go index 8c42dafa..69b95b7f 100644 --- a/cmd/store/import_test.go +++ b/cmd/store/import_test.go @@ -14,18 +14,22 @@ import ( ) func TestImportStore(t *testing.T) { - t.Run("Must create store and modelID when there's no store configured", func(t *testing.T) { - // Arrange + t.Run("Must create store and modelID when "+ + "there's no store configured", func(t *testing.T) { + t.Parallel() + clientConfig := fga.ClientConfig{ApiUrl: "https://localhost:8080"} storeData := &storetest.StoreData{} - authorizationModelID := "01HWJGBQQNNQATBQ661SH6585Y" + authorizationModelID := "01HWJGBQQNNQATBQ661SH6585Y001" storeID := "Test-001" ioAggregator := importStoreIODependencies{ - importTuples: func(fgaClient client.SdkClient, body client.ClientWriteRequest, maxTuplesPerWrite, maxParallelRequests int) (*tuple.ImportResponse, error) { - return nil, nil + importTuples: func(_ client.SdkClient, _ client.ClientWriteRequest, _, _ int, + ) (*tuple.ImportResponse, error) { + return &tuple.ImportResponse{}, nil }, - createStoreWithModel: func(clientConfig fga.ClientConfig, storeName, inputModel string, inputFormat authorizationmodel.ModelFormat) (*CreateStoreAndModelResponse, error) { + createStoreWithModel: func(_ fga.ClientConfig, _, _ string, _ authorizationmodel.ModelFormat, + ) (*CreateStoreAndModelResponse, error) { return &CreateStoreAndModelResponse{ Store: &client.ClientCreateStoreResponse{ Id: "01HWJGBQQHZZJHQEQZ6MCBC3B0", @@ -40,36 +44,48 @@ func TestImportStore(t *testing.T) { }, } - // Act - response, err := importStore(clientConfig, storeData, "", "", 2, 2, ioAggregator) - + response, err := importStore(clientConfig, + storeData, + "", + "", + 2, + 2, + ioAggregator, + ) // Assert if err != nil { t.Error(err) } + if response.Model.AuthorizationModelId != authorizationModelID { t.Fatalf("expected: %s\nreturned: %s", authorizationModelID, response.Model.AuthorizationModelId) } + if response.Store.Name != storeID { t.Fatalf("expected: %s\nreturned: %s", storeID, response.Store.Name) } }) - t.Run("Must return the Model ID and an empty Store when importing into an existing store", func(t *testing.T) { + t.Run("Must return the Model ID and an empty Store "+ + "when importing into an existing store", func(t *testing.T) { + t.Parallel() + clientConfig := fga.ClientConfig{ApiUrl: "https://localhost:8080"} storeData := &storetest.StoreData{} - authorizationModelID := "01HWJGBQQNNQATBQ661SH6585Y" + authorizationModelID := "01HWJGBQQNNQATBQ661SH6585Y002" ioAggregator := importStoreIODependencies{ - importTuples: func(fgaClient client.SdkClient, body client.ClientWriteRequest, maxTuplesPerWrite, maxParallelRequests int) (*tuple.ImportResponse, error) { - return nil, nil + importTuples: func(_ client.SdkClient, _ client.ClientWriteRequest, _, _ int, + ) (*tuple.ImportResponse, error) { + return &tuple.ImportResponse{}, nil }, - modelWrite: func(fgaClient client.SdkClient, inputModel authorizationmodel.AuthzModel) (*client.ClientWriteAuthorizationModelResponse, error) { + modelWrite: func(_ client.SdkClient, _ authorizationmodel.AuthzModel) (*client.ClientWriteAuthorizationModelResponse, error) { return &client.ClientWriteAuthorizationModelResponse{ AuthorizationModelId: authorizationModelID, }, nil }, - createStoreWithModel: func(clientConfig fga.ClientConfig, storeName, inputModel string, inputFormat authorizationmodel.ModelFormat) (*CreateStoreAndModelResponse, error) { + createStoreWithModel: func(_ fga.ClientConfig, _, _ string, _ authorizationmodel.ModelFormat, + ) (*CreateStoreAndModelResponse, error) { return &CreateStoreAndModelResponse{ Model: &client.ClientWriteAuthorizationModelResponse{ AuthorizationModelId: authorizationModelID, @@ -78,26 +94,36 @@ func TestImportStore(t *testing.T) { }, } - // Act - response, err := importStore(clientConfig, storeData, "", "01HWJGBQQHZZJHQEQZ6MCBC3B0", 2, 2, ioAggregator) - + response, err := importStore(clientConfig, + storeData, "", + "01HWJGBQQHZZJHQEQZ6MCBC3B0", + 2, + 2, + ioAggregator, + ) // Assert if err != nil { t.Error(err) } + if response.Store != nil { t.Fatalf("Expected: null\nReturn: %v", response.Store) } + if response.Model.AuthorizationModelId != authorizationModelID { t.Fatalf("expected: %s\nreturned: %s", authorizationModelID, response.Model.AuthorizationModelId) } }) - t.Run("Must returns the modelID, a null store object, and a list of failed/successfully imported tuples when tuples containing unregistered types are provided as input", func(t *testing.T) { + t.Run("Must returns the modelID, a null store object, and a list of "+ + "failed/successfully imported tuples when tuples containing unregistered "+ + "types are provided as input", func(t *testing.T) { + t.Parallel() + clientConfig := fga.ClientConfig{ApiUrl: "https://localhost:8080"} fileName := "./.test-data/failed-store-import-001.fga.yaml" - format, storeData, err := storetest.ReadFromFile(fileName, path.Dir(fileName)) - authorizationModelID := "01HWJGBQQNNQATBQ661SH6585Y" + format, storeData, _ := storetest.ReadFromFile(fileName, path.Dir(fileName)) + authorizationModelID := "01HWJGBQQNNQATBQ661SH6585Y003" successfulTupleImport := storeData.Tuples[0] failedTupleImport := storeData.Tuples[1] @@ -107,7 +133,10 @@ func TestImportStore(t *testing.T) { failedTupleImport.User, ) ioAggregator := importStoreIODependencies{ - importTuples: func(fgaClient client.SdkClient, body client.ClientWriteRequest, maxTuplesPerWrite, maxParallelRequests int) (*tuple.ImportResponse, error) { + importTuples: func(_ client.SdkClient, + _ client.ClientWriteRequest, _, + _ int, + ) (*tuple.ImportResponse, error) { return &tuple.ImportResponse{ Successful: []client.ClientTupleKey{ successfulTupleImport, @@ -120,12 +149,19 @@ func TestImportStore(t *testing.T) { }, }, nil }, - modelWrite: func(fgaClient client.SdkClient, inputModel authorizationmodel.AuthzModel) (*client.ClientWriteAuthorizationModelResponse, error) { + modelWrite: func( + _ client.SdkClient, + _ authorizationmodel.AuthzModel, + ) (*client.ClientWriteAuthorizationModelResponse, error) { return &client.ClientWriteAuthorizationModelResponse{ AuthorizationModelId: authorizationModelID, }, nil }, - createStoreWithModel: func(clientConfig fga.ClientConfig, storeName, inputModel string, inputFormat authorizationmodel.ModelFormat) (*CreateStoreAndModelResponse, error) { + createStoreWithModel: func(_ fga.ClientConfig, + _, + _ string, + _ authorizationmodel.ModelFormat, + ) (*CreateStoreAndModelResponse, error) { return &CreateStoreAndModelResponse{ Model: &client.ClientWriteAuthorizationModelResponse{ AuthorizationModelId: authorizationModelID, @@ -135,22 +171,34 @@ func TestImportStore(t *testing.T) { } // Act - importResponse, err := importStore(clientConfig, storeData, format, "01HWJGBQQHZZJHQEQZ6MCBC3B0", 2, 2, ioAggregator) + importResponse, err := importStore(clientConfig, + storeData, + format, + "01HWJGBQQHZZJHQEQZ6MCBC3B0", + 2, + 2, + ioAggregator, + ) if err != nil { t.Error(err) } + if len(importResponse.Tuple.Successful) != 1 { t.Fatalf("expected: %d\nreturned: %d", 1, len(importResponse.Tuple.Successful)) } + if len(importResponse.Tuple.Failed) != 1 { t.Fatalf("expected: %d\nreturned: %d", 1, len(importResponse.Tuple.Failed)) } + if !reflect.DeepEqual(importResponse.Tuple.Successful[0], successfulTupleImport) { t.Fatalf("expected: %v\nreturned: %v", successfulTupleImport, importResponse.Tuple.Successful[0]) } + if !reflect.DeepEqual(importResponse.Tuple.Failed[0].TupleKey, failedTupleImport) { t.Fatalf("expected: %v\nreturned: %v", failedTupleImport, importResponse.Tuple.Failed[0]) } + if failureReason != importResponse.Tuple.Failed[0].Reason { t.Fatalf("expected: %s\nreturned: %s", failureReason, importResponse.Tuple.Failed[0].Reason) } diff --git a/cmd/tuple/import.go b/cmd/tuple/import.go index 67bfae77..ec635e64 100644 --- a/cmd/tuple/import.go +++ b/cmd/tuple/import.go @@ -43,7 +43,7 @@ type FailedWriteResponse struct { } type ImportResponse struct { - Successful []client.ClientTupleKey `json:"successful,omitemptys"` + Successful []client.ClientTupleKey `json:"successful,omitempty"` Failed []FailedWriteResponse `json:"failed,omitempty"` } From 1ac1a61a4fc840cc6bebafdb5b5cc4a15f6a8c72 Mon Sep 17 00:00:00 2001 From: Edwin Marrima Date: Fri, 3 May 2024 21:15:11 +0200 Subject: [PATCH 3/3] fix: not log when store is provided --- cmd/store/create.go | 2 +- cmd/store/import.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd/store/create.go b/cmd/store/create.go index 4bb7acc9..6cc93071 100644 --- a/cmd/store/create.go +++ b/cmd/store/create.go @@ -32,7 +32,7 @@ import ( ) type CreateStoreAndModelResponse struct { - Store *client.ClientCreateStoreResponse `json:"store"` + Store *client.ClientCreateStoreResponse `json:"store,omitempty"` Model *client.ClientWriteAuthorizationModelResponse `json:"model,omitempty"` } diff --git a/cmd/store/import.go b/cmd/store/import.go index 417e9ec6..be657a3e 100644 --- a/cmd/store/import.go +++ b/cmd/store/import.go @@ -33,6 +33,7 @@ import ( "github.com/openfga/cli/internal/storetest" ) +// importStoreIODependencies defines IO dependencies for importing store type importStoreIODependencies struct { createStoreWithModel func( clientConfig fga.ClientConfig,