Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: adding unit test #25

Merged
merged 3 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
62 changes: 38 additions & 24 deletions cmd/models/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,48 +19,62 @@ 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 {
return "", fmt.Errorf("failed to get model %v due to %w", clientConfig.AuthorizationModelID, err)
}

modelJSON, err := json.Marshal(model)
if err != nil {
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")
}
}
78 changes: 45 additions & 33 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,64 @@ 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 {
return "", fmt.Errorf("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 {
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
return fmt.Errorf("failed to list models due to %w", err)
}

modelsJSON, err := json.Marshal(openfga.ReadAuthorizationModelsResponse{AuthorizationModels: &models})
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
Loading