Skip to content
Open
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
6 changes: 6 additions & 0 deletions cmd/doctor/doctor_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ func authLine(out string) string {

func TestDoctorCmd_AuthFailsWhenCredentialIsRefused(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
setHome(t, t.TempDir())
t.Setenv("KH_HOST", "") // ResolveHost reads it ahead of the factory's DefaultHost.
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
if r.URL.Path == khhttp.CredentialProbePath {
Expand All @@ -55,6 +57,8 @@ func TestDoctorCmd_AuthFailsWhenCredentialIsRefused(t *testing.T) {

func TestDoctorCmd_AuthPassesWhenCredentialIsAccepted(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
setHome(t, t.TempDir())
t.Setenv("KH_HOST", "") // ResolveHost reads it ahead of the factory's DefaultHost.
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
Expand All @@ -71,6 +75,8 @@ func TestDoctorCmd_AuthPassesWhenCredentialIsAccepted(t *testing.T) {

func TestDoctorCmd_AuthDoesNotProbeTheAnonymousTolerantEndpoint(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
setHome(t, t.TempDir())
t.Setenv("KH_HOST", "") // ResolveHost reads it ahead of the factory's DefaultHost.
// Doctor fans its checks out across goroutines, so the handler runs
// concurrently and the record of seen paths has to be guarded.
var mu sync.Mutex
Expand Down
43 changes: 32 additions & 11 deletions cmd/doctor/doctor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ func newDoctorFactory(ios *iostreams.IOStreams, svr *httptest.Server) *cmdutil.F
// all 6 check names appear in output and the command exits 0.
func TestDoctorCmd_AllPass(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
t.Setenv("HOME", t.TempDir())
setHome(t, t.TempDir())
t.Setenv("KH_HOST", "") // ResolveHost reads it ahead of the factory's DefaultHost.
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
switch r.URL.Path {
Expand Down Expand Up @@ -85,7 +86,8 @@ func TestDoctorCmd_AllPass(t *testing.T) {
// TestDoctorCmd_OneFail verifies that a failing check causes a non-zero exit.
func TestDoctorCmd_OneFail(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
t.Setenv("HOME", t.TempDir())
setHome(t, t.TempDir())
t.Setenv("KH_HOST", "") // ResolveHost reads it ahead of the factory's DefaultHost.

svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
Expand Down Expand Up @@ -122,7 +124,8 @@ func TestDoctorCmd_OneFail(t *testing.T) {
// TestDoctorCmd_WarnOnly verifies that warnings alone yield exit 0.
func TestDoctorCmd_WarnOnly(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
t.Setenv("HOME", t.TempDir())
setHome(t, t.TempDir())
t.Setenv("KH_HOST", "") // ResolveHost reads it ahead of the factory's DefaultHost.

svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
Expand Down Expand Up @@ -162,7 +165,8 @@ func TestDoctorCmd_WarnOnly(t *testing.T) {
// TestDoctorCmd_JSON verifies --json outputs a JSON array with exactly 6 objects.
func TestDoctorCmd_JSON(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
t.Setenv("HOME", t.TempDir())
setHome(t, t.TempDir())
t.Setenv("KH_HOST", "") // ResolveHost reads it ahead of the factory's DefaultHost.

svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
Expand Down Expand Up @@ -208,7 +212,8 @@ func TestDoctorCmd_Timeout(t *testing.T) {
t.Skip("skipping timeout test in short mode")
}
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
t.Setenv("HOME", t.TempDir())
setHome(t, t.TempDir())
t.Setenv("KH_HOST", "") // ResolveHost reads it ahead of the factory's DefaultHost.

svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
Expand Down Expand Up @@ -247,7 +252,8 @@ func TestDoctorCmd_Timeout(t *testing.T) {
// TestDoctorCmd_Output verifies all 6 check names appear in non-JSON output.
func TestDoctorCmd_Output(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
t.Setenv("HOME", t.TempDir())
setHome(t, t.TempDir())
t.Setenv("KH_HOST", "") // ResolveHost reads it ahead of the factory's DefaultHost.

svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
Expand Down Expand Up @@ -281,7 +287,8 @@ func TestDoctorCmd_NoLocalJSONFlag(t *testing.T) {
// TestDoctorCmd_ExitCodeOnFail verifies SilentError is returned on [fail] checks.
func TestDoctorCmd_ExitCodeOnFail(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
t.Setenv("HOME", t.TempDir())
setHome(t, t.TempDir())
t.Setenv("KH_HOST", "") // ResolveHost reads it ahead of the factory's DefaultHost.

svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
Expand Down Expand Up @@ -333,14 +340,28 @@ func walletServer(t *testing.T, userBody string) *httptest.Server {
}))
}

// setHome points the home directory at home for the duration of the test.
// os.UserHomeDir reads $HOME on Unix but %USERPROFILE% on Windows, so a
// fixture that sets only HOME leaves the real profile in play on Windows.
func setHome(t *testing.T, home string) {
t.Helper()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
}

func runDoctor(t *testing.T, svr *httptest.Server) string {
t.Helper()
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
// Cleared unconditionally. ResolveHost reads KH_HOST ahead of the factory's
// DefaultHost, so an exported KH_HOST sends these checks to the live host
// instead of svr. That is unrelated to the temporary profile below, so it
// does not belong behind KH_TEST_KEEP_HOME.
t.Setenv("KH_HOST", "")
// HOME too: the agentic check resolves ~/.keeperhub/wallet.json through
// os.UserHomeDir, so without this the suite reads a real credential off the
// developer's machine and signs a live request with it.
if os.Getenv("KH_TEST_KEEP_HOME") == "" {
t.Setenv("HOME", t.TempDir())
setHome(t, t.TempDir())
}
ios, outBuf, _, _ := iostreams.Test()
tc := doctor.NewTestableCmd(newDoctorFactory(ios, svr))
Expand Down Expand Up @@ -389,7 +410,7 @@ func agenticWallet(t *testing.T) (secret, subOrg, addr string) {
t.Helper()
secret, subOrg, addr = "s3cr3t-test-key", "sub_abc123", "0xABCD1234EF567890ABCD1234EF567890ABCD1234"
home := t.TempDir()
t.Setenv("HOME", home)
setHome(t, home)
t.Setenv("KH_TEST_KEEP_HOME", "1")
require.NoError(t, os.MkdirAll(filepath.Join(home, ".keeperhub"), 0o700))
body := `{"subOrgId":"` + subOrg + `","walletAddress":"` + addr + `","hmacSecret":"` + secret + `"}`
Expand Down Expand Up @@ -461,7 +482,7 @@ func TestDoctorCmd_AgenticWalletRejectedSignature(t *testing.T) {
}

func TestDoctorCmd_AgenticWalletNotConfigured(t *testing.T) {
t.Setenv("HOME", t.TempDir())
setHome(t, t.TempDir())
svr := walletServer(t, `{"walletAddress":"0xABC"}`)
defer svr.Close()

Expand Down Expand Up @@ -536,7 +557,7 @@ func TestDoctorCmd_AgenticUnknownSubOrgIsActionable(t *testing.T) {

// Absent is the normal state on most installs, so it must not warn.
func TestDoctorCmd_AgenticNotConfiguredIsNotAWarning(t *testing.T) {
t.Setenv("HOME", t.TempDir())
setHome(t, t.TempDir())
svr := walletServer(t, `{"walletAddress":"0xABC"}`)
defer svr.Close()

Expand Down
8 changes: 8 additions & 0 deletions cmd/doctor/doctor_version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ func versionDoctorFactory(ios *iostreams.IOStreams, appVersion, minimumHeader st

func TestDoctorCmd_CLIVersionPassesWhenServerAdvertisesNoMinimum(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
setHome(t, t.TempDir())
t.Setenv("KH_HOST", "") // ResolveHost reads it ahead of the factory's DefaultHost.
ios, outBuf, _, _ := iostreams.Test()
tc := doctor.NewTestableCmd(versionDoctorFactory(ios, "1.2.3", ""))
require.NoError(t, tc.Execute([]string{}))
Expand All @@ -70,6 +72,8 @@ func TestDoctorCmd_CLIVersionPassesWhenServerAdvertisesNoMinimum(t *testing.T) {

func TestDoctorCmd_CLIVersionWarnsWhenBelowServerMinimum(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
setHome(t, t.TempDir())
t.Setenv("KH_HOST", "") // ResolveHost reads it ahead of the factory's DefaultHost.
ios, outBuf, _, _ := iostreams.Test()
tc := doctor.NewTestableCmd(versionDoctorFactory(ios, "0.3.0", "0.11.1"))
require.NoError(t, tc.Execute([]string{}))
Expand All @@ -83,6 +87,8 @@ func TestDoctorCmd_CLIVersionWarnsWhenBelowServerMinimum(t *testing.T) {

func TestDoctorCmd_CLIVersionPassesWhenAtServerMinimum(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
setHome(t, t.TempDir())
t.Setenv("KH_HOST", "") // ResolveHost reads it ahead of the factory's DefaultHost.
ios, outBuf, _, _ := iostreams.Test()
tc := doctor.NewTestableCmd(versionDoctorFactory(ios, "0.11.1", "0.11.1"))
require.NoError(t, tc.Execute([]string{}))
Expand All @@ -94,6 +100,8 @@ func TestDoctorCmd_CLIVersionPassesWhenAtServerMinimum(t *testing.T) {

func TestDoctorCmd_CLIVersionReportsDevBuildWithoutComparing(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
setHome(t, t.TempDir())
t.Setenv("KH_HOST", "") // ResolveHost reads it ahead of the factory's DefaultHost.
ios, outBuf, _, _ := iostreams.Test()
// A minimum far above any real release: if dev builds were compared,
// this would incorrectly warn.
Expand Down
13 changes: 11 additions & 2 deletions internal/agentic/wallet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,19 @@ func TestSign_EveryFieldIsBound(t *testing.T) {
}
}

// setHome points the home directory at home for the duration of the test.
// os.UserHomeDir reads $HOME on Unix but %USERPROFILE% on Windows, so a
// fixture that sets only HOME leaves the real profile in play on Windows.
func setHome(t *testing.T, home string) {
t.Helper()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
}

func writeWallet(t *testing.T, body string) {
t.Helper()
home := t.TempDir()
t.Setenv("HOME", home)
setHome(t, home)
require.NoError(t, os.MkdirAll(filepath.Join(home, ".keeperhub"), 0o700))
require.NoError(t, os.WriteFile(
filepath.Join(home, ".keeperhub", agentic.ConfigName), []byte(body), 0o600,
Expand All @@ -70,7 +79,7 @@ func TestLoad_ReadsTheWallet(t *testing.T) {
}

func TestLoad_MissingFileIsNotConfigured(t *testing.T) {
t.Setenv("HOME", t.TempDir())
setHome(t, t.TempDir())

_, err := agentic.Load()

Expand Down
Loading