Skip to content
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
26 changes: 26 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,32 @@ func TestExample(t *testing.T) {
}
```

**Exception: Tests using `t.Setenv()`**

Tests that use `t.Setenv()` to set environment variables **cannot use `t.Parallel()`** on the parent test function. The Go testing framework enforces this restriction because environment variable changes affect the entire process.

```go
// CORRECT: No t.Parallel() when using t.Setenv()
func TestWithEnvVariable(t *testing.T) {
t.Run("subtest with env var", func(t *testing.T) {
t.Setenv("MY_VAR", "value")
// Test code here...
})
}

// INCORRECT: Will panic at runtime
func TestWithEnvVariable(t *testing.T) {
t.Parallel() // ❌ WRONG - cannot use with t.Setenv()

t.Run("subtest with env var", func(t *testing.T) {
t.Setenv("MY_VAR", "value")
// Test code here...
})
}
```

**Reference:** See `pkg/cmd/root_test.go:TestRootCmd_StorageEnvVariable()` for an example of testing with environment variables.

### Testing with Fake Objects

When testing code that uses interfaces (following the Module Design Pattern), **use fake implementations instead of real implementations or mocks**.
Expand Down
65 changes: 65 additions & 0 deletions pkg/cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,68 @@ func TestRootCmd_StorageFlagMissingValue(t *testing.T) {
t.Errorf("Expected error message to contain 'flag' or 'argument', got: %s", errMsg)
}
}

func TestRootCmd_StorageEnvVariable(t *testing.T) {
t.Run("env variable sets default", func(t *testing.T) {
// Set the environment variable
envPath := filepath.Join(t.TempDir(), "from-env")
t.Setenv("KORTEX_CLI_STORAGE", envPath)

rootCmd := NewRootCmd()
flag := rootCmd.PersistentFlags().Lookup("storage")
if flag == nil {
t.Fatal("Expected --storage flag to exist")
}

// Verify the default value is from the environment variable
if flag.DefValue != envPath {
t.Errorf("Expected default value to be '%s' (from env var), got '%s'", envPath, flag.DefValue)
}
})

t.Run("flag overrides env variable", func(t *testing.T) {
// Set the environment variable
envPath := filepath.Join(t.TempDir(), "from-env")
t.Setenv("KORTEX_CLI_STORAGE", envPath)

rootCmd := NewRootCmd()
buf := new(bytes.Buffer)
rootCmd.SetOut(buf)
rootCmd.SetErr(buf)

// Set the flag explicitly
flagPath := filepath.Join(t.TempDir(), "from-flag")
rootCmd.SetArgs([]string{"--storage", flagPath, "version"})

// Execute the command
if err := rootCmd.Execute(); err != nil {
t.Fatalf("Execute() failed: %v", err)
}

// Verify the flag value overrides the env var
storagePath, err := rootCmd.PersistentFlags().GetString("storage")
if err != nil {
t.Fatalf("Failed to get storage flag: %v", err)
}

if storagePath != flagPath {
t.Errorf("Expected storage to be '%s' (from flag), got '%s'", flagPath, storagePath)
}
})

t.Run("default used when env var not set", func(t *testing.T) {
// Explicitly unset the environment variable (in case it was set in the shell)
t.Setenv("KORTEX_CLI_STORAGE", "")

rootCmd := NewRootCmd()
flag := rootCmd.PersistentFlags().Lookup("storage")
if flag == nil {
t.Fatal("Expected --storage flag to exist")
}

// Verify the default value ends with .kortex-cli
if !strings.HasSuffix(flag.DefValue, ".kortex-cli") {
t.Errorf("Expected default value to end with '.kortex-cli', got '%s'", flag.DefValue)
}
})
}