github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/test/integration/activate_int_test.go (about) 1 package integration 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "os/exec" 8 "path/filepath" 9 "regexp" 10 "runtime" 11 "strings" 12 "testing" 13 "time" 14 15 "github.com/ActiveState/cli/internal/testhelpers/suite" 16 "github.com/ActiveState/termtest" 17 18 "github.com/ActiveState/cli/internal/rtutils" 19 20 "github.com/ActiveState/cli/internal/constants" 21 "github.com/ActiveState/cli/internal/fileutils" 22 "github.com/ActiveState/cli/internal/osutils" 23 "github.com/ActiveState/cli/internal/testhelpers/e2e" 24 "github.com/ActiveState/cli/internal/testhelpers/tagsuite" 25 ) 26 27 type ActivateIntegrationTestSuite struct { 28 tagsuite.Suite 29 } 30 31 func (suite *ActivateIntegrationTestSuite) TestActivatePython3() { 32 suite.OnlyRunForTags(tagsuite.Python, tagsuite.Activate, tagsuite.Critical) 33 suite.activatePython("3") 34 } 35 36 func (suite *ActivateIntegrationTestSuite) TestActivatePython3_zsh() { 37 suite.OnlyRunForTags(tagsuite.Python, tagsuite.Activate, tagsuite.Shell) 38 if _, err := exec.LookPath("zsh"); err != nil { 39 suite.T().Skip("This test requires a zsh shell in your PATH") 40 } 41 suite.activatePython("3", "SHELL=zsh") 42 } 43 44 func (suite *ActivateIntegrationTestSuite) TestActivatePython2() { 45 suite.OnlyRunForTags(tagsuite.Python, tagsuite.Activate) 46 suite.activatePython("2") 47 } 48 49 func (suite *ActivateIntegrationTestSuite) TestActivateWithoutRuntime() { 50 suite.OnlyRunForTags(tagsuite.Critical, tagsuite.Activate, tagsuite.ExitCode) 51 ts := e2e.New(suite.T(), false) 52 defer ts.Close() 53 close := suite.addForegroundSvc(ts) 54 defer close() 55 56 cp := ts.Spawn("activate", "ActiveState-CLI/Python2") 57 cp.Expect("Skipping runtime setup") 58 cp.Expect("Activated") 59 cp.ExpectInput() 60 61 cp.SendLine("exit 123") 62 cp.ExpectExitCode(123) 63 } 64 65 // addForegroundSvc launches the state-svc in a way where we can track its output for debugging purposes 66 // without this we are mostly blind to the svc exiting prematurely 67 func (suite *ActivateIntegrationTestSuite) addForegroundSvc(ts *e2e.Session) func() { 68 cmd, stdout, stderr, err := osutils.ExecuteInBackground(ts.SvcExe, []string{"foreground"}, func(cmd *exec.Cmd) error { 69 cmd.Env = append(ts.Env, "VERBOSE=true", "") // For whatever reason the last entry is ignored.. 70 return nil 71 }) 72 suite.Require().NoError(err) 73 74 // Wait for the svc to be ready 75 err = rtutils.Timeout(func() error { 76 code := -1 77 for code != 0 { 78 code, _, _ = osutils.Execute(ts.SvcExe, []string{"status"}, func(cmd *exec.Cmd) error { 79 cmd.Env = ts.Env 80 return nil 81 }) 82 } 83 return nil 84 }, 10*time.Second) 85 suite.Require().NoError(err) 86 87 // This function seems to trigger lots of flisten errors that do not appear to be actual errors 88 // (the integration test expectations all pass). Just ignore log errors for sessions that call 89 // this function. 90 ts.IgnoreLogErrors() 91 92 // Stop function 93 return func() { 94 go func() { 95 defer func() { 96 suite.Require().Nil(recover()) 97 }() 98 stdout, stderr, err := osutils.ExecSimple(ts.SvcExe, []string{"stop"}, ts.Env) 99 suite.Require().NoError(err, "svc stop failed: %s\n%s", stdout, stderr) 100 }() 101 102 verifyExit := true 103 104 err2 := rtutils.Timeout(func() error { return cmd.Wait() }, 10*time.Second) 105 if err2 != nil { 106 if !errors.Is(err2, rtutils.ErrTimeout) { 107 suite.Require().NoError(err2) 108 } 109 suite.T().Logf("svc did not stop in time, Stdout:\n%s\n\nStderr:\n%s", stdout.String(), stderr.String()) 110 err = cmd.Process.Kill() 111 suite.Require().NoError(err) 112 } 113 114 errMsg := fmt.Sprintf("svc foreground did not complete as expected. Stdout:\n%s\n\nStderr:\n%s", stdout.String(), stderr.String()) 115 if verifyExit { 116 suite.Require().NoError(err2, errMsg) 117 if cmd.ProcessState.ExitCode() != 0 { 118 suite.FailNow(errMsg) 119 } 120 } 121 122 // Goroutines don't necessarily cause the process to exit non-zero, so check for common errors/panics 123 rx := regexp.MustCompile(`(?:runtime error|invalid memory address|nil pointer|goroutine)`) 124 if rx.Match(stderr.Bytes()) { 125 suite.FailNow(errMsg) 126 } 127 } 128 } 129 130 func (suite *ActivateIntegrationTestSuite) TestActivateUsingCommitID() { 131 suite.OnlyRunForTags(tagsuite.Critical, tagsuite.Activate) 132 ts := e2e.New(suite.T(), false) 133 defer ts.Close() 134 close := suite.addForegroundSvc(ts) 135 defer close() 136 137 cp := ts.SpawnWithOpts( 138 e2e.OptArgs("activate", "ActiveState-CLI/Python3#6d9280e7-75eb-401a-9e71-0d99759fbad3", "--path", ts.Dirs.Work), 139 e2e.OptAppendEnv(constants.DisableRuntime+"=false"), 140 ) 141 cp.Expect("Activated", e2e.RuntimeSourcingTimeoutOpt) 142 cp.ExpectInput() 143 144 cp.SendLine("exit") 145 cp.ExpectExitCode(0) 146 } 147 148 func (suite *ActivateIntegrationTestSuite) TestActivateNotOnPath() { 149 suite.OnlyRunForTags(tagsuite.Critical, tagsuite.Activate) 150 ts := e2e.NewNoPathUpdate(suite.T(), false) 151 defer ts.Close() 152 close := suite.addForegroundSvc(ts) 153 defer close() 154 155 cp := ts.SpawnWithOpts( 156 e2e.OptArgs("activate", "activestate-cli/small-python", "--path", ts.Dirs.Work), 157 ) 158 cp.Expect("Skipping runtime setup") 159 cp.Expect("Activated") 160 cp.ExpectInput(termtest.OptExpectTimeout(10 * time.Second)) 161 162 if runtime.GOOS == "windows" { 163 cp.SendLine("doskey /macros | findstr state=") 164 } else { 165 cp.SendLine("alias state") 166 } 167 cp.Expect("state=") 168 169 cp.SendLine("state --version") 170 cp.Expect("ActiveState") 171 172 cp.SendLine("exit") 173 cp.ExpectExitCode(0) 174 } 175 176 // TestActivatePythonByHostOnly Tests whether we are only pulling in the build for the target host 177 func (suite *ActivateIntegrationTestSuite) TestActivatePythonByHostOnly() { 178 suite.OnlyRunForTags(tagsuite.Critical, tagsuite.Activate) 179 180 ts := e2e.New(suite.T(), false) 181 defer ts.Close() 182 close := suite.addForegroundSvc(ts) 183 defer close() 184 185 projectName := "Python-LinuxWorks" 186 cp := ts.SpawnWithOpts( 187 e2e.OptArgs("activate", "cli-integration-tests/"+projectName, "--path="+ts.Dirs.Work), 188 e2e.OptAppendEnv(constants.DisableRuntime+"=false"), 189 ) 190 191 if runtime.GOOS == "linux" { 192 cp.Expect("Creating a Virtual Environment") 193 cp.Expect("Activated", e2e.RuntimeSourcingTimeoutOpt) 194 cp.ExpectInput(termtest.OptExpectTimeout(40 * time.Second)) 195 cp.SendLine("exit") 196 cp.ExpectExitCode(0) 197 } else { 198 cp.Expect("Your current platform") 199 cp.Expect("does not appear to be configured") 200 cp.ExpectNotExitCode(0) 201 202 if strings.Count(cp.Snapshot(), " x ") != 1 { 203 suite.Fail("Expected exactly ONE error message, got: ", cp.Snapshot()) 204 } 205 } 206 ts.IgnoreLogErrors() 207 } 208 209 func (suite *ActivateIntegrationTestSuite) assertCompletedStatusBarReport(snapshot string) { 210 // ensure that terminal contains output "Installing x/y" with x, y numbers and x=y 211 installingString := regexp.MustCompile( 212 "Installing *([0-9]+) */ *([0-9]+)", 213 ).FindAllStringSubmatch(snapshot, -1) 214 suite.Require().Greater(len(installingString), 0, "no match for Installing x / x in\n%s", snapshot) 215 le := len(installingString) - 1 216 suite.Require().Equalf( 217 installingString[le][1], installingString[le][2], 218 "expected all artifacts are reported to be installed, got %s in\n%s", installingString[0][0], snapshot, 219 ) 220 } 221 222 func (suite *ActivateIntegrationTestSuite) activatePython(version string, extraEnv ...string) { 223 ts := e2e.New(suite.T(), false) 224 defer ts.Close() 225 close := suite.addForegroundSvc(ts) 226 defer close() 227 228 namespace := "ActiveState-CLI/Python" + version 229 230 cp := ts.SpawnWithOpts( 231 e2e.OptArgs("activate", namespace), 232 e2e.OptAppendEnv(constants.DisableRuntime+"=false"), 233 e2e.OptAppendEnv(extraEnv...), 234 ) 235 236 cp.Expect("Activated", e2e.RuntimeSourcingTimeoutOpt) 237 // ensure that shell is functional 238 cp.ExpectInput() 239 240 pythonExe := "python" + version 241 242 cp.SendLine(pythonExe + " -c \"import sys; print(sys.copyright)\"") 243 cp.Expect("ActiveState Software Inc.") 244 245 if runtime.GOOS == "windows" { 246 cp.SendLine("where " + pythonExe) 247 cp.Expect(`\exec\` + pythonExe) 248 } else { 249 cp.SendLine("which " + pythonExe) 250 cp.Expect("/exec/" + pythonExe) 251 } 252 253 cp.SendLine(pythonExe + " -c \"import pytest; print(pytest.__doc__)\"") 254 cp.Expect("unit and functional testing") 255 256 cp.SendLine("state activate --default ActiveState-CLI/cli") 257 cp.Expect("Cannot make ActiveState-CLI/cli always available for use while in an activated state") 258 259 cp.SendLine("state activate --default") 260 cp.Expect("Creating a Virtual Environment") 261 cp.ExpectInput(termtest.OptExpectTimeout(40 * time.Second)) 262 pythonShim := pythonExe + osutils.ExeExtension 263 264 // test that existing environment variables are inherited by the activated shell 265 if runtime.GOOS == "windows" { 266 cp.SendLine(fmt.Sprintf("echo %%%s%%", constants.DisableRuntime)) 267 } else { 268 cp.SendLine("echo $" + constants.DisableRuntime) 269 } 270 cp.Expect("false") 271 272 // test that other executables that use python work as well 273 pipExe := "pip" + version 274 cp.SendLine(fmt.Sprintf("%s --version", pipExe)) 275 276 // Exit activated state 277 cp.SendLine("exit") 278 cp.ExpectExitCode(0) 279 pendingOutput := cp.PendingOutput() // Without waiting for exit this isn't guaranteed to have our output yet 280 281 // Assert pip output 282 pipVersionRe := regexp.MustCompile(`pip \d+(?:\.\d+)+ from ([^ ]+) \(python`) 283 pipVersionMatch := pipVersionRe.FindStringSubmatch(pendingOutput) 284 suite.Require().Len(pipVersionMatch, 2, "expected pip version to match, pending output: %s", pendingOutput) 285 suite.Contains(pipVersionMatch[1], "cache", "pip loaded from activestate cache dir") 286 287 executor := filepath.Join(ts.Dirs.DefaultBin, pythonShim) 288 // check that default activation works 289 cp = ts.SpawnCmdWithOpts( 290 executor, 291 e2e.OptArgs("-c", "import sys; print(sys.copyright);"), 292 e2e.OptAppendEnv(constants.DisableRuntime+"=false"), 293 ) 294 cp.Expect("ActiveState Software Inc.", e2e.RuntimeSourcingTimeoutOpt) 295 cp.ExpectExitCode(0) 296 } 297 298 func (suite *ActivateIntegrationTestSuite) TestActivate_PythonPath() { 299 suite.OnlyRunForTags(tagsuite.Activate) 300 301 ts := e2e.New(suite.T(), false) 302 defer ts.Close() 303 close := suite.addForegroundSvc(ts) 304 defer close() 305 306 namespace := "ActiveState-CLI/Python3" 307 308 cp := ts.SpawnWithOpts( 309 e2e.OptArgs("activate", namespace), 310 e2e.OptAppendEnv(constants.DisableRuntime+"=false"), 311 ) 312 313 cp.Expect("Activated", e2e.RuntimeSourcingTimeoutOpt) 314 // ensure that shell is functional 315 cp.ExpectInput() 316 317 // Verify that PYTHONPATH is set correctly to the installed site-packages, not a temp runtime 318 // setup directory. 319 if runtime.GOOS == "windows" { 320 cp.SendLine("echo %PYTHONPATH%") 321 } else { 322 cp.SendLine("echo $PYTHONPATH") 323 } 324 suite.Assert().NotContains(cp.Output(), constants.LocalRuntimeTempDirectory) 325 // Verify the temp runtime setup directory has been removed. 326 runtimeFound := false 327 entries, err := fileutils.ListDir(ts.Dirs.Cache, true) 328 suite.Require().NoError(err) 329 for _, entry := range entries { 330 if entry.IsDir() && fileutils.DirExists(filepath.Join(entry.Path(), constants.LocalRuntimeEnvironmentDirectory)) { 331 runtimeFound = true 332 suite.Assert().NoDirExists(filepath.Join(entry.Path(), constants.LocalRuntimeTempDirectory)) 333 } 334 } 335 suite.Assert().True(runtimeFound, "runtime directory was not found in ts.Dirs.Cache") 336 337 // test that PYTHONPATH is preserved in environment (https://www.pivotaltracker.com/story/show/178458102) 338 if runtime.GOOS == "windows" { 339 cp.SendLine("set PYTHONPATH=/custom_pythonpath") 340 cp.SendLine(`python3 -c "import os; print(os.environ['PYTHONPATH']);"`) 341 } else { 342 cp.SendLine(`PYTHONPATH=/custom_pythonpath python3 -c 'import os; print(os.environ["PYTHONPATH"]);'`) 343 } 344 cp.Expect("/custom_pythonpath") 345 346 // de-activate shell 347 cp.SendLine("exit") 348 cp.ExpectExitCode(0) 349 } 350 351 func (suite *ActivateIntegrationTestSuite) TestActivate_SpaceInCacheDir() { 352 suite.OnlyRunForTags(tagsuite.Activate) 353 354 ts := e2e.New(suite.T(), false) 355 defer ts.Close() 356 close := suite.addForegroundSvc(ts) 357 defer close() 358 359 cacheDir := filepath.Join(ts.Dirs.Cache, "dir with spaces") 360 err := fileutils.MkdirUnlessExists(cacheDir) 361 suite.Require().NoError(err) 362 363 cp := ts.SpawnWithOpts( 364 e2e.OptAppendEnv(fmt.Sprintf("%s=%s", constants.CacheEnvVarName, cacheDir)), 365 e2e.OptAppendEnv(fmt.Sprintf(`%s=""`, constants.DisableRuntime)), 366 e2e.OptArgs("activate", "ActiveState-CLI/Python3"), 367 ) 368 369 cp.Expect("Activated", e2e.RuntimeSourcingTimeoutOpt) 370 cp.SendLine("python3 --version") 371 cp.Expect("Python 3.") 372 373 cp.SendLine("exit") 374 cp.ExpectExitCode(0) 375 } 376 377 func (suite *ActivateIntegrationTestSuite) TestActivatePerlCamel() { 378 suite.OnlyRunForTags(tagsuite.Activate, tagsuite.Perl, tagsuite.Critical) 379 if runtime.GOOS == "darwin" { 380 suite.T().Skip("Perl not supported on macOS") 381 } 382 383 ts := e2e.New(suite.T(), false) 384 defer ts.Close() 385 close := suite.addForegroundSvc(ts) 386 defer close() 387 388 cp := ts.SpawnWithOpts( 389 e2e.OptArgs("activate", "ActiveState-CLI/Perl"), 390 e2e.OptAppendEnv(constants.DisableRuntime+"=false"), 391 ) 392 393 cp.Expect("Downloading", termtest.OptExpectTimeout(40*time.Second)) 394 cp.Expect("Installing", termtest.OptExpectTimeout(140*time.Second)) 395 cp.Expect("Activated", e2e.RuntimeSourcingTimeoutOpt) 396 397 suite.assertCompletedStatusBarReport(cp.Output()) 398 399 // ensure that shell is functional 400 cp.ExpectInput() 401 402 cp.SendLine("perldoc -l DBI::DBD") 403 // Expect the source code to be installed in the cache directory 404 // Note: At least for Windows we cannot expect cp.Dirs.Cache, because it is unreliable how the path name formats are unreliable (sometimes DOS 8.3 format, sometimes not) 405 cp.Expect("cache") 406 cp.Expect("DBD.pm") 407 408 // Currently CI is searching for PPM in the @INC first before attempting 409 // to execute a script. https://activestatef.atlassian.net/browse/DX-620 410 if runtime.GOOS != "windows" { 411 // Expect PPM shim to be installed 412 cp.SendLine("ppm list") 413 cp.Expect("Shimming command") 414 } 415 416 cp.SendLine("exit") 417 cp.ExpectExitCode(0) 418 } 419 420 func (suite *ActivateIntegrationTestSuite) TestActivate_Subdir() { 421 suite.OnlyRunForTags(tagsuite.Activate, tagsuite.Critical) 422 ts := e2e.New(suite.T(), false) 423 defer ts.Close() 424 close := suite.addForegroundSvc(ts) 425 defer close() 426 err := fileutils.Mkdir(ts.Dirs.Work, "foo", "bar", "baz") 427 suite.Require().NoError(err) 428 429 // Create the project file at the root of the temp dir 430 content := strings.TrimSpace(fmt.Sprintf(` 431 project: "https://platform.activestate.com/ActiveState-CLI/Python3" 432 branch: %s 433 version: %s 434 `, constants.ChannelName, constants.Version)) 435 436 ts.PrepareActiveStateYAML(content) 437 ts.PrepareCommitIdFile("59404293-e5a9-4fd0-8843-77cd4761b5b5") 438 439 // Pull to ensure we have an up to date config file 440 cp := ts.Spawn("pull") 441 cp.Expect("activestate.yaml has been updated to") 442 cp.ExpectExitCode(0) 443 444 // Activate in the subdirectory 445 c2 := ts.SpawnWithOpts( 446 e2e.OptArgs("activate"), 447 e2e.OptWD(filepath.Join(ts.Dirs.Work, "foo", "bar", "baz")), 448 ) 449 c2.Expect("Activated") 450 451 c2.ExpectInput(termtest.OptExpectTimeout(40 * time.Second)) 452 c2.SendLine("exit") 453 c2.ExpectExitCode(0) 454 } 455 456 func (suite *ActivateIntegrationTestSuite) TestActivate_NamespaceWins() { 457 suite.OnlyRunForTags(tagsuite.Activate) 458 ts := e2e.New(suite.T(), false) 459 identifyPath := "identifyable-path" 460 targetPath := filepath.Join(ts.Dirs.Work, "foo", "bar", identifyPath) 461 defer ts.Close() 462 close := suite.addForegroundSvc(ts) 463 defer close() 464 err := fileutils.Mkdir(targetPath) 465 suite.Require().NoError(err) 466 467 // Create the project file at the root of the temp dir 468 ts.PrepareProject("ActiveState-CLI/Python3", "59404293-e5a9-4fd0-8843-77cd4761b5b5") 469 470 // Pull to ensure we have an up to date config file 471 cp := ts.Spawn("pull") 472 cp.Expect("activestate.yaml has been updated to") 473 cp.ExpectExitCode(0) 474 475 // Activate in the subdirectory 476 c2 := ts.SpawnWithOpts( 477 e2e.OptArgs("activate", "ActiveState-CLI/Python2"), // activate a different namespace 478 e2e.OptWD(targetPath), 479 e2e.OptAppendEnv(constants.DisableLanguageTemplates+"=true"), 480 ) 481 c2.Expect("ActiveState-CLI/Python2") 482 c2.Expect("Activated") 483 484 c2.ExpectInput(termtest.OptExpectTimeout(40 * time.Second)) 485 if runtime.GOOS == "windows" { 486 c2.SendLine("@echo %cd%") 487 } else { 488 c2.SendLine("pwd") 489 } 490 c2.Expect(identifyPath) 491 c2.SendLine("exit") 492 c2.ExpectExitCode(0) 493 } 494 495 func (suite *ActivateIntegrationTestSuite) TestActivate_InterruptedInstallation() { 496 suite.OnlyRunForTags(tagsuite.Activate) 497 if runtime.GOOS == "windows" && e2e.RunningOnCI() { 498 suite.T().Skip("interrupting installation does not work on Windows on CI") 499 } 500 ts := e2e.New(suite.T(), true) 501 defer ts.Close() 502 close := suite.addForegroundSvc(ts) 503 defer close() 504 505 cp := ts.SpawnShellWithOpts("bash", e2e.OptAppendEnv(constants.DisableRuntime+"=false")) 506 cp.SendLine("state deploy install ActiveState-CLI/small-python") 507 cp.Expect("Installing Runtime") // Ensure we don't send Ctrl+C too soon 508 cp.SendCtrlC() 509 cp.Expect("User interrupted") 510 cp.SendLine("exit") 511 cp.ExpectExit() 512 } 513 514 func (suite *ActivateIntegrationTestSuite) TestActivate_FromCache() { 515 suite.OnlyRunForTags(tagsuite.Activate, tagsuite.Critical) 516 ts := e2e.New(suite.T(), true) 517 err := ts.ClearCache() 518 suite.Require().NoError(err) 519 defer ts.Close() 520 close := suite.addForegroundSvc(ts) 521 defer close() 522 523 cp := ts.SpawnWithOpts( 524 e2e.OptArgs("activate", "ActiveState-CLI/small-python", "--path", ts.Dirs.Work), 525 e2e.OptAppendEnv(constants.DisableRuntime+"=false"), 526 ) 527 cp.Expect("Downloading") 528 cp.Expect("Installing") 529 cp.Expect("Activated", e2e.RuntimeSourcingTimeoutOpt) 530 531 suite.assertCompletedStatusBarReport(cp.Output()) 532 cp.SendLine("exit") 533 cp.ExpectExitCode(0) 534 535 // next activation is cached 536 cp = ts.SpawnWithOpts( 537 e2e.OptArgs("activate", "ActiveState-CLI/small-python", "--path", ts.Dirs.Work), 538 e2e.OptAppendEnv(constants.DisableRuntime+"=false"), 539 ) 540 541 cp.ExpectInput(e2e.RuntimeSourcingTimeoutOpt) 542 cp.SendLine("exit") 543 cp.ExpectExitCode(0) 544 suite.NotContains(cp.Output(), "Downloading") 545 } 546 547 func TestActivateIntegrationTestSuite(t *testing.T) { 548 suite.Run(t, new(ActivateIntegrationTestSuite)) 549 } 550 551 func (suite *ActivateIntegrationTestSuite) TestActivateCommitURL() { 552 suite.OnlyRunForTags(tagsuite.Activate) 553 ts := e2e.New(suite.T(), false) 554 defer ts.Close() 555 close := suite.addForegroundSvc(ts) 556 defer close() 557 558 // https://platform.activestate.com/ActiveState-CLI/Python3/customize?commitID=fbc613d6-b0b1-4f84-b26e-4aa5869c4e54 559 commitID := "fbc613d6-b0b1-4f84-b26e-4aa5869c4e54" 560 contents := fmt.Sprintf("project: https://platform.activestate.com/commit/%s\n", commitID) 561 ts.PrepareActiveStateYAML(contents) 562 563 cp := ts.Spawn("activate") 564 cp.Expect("Cannot operate on a headless project", e2e.RuntimeSourcingTimeoutOpt) 565 cp.ExpectExitCode(1) 566 ts.IgnoreLogErrors() 567 } 568 569 func (suite *ActivateIntegrationTestSuite) TestActivate_AlreadyActive() { 570 suite.OnlyRunForTags(tagsuite.Activate) 571 572 ts := e2e.New(suite.T(), false) 573 defer ts.Close() 574 close := suite.addForegroundSvc(ts) 575 defer close() 576 577 namespace := "ActiveState-CLI/Python3" 578 579 cp := ts.SpawnWithOpts(e2e.OptArgs("activate", namespace)) 580 cp.Expect("Skipping runtime setup") 581 cp.Expect("Activated") 582 // ensure that shell is functional 583 cp.ExpectInput() 584 585 cp.SendLine("state activate") 586 cp.Expect("Your project is already active") 587 cp.ExpectInput() 588 } 589 590 func (suite *ActivateIntegrationTestSuite) TestActivate_AlreadyActive_SameNamespace() { 591 suite.OnlyRunForTags(tagsuite.Activate) 592 593 ts := e2e.New(suite.T(), false) 594 defer ts.Close() 595 close := suite.addForegroundSvc(ts) 596 defer close() 597 598 namespace := "ActiveState-CLI/Python3" 599 600 cp := ts.SpawnWithOpts(e2e.OptArgs("activate", namespace)) 601 cp.Expect("Skipping runtime setup") 602 cp.Expect("Activated") 603 // ensure that shell is functional 604 cp.ExpectInput() 605 606 cp.SendLine(fmt.Sprintf("state activate %s", namespace)) 607 cp.Expect("Your project is already active") 608 cp.ExpectInput() 609 } 610 611 func (suite *ActivateIntegrationTestSuite) TestActivate_AlreadyActive_DifferentNamespace() { 612 suite.OnlyRunForTags(tagsuite.Activate) 613 614 ts := e2e.New(suite.T(), false) 615 defer ts.Close() 616 close := suite.addForegroundSvc(ts) 617 defer close() 618 619 namespace := "ActiveState-CLI/Python3" 620 621 cp := ts.SpawnWithOpts(e2e.OptArgs("activate", namespace)) 622 cp.Expect("Skipping runtime setup") 623 cp.Expect("Activated") 624 // ensure that shell is functional 625 cp.ExpectInput() 626 627 cp.SendLine(fmt.Sprintf("state activate %s", "ActiveState-CLI/Perl-5.32")) 628 cp.Expect("You cannot activate a new project when you are already in an activated state") 629 cp.ExpectInput() 630 } 631 632 func (suite *ActivateIntegrationTestSuite) TestActivateBranch() { 633 suite.OnlyRunForTags(tagsuite.Activate) 634 635 ts := e2e.New(suite.T(), false) 636 defer ts.Close() 637 close := suite.addForegroundSvc(ts) 638 defer close() 639 640 namespace := "ActiveState-CLI/Branches" 641 642 cp := ts.SpawnWithOpts( 643 e2e.OptArgs("activate", namespace, "--branch", "firstbranch"), 644 ) 645 cp.Expect("Skipping runtime setup") 646 cp.Expect("Activated") 647 cp.SendLine("exit") 648 cp.ExpectExitCode(0) 649 } 650 651 func (suite *ActivateIntegrationTestSuite) TestActivateBranchNonExistant() { 652 suite.OnlyRunForTags(tagsuite.Activate) 653 654 ts := e2e.New(suite.T(), false) 655 defer ts.Close() 656 close := suite.addForegroundSvc(ts) 657 defer close() 658 659 namespace := "ActiveState-CLI/Branches" 660 661 cp := ts.SpawnWithOpts(e2e.OptArgs("activate", namespace, "--branch", "does-not-exist")) 662 663 cp.Expect("has no branch") 664 } 665 666 func (suite *ActivateIntegrationTestSuite) TestActivateArtifactsCached() { 667 suite.OnlyRunForTags(tagsuite.Activate) 668 669 ts := e2e.New(suite.T(), false) 670 defer ts.Close() 671 close := suite.addForegroundSvc(ts) 672 defer close() 673 674 namespace := "ActiveState-CLI/Python3" 675 676 cp := ts.SpawnWithOpts( 677 e2e.OptArgs("activate", namespace), 678 e2e.OptAppendEnv(constants.DisableRuntime+"=false"), 679 ) 680 681 cp.Expect("Activated", e2e.RuntimeSourcingTimeoutOpt) 682 cp.SendLine("exit") 683 cp.ExpectExitCode(0) 684 685 artifactCacheDir := filepath.Join(ts.Dirs.Cache, constants.ArtifactMetaDir) 686 suite.True(fileutils.DirExists(artifactCacheDir), "artifact cache directory does not exist") 687 artifactInfoJson := filepath.Join(artifactCacheDir, constants.ArtifactCacheFileName) 688 suite.True(fileutils.FileExists(artifactInfoJson), "artifact cache info json file does not exist") 689 690 files, err := fileutils.ListDir(artifactCacheDir, false) 691 suite.NoError(err) 692 suite.True(len(files) > 1, "artifact cache is empty") // ignore json file 693 694 // Clear all cached data except artifact cache. 695 // This removes the runtime so that it needs to be created again. 696 files, err = fileutils.ListDir(ts.Dirs.Cache, true) 697 suite.NoError(err) 698 for _, entry := range files { 699 if entry.IsDir() && entry.RelativePath() != constants.ArtifactMetaDir { 700 os.RemoveAll(entry.Path()) 701 } 702 } 703 704 cp = ts.SpawnWithOpts( 705 e2e.OptArgs("activate", namespace), 706 e2e.OptAppendEnv( 707 constants.DisableRuntime+"=false", 708 "VERBOSE=true", // Necessary to assert "Fetched cached artifact" 709 ), 710 ) 711 712 cp.Expect("Fetched cached artifact") 713 cp.Expect("Activated", e2e.RuntimeSourcingTimeoutOpt) 714 cp.SendLine("exit") 715 cp.ExpectExitCode(0) 716 }