github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/test/integration/init_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/assets"
    11  	"github.com/ActiveState/cli/internal/constants"
    12  	"github.com/ActiveState/cli/internal/fileutils"
    13  	"github.com/ActiveState/cli/internal/language"
    14  	"github.com/ActiveState/cli/internal/strutils"
    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  	"github.com/ActiveState/cli/pkg/sysinfo"
    19  )
    20  
    21  type InitIntegrationTestSuite struct {
    22  	tagsuite.Suite
    23  }
    24  
    25  func (suite *InitIntegrationTestSuite) TestInit() {
    26  	suite.OnlyRunForTags(tagsuite.Init, tagsuite.Critical)
    27  	suite.runInitTest(false, "python", "python3")
    28  }
    29  
    30  func (suite *InitIntegrationTestSuite) TestInit_Path() {
    31  	suite.OnlyRunForTags(tagsuite.Init)
    32  	suite.runInitTest(true, "python", "python3")
    33  }
    34  
    35  func (suite *InitIntegrationTestSuite) TestInit_DisambiguatePython() {
    36  	suite.OnlyRunForTags(tagsuite.Init)
    37  	suite.runInitTest(false, "python", "python3")
    38  	suite.runInitTest(false, "python@3.10.0", "python3")
    39  	suite.runInitTest(false, "python@2.7.18", "python2")
    40  }
    41  
    42  func (suite *InitIntegrationTestSuite) TestInit_PartialVersions() {
    43  	suite.OnlyRunForTags(tagsuite.Init)
    44  	suite.runInitTest(false, "python@3.10", "python3")
    45  	suite.runInitTest(false, "python@3.10.x", "python3")
    46  	suite.runInitTest(false, "python@>=3", "python3")
    47  	suite.runInitTest(false, "python@2", "python2")
    48  }
    49  
    50  func (suite *InitIntegrationTestSuite) runInitTest(addPath bool, lang string, expectedConfigLanguage string, args ...string) {
    51  	ts := e2e.New(suite.T(), false)
    52  	defer ts.Close()
    53  	ts.LoginAsPersistentUser()
    54  
    55  	// Generate a new namespace for the project to be created.
    56  	pname := strutils.UUID()
    57  	namespace := fmt.Sprintf("%s/%s", e2e.PersistentUsername, pname)
    58  	computedArgs := append([]string{"init", "--language", lang, namespace}, args...)
    59  	if addPath {
    60  		computedArgs = append(computedArgs, ts.Dirs.Work)
    61  	}
    62  
    63  	// Run `state init`, creating the project.
    64  	cp := ts.Spawn(computedArgs...)
    65  	cp.Expect("Initializing Project")
    66  	cp.Expect("Skipping runtime setup")
    67  	cp.Expect(fmt.Sprintf("Project '%s' has been successfully initialized", namespace))
    68  	cp.ExpectExitCode(0)
    69  	ts.NotifyProjectCreated(e2e.PersistentUsername, pname.String())
    70  
    71  	// Verify the config template contains the correct shell, language, and content.
    72  	configFilepath := filepath.Join(ts.Dirs.Work, constants.ConfigFileName)
    73  	suite.Require().FileExists(configFilepath)
    74  
    75  	templateFile, err := assets.ReadFileBytes("activestate.yaml.python.tpl")
    76  	if err != nil {
    77  		panic(err.Error())
    78  	}
    79  	shell := "bash"
    80  	if runtime.GOOS == "windows" {
    81  		shell = "batch"
    82  	}
    83  	yaml, err := strutils.ParseTemplate(
    84  		string(templateFile),
    85  		map[string]interface{}{
    86  			"Owner":    e2e.PersistentUsername,
    87  			"Project":  pname.String(),
    88  			"Shell":    shell,
    89  			"Language": expectedConfigLanguage,
    90  			"LangExe":  language.MakeByName(expectedConfigLanguage).Executable().Filename(),
    91  		}, nil)
    92  	suite.Require().NoError(err)
    93  
    94  	content, err := os.ReadFile(configFilepath)
    95  	suite.Require().NoError(err)
    96  	suite.Contains(string(content), yaml)
    97  }
    98  
    99  func (suite *InitIntegrationTestSuite) TestInit_NoLanguage() {
   100  	suite.OnlyRunForTags(tagsuite.Init)
   101  	ts := e2e.New(suite.T(), false)
   102  	defer ts.Close()
   103  
   104  	cp := ts.Spawn("init", "test-user/test-project")
   105  	cp.ExpectNotExitCode(0)
   106  	ts.IgnoreLogErrors()
   107  }
   108  
   109  func (suite *InitIntegrationTestSuite) TestInit_InferLanguageFromUse() {
   110  	suite.OnlyRunForTags(tagsuite.Init)
   111  	ts := e2e.New(suite.T(), false)
   112  	defer ts.Close()
   113  	ts.LoginAsPersistentUser()
   114  
   115  	cp := ts.Spawn("checkout", "ActiveState-CLI/Python3")
   116  	cp.Expect("Skipping runtime setup")
   117  	cp.Expect("Checked out project")
   118  	cp.ExpectExitCode(0)
   119  
   120  	cp = ts.SpawnWithOpts(
   121  		e2e.OptArgs("use", "Python3"),
   122  		e2e.OptAppendEnv(constants.DisableRuntime+"=false"),
   123  	)
   124  	cp.Expect("Switched to project", e2e.RuntimeSourcingTimeoutOpt)
   125  	cp.ExpectExitCode(0)
   126  
   127  	pname := strutils.UUID()
   128  	namespace := fmt.Sprintf("%s/%s", e2e.PersistentUsername, pname)
   129  	cp = ts.Spawn("init", namespace)
   130  	cp.Expect("Skipping runtime setup")
   131  	cp.Expect("successfully initialized")
   132  	cp.ExpectExitCode(0)
   133  	ts.NotifyProjectCreated(e2e.PersistentUsername, pname.String())
   134  
   135  	suite.Contains(string(fileutils.ReadFileUnsafe(filepath.Join(ts.Dirs.Work, constants.ConfigFileName))), "language: python3")
   136  }
   137  
   138  func (suite *InitIntegrationTestSuite) TestInit_NotAuthenticated() {
   139  	suite.OnlyRunForTags(tagsuite.Init)
   140  	ts := e2e.New(suite.T(), false)
   141  	defer ts.Close()
   142  
   143  	cp := ts.Spawn("init", "test-user/test-project", "python3")
   144  	cp.Expect("You need to be authenticated to initialize a project.")
   145  }
   146  
   147  func (suite *InitIntegrationTestSuite) TestInit_AlreadyExists() {
   148  	suite.OnlyRunForTags(tagsuite.Init)
   149  	ts := e2e.New(suite.T(), false)
   150  	defer ts.Close()
   151  	ts.LoginAsPersistentUser()
   152  
   153  	cp := ts.Spawn("init", fmt.Sprintf("%s/test-project", e2e.PersistentUsername), "--language", "python@3")
   154  	cp.Expect("The project 'test-project' already exists under 'cli-integration-tests'")
   155  	cp.ExpectExitCode(1)
   156  }
   157  
   158  func (suite *InitIntegrationTestSuite) TestInit_Resolved() {
   159  	suite.OnlyRunForTags(tagsuite.Init, tagsuite.Languages)
   160  	ts := e2e.New(suite.T(), false)
   161  	defer ts.Close()
   162  	ts.LoginAsPersistentUser()
   163  
   164  	// Generate a new namespace for the project to be created.
   165  	pname := strutils.UUID()
   166  	namespace := fmt.Sprintf("%s/%s", e2e.PersistentUsername, pname)
   167  
   168  	// Run `state init`, creating the project.
   169  	cp := ts.SpawnWithOpts(
   170  		e2e.OptArgs("init", namespace, "--language", "python@3.10"),
   171  		e2e.OptAppendEnv(constants.DisableRuntime+"=false"),
   172  	)
   173  	cp.Expect(fmt.Sprintf("Project '%s' has been successfully initialized", namespace), e2e.RuntimeSourcingTimeoutOpt)
   174  	cp.ExpectExitCode(0)
   175  	ts.NotifyProjectCreated(e2e.PersistentUsername, pname.String())
   176  
   177  	// Run `state languages` to verify a full language version was resolved.
   178  	cp = ts.Spawn("languages")
   179  	cp.Expect("python")
   180  	cp.Expect(">=3.10,<3.11 → 3.10.") // note: the patch version is variable, so just expect that it exists
   181  	cp.ExpectExitCode(0)
   182  }
   183  
   184  func (suite *InitIntegrationTestSuite) TestInit_NoOrg() {
   185  	suite.OnlyRunForTags(tagsuite.Init)
   186  	ts := e2e.New(suite.T(), false)
   187  	defer ts.Close()
   188  	ts.LoginAsPersistentUser()
   189  
   190  	cp := ts.Spawn("init", "random-org/test-project", "--language", "python@3")
   191  	cp.Expect("The organization 'random-org' either does not exist, or you do not have permissions to create a project in it.")
   192  	cp.ExpectExitCode(1)
   193  }
   194  
   195  func (suite *InitIntegrationTestSuite) TestInit_InferredOrg() {
   196  	suite.OnlyRunForTags(tagsuite.Init)
   197  	ts := e2e.New(suite.T(), false)
   198  	defer ts.Close()
   199  	ts.LoginAsPersistentUser()
   200  	ts.IgnoreLogErrors()
   201  
   202  	org := "ActiveState-CLI"
   203  	projectName := fmt.Sprintf("test-project-%s", sysinfo.OS().String())
   204  
   205  	// First, checkout project to set last used org.
   206  	cp := ts.Spawn("checkout", fmt.Sprintf("%s/Python3", org))
   207  	cp.Expect("Skipping runtime setup")
   208  	cp.Expect("Checked out project")
   209  
   210  	// Now, run `state init` without specifying the org.
   211  	cp = ts.Spawn("init", projectName, "--language", "python@3")
   212  	cp.Expect(fmt.Sprintf("%s/%s", org, projectName))
   213  	cp.Expect("to track changes for this environment")
   214  	cp.Expect("successfully initialized")
   215  	cp.ExpectExitCode(0)
   216  	ts.NotifyProjectCreated(org, projectName)
   217  
   218  	// Verify the config file has the correct project owner.
   219  	suite.Contains(string(fileutils.ReadFileUnsafe(filepath.Join(ts.Dirs.Work, constants.ConfigFileName))), "ActiveState-CLI")
   220  }
   221  
   222  func TestInitIntegrationTestSuite(t *testing.T) {
   223  	suite.Run(t, new(InitIntegrationTestSuite))
   224  }