11package soltestutils
22
33import (
4- "io"
5- "os"
64 "path/filepath"
5+ "sync"
76 "testing"
87
98 "github.com/stretchr/testify/require"
@@ -13,71 +12,58 @@ import (
1312 "github.com/smartcontractkit/cld-changesets/legacy/pkg/family/solana/solutils"
1413)
1514
16- // LoadMCMSPrograms loads the MCMS program artifacts into the given directory.
17- //
18- // Returns the path to the temporary test directory and a map of program names to IDs.
19- func LoadMCMSPrograms (t * testing.T , dir string ) (string , map [string ]string ) {
15+ // programIDMu serializes Solana integration tests that mutate global gobinding
16+ // program IDs via SetProgramID. solana-go bindings use process-wide state, so
17+ // parallel package tests otherwise race and fail with "Program is not deployed".
18+ var programIDMu sync.Mutex
19+
20+ var (
21+ mcmsProgramsOnce sync.Once
22+ mcmsProgramsPath string
23+ mcmsProgramIDs map [string ]string
24+ )
25+
26+ // sharedMCMSPrograms downloads MCMS Solana program artifacts once per test process
27+ // and returns the shared cache directory plus program IDs.
28+ func sharedMCMSPrograms (t * testing.T ) (string , map [string ]string ) {
2029 t .Helper ()
2130
22- progIDs := loadProgramArtifacts (t ,
23- solutils .MCMSProgramNames , downloadChainlinkCCIPProgramArtifacts , dir ,
24- )
31+ mcmsProgramsOnce .Do (func () {
32+ mcmsProgramsPath = programsCacheDir ()
33+ err := solutils .DownloadChainlinkCCIPProgramArtifacts (t .Context (), mcmsProgramsPath , "" , nil )
34+ require .NoError (t , err )
35+
36+ mcmsProgramIDs = make (map [string ]string , len (solutils .MCMSProgramNames ))
37+ for _ , name := range solutils .MCMSProgramNames {
38+ id := solutils .GetProgramID (name )
39+ require .NotEmpty (t , id , "program id not found for program name: %s" , name )
40+ require .FileExists (t , filepath .Join (mcmsProgramsPath , name + ".so" ))
41+ mcmsProgramIDs [name ] = id
42+ }
43+ })
44+
45+ return mcmsProgramsPath , copyProgramIDs (mcmsProgramIDs )
46+ }
47+
48+ func copyProgramIDs (src map [string ]string ) map [string ]string {
49+ dst := make (map [string ]string , len (src ))
50+ for name , id := range src {
51+ dst [name ] = id
52+ }
2553
26- return dir , progIDs
54+ return dst
2755}
2856
2957// PreloadMCMS provides a convenience function to preload the MCMS program artifacts and address
3058// book for a given selector.
3159func PreloadMCMS (t * testing.T , selector uint64 ) (string , map [string ]string , * cldf.AddressBookMap ) {
3260 t .Helper ()
3361
34- dir := t .TempDir ()
35-
36- _ , programIDs := LoadMCMSPrograms (t , dir )
62+ programIDMu .Lock ()
63+ t .Cleanup (programIDMu .Unlock )
3764
65+ programsPath , programIDs := sharedMCMSPrograms (t )
3866 ab := PreloadAddressBookWithMCMSPrograms (t , selector )
3967
40- return dir , programIDs , ab
41- }
42-
43- // loadProgramArtifacts is a helper function that loads program artifacts into a temporary test directory.
44- // It downloads artifacts using the provided download function and copies the specified programs.
45- //
46- // Returns the map of program names to IDs.
47- func loadProgramArtifacts (t * testing.T , programNames []string , downloadFn downloadFunc , targetDir string ) map [string ]string {
48- t .Helper ()
49-
50- // Download the program artifacts using the provided download function
51- cachePath := downloadFn (t )
52-
53- progIDs := make (map [string ]string , len (programNames ))
54-
55- // Copy the specific artifacts to the target directory and add the program ID to the map
56- for _ , name := range programNames {
57- id := solutils .GetProgramID (name )
58- require .NotEmpty (t , id , "program id not found for program name: %s" , name )
59-
60- src := filepath .Join (cachePath , name + ".so" )
61- dst := filepath .Join (targetDir , name + ".so" )
62-
63- func () {
64- srcFile , err := os .Open (src )
65- require .NoError (t , err )
66- defer srcFile .Close ()
67-
68- dstFile , err := os .Create (dst )
69- require .NoError (t , err )
70- defer dstFile .Close ()
71-
72- _ , err = io .Copy (dstFile , srcFile )
73- require .NoError (t , err )
74- }()
75-
76- // Add the program ID to the map
77- progIDs [name ] = id
78- t .Logf ("copied solana program %s to %s" , name , dst )
79- }
80-
81- // Return the path to the cached artifacts and the map of program IDs
82- return progIDs
68+ return programsPath , programIDs , ab
8369}
0 commit comments