github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/test/integration/use_int_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"runtime"
     8  	"testing"
     9  
    10  	"github.com/ActiveState/cli/internal/config"
    11  	"github.com/ActiveState/cli/internal/constants"
    12  	"github.com/ActiveState/cli/internal/fileutils"
    13  	"github.com/ActiveState/cli/internal/osutils"
    14  	"github.com/ActiveState/cli/internal/subshell"
    15  	"github.com/ActiveState/cli/internal/testhelpers/e2e"
    16  	"github.com/ActiveState/cli/internal/testhelpers/suite"
    17  	"github.com/ActiveState/cli/internal/testhelpers/tagsuite"
    18  )
    19  
    20  type UseIntegrationTestSuite struct {
    21  	tagsuite.Suite
    22  }
    23  
    24  func (suite *UseIntegrationTestSuite) TestUse() {
    25  	suite.OnlyRunForTags(tagsuite.Use)
    26  
    27  	ts := e2e.New(suite.T(), false)
    28  	defer ts.Close()
    29  
    30  	// Checkout.
    31  	cp := ts.SpawnWithOpts(e2e.OptArgs("checkout", "ActiveState-CLI/Python3"))
    32  	cp.Expect("Skipping runtime setup")
    33  	cp.Expect("Checked out project")
    34  	cp.ExpectExitCode(0)
    35  
    36  	// Use.
    37  	cp = ts.SpawnWithOpts(
    38  		e2e.OptArgs("use", "ActiveState-CLI/Python3"),
    39  		e2e.OptAppendEnv(constants.DisableRuntime+"=false"),
    40  	)
    41  	cp.Expect("Switched to project", e2e.RuntimeSourcingTimeoutOpt)
    42  	cp.ExpectExitCode(0)
    43  
    44  	// Verify runtime works.
    45  	pythonExe := filepath.Join(ts.Dirs.DefaultBin, "python3"+osutils.ExeExtension)
    46  	cp = ts.SpawnCmd(pythonExe, "--version")
    47  	cp.Expect("Python 3")
    48  	cp.ExpectExitCode(0)
    49  
    50  	// Checkout another project.
    51  	cp = ts.SpawnWithOpts(e2e.OptArgs("checkout", "ActiveState-CLI/Python-3.9"))
    52  	cp.Expect("Skipping runtime setup")
    53  	cp.Expect("Checked out project")
    54  	cp.ExpectExitCode(0)
    55  
    56  	// Use it.
    57  	cp = ts.SpawnWithOpts(
    58  		e2e.OptArgs("use", "ActiveState-CLI/Python-3.9"),
    59  		e2e.OptAppendEnv(constants.DisableRuntime+"=false"),
    60  	)
    61  	cp.Expect("Switched to project", e2e.RuntimeSourcingTimeoutOpt)
    62  	cp.ExpectExitCode(0)
    63  
    64  	// Verify the new runtime works.
    65  	cp = ts.SpawnCmdWithOpts(pythonExe, e2e.OptArgs("--version"))
    66  	cp.Expect("Python 3")
    67  	cp.ExpectExitCode(0)
    68  
    69  	// Switch back using just the project name.
    70  	cp = ts.SpawnWithOpts(
    71  		e2e.OptArgs("use", "Python3"),
    72  		e2e.OptAppendEnv(constants.DisableRuntime+"=false"),
    73  	)
    74  	cp.Expect("Switched to project", e2e.RuntimeSourcingTimeoutOpt)
    75  	cp.ExpectExitCode(0)
    76  
    77  	// Verify the first runtime is set up correctly and usable.
    78  	cp = ts.SpawnCmdWithOpts(pythonExe, e2e.OptArgs("--version"))
    79  	cp.Expect("Python 3")
    80  	cp.ExpectExitCode(0)
    81  
    82  	// Test failure switching to project name that was not checked out.
    83  	cp = ts.SpawnWithOpts(e2e.OptArgs("use", "NotCheckedOut"))
    84  	cp.Expect("Cannot find the NotCheckedOut project.")
    85  	cp.ExpectExitCode(1)
    86  	ts.IgnoreLogErrors()
    87  }
    88  
    89  func (suite *UseIntegrationTestSuite) TestUseCwd() {
    90  	suite.OnlyRunForTags(tagsuite.Use)
    91  
    92  	ts := e2e.New(suite.T(), false)
    93  	defer ts.Close()
    94  
    95  	pythonDir := filepath.Join(ts.Dirs.Work, "MyPython3")
    96  
    97  	cp := ts.SpawnWithOpts(e2e.OptArgs("checkout", "ActiveState-CLI/Python3", pythonDir))
    98  	cp.Expect("Skipping runtime setup")
    99  	cp.Expect("Checked out project")
   100  	cp.ExpectExitCode(0)
   101  
   102  	cp = ts.SpawnWithOpts(
   103  		e2e.OptArgs("use"),
   104  		e2e.OptWD(pythonDir),
   105  		e2e.OptAppendEnv(constants.DisableRuntime+"=false"),
   106  	)
   107  	cp.Expect("Switched to project", e2e.RuntimeSourcingTimeoutOpt)
   108  	cp.ExpectExitCode(0)
   109  
   110  	emptyDir := filepath.Join(ts.Dirs.Work, "EmptyDir")
   111  	suite.Require().NoError(fileutils.Mkdir(emptyDir))
   112  	cp = ts.SpawnWithOpts(
   113  		e2e.OptArgs("use"),
   114  		e2e.OptWD(emptyDir),
   115  	)
   116  	cp.Expect("Unable to use project")
   117  	cp.ExpectExitCode(1)
   118  	ts.IgnoreLogErrors()
   119  }
   120  
   121  func (suite *UseIntegrationTestSuite) TestReset() {
   122  	suite.OnlyRunForTags(tagsuite.Use)
   123  
   124  	ts := e2e.New(suite.T(), false)
   125  	defer ts.Close()
   126  
   127  	ts.SetupRCFile()
   128  	suite.T().Setenv("ACTIVESTATE_HOME", ts.Dirs.HomeDir)
   129  
   130  	cp := ts.SpawnWithOpts(e2e.OptArgs("checkout", "ActiveState-CLI/Python3"))
   131  	cp.Expect("Skipping runtime setup")
   132  	cp.Expect("Checked out project")
   133  	cp.ExpectExitCode(0)
   134  
   135  	cp = ts.SpawnWithOpts(
   136  		e2e.OptArgs("use", "ActiveState-CLI/Python3"),
   137  		e2e.OptAppendEnv(constants.DisableRuntime+"=false"),
   138  	)
   139  	cp.Expect("Switched to project", e2e.RuntimeSourcingTimeoutOpt)
   140  	cp.ExpectExitCode(0)
   141  
   142  	python3Exe := filepath.Join(ts.Dirs.DefaultBin, "python3"+osutils.ExeExtension)
   143  	suite.True(fileutils.TargetExists(python3Exe), python3Exe+" not found")
   144  
   145  	cfg, err := config.New()
   146  	suite.NoError(err)
   147  	rcfile, err := subshell.New(cfg).RcFile()
   148  	if runtime.GOOS != "windows" && fileutils.FileExists(rcfile) {
   149  		suite.NoError(err)
   150  		suite.Contains(string(fileutils.ReadFileUnsafe(rcfile)), ts.Dirs.DefaultBin, "PATH does not have your project in it")
   151  	}
   152  
   153  	cp = ts.SpawnWithOpts(e2e.OptArgs("use", "reset"))
   154  	cp.Expect("Continue?")
   155  	cp.SendLine("n")
   156  	cp.Expect("Reset aborted by user")
   157  	cp.ExpectExitCode(1)
   158  	ts.IgnoreLogErrors()
   159  
   160  	cp = ts.SpawnWithOpts(e2e.OptArgs("use", "reset", "--non-interactive"))
   161  	cp.Expect("Stopped using your project runtime")
   162  	cp.Expect("Note you may need to")
   163  	cp.ExpectExitCode(0)
   164  
   165  	suite.False(fileutils.TargetExists(python3Exe), python3Exe+" still exists")
   166  
   167  	cp = ts.SpawnWithOpts(e2e.OptArgs("use", "reset"))
   168  	cp.Expect("No project to stop using")
   169  	cp.ExpectExitCode(1)
   170  
   171  	if runtime.GOOS != "windows" && fileutils.FileExists(rcfile) {
   172  		suite.NotContains(string(fileutils.ReadFileUnsafe(rcfile)), ts.Dirs.DefaultBin, "PATH still has your project in it")
   173  	}
   174  }
   175  
   176  func (suite *UseIntegrationTestSuite) TestShow() {
   177  	suite.OnlyRunForTags(tagsuite.Use)
   178  
   179  	ts := e2e.New(suite.T(), false)
   180  	defer ts.Close()
   181  
   182  	cp := ts.SpawnWithOpts(e2e.OptArgs("use", "show"))
   183  	cp.Expect("No project is being used")
   184  	cp.ExpectExitCode(1)
   185  	ts.IgnoreLogErrors()
   186  
   187  	cp = ts.SpawnWithOpts(e2e.OptArgs("checkout", "ActiveState-CLI/Python3"))
   188  	cp.Expect("Skipping runtime setup")
   189  	cp.Expect("Checked out project")
   190  	cp.ExpectExitCode(0)
   191  
   192  	cp = ts.SpawnWithOpts(
   193  		e2e.OptArgs("use", "ActiveState-CLI/Python3"),
   194  		e2e.OptAppendEnv(constants.DisableRuntime+"=false"),
   195  	)
   196  	cp.Expect("Switched to project", e2e.RuntimeSourcingTimeoutOpt)
   197  	cp.ExpectExitCode(0)
   198  
   199  	cp = ts.SpawnWithOpts(
   200  		e2e.OptArgs("use", "show"),
   201  	)
   202  	cp.Expect("The active project is ActiveState-CLI/Python3")
   203  	projectDir := filepath.Join(ts.Dirs.Work, "Python3")
   204  	if runtime.GOOS != "windows" {
   205  		cp.Expect(projectDir)
   206  	} else {
   207  		// Windows uses the long path here.
   208  		longPath, err := fileutils.GetLongPathName(projectDir)
   209  		suite.Require().NoError(err)
   210  		cp.Expect(longPath)
   211  	}
   212  	cp.Expect(ts.Dirs.Cache)
   213  	cp.Expect("exec")
   214  	cp.ExpectExitCode(0)
   215  
   216  	err := os.RemoveAll(projectDir)
   217  	suite.Require().NoError(err)
   218  
   219  	cp = ts.SpawnWithOpts(e2e.OptArgs("use", "show"))
   220  	cp.Expect("Cannot find your project")
   221  	// Both Windows and MacOS can run into path comparison issues with symlinks and long paths.
   222  	if runtime.GOOS == "linux" {
   223  		cp.Expect(fmt.Sprintf("Could not find project at %s", projectDir))
   224  	}
   225  	cp.ExpectExitCode(1)
   226  
   227  	cp = ts.SpawnWithOpts(e2e.OptArgs("use", "reset", "--non-interactive"))
   228  	cp.Expect("Stopped using your project runtime")
   229  	cp.ExpectExitCode(0)
   230  
   231  	cp = ts.SpawnWithOpts(e2e.OptArgs("use", "show"))
   232  	cp.Expect("No project is being used")
   233  	cp.ExpectExitCode(1)
   234  }
   235  
   236  func (suite *UseIntegrationTestSuite) TestSetupNotice() {
   237  	suite.OnlyRunForTags(tagsuite.Use)
   238  
   239  	ts := e2e.New(suite.T(), false)
   240  	defer ts.Close()
   241  
   242  	cp := ts.SpawnWithOpts(
   243  		e2e.OptArgs("checkout", "ActiveState-CLI/Python3"),
   244  		e2e.OptAppendEnv(constants.DisableRuntime+"=false"),
   245  	)
   246  	cp.Expect("Setting Up Runtime")
   247  	cp.Expect("Checked out project", e2e.RuntimeSourcingTimeoutOpt)
   248  	cp.ExpectExitCode(0)
   249  
   250  	suite.Require().NoError(os.RemoveAll(filepath.Join(ts.Dirs.Work, "Python3"))) // runtime marker still exists
   251  
   252  	cp = ts.SpawnWithOpts(
   253  		e2e.OptArgs("checkout", "ActiveState-CLI/Python3#623dadf8-ebf9-4876-bfde-f45afafe5ea8"),
   254  	)
   255  	cp.Expect("Skipping runtime setup")
   256  	cp.Expect("Checked out project")
   257  	cp.ExpectExitCode(0)
   258  
   259  	cp = ts.SpawnWithOpts(
   260  		e2e.OptArgs("use", "Python3"),
   261  		e2e.OptAppendEnv(constants.DisableRuntime+"=false"),
   262  	)
   263  	cp.Expect("Setting Up Runtime")
   264  	cp.Expect("Switched to project", e2e.RuntimeSourcingTimeoutOpt)
   265  	cp.ExpectExitCode(0)
   266  }
   267  
   268  func (suite *UseIntegrationTestSuite) TestJSON() {
   269  	suite.OnlyRunForTags(tagsuite.Use, tagsuite.JSON)
   270  	ts := e2e.New(suite.T(), false)
   271  	defer ts.Close()
   272  
   273  	cp := ts.Spawn("checkout", "ActiveState-CLI/Perl-5.32", ".")
   274  	cp.Expect("Skipping runtime setup")
   275  	cp.Expect("Checked out")
   276  	cp.ExpectExitCode(0)
   277  
   278  	cp = ts.SpawnWithOpts(
   279  		e2e.OptArgs("use", "-o", "json"),
   280  		e2e.OptAppendEnv(constants.DisableRuntime+"=false"),
   281  	)
   282  	cp.Expect(`"namespace":`, e2e.RuntimeSourcingTimeoutOpt)
   283  	cp.Expect(`"path":`)
   284  	cp.Expect(`"executables":`)
   285  	cp.ExpectExitCode(0)
   286  	AssertValidJSON(suite.T(), cp)
   287  
   288  	cp = ts.Spawn("use", "show", "--output", "json")
   289  	cp.Expect(`"namespace":`)
   290  	cp.Expect(`"path":`)
   291  	cp.Expect(`"executables":`)
   292  	cp.ExpectExitCode(0)
   293  	AssertValidJSON(suite.T(), cp)
   294  }
   295  
   296  func TestUseIntegrationTestSuite(t *testing.T) {
   297  	suite.Run(t, new(UseIntegrationTestSuite))
   298  }