diff --git a/internal/constants/constants.go b/internal/constants/constants.go index 6bd7f03ebb..3703e14648 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -528,6 +528,3 @@ const PlatformApiPrintRequestsEnvVarName = "ACTIVESTATE_CLI_PLATFORM_API_PRINT_R // ActiveStateCIEnvVarName is the environment variable set when running in an ActiveState CI environment. const ActiveStateCIEnvVarName = "ACTIVESTATE_CI" - -// OverrideSandbox is the environment variable to set when overriding the sandbox for integration tests. -const OverrideSandbox = "ACTIVESTATE_TEST_OVERRIDE_SANDBOX" diff --git a/internal/osutils/exeutils.go b/internal/osutils/exeutils.go index aa184fa016..8a334adb68 100644 --- a/internal/osutils/exeutils.go +++ b/internal/osutils/exeutils.go @@ -118,8 +118,10 @@ func ExecSimpleFromDir(dir, bin string, args []string, env []string) (string, st // Execute will run the given command and with optional settings for the exec.Cmd struct func Execute(command string, arg []string, optSetter func(cmd *exec.Cmd) error) (int, *exec.Cmd, error) { + logging.Debug("Executing command: %s, %v", command, arg) + cmd := exec.Command(command, arg...) - logging.Debug("Executing command: %s, with args: %s", cmd, arg) + if optSetter != nil { if err := optSetter(cmd); err != nil { return -1, nil, err diff --git a/internal/osutils/osutils_windows.go b/internal/osutils/osutils_windows.go index c9720bd800..9a20be13dd 100644 --- a/internal/osutils/osutils_windows.go +++ b/internal/osutils/osutils_windows.go @@ -38,7 +38,7 @@ func BashifyPathEnv(pathList string) (string, error) { cmd.Env = []string{"PATH=" + pathList} bashified, err := cmd.Output() if err != nil { - return "", errs.Wrap(err, "Unable to bashify PATH: %s, output: %s", pathList, string(bashified)) + return "", errs.Wrap(err, "Unable to bashify PATH: %s", pathList) } return string(bashified), nil } diff --git a/internal/testhelpers/e2e/dirs.go b/internal/testhelpers/e2e/dirs.go index 22af224c5c..39961262d3 100644 --- a/internal/testhelpers/e2e/dirs.go +++ b/internal/testhelpers/e2e/dirs.go @@ -23,8 +23,6 @@ type Dirs struct { SockRoot string // HomeDir is used as the test user's home directory HomeDir string - // TempDir is the directory where temporary files are stored - TempDir string } // NewDirs creates all temporary directories @@ -44,7 +42,6 @@ func NewDirs(base string) (*Dirs, error) { defaultBin := filepath.Join(base, "cache", "bin") sockRoot := filepath.Join(base, "sock") homeDir := filepath.Join(base, "home") - tempDir := filepath.Join(base, "temp") subdirs := []string{config, cache, bin, work, defaultBin} for _, subdir := range subdirs { @@ -62,7 +59,6 @@ func NewDirs(base string) (*Dirs, error) { DefaultBin: defaultBin, SockRoot: sockRoot, HomeDir: homeDir, - TempDir: tempDir, } return &dirs, nil diff --git a/internal/testhelpers/e2e/env.go b/internal/testhelpers/e2e/env.go deleted file mode 100644 index 1a4d801c20..0000000000 --- a/internal/testhelpers/e2e/env.go +++ /dev/null @@ -1,93 +0,0 @@ -package e2e - -import ( - "fmt" - "os" - "path/filepath" - "runtime" - "testing" - - "github.com/ActiveState/cli/internal/constants" - "github.com/ActiveState/cli/internal/errs" - "github.com/ActiveState/cli/internal/fileutils" - "github.com/stretchr/testify/require" -) - -func sandboxedTestEnvironment(t *testing.T, dirs *Dirs, updatePath bool, extraEnv ...string) []string { - var env []string - basePath := platformPath() - if os.Getenv(constants.OverrideSandbox) != "" { - basePath = os.Getenv("PATH") - env = append(env, os.Environ()...) - } - - env = append(env, []string{ - constants.ConfigEnvVarName + "=" + dirs.Config, - constants.CacheEnvVarName + "=" + dirs.Cache, - constants.DisableRuntime + "=true", - constants.ProjectEnvVarName + "=", - constants.E2ETestEnvVarName + "=true", - constants.DisableUpdates + "=true", - constants.DisableProjectMigrationPrompt + "=true", - constants.OptinUnstableEnvVarName + "=true", - constants.ServiceSockDir + "=" + dirs.SockRoot, - constants.HomeEnvVarName + "=" + dirs.HomeDir, - systemHomeEnvVarName + "=" + dirs.HomeDir, - "NO_COLOR=true", - "CI=true", - }...) - - if updatePath { - // add bin path - oldPath := basePath - newPath := fmt.Sprintf( - "PATH=%s%s%s", - dirs.Bin, string(os.PathListSeparator), oldPath, - ) - env = append(env, newPath) - } else { - env = append(env, "PATH="+basePath) - } - - // append platform specific environment variables - env = append(env, platformSpecificEnv(dirs)...) - - // Prepare sandboxed home directory - err := prepareHomeDir(dirs.HomeDir) - require.NoError(t, err) - - // add session environment variables - env = append(env, extraEnv...) - - return env -} - -func prepareHomeDir(dir string) error { - if runtime.GOOS == "windows" { - return nil - } - - if !fileutils.DirExists(dir) { - err := fileutils.Mkdir(dir) - if err != nil { - return errs.Wrap(err, "Could not create home dir") - } - } - - var filename string - switch runtime.GOOS { - case "linux": - filename = ".bashrc" - case "darwin": - filename = ".zshrc" - } - - rcFile := filepath.Join(dir, filename) - err := fileutils.Touch(rcFile) - if err != nil { - return errs.Wrap(err, "Could not create rc file") - } - - return nil - -} diff --git a/internal/testhelpers/e2e/env_unix.go b/internal/testhelpers/e2e/env_unix.go deleted file mode 100644 index e92aaf2653..0000000000 --- a/internal/testhelpers/e2e/env_unix.go +++ /dev/null @@ -1,17 +0,0 @@ -//go:build !windows -// +build !windows - -package e2e - -const ( - basePath = "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local:/usr/local/sbin:/usr/local/opt" - systemHomeEnvVarName = "HOME" -) - -func platformSpecificEnv(dirs *Dirs) []string { - return nil -} - -func platformPath() string { - return basePath -} diff --git a/internal/testhelpers/e2e/env_windows.go b/internal/testhelpers/e2e/env_windows.go deleted file mode 100644 index b16f5b3b50..0000000000 --- a/internal/testhelpers/e2e/env_windows.go +++ /dev/null @@ -1,46 +0,0 @@ -//go:build windows -// +build windows - -package e2e - -import ( - "fmt" - "os" - - "github.com/ActiveState/cli/internal/condition" -) - -const ( - basePath = `C:\Windows\System32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\PowerShell\7\;` - systemHomeEnvVarName = "USERPROFILE" -) - -func platformSpecificEnv(dirs *Dirs) []string { - return []string{ - "SystemDrive=C:", - "SystemRoot=C:\\Windows", - "PROGRAMFILES=C:\\Program Files", - "ProgramFiles(x86)=C:\\Program Files (x86)", - "PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC", - "HOMEDRIVE=C:", - "ALLUSERSPROFILE=C:\\ProgramData", - "ProgramData=C:\\ProgramData", - "COMSPEC=C:\\Windows\\System32\\cmd.exe", - "PROGRAMFILES=C:\\Program Files", - "CommonProgramW6432=C:\\Program Files\\Common Files", - "WINDIR=C:\\Windows", - "PUBLIC=C:\\Users\\Public", - "PSModuleAnalysisCachePath=C:\\PSModuleAnalysisCachePath\\ModuleAnalysisCache", - fmt.Sprintf("HOMEPATH=%s", dirs.HomeDir), - // Other environment variables are commonly set by CI systems, but this one is not. - // This is requried for some tests in order to get the correct powershell output. - fmt.Sprintf("PSModulePath=%s", os.Getenv("PSModulePath")), - } -} - -func platformPath() string { - if condition.OnCI() { - return `C:\msys64\usr\bin` + string(os.PathListSeparator) + basePath - } - return basePath -} diff --git a/internal/testhelpers/e2e/session.go b/internal/testhelpers/e2e/session.go index 588da45c2b..7745419de1 100644 --- a/internal/testhelpers/e2e/session.go +++ b/internal/testhelpers/e2e/session.go @@ -172,7 +172,57 @@ func New(t *testing.T, retainDirs bool, extraEnv ...string) *Session { func new(t *testing.T, retainDirs, updatePath bool, extraEnv ...string) *Session { dirs, err := NewDirs("") require.NoError(t, err) - env := sandboxedTestEnvironment(t, dirs, updatePath) + var env []string + env = append(env, os.Environ()...) + env = append(env, []string{ + constants.ConfigEnvVarName + "=" + dirs.Config, + constants.CacheEnvVarName + "=" + dirs.Cache, + constants.DisableRuntime + "=true", + constants.ProjectEnvVarName + "=", + constants.E2ETestEnvVarName + "=true", + constants.DisableUpdates + "=true", + constants.DisableProjectMigrationPrompt + "=true", + constants.OptinUnstableEnvVarName + "=true", + constants.ServiceSockDir + "=" + dirs.SockRoot, + constants.HomeEnvVarName + "=" + dirs.HomeDir, + "NO_COLOR=true", + }...) + + if updatePath { + // add bin path + // Remove release state tool installation from PATH in tests + // This is a workaround as our test sessions are not compeltely + // sandboxed. This should be addressed in: https://activestatef.atlassian.net/browse/DX-2285 + oldPath, _ := os.LookupEnv("PATH") + installPath, err := installation.InstallPathForChannel("release") + require.NoError(t, err) + + binPath := filepath.Join(installPath, "bin") + oldPath = strings.Replace(oldPath, binPath+string(os.PathListSeparator), "", -1) + newPath := fmt.Sprintf( + "PATH=%s%s%s", + dirs.Bin, string(os.PathListSeparator), oldPath, + ) + env = append(env, newPath) + t.Setenv("PATH", newPath) + + cfg, err := config.New() + require.NoError(t, err) + + // In order to ensure that the release state tool does not appear on the PATH + // when a new subshell is started we remove the installation entries from the + // rc file. This is added back later in the session's Close method. + // Again, this is a workaround to be addressed in: https://activestatef.atlassian.net/browse/DX-2285 + if runtime.GOOS != "windows" { + s := bash.SubShell{} + err = s.CleanUserEnv(cfg, sscommon.InstallID, false) + require.NoError(t, err) + } + t.Setenv(constants.HomeEnvVarName, dirs.HomeDir) + } + + // add session environment variables + env = append(env, extraEnv...) session := &Session{Dirs: dirs, Env: env, retainDirs: retainDirs, T: t} @@ -182,6 +232,14 @@ func new(t *testing.T, retainDirs, updatePath bool, extraEnv ...string) *Session session.SvcExe = session.copyExeToBinDir(svcExe) session.ExecutorExe = session.copyExeToBinDir(execExe) + // Set up environment for test runs. This is separate + // from the environment for the session itself. + // Setting environment variables here allows helper + // functions access to them. + // This is a workaround as our test sessions are not compeltely + // sandboxed. This should be addressed in: https://activestatef.atlassian.net/browse/DX-2285 + t.Setenv(constants.HomeEnvVarName, dirs.HomeDir) + err = fileutils.Touch(filepath.Join(dirs.Base, installation.InstallDirMarker)) require.NoError(session.T, err) @@ -295,6 +353,7 @@ func (s *Session) SpawnCmdWithOpts(exe string, optSetters ...SpawnOptSetter) *Sp cmd := exec.Command(shell, args...) cmd.Env = spawnOpts.Env + if spawnOpts.Dir != "" { cmd.Dir = spawnOpts.Dir } @@ -712,8 +771,6 @@ func (s *Session) SetupRCFile() { if runtime.GOOS == "windows" { return } - s.T.Setenv("HOME", s.Dirs.HomeDir) - defer s.T.Setenv("HOME", os.Getenv("HOME")) cfg, err := config.New() require.NoError(s.T, err) @@ -732,7 +789,7 @@ func (s *Session) SetupRCFileCustom(subshell subshell.SubShell) { if fileutils.TargetExists(filepath.Join(s.Dirs.HomeDir, filepath.Base(rcFile))) { err = fileutils.CopyFile(rcFile, filepath.Join(s.Dirs.HomeDir, filepath.Base(rcFile))) } else { - err = fileutils.Touch(filepath.Join(s.Dirs.HomeDir, filepath.Base(rcFile))) + err = fileutils.Touch(rcFile) } require.NoError(s.T, err) } diff --git a/test/integration/activate_int_test.go b/test/integration/activate_int_test.go index 1ad1ba898c..1f46f67624 100644 --- a/test/integration/activate_int_test.go +++ b/test/integration/activate_int_test.go @@ -134,10 +134,10 @@ func (suite *ActivateIntegrationTestSuite) TestActivateUsingCommitID() { cp := ts.SpawnWithOpts( e2e.OptArgs("activate", "ActiveState-CLI/Python3#6d9280e7-75eb-401a-9e71-0d99759fbad3", "--path", ts.Dirs.Work), - e2e.OptAppendEnv(constants.DisableRuntime+"=false"), ) - cp.Expect("Activated", e2e.RuntimeSourcingTimeoutOpt) - cp.ExpectInput() + cp.Expect("Skipping runtime setup") + cp.Expect("Activated") + cp.ExpectInput(termtest.OptExpectTimeout(10 * time.Second)) cp.SendLine("exit") cp.ExpectExitCode(0) diff --git a/test/integration/install_scripts_int_test.go b/test/integration/install_scripts_int_test.go index d83b20bf0a..323542d565 100644 --- a/test/integration/install_scripts_int_test.go +++ b/test/integration/install_scripts_int_test.go @@ -66,9 +66,7 @@ func (suite *InstallScriptsIntegrationTestSuite) TestInstall() { suite.Require().NoError(fileutils.WriteFile(script, b)) // Construct installer command to execute. - installDir := filepath.Join(ts.Dirs.Work, "install") argsPlain := []string{script} - argsPlain = append(argsPlain, "-t", installDir) if tt.Channel != "" { argsPlain = append(argsPlain, "-b", tt.Channel) } @@ -118,6 +116,20 @@ func (suite *InstallScriptsIntegrationTestSuite) TestInstall() { cp.Expect("ActiveState") } + // We get the default install path and use that to directly invoke + // the state tool. This is to avoid inadvertently using the state + // tool that is already on the PATH. + installPath, err := installation.InstallPathForChannel(constants.ChannelName) + suite.NoError(err) + + binPath := filepath.Join(installPath, "bin") + + if runtime.GOOS != "windows" { + cp.SendLine("echo $PATH") + } else { + cp.SendLine("echo %PATH%") + } + cp.Expect(installPath) cp.SendLine("state --version") cp.Expect("Version " + constants.Version) cp.Expect("Channel " + constants.ChannelName) @@ -126,12 +138,12 @@ func (suite *InstallScriptsIntegrationTestSuite) TestInstall() { cp.ExpectExitCode(0) - stateExec, err := installation.StateExecFromDir(installDir) + stateExec, err := installation.StateExecFromDir(ts.Dirs.HomeDir) suite.NoError(err) suite.FileExists(stateExec) - suite.assertBinDirContents(filepath.Join(installDir, "bin")) - suite.assertCorrectVersion(ts, installDir, tt.Version, tt.Channel) + suite.assertBinDirContents(binPath) + suite.assertCorrectVersion(ts, binPath, tt.Version, tt.Channel) suite.assertAnalytics(ts) suite.DirExists(ts.Dirs.Config) diff --git a/test/integration/shells_int_test.go b/test/integration/shells_int_test.go index f911d813b0..06d1c5a81d 100644 --- a/test/integration/shells_int_test.go +++ b/test/integration/shells_int_test.go @@ -2,14 +2,12 @@ package integration import ( "fmt" - "path/filepath" "runtime" "testing" "github.com/stretchr/testify/suite" "github.com/ActiveState/cli/internal/constants" - "github.com/ActiveState/cli/internal/fileutils" "github.com/ActiveState/cli/internal/testhelpers/e2e" "github.com/ActiveState/cli/internal/testhelpers/tagsuite" ) @@ -46,11 +44,6 @@ func (suite *ShellsIntegrationTestSuite) TestShells() { suite.T().Run(fmt.Sprintf("using_%s", shell), func(t *testing.T) { ts.SetT(t) - if shell == e2e.Zsh { - err := fileutils.Touch(filepath.Join(ts.Dirs.HomeDir, ".zshrc")) - suite.Require().NoError(err) - } - // Run the checkout in a particular shell. cp = ts.SpawnShellWithOpts(shell) cp.SendLine(e2e.QuoteCommand(shell, ts.ExecutablePath(), "checkout", "ActiveState-CLI/small-python", string(shell))) diff --git a/test/integration/uninstall_int_test.go b/test/integration/uninstall_int_test.go index ae59a272e0..6f94c0ae2d 100644 --- a/test/integration/uninstall_int_test.go +++ b/test/integration/uninstall_int_test.go @@ -78,7 +78,9 @@ func (suite *UninstallIntegrationTestSuite) testUninstall(all bool) { if runtime.GOOS == "linux" { // When installed in a non-desktop environment (i.e. on a server), verify the user's ~/.profile was changed. - profile := filepath.Join(ts.Dirs.HomeDir, ".profile") + homeDir, err := user.HomeDir() + suite.Require().NoError(err) + profile := filepath.Join(homeDir, ".profile") suite.Contains(string(fileutils.ReadFileUnsafe(profile)), svcExe, "autostart should be configured for Linux server environment") }