github.com/getgauge/gauge@v1.6.9/cmd/run_test.go (about) 1 /*---------------------------------------------------------------- 2 * Copyright (c) ThoughtWorks, Inc. 3 * Licensed under the Apache License, Version 2.0 4 * See LICENSE in the project root for license information. 5 *----------------------------------------------------------------*/ 6 7 package cmd 8 9 import ( 10 "bytes" 11 "fmt" 12 "os" 13 "os/exec" 14 "path/filepath" 15 "testing" 16 17 "github.com/getgauge/gauge/gauge" 18 19 "github.com/getgauge/gauge/execution" 20 "github.com/getgauge/gauge/execution/rerun" 21 22 "github.com/spf13/pflag" 23 24 "reflect" 25 26 "github.com/getgauge/gauge/config" 27 "github.com/spf13/cobra" 28 ) 29 30 var projectPath = "" 31 32 func before() { 33 projectPath, _ = filepath.Abs("_testData") 34 config.ProjectRoot = projectPath 35 } 36 37 func after() { 38 os.RemoveAll(projectPath) 39 } 40 41 func TestMain(m *testing.M) { 42 before() 43 runTests := m.Run() 44 after() 45 os.Exit(runTests) 46 } 47 48 func TestSaveCommandArgs(t *testing.T) { 49 if os.Getenv("TEST_EXITS") == "1" { 50 args := []string{"gauge", "run", "specs"} 51 52 rerun.WritePrevArgs(args) 53 54 prevArgs := rerun.ReadPrevArgs() 55 if !reflect.DeepEqual(prevArgs, args) { 56 fmt.Printf("Expected %v Got %v\n", args, prevArgs) 57 os.Exit(1) 58 } 59 return 60 } 61 cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", t.Name())) 62 cmd.Env = subEnv() 63 err := cmd.Run() 64 if err != nil { 65 t.Fatalf("process ran with err %v, want exit status 0", err) 66 } 67 } 68 69 func TestExecuteWritesPrevCommandArgs(t *testing.T) { 70 if os.Getenv("TEST_EXITS") == "1" { 71 args := []string{"gauge", "run", "specs"} 72 73 installPlugins = false 74 execution.ExecuteSpecs = func(s []string) int { return 0 } 75 cmd := &cobra.Command{} 76 77 os.Args = args 78 execute(cmd, args) 79 prevArgs := rerun.ReadPrevArgs() 80 if !reflect.DeepEqual(prevArgs, args) { 81 fmt.Printf("Expected %v Got %v\n", args, prevArgs) 82 os.Exit(1) 83 } 84 return 85 } 86 cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", t.Name())) 87 cmd.Env = subEnv() 88 err := cmd.Run() 89 if err != nil { 90 t.Fatalf("process ran with err %v, want exit status 0", err) 91 } 92 } 93 94 func TestRepeatShouldPreservePreviousArgs(t *testing.T) { 95 if os.Getenv("TEST_EXITS") == "1" { 96 cmd := &cobra.Command{} 97 98 var called bool 99 rerun.WritePrevArgs = func(x []string) { 100 called = true 101 } 102 rerun.ReadPrevArgs = func() []string { 103 return []string{"gauge", "run", "specs", "-l", "debug"} 104 } 105 installPlugins = false 106 repeatLastExecution(cmd) 107 108 if called { 109 panic("Unexpected call to writePrevArgs while repeat") 110 } 111 return 112 } 113 cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", t.Name())) 114 cmd.Env = subEnv() 115 err := cmd.Run() 116 if err != nil { 117 t.Fatalf("process ran with err %v, want exit status 0", err) 118 } 119 } 120 121 func TestSaveCommandArgsForFailed(t *testing.T) { 122 if os.Getenv("TEST_EXITS") == "1" { 123 execution.ExecuteSpecs = func(s []string) int { return 0 } 124 rerun.GetLastFailedState = func() ([]string, error) { 125 return []string{"run", "specs"}, nil 126 } 127 var args = []string{"gauge", "run", "--failed"} 128 129 rerun.WritePrevArgs = func(a []string) { 130 if !reflect.DeepEqual(a, args) { 131 panic(fmt.Sprintf("Expected %v Got %v", args, a)) 132 } 133 } 134 135 os.Args = args 136 executeFailed(runCmd) 137 return 138 } 139 140 cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", t.Name())) 141 cmd.Env = subEnv() 142 err := cmd.Run() 143 if err != nil { 144 t.Fatalf("process ran with err %v, want exit status 0", err) 145 } 146 } 147 148 func TestHandleConflictingParamsWithOtherArguments(t *testing.T) { 149 if os.Getenv("TEST_EXITS") == "1" { 150 args := []string{"specs"} 151 152 var flags = pflag.FlagSet{} 153 flags.BoolP("repeat", "r", false, "") 154 err := flags.Set("repeat", "true") 155 if err != nil { 156 t.Error(err) 157 } 158 159 repeat = true 160 expectedErrorMessage := "Invalid Command. Usage: gauge run --repeat" 161 err = handleConflictingParams(&flags, args) 162 163 if !reflect.DeepEqual(err.Error(), expectedErrorMessage) { 164 fmt.Printf("Expected %v Got %v\n", expectedErrorMessage, err) 165 panic("assert failed") 166 } 167 return 168 } 169 var stdout bytes.Buffer 170 cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", t.Name())) 171 cmd.Env = subEnv() 172 cmd.Stdout = &stdout 173 err := cmd.Run() 174 if err != nil { 175 t.Fatalf("process ran with err %v, want exit status 0. Stdout:\n%s", err, stdout.Bytes()) 176 } 177 } 178 179 func TestHandleConflictingParamsWithOtherFlags(t *testing.T) { 180 args := []string{} 181 182 var flags = pflag.FlagSet{} 183 flags.BoolP("repeat", "r", false, "") 184 err := flags.Set("repeat", "true") 185 if err != nil { 186 t.Error(err) 187 } 188 189 flags.StringP("tags", "", "", "") 190 err = flags.Set("tags", "abcd") 191 if err != nil { 192 t.Error(err) 193 } 194 195 repeat = true 196 expectedErrorMessage := "Invalid Command. Usage: gauge run --repeat" 197 err = handleConflictingParams(&flags, args) 198 199 if !reflect.DeepEqual(err.Error(), expectedErrorMessage) { 200 t.Errorf("Expected %v Got %v", expectedErrorMessage, err) 201 } 202 } 203 204 func TestHandleConflictingParamsWithJustRepeatFlag(t *testing.T) { 205 args := []string{} 206 207 var flags = pflag.FlagSet{} 208 flags.BoolP("repeat", "r", false, "") 209 err := flags.Set("repeat", "true") 210 if err != nil { 211 t.Error(err) 212 } 213 214 repeat = true 215 err = handleConflictingParams(&flags, args) 216 217 if err != nil { 218 t.Errorf("Expected %v Got %v", nil, err.Error()) 219 } 220 } 221 222 func TestHandleRerunFlagsWithVerbose(t *testing.T) { 223 if os.Getenv("TEST_EXITS") == "1" { 224 cmd := &cobra.Command{} 225 226 cmd.Flags().BoolP(verboseName, "v", verboseDefault, "Enable step level reporting on console, default being scenario level") 227 cmd.Flags().BoolP(simpleConsoleName, "", simpleConsoleDefault, "Removes colouring and simplifies the console output") 228 cmd.Flags().StringP(environmentName, "e", environmentDefault, "Specifies the environment to use") 229 cmd.Flags().StringP(tagsName, "t", tagsDefault, "Executes the specs and scenarios tagged with given tags") 230 cmd.Flags().StringP(rowsName, "r", rowsDefault, "Executes the specs and scenarios only for the selected rows. It can be specified by range as 2-4 or as list 2,4") 231 cmd.Flags().BoolP(parallelName, "p", parallelDefault, "Execute specs in parallel") 232 cmd.Flags().IntP(streamsName, "n", streamsDefault, "Specify number of parallel execution streams") 233 cmd.Flags().IntP(groupName, "g", groupDefault, "Specify which group of specification to execute based on -n flag") 234 cmd.Flags().StringP(strategyName, "", strategyDefault, "Set the parallelization strategy for execution. Possible options are: `eager`, `lazy`") 235 cmd.Flags().BoolP(sortName, "s", sortDefault, "Run specs in Alphabetical Order") 236 cmd.Flags().BoolP(installPluginsName, "i", installPluginsDefault, "Install All Missing Plugins") 237 cmd.Flags().BoolP(failedName, "f", failedDefault, "Run only the scenarios failed in previous run. This is an exclusive flag, it cannot be used in conjunction with any other argument") 238 cmd.Flags().BoolP(repeatName, "", repeatDefault, "Repeat last run. This is an exclusive flag, it cannot be used in conjunction with any other argument") 239 cmd.Flags().BoolP(hideSuggestionName, "", hideSuggestionDefault, "Prints a step implementation stub for every unimplemented step") 240 err := cmd.Flags().Set(repeatName, "true") 241 if err != nil { 242 t.Error(err) 243 } 244 err = cmd.Flags().Set(verboseName, "true") 245 if err != nil { 246 t.Error(err) 247 } 248 249 handleFlags(cmd, []string{"--repeat", "--verbose"}) 250 overridenFlagValue := cmd.Flag(verboseName).Value.String() 251 expectedFlag := "true" 252 253 if !reflect.DeepEqual(overridenFlagValue, expectedFlag) { 254 fmt.Printf("Expected %v Got %v\n", expectedFlag, overridenFlagValue) 255 os.Exit(1) 256 } 257 return 258 } 259 var stdout bytes.Buffer 260 cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", t.Name())) 261 cmd.Env = subEnv() 262 cmd.Stdout = &stdout 263 err := cmd.Run() 264 if err != nil { 265 t.Fatalf("process ran with err %v, want exit status 0. Stdout:\n%s", err, stdout.Bytes()) 266 } 267 } 268 269 func TestHandleFailedCommandForNonGaugeProject(t *testing.T) { 270 if os.Getenv("TEST_EXITS") == "1" { 271 config.ProjectRoot = "" 272 currDir, _ := os.Getwd() 273 defer func() { 274 err := os.Chdir(currDir) 275 if err != nil { 276 t.Error(err) 277 } 278 }() 279 testdir := filepath.Join(currDir, "dotGauge") 280 dotgaugeDir := filepath.Join(testdir, ".gauge") 281 err := os.Chdir(testdir) 282 if err != nil { 283 t.Error(err) 284 } 285 286 exit = func(err error, i string) { 287 if _, e := os.Stat(dotgaugeDir); os.IsExist(e) { 288 panic("Folder .gauge is created") 289 } 290 os.Exit(0) 291 } 292 293 os.Args = []string{"gauge", "run", "-f"} 294 295 err = runCmd.Execute() 296 297 if err != nil { 298 t.Error(err) 299 } 300 return 301 } 302 cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", t.Name())) 303 cmd.Env = subEnv() 304 err := cmd.Run() 305 if err != nil { 306 t.Fatalf("process ran with err %v, want exit status 0", err) 307 } 308 } 309 310 func TestHandleConflictingParamsWithLogLevelFlag(t *testing.T) { 311 args := []string{} 312 var flags = pflag.FlagSet{} 313 314 flags.StringP("log-level", "l", "info", "") 315 err := flags.Set("log-level", "debug") 316 if err != nil { 317 t.Error(err) 318 } 319 320 flags.BoolP("repeat", "r", false, "") 321 err = flags.Set("repeat", "true") 322 if err != nil { 323 t.Error(err) 324 } 325 326 repeat = true 327 328 err = handleConflictingParams(&flags, args) 329 330 if err != nil { 331 t.Errorf("Expected %v Got %v", nil, err.Error()) 332 } 333 } 334 335 func TestNoExitCodeShouldForceReturnZero(t *testing.T) { 336 if os.Getenv("TEST_EXITS") == "1" { 337 installPlugins = false 338 // simulate failure 339 execution.ExecuteSpecs = func(s []string) int { return execution.ExecutionFailed } 340 341 os.Args = []string{"gauge", "run", "--fail-safe", "specs"} 342 343 failSafe = true 344 err := runCmd.Execute() 345 if err != nil { 346 t.Error(err) 347 } 348 return 349 } 350 var stdout bytes.Buffer 351 cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", t.Name())) 352 cmd.Env = subEnv() 353 cmd.Stdout = &stdout 354 err := cmd.Run() 355 if err != nil { 356 t.Fatalf("%s process ran with err %v, want exit status 0. Stdout:\n%s", os.Args, err, stdout.Bytes()) 357 } 358 } 359 360 func TestFailureShouldReturnExitCodeForParseErrors(t *testing.T) { 361 if os.Getenv("TEST_EXITS") == "1" { 362 // simulate parse failure 363 execution.ExecuteSpecs = func(s []string) int { return execution.ParseFailed } 364 365 os.Args = []string{"gauge", "run", "--fail-safe", "specs"} 366 failSafe = true 367 err := runCmd.Execute() 368 if err != nil { 369 t.Error(err) 370 } 371 } 372 373 cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", t.Name())) 374 cmd.Env = append(os.Environ(), "TEST_EXITS=1") 375 err := cmd.Run() 376 if e, ok := err.(*exec.ExitError); ok && !e.Success() { 377 return 378 } 379 t.Fatalf("process ran with err %v, want exit status 2", err) 380 } 381 382 func TestFailureShouldReturnExitCode(t *testing.T) { 383 if os.Getenv("TEST_EXITS") == "1" { 384 // simulate execution failure 385 execution.ExecuteSpecs = func(s []string) int { return execution.ExecutionFailed } 386 os.Args = []string{"gauge", "run", "specs"} 387 err := runCmd.Execute() 388 if err != nil { 389 t.Error(err) 390 } 391 } 392 393 var stdout bytes.Buffer 394 cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", t.Name())) 395 cmd.Env = subEnv() 396 cmd.Stdout = &stdout 397 err := cmd.Run() 398 if e, ok := err.(*exec.ExitError); ok && !e.Success() { 399 return 400 } 401 t.Fatalf("process ran with err %v, want exit status 1. Stdout:\n%s", err, stdout.Bytes()) 402 } 403 404 func TestLogLevelCanBeOverriddenForFailed(t *testing.T) { 405 if os.Getenv("TEST_EXITS") == "1" { 406 // expect log level to be overridden 407 execution.ExecuteSpecs = func(s []string) int { 408 f, err := runCmd.Flags().GetString(logLevelName) 409 if err != nil { 410 fmt.Printf("Error parsing flags. %s\n", err.Error()) 411 panic(err) 412 } 413 if f != "info" { 414 fmt.Printf("Expecting log-level=info, got %s\n", f) 415 panic("assert failure") 416 } 417 return 0 418 } 419 420 rerun.ReadPrevArgs = func() []string { 421 return []string{"gauge", "run", "specs", "-l", "debug"} 422 } 423 os.Args = []string{"gauge", "run", "--failed", "-l", "info"} 424 err := os.MkdirAll(filepath.Join(projectPath, ".gauge"), 0755) 425 if err != nil { 426 t.Error(err) 427 } 428 file, err := os.OpenFile(filepath.Join(projectPath, ".gauge", "failures.json"), os.O_CREATE|os.O_WRONLY, 0644) 429 if err != nil { 430 t.Error(err) 431 } 432 _, err = file.Write([]byte("{\"Args\": [\"run\",\"-v\"],\"FailedItems\": [\"specs\"]}")) 433 if err != nil { 434 t.Error(err) 435 } 436 file.Close() 437 executeFailed(runCmd) 438 return 439 } 440 var stdout bytes.Buffer 441 cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", t.Name())) 442 cmd.Env = subEnv() 443 cmd.Stdout = &stdout 444 err := cmd.Run() 445 if err != nil { 446 t.Fatalf("process ran with err %v, want exit status 0.Stdout:\n%s", err, stdout.Bytes()) 447 } 448 } 449 450 func TestLogLevelCanBeOverriddenForRepeat(t *testing.T) { 451 if os.Getenv("TEST_EXITS") == "1" { 452 // expect log level to be overridden 453 execution.ExecuteSpecs = func(s []string) int { 454 f, err := runCmd.Flags().GetString(logLevelName) 455 if err != nil { 456 fmt.Printf("Error parsing flags. %s\n", err.Error()) 457 panic(err) 458 } 459 if f != "info" { 460 fmt.Printf("Expecting log-level=info, got %s\n", f) 461 panic("assert failure") 462 } 463 return 0 464 } 465 466 rerun.ReadPrevArgs = func() []string { 467 return []string{"gauge", "run", "specs", "-l=debug"} 468 } 469 os.Args = []string{"gauge", "run", "--failed", "-l=info"} 470 err := runCmd.ParseFlags(os.Args) 471 if err != nil { 472 t.Error(err) 473 } 474 475 repeatLastExecution(runCmd) 476 return 477 } 478 var stdout bytes.Buffer 479 cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", t.Name()), "-test.v") 480 cmd.Env = subEnv() 481 cmd.Stdout = &stdout 482 err := cmd.Run() 483 if err != nil { 484 t.Fatalf("process ran with err %v, want exit status 0.Stdout:\n%s", err, stdout.Bytes()) 485 } 486 } 487 488 func TestCorrectFlagsAreSetForRepeat(t *testing.T) { 489 if os.Getenv("TEST_EXITS") == "1" { 490 // expect "env" to be set to "test" 491 err := os.MkdirAll(filepath.Join(projectPath, "env", "test"), 0755) 492 if err != nil { 493 t.Error(err) 494 } 495 496 execution.ExecuteSpecs = func(s []string) int { 497 f, err := runCmd.Flags().GetString(environmentName) 498 if err != nil { 499 fmt.Printf("Error parsing flags. %s\n", err.Error()) 500 panic(err) 501 } 502 if f != "test" { 503 fmt.Printf("Expecting env=test, got %s\n", f) 504 panic("assert failure") 505 } 506 return 0 507 } 508 509 rerun.ReadPrevArgs = func() []string { 510 return []string{"gauge", "run", "specs", "--env=test"} 511 } 512 os.Args = []string{"gauge", "run", "--failed"} 513 err = runCmd.ParseFlags(os.Args) 514 if err != nil { 515 t.Error(err) 516 } 517 518 repeatLastExecution(runCmd) 519 return 520 } 521 var stdout bytes.Buffer 522 cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", t.Name())) 523 cmd.Env = subEnv() 524 cmd.Stdout = &stdout 525 err := cmd.Run() 526 if err != nil { 527 t.Fatalf("process ran with err %v, want exit status 0.Stdout:\n%s", err, stdout.Bytes()) 528 } 529 } 530 531 func TestCorrectFlagsAreSetForFailed(t *testing.T) { 532 if os.Getenv("TEST_EXITS") == "1" { 533 // expect "env" to be set to "test" 534 execution.ExecuteSpecs = func(s []string) int { 535 f, err := runCmd.Flags().GetString(environmentName) 536 if err != nil { 537 fmt.Printf("Error parsing flags. %s\n", err.Error()) 538 panic(err) 539 } 540 if f != "test" { 541 fmt.Printf("Expecting env=test, got %s\n", f) 542 panic("assert failure") 543 } 544 return 0 545 } 546 547 rerun.GetLastFailedState = func() ([]string, error) { 548 return []string{"run", "specs", "--env=test"}, nil 549 } 550 os.Args = []string{"gauge", "run", "--failed"} 551 executeFailed(runCmd) 552 return 553 } 554 var stdout bytes.Buffer 555 cmd := exec.Command(os.Args[0], fmt.Sprintf("-test.run=%s", t.Name()), "-test.v") 556 cmd.Env = subEnv() 557 cmd.Stdout = &stdout 558 err := cmd.Run() 559 if err != nil { 560 t.Fatalf("process ran with err %v, want exit status 0.Stdout:\n%s", err, stdout.Bytes()) 561 } 562 } 563 564 func subEnv() []string { 565 return append(os.Environ(), []string{"TEST_EXITS=1", "GAUGE_PLUGIN_INSTALL=false"}...) 566 } 567 568 func TestAddingFlagsToExecutionArgs(t *testing.T) { 569 var flags = &pflag.FlagSet{} 570 flags.BoolP("parallel", "p", false, "") 571 err := flags.Set("parallel", "true") 572 if err != nil { 573 t.Error(err) 574 } 575 576 execution.ExecutionArgs = []*gauge.ExecutionArg{} 577 addFlagsToExecutionArgs(flags) 578 if execution.ExecutionArgs[0].Name != "parallel" { 579 t.Fatalf("Expecting execution arg name parallel but found %s", execution.ExecutionArgs[0].Name) 580 } 581 if execution.ExecutionArgs[0].Value[0] != "true" { 582 t.Fatalf("Expecting execution arg value true but found %s", execution.ExecutionArgs[0].Value[0]) 583 } 584 } 585 586 func TestAddingMultipleFlagsToExecutionArgs(t *testing.T) { 587 var flags = &pflag.FlagSet{} 588 flags.BoolP("parallel", "p", false, "") 589 err := flags.Set("parallel", "true") 590 if err != nil { 591 t.Error(err) 592 } 593 594 flags.StringP("tags", "", "", "") 595 err = flags.Set("tags", "tag1") 596 if err != nil { 597 t.Error(err) 598 } 599 600 execution.ExecutionArgs = []*gauge.ExecutionArg{} 601 addFlagsToExecutionArgs(flags) 602 603 if execution.ExecutionArgs[0].Name != "parallel" { 604 t.Fatalf("Expecting execution arg name parallel but found %s", execution.ExecutionArgs[0].Name) 605 } 606 if execution.ExecutionArgs[1].Name != "tags" { 607 t.Fatalf("Expecting execution arg name tags but found %s", execution.ExecutionArgs[1].Name) 608 } 609 if execution.ExecutionArgs[1].Value[0] != "tag1" { 610 t.Fatalf("Expecting execution arg value tag1 but found %s", execution.ExecutionArgs[1].Value[0]) 611 } 612 }