test: #104 set USERPROFILE alongside HOME in the doctor and agentic fixtures - #114
li-jin-quan wants to merge 4 commits into
Conversation
…agentic fixtures The doctor and agentic suites isolate themselves from a real wallet by pointing HOME at a temp dir, but the code under test resolves that path with os.UserHomeDir, which reads $HOME on Unix and %USERPROFILE% on Windows. On Windows the redirection never took effect: 8 doctor tests and 5 agentic tests fail on a clean checkout, and the agentic suite reads the developer's real %USERPROFILE%\.keeperhub\wallet.json while it runs. Both packages now carry a four-line setHome helper that sets the two variables, used at all 13 fixture sites. runDoctor keeps the call inside the existing KH_TEST_KEEP_HOME conditional and agenticWallet keeps setting that flag - same shape as before, both variables instead of one. Verified on Windows (go 1.26.3), with a real wallet file present in the profile throughout: the two packages go from 13 failures to green, and go test ./... passes across all 35 packages.
What this changes
The mechanism holds. Go's Does it match the descriptionMatches. The scope statement is accurate, including the part that scopes BlockingNothing. Mechanical - actionable as-isNothing in the diff. Two adjacent gaps, neither introduced here and neither required for this to land. Taking them or leaving them is your call.
VerdictApproved - the conversion is complete, correct on every platform the CLI ships to, and the description matches the diff. |
ResolveHost reads KH_HOST ahead of the factory's DefaultHost, so an exported KH_HOST sent doctor's checks to the live host instead of the httptest server. Reproduced with KH_HOST=https://app.keeperhub.com go test ./cmd/doctor/ \ -run TestDoctorCmd_AgenticWalletSignatureIsAccepted the suite reaches app.keeperhub.com and the assertion fails with nothing pointing at the cause. setHome now clears KH_HOST, and the three probes in doctor_auth_test.go that build their own server get the same line.
|
Did the first one.
Reproduced before touching anything. With 897ms is the live host answering. Two side notes. Still no Left the |
What this changes since the last reviewOne commit, +9. Previously raised
BlockingNothing. Mechanical - actionable as-is
VerdictApproved - the conversion is complete and correct, and the isolation gap is closed everywhere except the version tests noted above. |
The four TestDoctorCmd_CLIVersion* tests isolate with XDG_CONFIG_HOME alone, so an exported KH_HOST sent checkCLIVersion to that host instead of the server versionDoctorFactory pins in Config.DefaultHost. Checked against a local server advertising 0.12.0: KH_HOST=http://127.0.0.1:18099 go test ./cmd/doctor/ \ -run TestDoctorCmd_CLIVersion --- FAIL: TestDoctorCmd_CLIVersionWarnsWhenBelowServerMinimum --- FAIL: TestDoctorCmd_CLIVersionPassesWhenAtServerMinimum Against app.keeperhub.com they happen to pass today, because its floor is 0.11.1 -- exactly the version the fixtures mock. They break as soon as that floor moves past a mocked version. Same one-line fix as the auth tests.
|
Fixed — thanks for the pointer. One correction on the repro, because it changes what you'd actually see: Against They only break once the floor moves past a mocked version. I stood up a local server advertising So it's the After the fix, same command, four green. The per-test cost also drops from 0.28–0.93s to 0.02–0.03s — that's the outbound call disappearing. Not taken: the three |
suisuss
left a comment
There was a problem hiding this comment.
What this changes
cmd/doctor/doctor_test.go and internal/agentic/wallet_test.go each gain a setHome helper that sets HOME and USERPROFILE together, and all 13 fixture sites move onto it. The doctor copy also clears KH_HOST (:348), and the three probes in doctor_auth_test.go (:36, :59, :76) plus the four TestDoctorCmd_CLIVersion* tests in doctor_version_test.go (:62, :74, :88, :100) clear it inline.
Both halves land on variables the code under test actually reads. agentic.ConfigPath resolves through os.UserHomeDir (internal/agentic/wallet.go:38), which reads %USERPROFILE% on Windows with no HOMEDRIVE/HOMEPATH fallback. ResolveHost returns os.Getenv("KH_HOST") ahead of cfg.DefaultHost (pkg/cmdutil/host.go:24-30), and the non-empty guard there means t.Setenv("KH_HOST", "") does neutralise it rather than resolving to an empty host. Every site is t.Setenv, so nothing leaks past the test that set it; the repo has no bare os.Setenv and no t.Parallel, so the process-global writes cannot race.
Does it match the description
Undersells. The body describes only the home redirection - "One change", "two test files" - and the diff is four files and two changes: the KH_HOST clearing is not in it. It is fully described in the thread, at my request, so nothing here is hidden; the body just has not caught up with the last two commits.
Mechanical - actionable as-is
-
cmd/doctor/doctor_auth_test.go:36,:59,:76andcmd/doctor/doctor_version_test.go:62,:74,:88,:100- these seven got theKH_HOSTthird ofsetHomebut not theHOME/USERPROFILEhalf, which is the half #104 is about. They calltc.Executedirectly rather thanrunDoctor, so all six checks run, andcheckAgenticWallet(cmd/doctor/doctor.go:492-493) loads the developer's real~/.keeperhub/wallet.jsonand signs it into the outbound request. No assertion breaks -checkAgenticWalletreturns onlypassorwarn, neverfail, sorequire.NoError(t, tc.Execute(...))holds either way - but on Windows these seven are still pointed at the real profile. Replace the baret.Setenv("KH_HOST", "")withsetHome(t, t.TempDir()), which already clearsKH_HOST. -
cmd/doctor/doctor_test.go:348with:357- theKH_HOSTclear sits insidesetHome, andrunDoctorcallssetHomeonly whenKH_TEST_KEEP_HOMEis empty, so the host guard inherits a conditional that exists for the home directory. I asked for that conditional shape on the issue when the helper carriedHOMEalone; carryingKH_HOSTas well changes what it gates. Every in-repo path is still covered, because the only writer ofKH_TEST_KEEP_HOMEisagenticWallet(:408), which callssetHomeitself - the gap is an ambient export only. Movet.Setenv("KH_HOST", "")out ofsetHomeand call it unconditionally at the top ofrunDoctor. -
The body's Scope section: fold the
KH_HOSTchange into it so a squash merge does not record this as a one-variable change.
Answers to the two open questions
The Windows CI job is mine, not yours - I said on the issue I would raise it separately and I still will. Nothing for you to file.
The three CF_* variables stay out, as agreed. Nothing to revisit.
With the team
- The ~15 other
cmd/packages with the same ambient-KH_HOSTexposure - 33 test files pinConfig.DefaultHostto anhttptestserver, and your run found 12 failing under an exportedKH_HOST. I'm weighing a per-testt.Setenv("KH_HOST", "")line against a package-levelTestMain(there is already one atinternal/auth/keyring_test.go:85) - the tradeoff is a few hundred repeated lines and the next fixture silently missing one, against a hook that hides the isolation from the test that depends on it. I'm discussing it with the core team now and will come back with a verdict shortly. Nothing here is blocked on you, and I'd rather settle the shape before you spend a PR on it.
Not yours to clear
CI has not run on any of the three commits - lint, test and docs-check are all action_required at 365aa5c, so go test -race ./... still has not executed against this change on any machine. That is a fork-run approval on my side. For what it is worth, I read the concurrency shape rather than relying on the run: Execute waits on its WaitGroup before returning, no test calls t.Parallel, and Go's env accessors are mutex-guarded, so I do not expect -race to have anything to say here.
Verdict
Changes requested - the seven direct-Execute tests in doctor_auth_test.go and doctor_version_test.go still read the real home, which is the isolation #104 asks for, and it is one call each.
…fixtures setHome is about the home directory, and runDoctor gates it on KH_TEST_KEEP_HOME, so carrying KH_HOST inside it handed the host guard a conditional that only exists for the profile. Drop it from setHome and clear it unconditionally at the top of runDoctor instead. Removing it from setHome also removed the clear that seven fixtures were getting for free: the seven in doctor_test.go that call tc.Execute themselves rather than runDoctor - AllPass, OneFail, WarnOnly, JSON, Timeout, Output and ExitCodeOnFail. Each now clears KH_HOST on its own line, beside its setHome call. The three probes in doctor_auth_test.go and the four TestDoctorCmd_CLIVersion* tests already carry their own clear from the previous two commits; this only adds setHome to them, which is the home half they were missing. Reproduced on Windows, go 1.26.3, by exporting KH_HOST and taking those seven clears back off: KH_HOST=https://live.invalid go test ./cmd/doctor/ --- FAIL: TestDoctorCmd_AllPass --- FAIL: TestDoctorCmd_WarnOnly --- FAIL: TestDoctorCmd_JSON Green with them, and green on 365aa5c either way, because setHome used to supply the clear as a side effect. go test ./... passes across the 35 packages, go vet ./... is clean, and go test -race ./cmd/doctor/ ./internal/agentic/ passes with a C toolchain on PATH, which the opening commit said this machine did not have.
c64ffbe to
303e75c
Compare
|
Both landed in 303e75c. Your two asks interact, so flagging it rather than letting the diff decide quietly: taking
The Scope section covers both changes now.
|
Issue
Closes #104
What this changes
Both halves are test-only.
Home redirection. The doctor and agentic suites isolate themselves from a real wallet by pointing
HOMEat a temp dir. The code under test resolves that path withos.UserHomeDir, which reads$HOMEon Unix but%USERPROFILE%on Windows - so on Windows the isolation never took effect. Both packages now carry asetHomehelper that sets the two variables, used at the fixture sites. Same shape as your comment on the issue: the helper is duplicated per package rather than shared,runDoctorkeeps the call inside the existingKH_TEST_KEEP_HOMEconditional, andagenticWalletkeeps setting that flag.KH_HOST.
ResolveHostreadsKH_HOSTahead of the factory'sDefaultHost, so an exportedKH_HOSTsends the checks to the live host instead of the httptest server and the assertions fail with nothing pointing at the cause. That clear does not belong insetHome: it has nothing to do with the temporary profile, and becauserunDoctorgatessetHomeonKH_TEST_KEEP_HOME, putting it there handed the host guard a conditional that only exists for the home directory.setHomenow sets the two home variables and nothing else, andrunDoctorclearsKH_HOSTunconditionally at the top.Taking it out of
setHomeremoved the clear that seven fixtures were getting for free - the seven indoctor_test.gothat calltc.Executethemselves rather thanrunDoctor. Each of them clearsKH_HOSTon its own line now. The three probes indoctor_auth_test.goand the fourTestDoctorCmd_CLIVersion*tests already carried their own clear from the two earlier commits;setHomeis the half they were missing.Scope
Both changes: the home-directory redirection and the
KH_HOSTclear, incmd/doctorandinternal/agentic. Test-only. No production code, no other packages, no CI.internal/cacheandinternal/configalso callos.UserHomeDir, but their tests set noHOMEat all, so they are outside this and I left them alone.How it was verified
On Windows, go 1.26.3, same machine, with a real wallet file in the profile the whole time:
go test ./cmd/doctor/ ./internal/agentic/KH_HOST=https://live.invalid, same two packages365aa5cgo test ./...go vet ./...go test -race ./cmd/doctor/ ./internal/agentic/go test -race ./...(whatmake testruns)Since this fixes the fixtures rather than the code under test, the failing run is the reproduction. Two details from it are worth naming:
TestLoad_ReadsTheWalletassertedsub_abc123and got the developer's own subOrgId - the real profile being read, not a missing file.TestLoad_MissingFileIsNotConfiguredfailed because that real wallet existed. It passes now, which is the case it was written for.A third, from the
KH_HOSThalf: with the clear taken back off the seven fixtures indoctor_test.go,KH_HOST=https://live.invalid go test ./cmd/doctor/failsTestDoctorCmd_AllPass,TestDoctorCmd_WarnOnlyandTestDoctorCmd_JSON. That is the run the last commit is built on.Correcting a note from the first version of this body:
-racedid not run then because I read this machine as having no C compiler. It has one onPATH, so it ran -make testisgo test -race ./...and that is green across the 30 packages. Same formake lint- it only needed golangci-lint, so I installed it, and it reports 0 issues.mainmake lintandmake testpass - all three CI jobs replicated locally:golangci-lint run ./...reports 0 issues (2.13.2, against this repo's v2 config),go test -race -coverprofile=coverage.txt ./...is green across the 30 packages,CGO_ENABLED=0 go build -o bin/kh ./cmd/khsucceeds, andgo generate ./docs/leaves no diffgo generate ./docs/not needed - no command or flag changed