github.com/filecoin-project/bacalhau@v0.3.23-0.20230228154132-45c989550ace/pkg/test/devstack/pythonwasm_test.go (about) 1 //go:build integration 2 3 package devstack 4 5 import ( 6 "context" 7 "fmt" 8 "os" 9 "path/filepath" 10 "strings" 11 "testing" 12 "time" 13 14 "github.com/filecoin-project/bacalhau/pkg/devstack" 15 "github.com/filecoin-project/bacalhau/pkg/docker" 16 "github.com/filecoin-project/bacalhau/pkg/ipfs" 17 "github.com/filecoin-project/bacalhau/pkg/logger" 18 "github.com/filecoin-project/bacalhau/pkg/node" 19 testutils "github.com/filecoin-project/bacalhau/pkg/test/utils" 20 21 cmd "github.com/filecoin-project/bacalhau/cmd/bacalhau" 22 _ "github.com/filecoin-project/bacalhau/pkg/logger" 23 "github.com/filecoin-project/bacalhau/pkg/requester/publicapi" 24 "github.com/filecoin-project/bacalhau/pkg/system" 25 "github.com/rs/zerolog/log" 26 27 "github.com/stretchr/testify/require" 28 "github.com/stretchr/testify/suite" 29 ) 30 31 type DevstackPythonWASMSuite struct { 32 suite.Suite 33 } 34 35 // In order for 'go test' to run this suite, we need to create 36 // a normal test function and pass our suite to suite.Run 37 func TestDevstackPythonWASMSuite(t *testing.T) { 38 suite.Run(t, new(DevstackPythonWASMSuite)) 39 } 40 41 // Before each test 42 func (s *DevstackPythonWASMSuite) SetupTest() { 43 docker.MustHaveDocker(s.T()) 44 45 logger.ConfigureTestLogging(s.T()) 46 err := system.InitConfigForTesting(s.T()) 47 require.NoError(s.T(), err) 48 } 49 50 // full end-to-end test of python/wasm: 51 // 52 // * use CLI to submit a python job with --deterministic set 53 // * context (python file and requirements.txt) should be pinned to ipfs by 54 // requester node 55 // * docker executor downloads context and starts wasm container image with the 56 // context mounted in 57 58 func (s *DevstackPythonWASMSuite) TestPythonWasmVolumes() { 59 testutils.SkipIfArm(s.T(), "https://github.com/filecoin-project/bacalhau/issues/1268") 60 cmd.Fatal = cmd.FakeFatalErrorHandler 61 62 nodeCount := 1 63 inputPath := "/input" 64 outputPath := "/output" 65 fileContents := "pineapples" 66 67 ctx := context.Background() 68 stack, _ := testutils.SetupTest(ctx, s.T(), nodeCount, 0, false, 69 node.NewComputeConfigWithDefaults(), 70 node.NewRequesterConfigWithDefaults()) 71 72 tmpDir := s.T().TempDir() 73 74 oldDir, err := os.Getwd() 75 require.NoError(s.T(), err) 76 err = os.Chdir(tmpDir) 77 require.NoError(s.T(), err) 78 defer func() { 79 err := os.Chdir(oldDir) 80 require.NoError(s.T(), err) 81 }() 82 83 fileCid, err := ipfs.AddTextToNodes(ctx, []byte(fileContents), devstack.ToIPFSClients(stack.Nodes[:nodeCount])...) 84 require.NoError(s.T(), err) 85 86 // write bytes to main.py 87 mainPy := []byte(fmt.Sprintf(` 88 import os 89 print("LIST /") 90 print(os.listdir("/")) 91 print("LIST %s") 92 print(os.listdir("%s")) 93 open("%s/test.txt", "w").write(open("%s").read()) 94 `, outputPath, outputPath, outputPath, inputPath)) 95 96 err = os.WriteFile("main.py", mainPy, 0644) 97 require.NoError(s.T(), err) 98 99 _, out, err := cmd.ExecuteTestCobraCommand(s.T(), 100 fmt.Sprintf("--api-port=%d", stack.Nodes[0].APIServer.Port), 101 "--api-host=localhost", 102 "run", 103 "-v", fmt.Sprintf("%s:%s", fileCid, inputPath), 104 "-o", fmt.Sprintf("%s:%s", "output", outputPath), 105 "python", 106 "--deterministic", 107 "main.py", 108 ) 109 jobID := system.FindJobIDInTestOutput(out) 110 require.NoError(s.T(), err) 111 log.Debug().Msgf("jobId=%s", jobID) 112 time.Sleep(time.Second * 5) 113 114 node := stack.Nodes[0] 115 apiUri := node.APIServer.GetURI() 116 apiClient := publicapi.NewRequesterAPIClient(apiUri) 117 resolver := apiClient.GetJobStateResolver() 118 require.NoError(s.T(), err) 119 err = resolver.WaitUntilComplete(ctx, jobID) 120 require.NoError(s.T(), err) 121 122 shards, err := resolver.GetShards(ctx, jobID) 123 require.NoError(s.T(), err) 124 require.True(s.T(), len(shards) > 0) 125 126 shard := shards[0] 127 128 outputDir := s.T().TempDir() 129 require.NotEmpty(s.T(), shard.PublishedResult.CID) 130 131 finalOutputPath := filepath.Join(outputDir, shard.PublishedResult.CID) 132 err = node.IPFSClient.Get(ctx, shard.PublishedResult.CID, finalOutputPath) 133 require.NoError(s.T(), err) 134 135 err = filepath.Walk(finalOutputPath, 136 func(path string, info os.FileInfo, err error) error { 137 require.NoError(s.T(), err) 138 log.Debug().Msgf("%s - %d", path, info.Size()) 139 return err 140 }) 141 require.NoError(s.T(), err) 142 143 stdoutContents, err := os.ReadFile(filepath.Join(finalOutputPath, "stdout")) 144 require.NoError(s.T(), err) 145 require.NotEmpty(s.T(), stdoutContents) 146 147 log.Debug().Msgf("stdoutContents=> %s", stdoutContents) 148 149 // stderrContents, err := ioutil.ReadFile(filepath.Join(finalOutputPath, "stderr")) 150 // require.NoError(s.T(), err) 151 // require.Empty(s.T(), stderrContents, "stderr should be empty: %s", stderrContents) 152 153 filePath := fmt.Sprintf("%s/output/test.txt", finalOutputPath) 154 outputData, err := os.ReadFile(filePath) 155 require.NoError(s.T(), err) 156 157 require.Equal(s.T(), fileContents, strings.TrimSpace(string(outputData))) 158 } 159 func (s *DevstackPythonWASMSuite) TestSimplestPythonWasmDashC() { 160 testutils.SkipIfArm(s.T(), "https://github.com/filecoin-project/bacalhau/issues/1268") 161 cmd.Fatal = cmd.FakeFatalErrorHandler 162 163 ctx := context.Background() 164 stack, _ := testutils.SetupTest(ctx, s.T(), 1, 0, false, 165 node.NewComputeConfigWithDefaults(), 166 node.NewRequesterConfigWithDefaults()) 167 168 // TODO: see also list_test.go, maybe factor out a common way to do this cli 169 // setup 170 _, out, err := cmd.ExecuteTestCobraCommand(s.T(), 171 fmt.Sprintf("--api-port=%d", stack.Nodes[0].APIServer.Port), 172 "--api-host=localhost", 173 "run", 174 "python", 175 "--deterministic", 176 "-c", 177 "print(1+1)", 178 ) 179 require.NoError(s.T(), err) 180 181 jobId := system.FindJobIDInTestOutput(out) 182 require.NoError(s.T(), err) 183 log.Debug().Msgf("jobId=%s", jobId) 184 time.Sleep(time.Second * 5) 185 186 node := stack.Nodes[0] 187 apiUri := node.APIServer.GetURI() 188 apiClient := publicapi.NewRequesterAPIClient(apiUri) 189 resolver := apiClient.GetJobStateResolver() 190 require.NoError(s.T(), err) 191 err = resolver.WaitUntilComplete(ctx, jobId) 192 require.NoError(s.T(), err) 193 194 } 195 196 // TODO: test that > 10MB context is rejected 197 198 func (s *DevstackPythonWASMSuite) TestSimplePythonWasm() { 199 testutils.SkipIfArm(s.T(), "https://github.com/filecoin-project/bacalhau/issues/1268") 200 cmd.Fatal = cmd.FakeFatalErrorHandler 201 202 ctx := context.Background() 203 stack, _ := testutils.SetupTest(ctx, s.T(), 1, 0, false, 204 node.NewComputeConfigWithDefaults(), 205 node.NewRequesterConfigWithDefaults()) 206 207 tmpDir := s.T().TempDir() 208 209 oldDir, err := os.Getwd() 210 require.NoError(s.T(), err) 211 err = os.Chdir(tmpDir) 212 require.NoError(s.T(), err) 213 defer func() { 214 err := os.Chdir(oldDir) 215 require.NoError(s.T(), err) 216 }() 217 218 // write bytes to main.py 219 mainPy := []byte("print(1+1)\n") 220 err = os.WriteFile("main.py", mainPy, 0644) 221 require.NoError(s.T(), err) 222 223 _, out, err := cmd.ExecuteTestCobraCommand(s.T(), 224 fmt.Sprintf("--api-port=%d", stack.Nodes[0].APIServer.Port), 225 "--api-host=localhost", 226 "run", 227 "python", 228 "--deterministic", 229 "main.py", 230 ) 231 require.NoError(s.T(), err) 232 233 jobId := system.FindJobIDInTestOutput(out) 234 require.NotEmpty(s.T(), jobId, "Unable to find Job ID in", out) 235 log.Debug().Msgf("jobId=%s", jobId) 236 time.Sleep(time.Second * 5) 237 238 apiUri := stack.Nodes[0].APIServer.GetURI() 239 apiClient := publicapi.NewRequesterAPIClient(apiUri) 240 resolver := apiClient.GetJobStateResolver() 241 require.NoError(s.T(), err) 242 err = resolver.WaitUntilComplete(ctx, jobId) 243 require.NoError(s.T(), err) 244 } 245 246 // func TestPythonWasmWithRequirements(t *testing.T) { 247 // tmpDir, err := ioutil.TempDir("", "devstack_test") 248 // require.NoError(t, err) 249 // defer func() { 250 // err := os.RemoveAll(tmpDir) 251 // require.NoError(t, err) 252 // }() 253 254 // oldDir, err := os.Getwd() 255 // require.NoError(t, err) 256 // err = os.Chdir(tmpDir) 257 // require.NoError(t, err) 258 // defer func() { 259 // err := os.Chdir(oldDir) 260 // require.NoError(t, err) 261 // }() 262 263 // _, out, err := ExecuteTestCobraCommand(t, RootCmd, 264 // "run", 265 // "python", 266 // "--deterministic", 267 // "main.py", 268 // ) 269 // require.NoError(t, err) 270 271 // }