Skip to content
This repository was archived by the owner on Feb 25, 2026. It is now read-only.

Commit 381c88a

Browse files
committed
Enhancements for consistency and clarity
1 parent 2e83f48 commit 381c88a

1 file changed

Lines changed: 74 additions & 49 deletions

File tree

internal/cmd/fga.go

Lines changed: 74 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,15 @@ import (
2525
const (
2626
ResourceSeparator = ":"
2727
RelationSeparator = "#"
28+
29+
TestFileExtensionJSON = ".test.json"
30+
TestFileExtensionYAML = ".test.yaml"
31+
TestFileExtensionYML = ".test.yml"
2832
)
2933

3034
var resourceTypesFile string
35+
var AcceptedTestFileExtensions = []string{TestFileExtensionJSON, TestFileExtensionYAML, TestFileExtensionYML}
36+
var AcceptedTestFileExtensionErrorMessage = fmt.Sprintf("Accepted test file extensions are: %s", strings.Join(AcceptedTestFileExtensions, ", "))
3137

3238
func init() {
3339
// resource-types
@@ -810,55 +816,66 @@ var applySchemaCmd = &cobra.Command{
810816
}
811817

812818
// Test spec types
813-
type warrants struct {
819+
820+
type WarrantSetup struct {
814821
Subject string `yaml:"subject" json:"subject"`
815822
Relation string `yaml:"relation" json:"relation"`
816823
Resource string `yaml:"resource" json:"resource"`
817824
Policy string `yaml:"policy,omitempty" json:"policy,omitempty"`
818825
}
819826

820-
type setupSection struct {
821-
Warrants []warrants `yaml:"warrants" json:"warrants"`
827+
type FGATestSetupSection struct {
828+
Warrants []WarrantSetup `yaml:"warrants" json:"warrants"`
822829
}
823830

824-
type testCheck struct {
831+
type FGATestCheck struct {
825832
Subject string `yaml:"subject" json:"subject"`
826833
Relation string `yaml:"relation" json:"relation"`
827834
Resource string `yaml:"resource" json:"resource"`
828835
Context map[string]interface{} `yaml:"context,omitempty" json:"context,omitempty"`
829836
}
830837

831-
type testCase struct {
832-
Name string `yaml:"name" json:"name"`
833-
Check testCheck `yaml:"check" json:"check"`
834-
Expect bool `yaml:"expect" json:"expect"`
838+
type FGATestCase struct {
839+
Name string `yaml:"name" json:"name"`
840+
Check FGATestCheck `yaml:"check" json:"check"`
841+
Expect bool `yaml:"expect" json:"expect"`
842+
}
843+
844+
type FGATestTeardownSection struct {
845+
Warrants []WarrantSetup `yaml:"warrants" json:"warrants"`
846+
Resources []string `yaml:"resources" json:"resources"`
835847
}
836848

837-
type teardownSection struct {
838-
Warrants []warrants `yaml:"warrants" json:"warrants"`
839-
Resources []string `yaml:"resources" json:"resources"`
849+
type FGATestYaml struct {
850+
Setup FGATestSetupSection `yaml:"setup" json:"setup"`
851+
Tests []FGATestCase `yaml:"tests" json:"tests"`
852+
Teardown *FGATestTeardownSection `yaml:"teardown,omitempty" json:"teardown,omitempty"`
840853
}
841854

842-
type testYaml struct {
843-
Setup setupSection `yaml:"setup" json:"setup"`
844-
Tests []testCase `yaml:"tests" json:"tests"`
845-
Teardown *teardownSection `yaml:"teardown,omitempty" json:"teardown,omitempty"`
855+
type FGATestResult struct {
856+
Passed bool
857+
NumPassed int
858+
NumTotal int
846859
}
847860

848-
func parseTestFile(testFile string) (testYaml, error) {
849-
var testSpec testYaml
861+
func parseTestFile(testFile string) (FGATestYaml, error) {
862+
var testSpec FGATestYaml
850863
bytes, err := os.ReadFile(testFile)
851864
if err != nil {
852865
return testSpec, errors.Wrap(err, "failed to read test file")
853866
}
854-
ext := filepath.Ext(testFile)
855-
switch ext {
856-
case ".yaml", ".yml":
867+
868+
if !isTestFile(testFile) {
869+
return testSpec, errors.Errorf("invalid test file format. %s", AcceptedTestFileExtensionErrorMessage)
870+
}
871+
872+
switch {
873+
case strings.HasSuffix(testFile, TestFileExtensionYAML), strings.HasSuffix(testFile, TestFileExtensionYML):
857874
err = yaml.Unmarshal(bytes, &testSpec)
858-
case ".json":
875+
case strings.HasSuffix(testFile, TestFileExtensionJSON):
859876
err = json.Unmarshal(bytes, &testSpec)
860877
default:
861-
return testSpec, errors.Errorf("unsupported test file extension: %s (must be .yaml, .yml, or .json)", ext)
878+
return testSpec, errors.New("failed to parse test file: " + AcceptedTestFileExtensionErrorMessage)
862879
}
863880
if err != nil {
864881
return testSpec, errors.Wrap(err, "failed to parse test file")
@@ -874,7 +891,7 @@ func parseTestFile(testFile string) (testYaml, error) {
874891
return testSpec, nil
875892
}
876893

877-
func setupWarrants(setup setupSection) (string, error) {
894+
func setupTestWarrants(setup FGATestSetupSection) (string, error) {
878895
batchWrites := make([]fga.WriteWarrantOpts, 0, len(setup.Warrants))
879896
for _, w := range setup.Warrants {
880897
subjectType, subjectIdRelation, valid := strings.Cut(w.Subject, ResourceSeparator)
@@ -909,13 +926,7 @@ func setupWarrants(setup setupSection) (string, error) {
909926
return "", nil
910927
}
911928

912-
type TestResult struct {
913-
Passed bool
914-
NumPassed int
915-
NumTotal int
916-
}
917-
918-
func runTestCases(tests []testCase, warrantToken string) (TestResult, error) {
929+
func runTestCases(tests []FGATestCase, warrantToken string) (FGATestResult, error) {
919930
allPassed := true
920931
passed := 0
921932
total := len(tests)
@@ -964,10 +975,10 @@ func runTestCases(tests []testCase, warrantToken string) (TestResult, error) {
964975
allPassed = false
965976
}
966977
}
967-
return TestResult{Passed: allPassed, NumPassed: passed, NumTotal: total}, nil
978+
return FGATestResult{Passed: allPassed, NumPassed: passed, NumTotal: total}, nil
968979
}
969980

970-
func teardown(teardown *teardownSection) error {
981+
func teardownTest(teardown *FGATestTeardownSection) error {
971982
if teardown == nil {
972983
return nil
973984
}
@@ -1018,7 +1029,7 @@ func teardown(teardown *teardownSection) error {
10181029
return nil
10191030
}
10201031

1021-
func cleanupResources(cmd *cobra.Command, setup setupSection) error {
1032+
func cleanupTestResources(cmd *cobra.Command, setup FGATestSetupSection) error {
10221033
cleanupResources, err := cmd.Flags().GetBool("cleanup")
10231034
if err != nil {
10241035
return errors.Wrap(err, "failed to get cleanup flag")
@@ -1047,62 +1058,76 @@ func cleanupResources(cmd *cobra.Command, setup setupSection) error {
10471058
return nil
10481059
}
10491060

1050-
func runTestFile(cmd *cobra.Command, testFile string) (TestResult, error) {
1061+
func runTestFile(cmd *cobra.Command, testFile string) (FGATestResult, error) {
10511062
testSpec, err := parseTestFile(testFile)
10521063
if err != nil {
1053-
return TestResult{}, err
1064+
return FGATestResult{}, err
10541065
}
1055-
warrantToken, err := setupWarrants(testSpec.Setup)
1066+
warrantToken, err := setupTestWarrants(testSpec.Setup)
10561067
if err != nil {
10571068
printer.PrintMsg(printer.RedText(printer.Cross, err.Error()))
1058-
return TestResult{}, err
1069+
return FGATestResult{}, err
10591070
}
10601071
result, err := runTestCases(testSpec.Tests, warrantToken)
10611072
if err != nil {
10621073
return result, err
10631074
}
1064-
if err := teardown(testSpec.Teardown); err != nil {
1075+
if err := teardownTest(testSpec.Teardown); err != nil {
10651076
return result, err
10661077
}
1067-
if err := cleanupResources(cmd, testSpec.Setup); err != nil {
1078+
if err := cleanupTestResources(cmd, testSpec.Setup); err != nil {
10681079
return result, err
10691080
}
10701081
return result, nil
10711082
}
10721083

1073-
func runTestDirectory(cmd *cobra.Command, path string) (TestResult, error) {
1084+
func isTestFile(fileName string) bool {
1085+
for _, extToCheck := range AcceptedTestFileExtensions {
1086+
if strings.HasSuffix(fileName, extToCheck) {
1087+
return true
1088+
}
1089+
}
1090+
1091+
return false
1092+
}
1093+
1094+
func runTestDirectory(cmd *cobra.Command, path string) (FGATestResult, error) {
10741095
entries, err := os.ReadDir(path)
10751096
if err != nil {
1076-
return TestResult{}, errors.Wrap(err, "failed to read directory")
1097+
return FGATestResult{}, errors.Wrap(err, "failed to read directory")
10771098
}
10781099
var testFiles []string
10791100
for _, entry := range entries {
10801101
if entry.IsDir() {
10811102
continue
10821103
}
10831104
name := entry.Name()
1084-
if strings.HasSuffix(name, ".test.yaml") || strings.HasSuffix(name, ".test.yml") || strings.HasSuffix(name, ".test.json") {
1105+
if isTestFile(name) {
10851106
testFiles = append(testFiles, filepath.Join(path, name))
10861107
}
10871108
}
10881109
if len(testFiles) == 0 {
1089-
printer.PrintMsg("No test files found in directory. Make sure to name your test files with the .test.yaml, .test.yml, or .test.json extension.")
1090-
return TestResult{Passed: true, NumPassed: 0, NumTotal: 0}, nil
1110+
printer.PrintMsg("No test files found in directory. " + AcceptedTestFileExtensionErrorMessage)
1111+
return FGATestResult{Passed: true, NumPassed: 0, NumTotal: 0}, nil
10911112
}
1092-
finalResult := TestResult{Passed: true, NumPassed: 0, NumTotal: 0}
1113+
1114+
finalResult := FGATestResult{Passed: true, NumPassed: 0, NumTotal: 0}
10931115
for _, file := range testFiles {
10941116
printer.PrintMsg("")
10951117
printer.PrintMsg("Running tests in " + file)
10961118
result, err := runTestFile(cmd, file)
1119+
10971120
finalResult.NumPassed += result.NumPassed
10981121
finalResult.NumTotal += result.NumTotal
1122+
10991123
if err != nil {
11001124
printer.PrintMsg(printer.RedText(printer.Cross, err.Error()))
11011125
finalResult.Passed = false
11021126
} else if !result.Passed {
11031127
finalResult.Passed = false
11041128
}
11051129
}
1130+
11061131
printer.PrintMsg("")
11071132
if finalResult.Passed {
11081133
printer.PrintMsg(fmt.Sprintf("All tests passed (%d/%d)", finalResult.NumPassed, finalResult.NumTotal))
@@ -1114,9 +1139,9 @@ func runTestDirectory(cmd *cobra.Command, path string) (TestResult, error) {
11141139
}
11151140

11161141
var testCmd = &cobra.Command{
1117-
Use: "test <test_file.yaml|json|directory>",
1118-
Short: "Run FGA permission tests from a YAML/JSON file or all test files in a directory",
1119-
Long: `Run FGA permission tests from a YAML or JSON file, or all .test.yaml/.test.json files in a directory, setting up and tearing down warrants and resources as specified.
1142+
Use: "test <test_file.test.yaml|json|directory>",
1143+
Short: "Run FGA permission tests from a YAML/JSON file or all test files in a directory",
1144+
Long: `Run FGA permission tests from a YAML or JSON file, or all .test.yaml/.test.json files in a directory, setting up and tearing down warrants and resources as specified.
11201145
11211146
Test file format (YAML or JSON):
11221147
@@ -1160,7 +1185,7 @@ JSON:
11601185
11611186
Each test file must have a 'setup' section, a 'tests' array, and an optional 'teardown' section.
11621187
`,
1163-
Example: "workos fga test ./tests.yaml --cleanup\nworkos fga test ./tests.json --cleanup\nworkos fga test ./test-directory/ --cleanup",
1188+
Example: "workos fga test ./schema.test.yaml --cleanup\nworkos fga test ./schema.test.json --cleanup\nworkos fga test ./test-directory/ --cleanup",
11641189
Args: cobra.ExactArgs(1),
11651190
RunE: func(cmd *cobra.Command, args []string) error {
11661191
path := args[0]

0 commit comments

Comments
 (0)