github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/test/integration/push_int_test.go (about) 1 package integration 2 3 import ( 4 "fmt" 5 "path/filepath" 6 "runtime" 7 "strings" 8 "testing" 9 "time" 10 11 "github.com/ActiveState/cli/internal/testhelpers/suite" 12 "github.com/ActiveState/termtest" 13 14 "github.com/ActiveState/cli/internal/constants" 15 "github.com/ActiveState/cli/internal/strutils" 16 "github.com/ActiveState/cli/internal/testhelpers/e2e" 17 "github.com/ActiveState/cli/internal/testhelpers/tagsuite" 18 "github.com/ActiveState/cli/pkg/project" 19 "github.com/ActiveState/cli/pkg/projectfile" 20 ) 21 22 type PushIntegrationTestSuite struct { 23 tagsuite.Suite 24 username string 25 26 // some variables re-used between tests 27 baseProject string 28 language string 29 languageFull string 30 extraPackage string 31 extraPackage2 string 32 } 33 34 func (suite *PushIntegrationTestSuite) SetupSuite() { 35 suite.username = e2e.PersistentUsername 36 suite.language = "perl" 37 suite.languageFull = "perl@5.32.0" 38 suite.baseProject = "ActiveState-CLI/Perl-5.32" 39 suite.extraPackage = "JSON" 40 suite.extraPackage2 = "DateTime" 41 if runtime.GOOS == "darwin" { 42 suite.language = "python" 43 suite.languageFull = "python" 44 suite.baseProject = "ActiveState-CLI/small-python" 45 suite.extraPackage = "trender" 46 } 47 } 48 49 func (suite *PushIntegrationTestSuite) TestInitAndPush() { 50 suite.OnlyRunForTags(tagsuite.Push) 51 ts := e2e.New(suite.T(), false) 52 defer ts.Close() 53 ts.LoginAsPersistentUser() 54 pname := strutils.UUID() 55 namespace := fmt.Sprintf("%s/%s", suite.username, pname) 56 cp := ts.Spawn( 57 "init", 58 "--language", 59 suite.languageFull, 60 namespace, 61 ".", 62 ) 63 cp.Expect("successfully initialized") 64 cp.ExpectExitCode(0) 65 ts.NotifyProjectCreated(suite.username, pname.String()) 66 67 pjfilepath := filepath.Join(ts.Dirs.Work, constants.ConfigFileName) 68 suite.Require().FileExists(pjfilepath) 69 70 // Check that languages were reset 71 pj, err := project.FromPath(pjfilepath) 72 suite.Require().NoError(err) 73 suite.Require().NotEmpty(ts.CommitID(), "commitID was not set after running push for project creation") 74 suite.Require().NotEmpty(pj.BranchName(), "branch was not set after running push for project creation") 75 76 // ensure that we are logged out 77 cp = ts.Spawn(tagsuite.Auth, "logout") 78 cp.ExpectExitCode(0) 79 80 cp = ts.SpawnWithOpts(e2e.OptArgs("install", suite.extraPackage)) 81 switch runtime.GOOS { 82 case "darwin": 83 cp.ExpectRe("added|being built", termtest.OptExpectTimeout(60*time.Second)) // while cold storage is off 84 cp.Wait() 85 default: 86 cp.Expect("added", termtest.OptExpectTimeout(60*time.Second)) 87 cp.ExpectExitCode(0) 88 } 89 90 pj, err = project.FromPath(pjfilepath) 91 suite.Require().NoError(err) 92 if !strings.Contains(pj.Source().Project, fmt.Sprintf("/%s?", namespace)) { 93 suite.FailNow("project field should include project (not headless): " + pj.Source().Project) 94 } 95 96 ts.LoginAsPersistentUser() 97 98 cp = ts.SpawnWithOpts(e2e.OptArgs("push", namespace)) 99 cp.Expect("Pushing to project") 100 cp.ExpectExitCode(0) 101 } 102 103 // Test pushing without permission, and choosing to create a new project 104 func (suite *PushIntegrationTestSuite) TestPush_NoPermission_NewProject() { 105 if runtime.GOOS == "windows" { 106 suite.T().Skip("Skipped on Windows for now because SendKeyDown() doesnt work (regardless of bash/cmd)") 107 } 108 109 suite.OnlyRunForTags(tagsuite.Push) 110 ts := e2e.New(suite.T(), false) 111 defer ts.Close() 112 user := ts.CreateNewUser() 113 pname := strutils.UUID() 114 115 cp := ts.SpawnWithOpts(e2e.OptArgs("activate", suite.baseProject, "--path", ts.Dirs.Work)) 116 cp.Expect("Activated", termtest.OptExpectTimeout(40*time.Second)) 117 cp.ExpectInput(termtest.OptExpectTimeout(10 * time.Second)) 118 cp.SendLine("exit") 119 cp.ExpectExitCode(0) 120 121 cp = ts.SpawnWithOpts(e2e.OptArgs("install", suite.extraPackage)) 122 switch runtime.GOOS { 123 case "darwin": 124 cp.ExpectRe("added|being built", termtest.OptExpectTimeout(60*time.Second)) // while cold storage is off 125 cp.Wait() 126 default: 127 cp.Expect("added", termtest.OptExpectTimeout(60*time.Second)) 128 cp.ExpectExitCode(0) 129 } 130 131 pjfilepath := filepath.Join(ts.Dirs.Work, constants.ConfigFileName) 132 pjfile, err := projectfile.Parse(pjfilepath) 133 suite.Require().NoError(err) 134 suite.Require().Contains(pjfile.Project, suite.baseProject) 135 136 cp = ts.SpawnWithOpts(e2e.OptArgs("push")) 137 cp.Expect("not authorized") 138 cp.Expect("(Y/n)") 139 cp.SendLine("y") 140 cp.Expect("Who would you like the owner of this project to be?") 141 cp.SendEnter() 142 cp.Expect("What would you like the name of this project to be?") 143 cp.SendKeyDown() 144 cp.Expect("> Other") 145 cp.SendEnter() 146 cp.Expect(">") 147 cp.SendLine(pname.String()) 148 cp.Expect("Project created") 149 cp.ExpectExitCode(0) 150 // Note: no need for ts.NotifyProjectCreated because newly created users and their projects are 151 // auto-cleaned by e2e. 152 153 pjfile, err = projectfile.Parse(pjfilepath) 154 suite.Require().NoError(err) 155 suite.Require().Contains(pjfile.Project, user.Username) 156 suite.Require().Contains(pjfile.Project, pname.String()) 157 } 158 159 func (suite *PushIntegrationTestSuite) TestCarlisle() { 160 suite.OnlyRunForTags(tagsuite.Push, tagsuite.Carlisle) 161 ts := e2e.New(suite.T(), false) 162 defer ts.Close() 163 pname := strutils.UUID() 164 namespace := fmt.Sprintf("%s/%s", suite.username, pname) 165 166 wd := filepath.Join(ts.Dirs.Work, namespace) 167 cp := ts.SpawnWithOpts( 168 e2e.OptArgs( 169 "activate", suite.baseProject, 170 "--path", wd), 171 e2e.OptAppendEnv(constants.DisableRuntime+"=false"), 172 ) 173 // The activestate.yaml on Windows runs custom activation to set shortcuts and file associations. 174 cp.Expect("Activated", e2e.RuntimeSourcingTimeoutOpt) 175 cp.SendLine("exit") 176 cp.ExpectExitCode(0) 177 178 // ensure that we are logged out 179 cp = ts.Spawn(tagsuite.Auth, "logout") 180 cp.ExpectExitCode(0) 181 182 // anonymous commit 183 cp = ts.SpawnWithOpts(e2e.OptArgs( 184 "install", suite.extraPackage), 185 e2e.OptWD(wd), 186 e2e.OptAppendEnv(constants.DisableRuntime+"=false"), 187 ) 188 switch runtime.GOOS { 189 case "darwin": 190 cp.ExpectRe("added|being built", e2e.RuntimeSourcingTimeoutOpt) // while cold storage is off 191 cp.Wait() 192 default: 193 cp.Expect("added", e2e.RuntimeSourcingTimeoutOpt) 194 cp.ExpectExitCode(0) 195 } 196 197 prj, err := project.FromPath(filepath.Join(wd, constants.ConfigFileName)) 198 suite.Require().NoError(err, "Could not parse project file") 199 suite.Assert().False(prj.IsHeadless(), "project should NOT be headless: URL is %s", prj.URL()) 200 201 ts.LoginAsPersistentUser() 202 203 cp = ts.SpawnWithOpts(e2e.OptArgs("push", namespace), e2e.OptWD(wd)) 204 cp.Expect("continue? (Y/n)") 205 cp.SendLine("y") 206 cp.Expect("Project created") 207 cp.ExpectExitCode(0) 208 ts.NotifyProjectCreated(suite.username, pname.String()) 209 } 210 211 func (suite *PushIntegrationTestSuite) TestPush_NoProject() { 212 suite.OnlyRunForTags(tagsuite.Push) 213 214 ts := e2e.New(suite.T(), false) 215 defer ts.Close() 216 217 ts.LoginAsPersistentUser() 218 cp := ts.SpawnWithOpts(e2e.OptArgs("push")) 219 cp.Expect("No project found") 220 cp.ExpectExitCode(1) 221 ts.IgnoreLogErrors() 222 223 if strings.Count(cp.Snapshot(), " x ") != 1 { 224 suite.Fail("Expected exactly ONE error message, got: ", cp.Snapshot()) 225 } 226 } 227 228 func (suite *PushIntegrationTestSuite) TestPush_NoAuth() { 229 suite.OnlyRunForTags(tagsuite.Push) 230 231 ts := e2e.New(suite.T(), false) 232 defer ts.Close() 233 234 ts.PrepareProject("ActiveState-CLI/cli", "882ae76e-fbb7-4989-acc9-9a8b87d49388") 235 236 cp := ts.SpawnWithOpts(e2e.OptArgs("push")) 237 cp.Expect("you need to be authenticated") 238 cp.ExpectExitCode(1) 239 ts.IgnoreLogErrors() 240 241 if strings.Count(cp.Snapshot(), " x ") != 1 { 242 suite.Fail("Expected exactly ONE error message, got: ", cp.Snapshot()) 243 } 244 } 245 246 func (suite *PushIntegrationTestSuite) TestPush_NoChanges() { 247 suite.OnlyRunForTags(tagsuite.Push) 248 249 ts := e2e.New(suite.T(), false) 250 defer ts.Close() 251 252 cp := ts.SpawnWithOpts(e2e.OptArgs("checkout", "ActiveState-CLI/small-python", ".")) 253 cp.ExpectExitCode(0) 254 255 ts.LoginAsPersistentUser() 256 cp = ts.SpawnWithOpts(e2e.OptArgs("push")) 257 cp.Expect("no local changes to push") 258 cp.ExpectExitCode(1) 259 ts.IgnoreLogErrors() 260 261 if strings.Count(cp.Snapshot(), " x ") != 1 { 262 suite.Fail("Expected exactly ONE error message, got: ", cp.Snapshot()) 263 } 264 } 265 266 func (suite *PushIntegrationTestSuite) TestPush_NameInUse() { 267 suite.OnlyRunForTags(tagsuite.Push) 268 269 ts := e2e.New(suite.T(), false) 270 defer ts.Close() 271 272 // Source project we do not have access to 273 ts.PrepareProject("ActiveState-Test-DevNull/push-error-test", "2aa0b8fa-04e2-4079-bde1-d46764e3cb53") 274 275 ts.LoginAsPersistentUser() 276 // Target project already exists 277 cp := ts.SpawnWithOpts(e2e.OptArgs("push", "-n", "ActiveState-CLI/push-error-test")) 278 cp.Expect("already in use") 279 cp.ExpectExitCode(1) 280 ts.IgnoreLogErrors() 281 282 if strings.Count(cp.Snapshot(), " x ") != 1 { 283 suite.Fail("Expected exactly ONE error message, got: ", cp.Snapshot()) 284 } 285 } 286 287 func (suite *PushIntegrationTestSuite) TestPush_Aborted() { 288 // Skipped for now due to DX-2244 289 suite.T().Skip("Confirming prompt with N not working, must fix first") 290 291 suite.OnlyRunForTags(tagsuite.Push) 292 293 ts := e2e.New(suite.T(), true) 294 defer ts.Close() 295 296 // Source project we do not have access to 297 ts.PrepareProject("ActiveState-Test-DevNull/push-error-test", "2aa0b8fa-04e2-4079-bde1-d46764e3cb53") 298 299 ts.LoginAsPersistentUser() 300 // Target project already exists 301 cp := ts.SpawnWithOpts(e2e.OptArgs("push")) 302 cp.Expect("Would you like to create a new project") 303 cp.SendLine("n") 304 cp.Expect("Project creation aborted by user", termtest.OptExpectTimeout(5*time.Second)) 305 cp.ExpectExitCode(1) 306 ts.IgnoreLogErrors() 307 308 if strings.Count(cp.Snapshot(), " x ") != 1 { 309 suite.Fail("Expected exactly ONE error message, got: ", cp.Snapshot()) 310 } 311 } 312 313 func (suite *PushIntegrationTestSuite) TestPush_InvalidHistory() { 314 suite.OnlyRunForTags(tagsuite.Push) 315 316 ts := e2e.New(suite.T(), true) 317 defer ts.Close() 318 319 // Note the commit we're using here is for another project, in order to repro the error 320 ts.PrepareProject("ActiveState-CLI/small-python", "dbc0415e-91e8-407b-ad36-1de0cc5c0cbb") 321 322 ts.LoginAsPersistentUser() 323 // Target project already exists 324 cp := ts.SpawnWithOpts(e2e.OptArgs("push", "ActiveState-CLI/push-error-test")) 325 cp.Expect("commit history does not match") 326 cp.ExpectExitCode(1) 327 ts.IgnoreLogErrors() 328 329 if strings.Count(cp.Snapshot(), " x ") != 1 { 330 suite.Fail("Expected exactly ONE error message, got: ", cp.Snapshot()) 331 } 332 } 333 334 func (suite *PushIntegrationTestSuite) TestPush_PullNeeded() { 335 suite.OnlyRunForTags(tagsuite.Push) 336 337 ts := e2e.New(suite.T(), true) 338 defer ts.Close() 339 340 ts.PrepareProject("ActiveState-CLI/push-error-test", "899c9b4c-d28d-441a-9c28-c84819ba8b1a") 341 342 ts.LoginAsPersistentUser() 343 // Target project already exists 344 cp := ts.SpawnWithOpts(e2e.OptArgs("push")) 345 cp.Expect("changes available that need to be merged") 346 cp.ExpectExitCode(1) 347 ts.IgnoreLogErrors() 348 349 if strings.Count(cp.Snapshot(), " x ") != 1 { 350 suite.Fail("Expected exactly ONE error message, got: ", cp.Snapshot()) 351 } 352 } 353 354 func (suite *PushIntegrationTestSuite) TestPush_Outdated() { 355 suite.OnlyRunForTags(tagsuite.Push) 356 unPushedCommit := "882ae76e-fbb7-4989-acc9-9a8b87d49388" 357 358 ts := e2e.New(suite.T(), false) 359 defer ts.Close() 360 361 ts.PrepareProject("ActiveState-CLI/cli", unPushedCommit) 362 363 ts.LoginAsPersistentUser() 364 cp := ts.SpawnWithOpts(e2e.OptArgs("push")) 365 cp.Expect("Your project has new changes available") 366 cp.ExpectExitCode(1) 367 ts.IgnoreLogErrors() 368 } 369 370 func TestPushIntegrationTestSuite(t *testing.T) { 371 suite.Run(t, new(PushIntegrationTestSuite)) 372 }