github.com/taubyte/tau-cli@v0.1.13-0.20240326000942-487f0d57edfc/tests/utils_monkey_test.go (about) 1 package tests 2 3 import ( 4 "fmt" 5 "os" 6 "path" 7 "path/filepath" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/pterm/pterm" 13 "github.com/spf13/afero" 14 "github.com/taubyte/go-project-schema/project" 15 "github.com/taubyte/tau-cli/common" 16 "github.com/taubyte/tau-cli/singletons/session" 17 "gotest.tools/v3/assert" 18 ) 19 20 func newMonkey(s *spiderTestContext, tm testMonkey) *monkeyTestContext { 21 return &monkeyTestContext{ 22 spider: s, 23 testMonkey: tm, 24 } 25 } 26 27 func newMonkeyRunContext(tm testMonkey, rr roadRunner, isChild bool) *monkeyRunContext { 28 prefix := "Command" 29 if isChild { 30 prefix = "Child-Command" 31 } 32 33 return &monkeyRunContext{ 34 prefix: prefix, 35 testMonkey: tm, 36 rr: rr, 37 isChild: isChild, 38 } 39 } 40 41 func (ctx *monkeyRunContext) checkSession(t *testing.T, result *commandResult) { 42 if ctx.evaluateSession != nil { 43 sessionLock.Lock() 44 defer sessionLock.Unlock() 45 46 err := session.LoadSessionInDir(ctx.rr.sessionFile) 47 if err != nil { 48 t.Errorf("loading session at `%s` failed with: %s", ctx.rr.sessionFile, err) 49 return 50 } 51 52 err = ctx.evaluateSession(session.Get()) 53 if err != nil { 54 result.Error(t, fmt.Sprintf("Session evaluation failed with: %s", err.Error())) 55 return 56 } 57 } 58 } 59 60 func (ctx *monkeyRunContext) checkProject(t *testing.T) { 61 if ctx.confirmProject != nil { 62 _project, err := project.Open(project.VirtualFS(afero.NewOsFs(), path.Join(ctx.rr.dir, "test_project/config"))) 63 if err != nil { 64 panic(err) 65 } 66 67 err = ctx.confirmProject(_project) 68 if err != nil { 69 t.Errorf("\n\nConfirming project failed with error: %s\n\n", err) 70 return 71 } 72 } 73 } 74 75 func (ctx *monkeyRunContext) Run(t *testing.T) { 76 result := &commandResult{ 77 monkeyRunContext: ctx, 78 } 79 result.err, result.exitCode, result.out1, result.out2 = ctx.rr.Run(ctx.args...) 80 result.printDebugInfo() 81 82 // confirm error is as expected, either nil or containing string 83 result.checkError(t) 84 85 // confirm wantOut and dontWantOut 86 result.checkWantOut(t) 87 88 // Check exit code, defaults 0 89 result.checkExitCode(t) 90 91 // confirm wantDir and dontWantDir 92 result.checkDirectories(t) 93 94 // Run confirmProject 95 ctx.checkProject(t) 96 97 // Run evaluateSession 98 ctx.checkSession(t, result) 99 } 100 101 func (tm *monkeyTestContext) setParallel(t *testing.T) { 102 if tm.spider.parallel { 103 t.Parallel() 104 } 105 } 106 107 func (tm *monkeyTestContext) getOrCreateDir() (err error) { 108 // Create temp configFile 109 if tm.spider.debug { 110 tm.dir = "./_fakeroot/debug/" + tm.name 111 } else { 112 tm.dir, err = os.MkdirTemp("_fakeroot", "tests") 113 if err != nil { 114 return err 115 } 116 } 117 118 // Transform dir to an absolute 119 tm.dir, err = filepath.Abs(tm.dir) 120 if err != nil { 121 return err 122 } 123 124 // Define the location of the config file 125 // in the temp directory, or named directory if in 126 // debug mode 127 tm.configLoc, _ = filepath.Abs(tm.dir + "/tau.yaml") 128 tm.sessionLoc, _ = filepath.Abs(tm.dir + "/session") 129 130 return nil 131 } 132 133 func (tm *monkeyTestContext) refreshTestFiles() error { 134 // Remove previous debug files, as they don't get removed 135 // when debugging 136 if tm.spider.debug { 137 os.Remove(tm.configLoc) 138 os.Remove(tm.sessionLoc) 139 os.RemoveAll(tm.dir) 140 } 141 142 // Create the project config and code directories for testing 143 if tm.spider.projectName != "" { 144 err := os.MkdirAll(fmt.Sprintf("%s/%s/config", tm.dir, tm.spider.projectName), 0755) 145 if err != nil { 146 return err 147 } 148 149 err = os.MkdirAll(fmt.Sprintf("%s/%s/code", tm.dir, tm.spider.projectName), 0755) 150 if err != nil { 151 return err 152 } 153 } else { 154 err := os.MkdirAll(tm.dir, 0755) 155 if err != nil { 156 return err 157 } 158 } 159 160 return nil 161 } 162 163 func (tm *monkeyTestContext) Run(t *testing.T) { 164 defer func() { 165 if tm.cleanUp != nil { 166 assert.NilError(t, tm.cleanUp()) 167 } 168 pterm.Info.Printfln("%s is done.", tm.name) 169 }() 170 171 tm.setParallel(t) 172 173 // Call a function to clear vars and lock 174 // TODO do this better, as of 1.20 we can test coverage with a binary rather than this hack 175 deferment := takeCover() 176 defer deferment() 177 178 err := tm.getOrCreateDir() 179 assert.NilError(t, err) 180 181 // Remove old test files, create the new directories, and test tm values for relative directories 182 err = tm.refreshTestFiles() 183 assert.NilError(t, err) 184 185 // Write the test config based on a spider supplied config method 186 err = tm.spider.writeConfig(tm.dir, tm.configLoc) 187 assert.NilError(t, err) 188 189 // Write the session dir for tests in which values will not be set, but seer still needs to open 190 err = os.Mkdir(tm.sessionLoc, common.DefaultDirPermission) 191 assert.NilError(t, err) 192 193 // Set selected project in the session 194 err = tm.setSessionProject() 195 assert.NilError(t, err) 196 197 // Call a provided method to write files to the temp directory 198 if tm.writeFilesInDir != nil { 199 tm.writeFilesInDir(tm.dir) 200 } 201 202 // Make sure env is not nil 203 if tm.env == nil { 204 tm.env = make(map[string]string, 0) 205 } 206 207 // Set the default wait time if none is set 208 if tm.waitTime == 0 { 209 tm.waitTime = 30 * time.Second 210 } 211 212 // Start the mock server and get the url 213 if tm.mock { 214 // TODO dreamland 215 216 // // get a random port 1024 to 65353 and start it 217 port := fmt.Sprintf("%v", random.Intn(64329)+1024) 218 tm.authUrl = "http://localhost:" + port 219 mockServerStop := startMockOnPort(port) 220 221 // wait for mock server to start 222 // TODO, check ping the port 223 time.Sleep(1500 * time.Millisecond) 224 225 if tm.debug { 226 fmt.Println("Started mock on", tm.authUrl) 227 } 228 defer func() { 229 mockServerStop() 230 // Give the server a moment to shut down 231 time.Sleep(500 * time.Millisecond) 232 }() 233 } else { 234 tm.authUrl = "https://auth.tau.sandbox.taubyte.com" 235 } 236 237 rr := roadRunner{ 238 configFile: tm.configLoc, 239 sessionFile: tm.sessionLoc, 240 authUrl: tm.authUrl, 241 waitTime: tm.waitTime, 242 env: tm.env, 243 dir: tm.dir, 244 } 245 246 // run preRun commands 247 tm.runPreRun(t, rr) 248 249 tm.runBabyMonkeys(t, rr) 250 251 // run main command 252 newMonkeyRunContext(tm.testMonkey, rr, false).Run(t) 253 254 // Cleanup 255 if !tm.spider.debug { 256 os.Remove(tm.configLoc) 257 os.RemoveAll(tm.dir) 258 } 259 } 260 261 func (tm *monkeyTestContext) setSessionProject() error { 262 projectName := tm.spider.projectName 263 264 if projectName == "" { 265 return nil 266 } 267 sessionLock.Lock() 268 defer sessionLock.Unlock() 269 270 err := session.LoadSessionInDir(tm.sessionLoc) 271 if err != nil { 272 return fmt.Errorf("loading session at `%s` failed with: %s", tm.sessionLoc, err) 273 } 274 275 err = session.Set().SelectedProject(projectName) 276 if err != nil { 277 return fmt.Errorf("setting selected project to `%s` failed with: %s", projectName, err) 278 } 279 280 return nil 281 } 282 283 func (tm *monkeyTestContext) runPreRun(t *testing.T, rr roadRunner) { 284 runBefore := tm.spider.getBeforeEach(tm.testMonkey) 285 286 if tm.preRun != nil { 287 runBefore = append(runBefore, tm.preRun...) 288 } 289 for _, _args := range runBefore { 290 err, exitCode, out1, out2 := rr.Run(_args...) 291 if err != nil { 292 t.Errorf("RunBefore(%s) failed with error: %s \nOut1 %s:\n %s\nOut2:%s \n(%s)", _args, err, rr.dir, out1, out2, tm.name) 293 return 294 } 295 296 if tm.debug { 297 pterm.FgLightYellow.Println("RunBefore args:") 298 fmt.Print(cleanArgs(_args), "\n\n") 299 300 pterm.FgLightYellow.Print("RunBefore exitCode: ") 301 fmt.Print(exitCode, "\n\n") 302 303 pterm.FgLightYellow.Println("RunBefore Out:") 304 fmt.Println(out1) 305 306 pterm.FgLightYellow.Println("RunBefore Error:") 307 fmt.Println(out2) 308 309 fmt.Print(strings.Repeat("-", 50), "\n\n") 310 } 311 } 312 }