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

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"os/exec"
     7  	"path/filepath"
     8  	"runtime"
     9  	"testing"
    10  
    11  	"github.com/ActiveState/cli/internal/testhelpers/suite"
    12  
    13  	svcApp "github.com/ActiveState/cli/cmd/state-svc/app"
    14  	svcAutostart "github.com/ActiveState/cli/cmd/state-svc/autostart"
    15  	"github.com/ActiveState/cli/internal/config"
    16  	"github.com/ActiveState/cli/internal/constants"
    17  	"github.com/ActiveState/cli/internal/fileutils"
    18  	"github.com/ActiveState/cli/internal/osutils"
    19  	"github.com/ActiveState/cli/internal/osutils/autostart"
    20  	"github.com/ActiveState/cli/internal/osutils/user"
    21  	"github.com/ActiveState/cli/internal/rtutils/singlethread"
    22  	"github.com/ActiveState/cli/internal/subshell"
    23  	"github.com/ActiveState/cli/internal/testhelpers/e2e"
    24  	"github.com/ActiveState/cli/internal/testhelpers/tagsuite"
    25  	"github.com/ActiveState/cli/pkg/platform/runtime/setup"
    26  	rt "github.com/ActiveState/cli/pkg/platform/runtime/target"
    27  )
    28  
    29  type PrepareIntegrationTestSuite struct {
    30  	tagsuite.Suite
    31  }
    32  
    33  func (suite *PrepareIntegrationTestSuite) TestPrepare() {
    34  	// Disable test for v0.36: https://activestatef.atlassian.net/browse/DX-1501.
    35  	// This test should be re-enabled by https://activestatef.atlassian.net/browse/DX-1435.
    36  	suite.T().SkipNow()
    37  
    38  	suite.OnlyRunForTags(tagsuite.Prepare)
    39  	if !e2e.RunningOnCI() {
    40  		suite.T().Skipf("Skipping TestPrepare when not running on CI or on MacOS, as it modifies PATH")
    41  	}
    42  
    43  	ts := e2e.New(suite.T(), false)
    44  	defer ts.Close()
    45  
    46  	autostartDir := filepath.Join(ts.Dirs.Work, "autostart")
    47  	err := fileutils.Mkdir(autostartDir)
    48  	suite.Require().NoError(err)
    49  
    50  	cp := ts.SpawnWithOpts(
    51  		e2e.OptArgs("_prepare"),
    52  		e2e.OptAppendEnv(fmt.Sprintf("%s=%s", constants.AutostartPathOverrideEnvVarName, autostartDir)),
    53  		// e2e.OptAppendEnv(fmt.Sprintf("%s=%s", constants.ConfigEnvVarName, ts.Dirs.Work)),
    54  	)
    55  	cp.ExpectExitCode(0)
    56  
    57  	isAdmin, err := osutils.IsAdmin()
    58  	suite.Require().NoError(err, "Could not determine if we are a Windows Administrator")
    59  	// For Windows Administrator users `state _prepare` is doing nothing now (because it doesn't make sense...)
    60  	if isAdmin {
    61  		return
    62  	}
    63  	suite.AssertConfig(filepath.Join(ts.Dirs.Cache, "bin"))
    64  
    65  	// Verify autostart was enabled.
    66  	app, err := svcApp.New()
    67  	suite.Require().NoError(err)
    68  	enabled, err := autostart.IsEnabled(app.Path(), svcAutostart.Options)
    69  	suite.Require().NoError(err)
    70  	suite.Assert().True(enabled, "autostart is not enabled")
    71  
    72  	// When installed in a non-desktop environment (i.e. on a server), verify the user's ~/.profile was amended.
    73  	if runtime.GOOS == "linux" {
    74  		homeDir, err := user.HomeDir()
    75  		suite.Require().NoError(err)
    76  		profile := filepath.Join(homeDir, ".profile")
    77  		profileContents := string(fileutils.ReadFileUnsafe(profile))
    78  		suite.Contains(profileContents, app.Path(), "autostart should be configured for Linux server environment")
    79  	}
    80  
    81  	// Verify autostart can be disabled.
    82  	err = autostart.Disable(app.Path(), svcAutostart.Options)
    83  	suite.Require().NoError(err)
    84  	enabled, err = autostart.IsEnabled(app.Path(), svcAutostart.Options)
    85  	suite.Require().NoError(err)
    86  	suite.Assert().False(enabled, "autostart is still enabled")
    87  
    88  	// When installed in a non-desktop environment (i.e. on a server), verify the user's ~/.profile was reverted.
    89  	if runtime.GOOS == "linux" {
    90  		homeDir, err := user.HomeDir()
    91  		suite.Require().NoError(err)
    92  		profile := filepath.Join(homeDir, ".profile")
    93  		profileContents := fileutils.ReadFileUnsafe(profile)
    94  		suite.NotContains(profileContents, app.Exec, "autostart should not be configured for Linux server environment anymore")
    95  	}
    96  }
    97  
    98  func (suite *PrepareIntegrationTestSuite) AssertConfig(target string) {
    99  	if runtime.GOOS != "windows" {
   100  		// Test config file
   101  		cfg, err := config.New()
   102  		suite.Require().NoError(err)
   103  
   104  		subshell := subshell.New(cfg)
   105  		rcFile, err := subshell.RcFile()
   106  		suite.Require().NoError(err)
   107  
   108  		bashContents := fileutils.ReadFileUnsafe(rcFile)
   109  		suite.Contains(string(bashContents), constants.RCAppendDefaultStartLine, "config file should contain our RC Append Start line")
   110  		suite.Contains(string(bashContents), constants.RCAppendDefaultStopLine, "config file should contain our RC Append Stop line")
   111  		suite.Contains(string(bashContents), target, "config file should contain our target dir")
   112  	} else {
   113  		// Test registry
   114  		out, err := exec.Command("reg", "query", `HKCU\Environment`, "/v", "Path").Output()
   115  		suite.Require().NoError(err)
   116  		suite.Contains(string(out), target, "Windows system PATH should contain our target dir")
   117  	}
   118  }
   119  
   120  func (suite *PrepareIntegrationTestSuite) TestResetExecutors() {
   121  	suite.OnlyRunForTags(tagsuite.Prepare)
   122  	ts := e2e.New(suite.T(), true, constants.DisableRuntime+"=false")
   123  	err := ts.ClearCache()
   124  	suite.Require().NoError(err)
   125  	defer ts.Close()
   126  
   127  	cp := ts.SpawnWithOpts(
   128  		e2e.OptArgs("activate", "ActiveState-CLI/small-python", "--path", ts.Dirs.Work, "--default"),
   129  	)
   130  	cp.Expect("This project will always be available for use")
   131  	cp.Expect("Downloading")
   132  	cp.Expect("Installing")
   133  	cp.Expect("Activated", e2e.RuntimeSourcingTimeoutOpt)
   134  
   135  	cp.SendLine("exit")
   136  	cp.ExpectExitCode(0)
   137  
   138  	cfg, err := config.NewCustom(ts.Dirs.Config, singlethread.New(), true)
   139  	suite.Require().NoError(err)
   140  	suite.Require().Equal(ts.Dirs.Work, cfg.GetString(constants.GlobalDefaultPrefname))
   141  	suite.Require().NoError(cfg.Close())
   142  
   143  	// Remove global executors
   144  	globalExecDir := filepath.Join(ts.Dirs.Cache, "bin")
   145  	err = os.RemoveAll(globalExecDir)
   146  	suite.Assert().NoError(err, "should have removed executor directory, to ensure that it gets re-created")
   147  
   148  	// check existens of exec dir
   149  	targetDir := rt.ProjectDirToTargetDir(ts.Dirs.Work, ts.Dirs.Cache)
   150  	projectExecDir := setup.ExecDir(targetDir)
   151  	suite.DirExists(projectExecDir)
   152  
   153  	// remove complete marker to force re-creation of executors
   154  	err = os.Remove(filepath.Join(targetDir, constants.LocalRuntimeEnvironmentDirectory, constants.RuntimeInstallationCompleteMarker))
   155  	suite.Assert().NoError(err, "removal of complete marker should have worked")
   156  
   157  	cp = ts.Spawn("_prepare")
   158  	cp.ExpectExitCode(0)
   159  
   160  	suite.FileExists(filepath.Join(globalExecDir, "python3"+osutils.ExeExtension))
   161  	err = os.RemoveAll(projectExecDir)
   162  	suite.Assert().NoError(err, "should have removed executor directory, to ensure that it gets re-created")
   163  
   164  	cp = ts.Spawn("activate")
   165  	cp.Expect("Activated", e2e.RuntimeSourcingTimeoutOpt)
   166  	cp.SendLine("which python3")
   167  	cp.SendLine("python3 --version")
   168  	cp.Expect("ActiveState")
   169  	cp.SendLine("exit")
   170  	cp.ExpectExitCode(0)
   171  
   172  	// executor dir should be re-created
   173  	suite.DirExists(projectExecDir)
   174  }
   175  
   176  func TestPrepareIntegrationTestSuite(t *testing.T) {
   177  	suite.Run(t, new(PrepareIntegrationTestSuite))
   178  }