@@ -17,6 +17,48 @@ import (
1717
1818// --- shared batch test fixtures ------------------------------------------
1919
20+ // fakeAbsDir returns an absolute directory on the REAL host OS this test
21+ // process is actually running on, built from elems — never touching real
22+ // disk, since it only ever backs a fake Env.PathDirs/HostDir func (a test
23+ // that touches real disk uses t.TempDir() directly instead, which is
24+ // already host-OS-native).
25+ //
26+ // searchDirs' own filepath.IsAbs filter runs under the actual runtime.GOOS
27+ // the test process executes on, NEVER under a test's own goosName override
28+ // (the package-level var some tests force to a different value specifically
29+ // to exercise that OS's naming policy in isolation — see e.g.
30+ // TestProbe_WindowsExecutableSuffix). A hardcoded POSIX literal like
31+ // "/usr/bin" is not absolute on Windows (filepath.IsAbs requires a drive
32+ // letter or UNC root there), so on a REAL Windows test run searchDirs
33+ // silently dropped every such fake PATH/HostDir entry, and every target
34+ // behind it went unseen — this is what made most of this package's own
35+ // test suite report "not installed" (or panic on the resulting nil result)
36+ // the first time task-22's S5 ran it on real Windows CI.
37+ func fakeAbsDir (elems ... string ) string {
38+ if runtime .GOOS == "windows" {
39+ return filepath .Join (`C:\fakeroot` , filepath .Join (elems ... ))
40+ }
41+ return "/" + filepath .Join (elems ... )
42+ }
43+
44+ // fakeAbsExe joins dir and name the same way probeOne itself locates an
45+ // executable: the ".exe" suffix decision follows goosName (the package's
46+ // own test seam over runtime.GOOS — see status.go's own doc comment on
47+ // it), exactly like probeOne's own filename construction, while the join
48+ // itself uses the REAL stdlib filepath.Join, exactly like probeOne's own
49+ // candidate construction (which is never goosName-parameterized — see
50+ // fakeAbsDir's own doc comment for why that must track the real host
51+ // GOOS). Most callers never override goosName, so the two coincide; a
52+ // caller that does (to exercise a specific OS's naming policy in
53+ // isolation, e.g. an ".exe" suffix test running for real on Linux CI)
54+ // still gets exactly what probeOne would search for.
55+ func fakeAbsExe (dir , name string ) string {
56+ if goosName == "windows" {
57+ name += ".exe"
58+ }
59+ return filepath .Join (dir , name )
60+ }
61+
2062// batchEnv builds an InstallEnv from plain maps/funcs, mirroring status_
2163// test.go's fakeEnv but for the extra install-only dependencies
2264// (cli-install#req:no-network-in-tests).
@@ -37,13 +79,15 @@ func batchEnv(pathDirs []string, hostDir string, executables map[string]bool, ru
3779}
3880
3981// multiJSONRun answers "version --json" for any probed path by looking up
40- // that path's base filename in versions, naming itself after that base —
41- // so one Run func can back several distinct targets probed at different
42- // paths in the same test.
82+ // that path's base filename (with any platform executable suffix trimmed
83+ // — probeOne appends ".exe" on windows, but versions' own keys are the
84+ // bare catalog id, e.g. "ovdb" not "ovdb.exe") in versions, naming itself
85+ // after that base — so one Run func can back several distinct targets
86+ // probed at different paths in the same test.
4387func multiJSONRun (versions map [string ]string ) func (context.Context , string , []string ) ([]byte , error ) {
4488 return func (_ context.Context , path string , args []string ) ([]byte , error ) {
4589 if len (args ) == 2 && args [0 ] == "version" && args [1 ] == "--json" {
46- base := filepath .Base (path )
90+ base := strings . TrimSuffix ( filepath .Base (path ), filepath . Ext ( path ) )
4791 if v , ok := versions [base ]; ok {
4892 b , _ := json .Marshal (buildinfo.VersionJSON {Name : base , Version : v })
4993 return b , nil
@@ -138,9 +182,10 @@ func TestPlan_HostDirErrorTreatedAsEmpty(t *testing.T) {
138182}
139183
140184func TestPlan_AlreadyInstalledIsNotReinstalled (t * testing.T ) {
141- executables := map [string ]bool {"/bin1/ovdb" : true }
185+ bin1 := fakeAbsDir ("bin1" )
186+ executables := map [string ]bool {fakeAbsExe (bin1 , "ovdb" ): true }
142187 run := multiJSONRun (map [string ]string {"ovdb" : "1.2.3" })
143- env := batchEnv ([]string {"/ bin1" }, "/ usr/ bin" , executables , run , noRunManaged )
188+ env := batchEnv ([]string {bin1 }, fakeAbsDir ( " usr" , " bin") , executables , run , noRunManaged )
144189 opts := Options {HostID : "datatug" , Env : env }
145190
146191 result , err := Plan (context .Background (), []string {"ovdb" }, opts )
@@ -169,9 +214,19 @@ func TestPlan_DedupesNames(t *testing.T) {
169214}
170215
171216func TestPlan_UnrecognizedAtDestinationFails (t * testing.T ) {
172- hostDir := "/home/alex/go/bin" // Manual, not denylisted
173- destPath := "/home/alex/go/bin/ovdb"
174- executables := map [string ]bool {destPath : true }
217+ hostDir := fakeAbsDir ("home" , "alex" , "go" , "bin" ) // Manual, not denylisted
218+ // installFilePath is the SAME function Plan itself uses to build the
219+ // planned destination path — computing the expected value through it
220+ // (rather than a hand-typed parallel literal) keeps this assertion
221+ // correct under any goosName/host-OS combination, including the
222+ // ".exe" suffix windows adds. fakeAbsExe instead matches what
223+ // probeOne's own real filepath.Join search looks for (see its own
224+ // doc comment for why the two joiners can differ) — here, with
225+ // goosName left at its default, both happen to agree, but the
226+ // executables map key is built the way probeOne actually searches.
227+ destPath := installFilePath (goosName , hostDir , "ovdb" )
228+ locatedPath := fakeAbsExe (hostDir , "ovdb" )
229+ executables := map [string ]bool {locatedPath : true }
175230 run := func (context.Context , string , []string ) ([]byte , error ) {
176231 return []byte ("somethingelse 9.9.9 (abc) 2026-01-01" ), nil
177232 }
@@ -202,9 +257,15 @@ func TestPlan_UnrecognizedAtDestinationFails_CaseVariant(t *testing.T) {
202257 t .Cleanup (func () { goosName = origGOOS })
203258 goosName = "darwin"
204259
205- hostDir := "/Users/alex/go/bin" // Manual, not denylisted; planning builds destPath from this
206- pathEntry := "/Users/Alex/go/bin" // same directory, different case, found on PATH
207- locatedPath := "/Users/Alex/go/bin/ovdb" // located copy: pathEntry + id
260+ hostDir := fakeAbsDir ("Users" , "alex" , "go" , "bin" ) // Manual, not denylisted; planning builds destPath from this
261+ pathEntry := fakeAbsDir ("Users" , "Alex" , "go" , "bin" ) // same directory, different case, found on PATH
262+ // fakeAbsExe (not installFilePath): this must match what probeOne's
263+ // own real filepath.Join search actually looks for, not Plan's
264+ // separately-implemented destination-path joiner (see fakeAbsExe's
265+ // own doc comment) — the test only asserts Outcome/Kind below, not an
266+ // exact Failure.Path string, so the two joiners' possibly-differing
267+ // separator styles never need to agree here.
268+ locatedPath := fakeAbsExe (pathEntry , "ovdb" )
208269 executables := map [string ]bool {locatedPath : true }
209270 run := func (context.Context , string , []string ) ([]byte , error ) {
210271 return []byte ("somethingelse 9.9.9 (abc) 2026-01-01" ), nil
@@ -226,13 +287,14 @@ func TestPlan_UnrecognizedElsewhereWarns(t *testing.T) {
226287 // The unrecognized copy is on PATH at /bin1, earlier than the planned
227288 // destination /home/alex/go/bin (not on PATH at all) — REQ:
228289 // unrecognized-copy-not-trusted's shadowing case.
229- hostDir := "/home/alex/go/bin"
230- unrecognizedPath := "/bin1/ovdb"
290+ hostDir := fakeAbsDir ("home" , "alex" , "go" , "bin" )
291+ bin1 := fakeAbsDir ("bin1" )
292+ unrecognizedPath := fakeAbsExe (bin1 , "ovdb" )
231293 executables := map [string ]bool {unrecognizedPath : true }
232294 run := func (context.Context , string , []string ) ([]byte , error ) {
233295 return []byte ("somethingelse 9.9.9 (abc) 2026-01-01" ), nil
234296 }
235- env := batchEnv ([]string {"/ bin1" }, hostDir , executables , run , noRunManaged )
297+ env := batchEnv ([]string {bin1 }, hostDir , executables , run , noRunManaged )
236298 srv := newReleaseServer (t , `[{"tag_name":"v1.0.0","prerelease":false,"draft":false}]` , nil )
237299 opts := Options {HostID : "datatug" , Env : env , ConfigureRelease : configureReleaseFromServer (srv )}
238300
@@ -256,7 +318,16 @@ func TestPlan_UnrecognizedElsewhereWarns(t *testing.T) {
256318}
257319
258320func TestPlan_HomebrewNeedsNoNetwork (t * testing.T ) {
259- hostDir := "/opt/homebrew/Caskroom/wb/1.0.0"
321+ // Homebrew casks are POSIX-only (wb/ovdb's own catalog entries declare
322+ // CaskOS: darwin/linux, never windows), so caskSupportsOS only chooses
323+ // MethodHomebrew there — pin goosName so this Homebrew-policy fixture
324+ // exercises that regardless of the REAL host OS running the test (same
325+ // pattern as TestPlanMethod_DirGivenAllowed).
326+ origGOOS := goosName
327+ t .Cleanup (func () { goosName = origGOOS })
328+ goosName = "darwin"
329+
330+ hostDir := fakeAbsDir ("opt" , "homebrew" , "Caskroom" , "wb" , "1.0.0" )
260331 env := batchEnv (nil , hostDir , nil , func (context.Context , string , []string ) ([]byte , error ) { return nil , errors .New ("should not run" ) }, noRunManaged )
261332 opts := Options {HostID : "wb" , Env : env }
262333
@@ -405,9 +476,10 @@ func TestExecute_ConfirmationGate_NamesOnlyPendingTargets(t *testing.T) {
405476 // "ovdb" is already installed (excluded from confirmation); "datatug"
406477 // is not (included) — REQ: confirmation-gate: "Targets that are
407478 // already installed... are excluded from the question."
408- executables := map [string ]bool {"/bin1/ovdb" : true }
479+ bin1 := fakeAbsDir ("bin1" )
480+ executables := map [string ]bool {fakeAbsExe (bin1 , "ovdb" ): true }
409481 run := multiJSONRun (map [string ]string {"ovdb" : "1.0.0" })
410- env := batchEnv ([]string {"/ bin1" }, "/ home/ alex/go/ bin" , executables , run , noRunManaged )
482+ env := batchEnv ([]string {bin1 }, fakeAbsDir ( " home" , " alex" , "go" , " bin") , executables , run , noRunManaged )
411483 srv := newReleaseServer (t , `[{"tag_name":"v1.0.0","prerelease":false,"draft":false}]` , nil )
412484 opts := Options {HostID : "wb" , Env : env , ConfigureRelease : configureReleaseFromServer (srv )}
413485 plan , err := Plan (context .Background (), []string {"ovdb" , "datatug" }, opts )
@@ -461,7 +533,13 @@ func TestExecute_DeclinedKeepsStatusAndDestination(t *testing.T) {
461533}
462534
463535func TestExecute_HomebrewPrintOnlyRedirectsWithoutRunning (t * testing.T ) {
464- hostDir := "/opt/homebrew/Caskroom/wb/1.0.0"
536+ // Same reasoning as TestPlan_HomebrewNeedsNoNetwork: pin goosName so
537+ // this Homebrew-policy fixture works regardless of the real host OS.
538+ origGOOS := goosName
539+ t .Cleanup (func () { goosName = origGOOS })
540+ goosName = "darwin"
541+
542+ hostDir := fakeAbsDir ("opt" , "homebrew" , "Caskroom" , "wb" , "1.0.0" )
465543 env := batchEnv (nil , hostDir , nil , func (context.Context , string , []string ) ([]byte , error ) { return nil , errors .New ("should not run" ) }, noRunManaged )
466544 opts := Options {HostID : "wb" , Env : env }
467545 plan , err := Plan (context .Background (), []string {"ovdb" }, opts )
@@ -486,17 +564,24 @@ func TestExecute_HomebrewPrintOnlyRedirectsWithoutRunning(t *testing.T) {
486564// managed command succeeds and one whose fails — both get a result, in
487565// order, and the earlier failure never stops the later target.
488566func TestExecute_AcceptedBatchInstallsIndependently (t * testing.T ) {
567+ // Same reasoning as TestPlan_HomebrewNeedsNoNetwork: pin goosName so
568+ // this Homebrew-policy fixture works regardless of the real host OS.
569+ origGOOS := goosName
570+ t .Cleanup (func () { goosName = origGOOS })
571+ goosName = "darwin"
572+
489573 executables := map [string ]bool {}
574+ homebrewBin := fakeAbsDir ("opt" , "homebrew" , "bin" )
490575 run := multiJSONRun (map [string ]string {"ovdb" : "2.0.0" })
491576 runManaged := func (_ context.Context , exe string , args []string ) error {
492577 token := args [len (args )- 1 ]
493578 if token == "openvaultdb/tap/ovdb" {
494- executables ["/opt/homebrew/bin/ ovdb" ] = true
579+ executables [fakeAbsExe ( homebrewBin , " ovdb") ] = true
495580 return nil
496581 }
497582 return errors .New ("brew: cask not found" )
498583 }
499- env := batchEnv ([]string {"/ opt/homebrew/bin" } , "/opt/ homebrew/ Caskroom/wb/ 1.0.0" , executables , run , runManaged )
584+ env := batchEnv ([]string {homebrewBin }, fakeAbsDir ( " opt" , "homebrew" , " Caskroom" , "wb" , " 1.0.0") , executables , run , runManaged )
500585 opts := Options {HostID : "wb" , Env : env }
501586 plan , err := Plan (context .Background (), []string {"ovdb" , "datatug" }, opts )
502587 if err != nil {
@@ -537,8 +622,8 @@ func TestExecute_DirectBatchOneFailsOthersSucceed(t *testing.T) {
537622 // shared GoReleaser-shaped default — Plan() looks the target up in
538623 // the real compiled catalog, so this fixture must match that entry
539624 // exactly, not a hand-picked naming.
540- okAsset := fmt . Sprintf ( "ovdb_%s_%s_%s.tar.gz " , version , runtime . GOOS , runtime . GOARCH )
541- archive := makeTarGz ( t , "ovdb " , binContent )
625+ archive , ext := makeArchive ( t , "ovdb " , binContent )
626+ okAsset := fmt . Sprintf ( "ovdb_%s_%s_%s.%s " , version , runtime . GOOS , runtime . GOARCH , ext )
542627 checksums := fmt .Sprintf ("%s %s\n " , sha256Hex (archive ), okAsset )
543628
544629 okServer := newReleaseServer (t , `[{"tag_name":"` + tag + `","prerelease":false,"draft":false}]` , map [string ][]byte {
@@ -549,7 +634,7 @@ func TestExecute_DirectBatchOneFailsOthersSucceed(t *testing.T) {
549634
550635 destDir := t .TempDir ()
551636 run := multiJSONRun (map [string ]string {"ovdb" : version })
552- env := batchEnv ([]string {destDir }, "/ nonexistent-host-dir" , nil , run , noRunManaged )
637+ env := batchEnv ([]string {destDir }, fakeAbsDir ( " nonexistent-host-dir") , nil , run , noRunManaged )
553638 // IsExecutable must reflect a real install landing in destDir so the
554639 // post-install verification probe (and the batch's own PATH-based
555640 // executable check) sees it.
@@ -617,7 +702,13 @@ func TestInstall_PanicsOnUnknownHost(t *testing.T) {
617702}
618703
619704func TestInstall_DryRunNeverCallsExecute (t * testing.T ) {
620- hostDir := "/opt/homebrew/Caskroom/wb/1.0.0"
705+ // Same reasoning as TestPlan_HomebrewNeedsNoNetwork: pin goosName so
706+ // this Homebrew-policy fixture works regardless of the real host OS.
707+ origGOOS := goosName
708+ t .Cleanup (func () { goosName = origGOOS })
709+ goosName = "darwin"
710+
711+ hostDir := fakeAbsDir ("opt" , "homebrew" , "Caskroom" , "wb" , "1.0.0" )
621712 env := batchEnv (nil , hostDir , nil , func (context.Context , string , []string ) ([]byte , error ) { return nil , errors .New ("should not run" ) }, noRunManaged )
622713 opts := Options {HostID : "wb" , Env : env , DryRun : true } // no Confirm set: panics if Execute is ever reached
623714
@@ -645,9 +736,10 @@ func TestInstall_UnknownNameNeverReachesExecute(t *testing.T) {
645736}
646737
647738func TestInstall_RealRunExecutesAfterPlan (t * testing.T ) {
648- executables := map [string ]bool {"/bin1/ovdb" : true }
739+ bin1 := fakeAbsDir ("bin1" )
740+ executables := map [string ]bool {fakeAbsExe (bin1 , "ovdb" ): true }
649741 run := multiJSONRun (map [string ]string {"ovdb" : "1.0.0" })
650- env := batchEnv ([]string {"/ bin1" }, "/ usr/ bin" , executables , run , noRunManaged )
742+ env := batchEnv ([]string {bin1 }, fakeAbsDir ( " usr" , " bin") , executables , run , noRunManaged )
651743 opts := Options {HostID : "datatug" , Env : env , Yes : true }
652744
653745 result , err := Install (context .Background (), []string {"ovdb" }, opts )
0 commit comments