Skip to content

Commit

Permalink
chore: adding unit test
Browse files Browse the repository at this point in the history
Part of #7
  • Loading branch information
adriantam committed Jun 28, 2023
1 parent 8fd6093 commit 984d913
Show file tree
Hide file tree
Showing 12 changed files with 3,347 additions and 73 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ jobs:
- name: Build
run: make build

- name: Run unit test
run: make test

release:
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
Expand Down
11 changes: 11 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ linters:
- ifshort
- golint
- nosnakecase
- testpackage
linters-settings:
depguard:
rules:
Expand All @@ -40,10 +41,20 @@ linters-settings:
- "$test"
allow:
- $gostd
- github.com/golang/mock/gomock
- github.com/stretchr
- github.com/openfga/cli
- github.com/openfga/go-sdk

tagliatelle:
case:
use-field-name: true
rules:
json: snake

funlen:
lines: 120
statements: 80

skip-dirs:
- mocks
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ clean:
go clean
rm -f ${BINARY_NAME}

test:
go test -race \
-coverpkg=./... \
-coverprofile=coverageunit.tmp.out \
-covermode=atomic \
-count=1 \
-timeout=5m \
./...
@cat coverageunit.tmp.out | grep -v "mocks" > coverageunit.out
@rm coverageunit.tmp.out

lint:
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest && golangci-lint run

Expand Down
66 changes: 43 additions & 23 deletions cmd/models/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,48 +19,68 @@ import (
"context"
"encoding/json"
"fmt"
"os"

"github.com/openfga/cli/lib/cmd-utils"
"github.com/openfga/cli/lib/fga"
openfga "github.com/openfga/go-sdk"
"github.com/openfga/go-sdk/client"
"github.com/spf13/cobra"
)

func getModel(clientConfig fga.ClientConfig, fgaClient client.SdkClient) (string, error) {
authorizationModelID := clientConfig.AuthorizationModelID

var err error

var model *openfga.ReadAuthorizationModelResponse

if authorizationModelID != "" {
options := client.ClientReadAuthorizationModelOptions{
AuthorizationModelId: openfga.PtrString(authorizationModelID),
}
model, err = fgaClient.ReadAuthorizationModel(context.Background()).Options(options).Execute()
} else {
options := client.ClientReadLatestAuthorizationModelOptions{}
model, err = fgaClient.ReadLatestAuthorizationModel(context.Background()).Options(options).Execute()
}

if err != nil {
fmt.Printf("Failed to get model %v due to %v", clientConfig.AuthorizationModelID, err)

return "", fmt.Errorf("failed to get model %v due to %w", clientConfig.AuthorizationModelID, err)
}

modelJSON, err := json.Marshal(model)
if err != nil {
fmt.Printf("Failed to get model due to %v", err)

return "", fmt.Errorf("failed to get model due to %w", err)
}

return string(modelJSON), nil
}

// getCmd represents the get command.
var getCmd = &cobra.Command{
Use: "get",
Short: "Read a Single Authorization Model",
Run: func(cmd *cobra.Command, args []string) {
RunE: func(cmd *cobra.Command, args []string) error {
clientConfig := cmdutils.GetClientConfig(cmd)

fgaClient, err := clientConfig.GetFgaClient()
if err != nil {
fmt.Printf("Failed to initialize FGA Client due to %v", err)
os.Exit(1)
}
authorizationModelID := clientConfig.AuthorizationModelID

var model *openfga.ReadAuthorizationModelResponse
if authorizationModelID != "" {
options := client.ClientReadAuthorizationModelOptions{
AuthorizationModelId: openfga.PtrString(authorizationModelID),
}
model, err = fgaClient.ReadAuthorizationModel(context.Background()).Options(options).Execute()
} else {
options := client.ClientReadLatestAuthorizationModelOptions{}
model, err = fgaClient.ReadLatestAuthorizationModel(context.Background()).Options(options).Execute()

return fmt.Errorf("failed to initialize FGA Client due to %w", err)
}
output, err := getModel(clientConfig, fgaClient)
if err != nil {
fmt.Printf("Failed to get model %v due to %v", clientConfig.AuthorizationModelID, err)
os.Exit(1)
return err
}

modelJSON, err := json.Marshal(model)
if err != nil {
fmt.Printf("Failed to get model due to %v", err)
os.Exit(1)
}
fmt.Print(string(modelJSON))
fmt.Print(output)

return nil
},
}

Expand Down
115 changes: 115 additions & 0 deletions cmd/models/get_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package models

import (
"context"
"encoding/json"
"errors"
"testing"

"github.com/golang/mock/gomock"
"github.com/openfga/cli/lib/fga"
mock_client "github.com/openfga/cli/mocks"
openfga "github.com/openfga/go-sdk"
"github.com/openfga/go-sdk/client"
)

var errMockGet = errors.New("mock error")

// Test the case where get model is called without auth model ID is not specified.
func TestGetModelNoAuthModelID(t *testing.T) {
t.Parallel()

mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockFgaClient := mock_client.NewMockSdkClient(mockCtrl)

mockExecute := mock_client.NewMockSdkClientReadLatestAuthorizationModelRequestInterface(mockCtrl)

var expectedResponse client.ClientReadAuthorizationModelResponse

modelJSON := `{"authorization_model":{"id":"01GXSA8YR785C4FYS3C0RTG7B1","schema_version":"1.1","type_definitions":[{"relations":{"viewer":{"this":{}}},"type":"github-repo"}]}}` //nolint:all
if err := json.Unmarshal([]byte(modelJSON), &expectedResponse); err != nil {
t.Fatalf("%v", err)
}

mockExecute.EXPECT().Execute().Return(&expectedResponse, nil)

mockRequest := mock_client.NewMockSdkClientReadLatestAuthorizationModelRequestInterface(mockCtrl)
options := client.ClientReadLatestAuthorizationModelOptions{}
mockRequest.EXPECT().Options(options).Return(mockExecute)
mockFgaClient.EXPECT().ReadLatestAuthorizationModel(context.Background()).Return(mockRequest)

var clientConfig fga.ClientConfig

output, err := getModel(clientConfig, mockFgaClient)
if err != nil {
t.Fatalf("%v", err)
} else if output != modelJSON {
t.Fatalf("Expect output %v actual %v", modelJSON, output)
}
}

// Test the case where get model is called without auth model ID is specified.
func TestGetModelAuthModelID(t *testing.T) {
t.Parallel()

mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockFgaClient := mock_client.NewMockSdkClient(mockCtrl)

mockExecute := mock_client.NewMockSdkClientReadAuthorizationModelRequestInterface(mockCtrl)

var expectedResponse client.ClientReadAuthorizationModelResponse

modelJSON := `{"authorization_model":{"id":"01GXSA8YR785C4FYS3C0RTG7B1","schema_version":"1.1","type_definitions":[{"relations":{"viewer":{"this":{}}},"type":"github-repo"}]}}` //nolint:all
if err := json.Unmarshal([]byte(modelJSON), &expectedResponse); err != nil {
t.Fatalf("%v", err)
}

mockExecute.EXPECT().Execute().Return(&expectedResponse, nil)

mockRequest := mock_client.NewMockSdkClientReadAuthorizationModelRequestInterface(mockCtrl)
options := client.ClientReadAuthorizationModelOptions{
AuthorizationModelId: openfga.PtrString("01GXSA8YR785C4FYS3C0RTG7B1"),
}
mockRequest.EXPECT().Options(options).Return(mockExecute)
mockFgaClient.EXPECT().ReadAuthorizationModel(context.Background()).Return(mockRequest)

clientConfig := fga.ClientConfig{
AuthorizationModelID: "01GXSA8YR785C4FYS3C0RTG7B1",
}

output, err := getModel(clientConfig, mockFgaClient)
if err != nil {
t.Fatalf("%v", err)
} else if output != modelJSON {
t.Fatalf("Expect output %v actual %v", modelJSON, output)
}
}

// Test the case where get model is called, but it returns error.
func TestGetModelNoAuthModelIDError(t *testing.T) {
t.Parallel()

mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
mockFgaClient := mock_client.NewMockSdkClient(mockCtrl)

mockExecute := mock_client.NewMockSdkClientReadLatestAuthorizationModelRequestInterface(mockCtrl)

var expectedResponse client.ClientReadAuthorizationModelResponse

mockExecute.EXPECT().Execute().Return(&expectedResponse, errMockGet)

mockRequest := mock_client.NewMockSdkClientReadLatestAuthorizationModelRequestInterface(mockCtrl)
options := client.ClientReadLatestAuthorizationModelOptions{}
mockRequest.EXPECT().Options(options).Return(mockExecute)
mockFgaClient.EXPECT().ReadLatestAuthorizationModel(context.Background()).Return(mockRequest)

var clientConfig fga.ClientConfig

_, err := getModel(clientConfig, mockFgaClient)
if err == nil {
t.Fatalf("Expect error but there is none")
}
}
82 changes: 51 additions & 31 deletions cmd/models/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"context"
"encoding/json"
"fmt"
"os"

"github.com/openfga/cli/lib/cmd-utils"
openfga "github.com/openfga/go-sdk"
Expand All @@ -30,51 +29,72 @@ import (
// MaxModelsPagesLength Limit the models so that we are not paginating indefinitely.
var MaxModelsPagesLength = 20

func listModels(fgaClient client.SdkClient, maxPages int) (string, error) {
// This is needed to ensure empty array is marshaled as [] instead of nil
models := make([]openfga.AuthorizationModel, 0)

var continuationToken *string

pageIndex := 0

for {
options := client.ClientReadAuthorizationModelsOptions{
ContinuationToken: continuationToken,
}

response, err := fgaClient.ReadAuthorizationModels(context.Background()).Options(options).Execute()
if err != nil {
fmt.Printf("XXX Failed to list models due to %v", err)

return "", fmt.Errorf("xxx failed to list models due to %w", err)
}

models = append(models, *response.AuthorizationModels...)

pageIndex++

continuationToken = response.ContinuationToken

if continuationToken == nil || pageIndex > maxPages {
break
}
}

modelsJSON, err := json.Marshal(openfga.ReadAuthorizationModelsResponse{AuthorizationModels: &models})
if err != nil {
fmt.Printf("Failed to marshal listed models due to %v", err)

return "", fmt.Errorf("failed to marshal listed models due to %w", err)
}

return string(modelsJSON), nil
}

// listCmd represents the list command.
var listCmd = &cobra.Command{
Use: "list",
Short: "Read Authorization Models",
Run: func(cmd *cobra.Command, args []string) {
RunE: func(cmd *cobra.Command, args []string) error {
clientConfig := cmdutils.GetClientConfig(cmd)
fgaClient, err := clientConfig.GetFgaClient()
if err != nil {
fmt.Printf("Failed to initialize FGA Client due to %v", err)
os.Exit(1)

return fmt.Errorf("failed to intialized FGA client due to %w", err)
}
maxPages, err := cmd.Flags().GetInt("max-pages")
if err != nil {
fmt.Printf("Failed to list models due to %v", err)
os.Exit(1)
}
models := []openfga.AuthorizationModel{}
var continuationToken *string
pageIndex := 0
for {
options := client.ClientReadAuthorizationModelsOptions{
ContinuationToken: continuationToken,
}
response, err := fgaClient.ReadAuthorizationModels(context.Background()).Options(options).Execute()
if err != nil {
fmt.Printf("Failed to list models due to %v", err)
os.Exit(1)
}

models = append(models, *response.AuthorizationModels...)

pageIndex++
if continuationToken == nil || pageIndex > maxPages {
break
}

continuationToken = response.ContinuationToken
}

modelsJSON, err := json.Marshal(openfga.ReadAuthorizationModelsResponse{AuthorizationModels: &models})
return fmt.Errorf("failed to list models due to %w", err)
}
output, err := listModels(fgaClient, maxPages)
if err != nil {
fmt.Printf("Failed to list models due to %v", err)
os.Exit(1)
return err
}
fmt.Print(string(modelsJSON))
fmt.Print(output)

return nil
},
}

Expand Down
Loading

0 comments on commit 984d913

Please sign in to comment.