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
44 changes: 42 additions & 2 deletions cli/cmd/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ func TestResolveContext(t *testing.T) {
// holding a config whose only context, lab, points at a fake API. It returns
// the output, the exit code, and how many requests reached the API.
func runKatesCLI(t *testing.T, env []string, args ...string) (out string, code int, requests int64) {
t.Helper()
return runKatesCLIConfig(t, func(apiURL string) string {
return "current-context: lab\ncontexts:\n lab:\n url: " + apiURL + "\n"
}, env, args...)
}

// runKatesCLIConfig is runKatesCLI with the config file config writes for the
// fake API's URL.
func runKatesCLIConfig(t *testing.T, config func(apiURL string) string, env []string, args ...string) (out string, code int, requests int64) {
t.Helper()
var hits atomic.Int64
api := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -81,8 +90,7 @@ func runKatesCLI(t *testing.T, env []string, args ...string) (out string, code i
t.Cleanup(api.Close)

home := t.TempDir()
config := "current-context: lab\ncontexts:\n lab:\n url: " + api.URL + "\n"
if err := os.WriteFile(filepath.Join(home, ".kates.yaml"), []byte(config), 0o600); err != nil {
if err := os.WriteFile(filepath.Join(home, ".kates.yaml"), []byte(config(api.URL)), 0o600); err != nil {
t.Fatal(err)
}

Expand Down Expand Up @@ -127,6 +135,38 @@ func TestUnknownContextReachesNoServer(t *testing.T) {
}
}

// A config kates could not parse used to send every command to
// http://localhost:8080, whatever answered there, without the API key of the
// context the file names.
func TestUnreadableConfigReachesNoServer(t *testing.T) {
broken := func(apiURL string) string {
return "current-context: lab\ncontexts:\n lab:\n url: " + apiURL + "\n [unclosed\n"
}
out, code, requests := runKatesCLIConfig(t, broken, nil, "health")
if code != 1 || requests != 0 {
t.Errorf("exit %d after %d requests, want 1 after none:\n%s", code, requests, out)
}
if !strings.Contains(out, "could not load config") || !strings.Contains(out, ".kates.yaml") {
t.Errorf("the error does not name the config file:\n%s", out)
}

// --url and KATES_URL name the server themselves.
var hits atomic.Int64
other := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
hits.Add(1)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"items":[],"page":0,"size":100,"total":0,"totalPages":0,"count":0}`))
}))
t.Cleanup(other.Close)
if out, code, _ := runKatesCLIConfig(t, broken, nil, "--url", other.URL, "test", "list"); code != 0 || hits.Load() == 0 {
t.Errorf("--url: exit %d after %d requests, want 0 after some:\n%s", code, hits.Load(), out)
}
hits.Store(0)
if out, code, _ := runKatesCLIConfig(t, broken, []string{"KATES_URL=" + other.URL}, "test", "list"); code != 0 || hits.Load() == 0 {
t.Errorf("KATES_URL: exit %d after %d requests, want 0 after some:\n%s", code, hits.Load(), out)
}
}

// Commands that never call the API still run, so a context can be created
// while KATES_CONTEXT already names it.
func TestUnknownContextCanBeCreated(t *testing.T) {
Expand Down
16 changes: 14 additions & 2 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,18 @@ func configPath() string {
}

func loadConfig() Config {
cfg, _ := loadConfigErr()
return cfg
}

// loadConfigErr is loadConfig, also returning the error it warned about.
func loadConfigErr() (Config, error) {
cfg, err := readConfig()
if err != nil && !configWarned {
fmt.Fprintf(os.Stderr, "Warning: could not load config %s: %v\n", configPath(), err)
configWarned = true
}
return cfg
return cfg, err
}

// configWarned keeps loadConfig's warning to one a process: the help function
Expand Down Expand Up @@ -492,7 +498,7 @@ var rootCmd = &cobra.Command{
}
}
readContextEnv()
cfg := loadConfig()
cfg, cfgErr := loadConfigErr()
ctxName, ctx, ctxErr := resolveContext(cfg)
profiles, profilesFrom := activeProfiles(ctxName, ctx)
urlOverridden := apiURL != ""
Expand All @@ -503,6 +509,12 @@ var rootCmd = &cobra.Command{
apiURL = ctx.URL
}
}
// A file kates could not read or parse used to leave it on the
// built-in http://localhost:8080, without the API key of the context
// the file names, so its requests went to whatever answered there.
if cfgErr != nil && !urlOverridden {
ctxErr = fmt.Errorf("could not load config %s: %w. Fix the file, or pass --url or set KATES_URL", configPath(), cfgErr)
}
activeContext = ctxName
activeProfileNames, activeProfilesFrom = profiles, profilesFrom
apiURLOverridden = urlOverridden
Expand Down
Loading