Skip to content

Commit ffcf0e7

Browse files
ostermanclaude
andcommitted
test(imports): isolate remote-importer cache to a temp dir
TestResolveImportPaths_MixedPaths flaked on the Windows CI runner: open C:\...\cache\atmos\stack-imports\<hash>.yaml: The system cannot find the path specified. The remote-import tests drive the package-global importer, which lazily builds a real-user-cache-backed importer via getGlobalImporter() -> globalImporterOnce.Do(). The tests tried to isolate it by assigning a temp-cache importer after `globalImporterOnce = sync.Once{}`, but a freshly reset Once still runs on the next getGlobalImporter() call and overwrites the injection with a real-cache importer. So every remote-import test actually wrote to (and read back from) the shared user cache dir — which races/flakes on CI runners (Windows most visibly). Add useTestGlobalImporter(t, cfg) which primes the Once (consumes it via Do) so the injected temp-cache importer survives, and restores the globals on cleanup. Route all remote-import tests through it. Verified: with XDG_CACHE_HOME pointed at an empty dir, the package no longer writes any stack-imports/*.yaml there — downloads stay in t.TempDir(). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent b879809 commit ffcf0e7

1 file changed

Lines changed: 36 additions & 31 deletions

File tree

pkg/stack/imports/remote_test.go

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,28 @@ func newTestRemoteImporter(t *testing.T, atmosConfig *schema.AtmosConfiguration)
4040
return importer
4141
}
4242

43+
// useTestGlobalImporter swaps the package-global remote importer for one backed by an
44+
// isolated temp cache dir, and restores it on cleanup. It must prime globalImporterOnce
45+
// (not just assign globalImporter): getGlobalImporter() calls globalImporterOnce.Do, so a
46+
// freshly-reset Once would otherwise run and overwrite the injection with a real-cache
47+
// importer that writes to the shared user cache dir — which flakes on CI runners
48+
// (notably Windows: "The system cannot find the path specified").
49+
func useTestGlobalImporter(t *testing.T, atmosConfig *schema.AtmosConfiguration) {
50+
t.Helper()
51+
importer := newTestRemoteImporter(t, atmosConfig)
52+
53+
globalImporterOnce = sync.Once{}
54+
globalImporterErr = nil
55+
// Consume the Once now so the lazy getGlobalImporter() keeps our injected importer.
56+
globalImporterOnce.Do(func() { globalImporter = importer })
57+
58+
t.Cleanup(func() {
59+
globalImporterOnce = sync.Once{}
60+
globalImporter = nil
61+
globalImporterErr = nil
62+
})
63+
}
64+
4365
func initGitRepo(t *testing.T, files map[string]string) string {
4466
t.Helper()
4567

@@ -528,14 +550,7 @@ func TestRemoteImporter_ResolveRemoteImport_GlobalImporter(t *testing.T) {
528550
}))
529551
defer server.Close()
530552

531-
globalImporterOnce = sync.Once{}
532-
globalImporter = newTestRemoteImporter(t, &schema.AtmosConfiguration{})
533-
globalImporterErr = nil
534-
t.Cleanup(func() {
535-
globalImporterOnce = sync.Once{}
536-
globalImporter = nil
537-
globalImporterErr = nil
538-
})
553+
useTestGlobalImporter(t, &schema.AtmosConfiguration{})
539554

540555
uri := server.URL + "/config.yaml"
541556
matches, err := ResolveRemoteImport(&schema.AtmosConfiguration{}, uri)
@@ -556,14 +571,7 @@ func TestRemoteImporter_DownloadRemoteImport_GlobalImporter(t *testing.T) {
556571
}))
557572
defer server.Close()
558573

559-
globalImporterOnce = sync.Once{}
560-
globalImporter = newTestRemoteImporter(t, &schema.AtmosConfiguration{})
561-
globalImporterErr = nil
562-
t.Cleanup(func() {
563-
globalImporterOnce = sync.Once{}
564-
globalImporter = nil
565-
globalImporterErr = nil
566-
})
574+
useTestGlobalImporter(t, &schema.AtmosConfiguration{})
567575

568576
path, err := DownloadRemoteImport(&schema.AtmosConfiguration{}, server.URL+"/config.yaml")
569577
require.NoError(t, err)
@@ -636,12 +644,11 @@ func TestProcessImportPath_Remote(t *testing.T) {
636644
}))
637645
defer server.Close()
638646

639-
// Reset the global importer for this test.
640-
globalImporterOnce = sync.Once{}
641-
globalImporter = nil
642-
globalImporterErr = nil
643-
644647
atmosConfig := &schema.AtmosConfiguration{}
648+
// Isolate the global importer's cache to a temp dir so the remote download does not
649+
// write to (and flake on) the shared real user cache dir.
650+
useTestGlobalImporter(t, atmosConfig)
651+
645652
basePath := filepath.Join(string(os.PathSeparator), "stacks")
646653

647654
// Process a remote import path.
@@ -694,12 +701,11 @@ func TestResolveImportPaths_MixedPaths(t *testing.T) {
694701
}))
695702
defer server.Close()
696703

697-
// Reset the global importer for this test.
698-
globalImporterOnce = sync.Once{}
699-
globalImporter = nil
700-
globalImporterErr = nil
701-
702704
atmosConfig := &schema.AtmosConfiguration{}
705+
// Isolate the global importer's cache to a temp dir so the remote download does not
706+
// write to (and flake on) the shared real user cache dir.
707+
useTestGlobalImporter(t, atmosConfig)
708+
703709
basePath := filepath.Join(string(os.PathSeparator), "stacks")
704710

705711
importPaths := []string{
@@ -830,12 +836,11 @@ func TestResolveImportPaths_ErrorPropagation(t *testing.T) {
830836
}))
831837
defer server.Close()
832838

833-
// Reset the global importer for this test.
834-
globalImporterOnce = sync.Once{}
835-
globalImporter = nil
836-
globalImporterErr = nil
837-
838839
atmosConfig := &schema.AtmosConfiguration{}
840+
// Isolate the global importer's cache to a temp dir so the remote download does not
841+
// write to (and flake on) the shared real user cache dir.
842+
useTestGlobalImporter(t, atmosConfig)
843+
839844
basePath := filepath.Join(string(os.PathSeparator), "stacks")
840845

841846
importPaths := []string{

0 commit comments

Comments
 (0)