github.com/getgauge/gauge@v1.6.9/execution/specExecutor_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 execution 8 9 import ( 10 "fmt" 11 "net" 12 "testing" 13 14 "github.com/getgauge/gauge/runner" 15 16 "sync" 17 18 "github.com/getgauge/gauge-proto/go/gauge_messages" 19 "github.com/getgauge/gauge/execution/event" 20 "github.com/getgauge/gauge/execution/result" 21 "github.com/getgauge/gauge/gauge" 22 "github.com/getgauge/gauge/parser" 23 "github.com/getgauge/gauge/validation" 24 . "gopkg.in/check.v1" 25 ) 26 27 type specBuilder struct { 28 lines []string 29 } 30 31 func newSpecBuilder() *specBuilder { 32 return &specBuilder{lines: make([]string, 0)} 33 } 34 35 func (specBuilder *specBuilder) addPrefix(prefix string, line string) string { 36 return fmt.Sprintf("%s%s\n", prefix, line) 37 } 38 39 func (specBuilder *specBuilder) String() string { 40 var specResult string 41 for _, line := range specBuilder.lines { 42 specResult = fmt.Sprintf("%s%s", specResult, line) 43 } 44 return specResult 45 } 46 47 func (specBuilder *specBuilder) specHeading(heading string) *specBuilder { 48 line := specBuilder.addPrefix("#", heading) 49 specBuilder.lines = append(specBuilder.lines, line) 50 return specBuilder 51 } 52 53 func (specBuilder *specBuilder) scenarioHeading(heading string) *specBuilder { 54 line := specBuilder.addPrefix("##", heading) 55 specBuilder.lines = append(specBuilder.lines, line) 56 return specBuilder 57 } 58 59 func (specBuilder *specBuilder) step(stepText string) *specBuilder { 60 line := specBuilder.addPrefix("* ", stepText) 61 specBuilder.lines = append(specBuilder.lines, line) 62 return specBuilder 63 } 64 65 func (specBuilder *specBuilder) tableHeader(cells ...string) *specBuilder { 66 return specBuilder.tableRow(cells...) 67 } 68 func (specBuilder *specBuilder) tableRow(cells ...string) *specBuilder { 69 rowInMarkdown := "|" 70 for _, cell := range cells { 71 rowInMarkdown = fmt.Sprintf("%s%s|", rowInMarkdown, cell) 72 } 73 specBuilder.lines = append(specBuilder.lines, fmt.Sprintf("%s\n", rowInMarkdown)) 74 return specBuilder 75 } 76 77 type tableRow struct { 78 name string 79 input string // input by user for data table rows 80 output []int // data table indexes to be executed 81 } 82 83 var tableRowTests = []*tableRow{ 84 {"Valid single row number", "2", []int{1}}, 85 {"Valid row numbers list", "2,3,4", []int{1, 2, 3}}, 86 {"Valid table rows range", "2-5", []int{1, 2, 3, 4}}, 87 {"Empty table rows range", "", []int(nil)}, 88 {"Table rows list with spaces", "2, 4 ", []int{1, 3}}, 89 } 90 91 func (s *MySuite) TestToGetDataTableRowsRangeFromInputFlag(c *C) { 92 for _, test := range tableRowTests { 93 got := getDataTableRows(test.input) 94 want := test.output 95 c.Assert(got, DeepEquals, want, Commentf(test.name)) 96 } 97 } 98 99 func (s *MySuite) TestCreateSkippedSpecResult(c *C) { 100 spec := &gauge.Specification{Heading: &gauge.Heading{LineNo: 0, Value: "SPEC_HEADING"}, FileName: "FILE"} 101 r := &mockRunner{} 102 se := newSpecExecutor(spec, r, nil, nil, 0) 103 se.errMap = getValidationErrorMap() 104 se.specResult = &result.SpecResult{} 105 se.skipSpecForError(fmt.Errorf("ERROR")) 106 107 c.Assert(se.specResult.IsFailed, Equals, false) 108 c.Assert(se.specResult.Skipped, Equals, true) 109 c.Assert(len(se.errMap.SpecErrs[spec]), Equals, 1) 110 } 111 112 func (s *MySuite) TestCreateSkippedSpecResultWithScenarios(c *C) { 113 r := &mockRunner{} 114 se := newSpecExecutor(anySpec(), r, nil, nil, 0) 115 se.errMap = getValidationErrorMap() 116 se.specResult = &result.SpecResult{ProtoSpec: &gauge_messages.ProtoSpec{}} 117 se.skipSpecForError(fmt.Errorf("ERROR")) 118 119 c.Assert(len(se.errMap.ScenarioErrs[se.specification.Scenarios[0]]), Equals, 1) 120 c.Assert(len(se.errMap.SpecErrs[se.specification]), Equals, 1) 121 } 122 123 func anySpec() *gauge.Specification { 124 125 specText := newSpecBuilder().specHeading("A spec heading"). 126 scenarioHeading("First scenario"). 127 step("create user \"456\" \"foo\" and \"9900\""). 128 String() 129 130 spec, _, _ := new(parser.SpecParser).Parse(specText, gauge.NewConceptDictionary(), "") 131 spec.FileName = "FILE" 132 return spec 133 } 134 135 func (s *MySuite) TestSpecIsSkippedIfDataRangeIsInvalid(c *C) { 136 errMap := &gauge.BuildErrors{ 137 SpecErrs: make(map[*gauge.Specification][]error), 138 ScenarioErrs: make(map[*gauge.Scenario][]error), 139 StepErrs: make(map[*gauge.Step]error), 140 } 141 r := &mockRunner{} 142 spec := anySpec() 143 errMap.SpecErrs[spec] = []error{validation.NewSpecValidationError("Table row number out of range", spec.FileName)} 144 se := newSpecExecutor(spec, r, nil, errMap, 0) 145 146 specResult := se.execute(true, false, false) 147 c.Assert(specResult.Skipped, Equals, true) 148 } 149 150 func (s *MySuite) TestDataTableRowsAreSkippedForUnimplemetedStep(c *C) { 151 MaxRetriesCount = 1 152 stepText := "Unimplememted step" 153 154 specText := newSpecBuilder().specHeading("A spec heading"). 155 tableHeader("id", "name", "phone"). 156 tableRow("123", "foo", "8800"). 157 tableRow("666", "bar", "9900"). 158 scenarioHeading("First scenario"). 159 step(stepText). 160 step("create user <id> <name> and <phone>"). 161 String() 162 163 spec, _, _ := new(parser.SpecParser).Parse(specText, gauge.NewConceptDictionary(), "") 164 165 errMap := &gauge.BuildErrors{ 166 SpecErrs: make(map[*gauge.Specification][]error), 167 ScenarioErrs: make(map[*gauge.Scenario][]error), 168 StepErrs: make(map[*gauge.Step]error), 169 } 170 r := &mockRunner{} 171 errMap.SpecErrs[spec] = []error{validation.NewSpecValidationError("Step implementation not found", spec.FileName)} 172 errMap.ScenarioErrs[spec.Scenarios[0]] = []error{validation.NewSpecValidationError("Step implementation not found", spec.FileName)} 173 se := newSpecExecutor(spec, r, nil, errMap, 0) 174 175 specResult := se.execute(true, true, true) 176 c.Assert(specResult.ProtoSpec.GetIsTableDriven(), Equals, true) 177 c.Assert(specResult.Skipped, Equals, true) 178 } 179 180 func (s *MySuite) TestConvertParseErrorToGaugeMessagesError(c *C) { 181 spec := &gauge.Specification{Heading: &gauge.Heading{LineNo: 0, Value: "SPEC_HEADING"}, FileName: "FILE"} 182 e := parser.ParseError{Message: "Message", LineNo: 5, FileName: "filename"} 183 r := &mockRunner{} 184 se := newSpecExecutor(spec, r, nil, nil, 0) 185 186 errs := se.convertErrors([]error{e}) 187 188 expected := &gauge_messages.Error{ 189 Type: gauge_messages.Error_PARSE_ERROR, 190 Message: "filename:5 Message => ''", 191 LineNumber: 5, 192 Filename: "filename", 193 } 194 195 c.Assert(len(errs), DeepEquals, 1) 196 c.Assert(errs[0], DeepEquals, expected) 197 } 198 199 func (s *MySuite) TestConvertSpecValidationErrorToGaugeMessagesError(c *C) { 200 spec := &gauge.Specification{Heading: &gauge.Heading{LineNo: 0, Value: "SPEC_HEADING"}, FileName: "FILE"} 201 e := validation.NewSpecValidationError("Message", "filename") 202 r := &mockRunner{} 203 se := newSpecExecutor(spec, r, nil, nil, 0) 204 205 errs := se.convertErrors([]error{e}) 206 207 expected := &gauge_messages.Error{ 208 Type: gauge_messages.Error_VALIDATION_ERROR, 209 Message: "filename Message", 210 } 211 212 c.Assert(len(errs), DeepEquals, 1) 213 c.Assert(errs[0], DeepEquals, expected) 214 } 215 216 func (s *MySuite) TestConvertStepValidationErrorToGaugeMessagesError(c *C) { 217 spec := &gauge.Specification{Heading: &gauge.Heading{LineNo: 0, Value: "SPEC_HEADING"}, FileName: "FILE"} 218 e := validation.NewStepValidationError(&gauge.Step{LineText: "step", LineNo: 3}, "Step Message", "filename", nil, "") 219 r := &mockRunner{} 220 se := newSpecExecutor(spec, r, nil, nil, 0) 221 222 errs := se.convertErrors([]error{e}) 223 224 expected := &gauge_messages.Error{ 225 Type: gauge_messages.Error_VALIDATION_ERROR, 226 Message: "filename:3 Step Message => 'step'", 227 } 228 229 c.Assert(len(errs), DeepEquals, 1) 230 c.Assert(errs[0], DeepEquals, expected) 231 } 232 233 type mockRunner struct { 234 ExecuteAndGetStatusFunc func(m *gauge_messages.Message) *gauge_messages.ProtoExecutionResult 235 } 236 237 func (r *mockRunner) ExecuteMessageWithTimeout(m *gauge_messages.Message) (*gauge_messages.Message, error) { 238 return nil, nil 239 } 240 func (r *mockRunner) ExecuteAndGetStatus(m *gauge_messages.Message) *gauge_messages.ProtoExecutionResult { 241 return r.ExecuteAndGetStatusFunc(m) 242 } 243 244 func (r *mockRunner) Alive() bool { 245 return false 246 } 247 248 func (r *mockRunner) Kill() error { 249 return nil 250 } 251 252 func (r *mockRunner) Connection() net.Conn { 253 return nil 254 } 255 256 func (r *mockRunner) IsMultithreaded() bool { 257 return false 258 } 259 260 func (r *mockRunner) Info() *runner.RunnerInfo { 261 return &runner.RunnerInfo{Killed: false} 262 } 263 264 func (r *mockRunner) Pid() int { 265 return -1 266 } 267 268 type mockPluginHandler struct { 269 NotifyPluginsfunc func(*gauge_messages.Message) 270 GracefullyKillPluginsfunc func() 271 } 272 273 func (h *mockPluginHandler) NotifyPlugins(m *gauge_messages.Message) { 274 h.NotifyPluginsfunc(m) 275 } 276 277 func (h *mockPluginHandler) GracefullyKillPlugins() { 278 h.GracefullyKillPluginsfunc() 279 } 280 281 func (h *mockPluginHandler) ExtendTimeout(id string) { 282 283 } 284 285 var exampleSpec = &gauge.Specification{Heading: &gauge.Heading{Value: "Example Spec"}, FileName: "example.spec", Tags: &gauge.Tags{}} 286 287 var exampleSpecWithScenarios = &gauge.Specification{ 288 Heading: &gauge.Heading{Value: "Example Spec"}, 289 FileName: "example.spec", 290 Tags: &gauge.Tags{}, 291 Scenarios: []*gauge.Scenario{ 292 {Heading: &gauge.Heading{Value: "Example Scenario 1"}, Items: make([]gauge.Item, 0), Tags: &gauge.Tags{}, Span: &gauge.Span{}}, 293 {Heading: &gauge.Heading{Value: "Example Scenario 2"}, Items: make([]gauge.Item, 0), Tags: &gauge.Tags{}, Span: &gauge.Span{}}, 294 }, 295 } 296 297 func TestExecuteFailsWhenSpecHasParseErrors(t *testing.T) { 298 errs := gauge.NewBuildErrors() 299 r := &mockRunner{} 300 errs.SpecErrs[exampleSpec] = append(errs.SpecErrs[exampleSpec], parser.ParseError{Message: "some error"}) 301 se := newSpecExecutor(exampleSpec, r, nil, errs, 0) 302 303 res := se.execute(false, true, false) 304 305 if !res.GetFailed() { 306 t.Errorf("Expected result.Failed=true, got %t", res.GetFailed()) 307 } 308 309 c := len(res.Errors) 310 if c != 1 { 311 t.Errorf("Expected result to contain 1 error, got %d", c) 312 } 313 } 314 315 func TestExecuteSkipsWhenSpecHasErrors(t *testing.T) { 316 errs := gauge.NewBuildErrors() 317 r := &mockRunner{} 318 errs.SpecErrs[exampleSpec] = append(errs.SpecErrs[exampleSpec], fmt.Errorf("some error")) 319 se := newSpecExecutor(exampleSpec, r, nil, errs, 0) 320 321 res := se.execute(false, true, false) 322 323 if !res.Skipped { 324 t.Errorf("Expected result.Skipped=true, got %t", res.Skipped) 325 } 326 } 327 328 func TestExecuteInitSpecDatastore(t *testing.T) { 329 errs := gauge.NewBuildErrors() 330 r := &mockRunner{} 331 h := &mockPluginHandler{NotifyPluginsfunc: func(m *gauge_messages.Message) {}, GracefullyKillPluginsfunc: func() {}} 332 dataStoreInitCalled := false 333 r.ExecuteAndGetStatusFunc = func(m *gauge_messages.Message) *gauge_messages.ProtoExecutionResult { 334 if m.MessageType == gauge_messages.Message_SpecDataStoreInit { 335 dataStoreInitCalled = true 336 } 337 return &gauge_messages.ProtoExecutionResult{} 338 } 339 se := newSpecExecutor(exampleSpecWithScenarios, r, h, errs, 0) 340 se.execute(true, false, false) 341 342 if !dataStoreInitCalled { 343 t.Error("Expected runner to be called with SpecDataStoreInit") 344 } 345 } 346 347 func TestExecuteShouldNotInitSpecDatastoreWhenBeforeIsFalse(t *testing.T) { 348 errs := gauge.NewBuildErrors() 349 r := &mockRunner{} 350 351 dataStoreInitCalled := false 352 r.ExecuteAndGetStatusFunc = func(m *gauge_messages.Message) *gauge_messages.ProtoExecutionResult { 353 if m.MessageType == gauge_messages.Message_SpecDataStoreInit { 354 dataStoreInitCalled = true 355 } 356 return &gauge_messages.ProtoExecutionResult{} 357 } 358 se := newSpecExecutor(exampleSpec, r, nil, errs, 0) 359 se.execute(false, false, false) 360 361 if dataStoreInitCalled { 362 t.Error("Expected SpecDataStoreInit to not be called") 363 } 364 } 365 366 func TestExecuteSkipsWhenSpecDatastoreInitFails(t *testing.T) { 367 errs := gauge.NewBuildErrors() 368 r := &mockRunner{} 369 370 r.ExecuteAndGetStatusFunc = func(m *gauge_messages.Message) *gauge_messages.ProtoExecutionResult { 371 return &gauge_messages.ProtoExecutionResult{Failed: true, ErrorMessage: "datastore init error"} 372 } 373 se := newSpecExecutor(exampleSpecWithScenarios, r, nil, errs, 0) 374 res := se.execute(true, false, false) 375 376 if !res.Skipped { 377 t.Errorf("Expected result.Skipped=true, got %t", res.Skipped) 378 } 379 380 e := res.Errors[0] 381 expected := "example.spec:0 Failed to initialize spec datastore. Error: datastore init error => 'Example Spec'" 382 if e.Message != expected { 383 t.Errorf("Expected error = '%s', got '%s'", expected, e.Message) 384 } 385 } 386 387 func TestExecuteBeforeSpecHook(t *testing.T) { 388 errs := gauge.NewBuildErrors() 389 r := &mockRunner{} 390 h := &mockPluginHandler{NotifyPluginsfunc: func(m *gauge_messages.Message) {}, GracefullyKillPluginsfunc: func() {}} 391 392 beforeSpecHookCalled := false 393 r.ExecuteAndGetStatusFunc = func(m *gauge_messages.Message) *gauge_messages.ProtoExecutionResult { 394 if m.MessageType == gauge_messages.Message_SpecExecutionStarting { 395 beforeSpecHookCalled = true 396 } 397 return &gauge_messages.ProtoExecutionResult{} 398 } 399 se := newSpecExecutor(exampleSpecWithScenarios, r, h, errs, 0) 400 se.execute(true, false, false) 401 402 if !beforeSpecHookCalled { 403 t.Error("Expected runner to be called with SpecExecutionStarting") 404 } 405 } 406 407 func TestExecuteShouldNotifyBeforeSpecEvent(t *testing.T) { 408 errs := gauge.NewBuildErrors() 409 r := &mockRunner{} 410 h := &mockPluginHandler{NotifyPluginsfunc: func(m *gauge_messages.Message) {}, GracefullyKillPluginsfunc: func() {}} 411 412 eventRaised := false 413 r.ExecuteAndGetStatusFunc = func(m *gauge_messages.Message) *gauge_messages.ProtoExecutionResult { 414 return &gauge_messages.ProtoExecutionResult{} 415 } 416 417 ch := make(chan event.ExecutionEvent) 418 event.InitRegistry() 419 event.Register(ch, event.SpecStart) 420 wg := &sync.WaitGroup{} 421 wg.Add(1) 422 go func() { 423 for { 424 e := <-ch 425 t.Log(e.Topic) 426 if e.Topic == event.SpecStart { 427 eventRaised = true 428 wg.Done() 429 } 430 } 431 }() 432 se := newSpecExecutor(exampleSpecWithScenarios, r, h, errs, 0) 433 se.execute(true, false, false) 434 435 wg.Wait() 436 if !eventRaised { 437 t.Error("Expected SpecStart event to be raised") 438 } 439 event.InitRegistry() 440 } 441 func TestExecuteAfterSpecHook(t *testing.T) { 442 errs := gauge.NewBuildErrors() 443 r := &mockRunner{} 444 h := &mockPluginHandler{NotifyPluginsfunc: func(m *gauge_messages.Message) {}, GracefullyKillPluginsfunc: func() {}} 445 446 afterSpecHookCalled := false 447 r.ExecuteAndGetStatusFunc = func(m *gauge_messages.Message) *gauge_messages.ProtoExecutionResult { 448 if m.MessageType == gauge_messages.Message_SpecExecutionEnding { 449 afterSpecHookCalled = true 450 } 451 return &gauge_messages.ProtoExecutionResult{} 452 } 453 se := newSpecExecutor(exampleSpecWithScenarios, r, h, errs, 0) 454 se.execute(false, false, true) 455 456 if !afterSpecHookCalled { 457 t.Error("Expected runner to be called with SpecExecutionAfter") 458 } 459 } 460 461 func TestExecuteAddsSpecHookExecutionMessages(t *testing.T) { 462 errs := gauge.NewBuildErrors() 463 mockRunner := &mockRunner{} 464 mockHandler := &mockPluginHandler{NotifyPluginsfunc: func(m *gauge_messages.Message) {}, GracefullyKillPluginsfunc: func() {}} 465 466 mockRunner.ExecuteAndGetStatusFunc = func(m *gauge_messages.Message) *gauge_messages.ProtoExecutionResult { 467 if m.MessageType == gauge_messages.Message_SpecExecutionEnding { 468 return &gauge_messages.ProtoExecutionResult{ 469 Message: []string{"After Spec Called"}, 470 Failed: false, 471 ExecutionTime: 10, 472 } 473 } else if m.MessageType == gauge_messages.Message_SpecExecutionStarting { 474 return &gauge_messages.ProtoExecutionResult{ 475 Message: []string{"Before Spec Called"}, 476 Failed: false, 477 ExecutionTime: 10, 478 } 479 } 480 return &gauge_messages.ProtoExecutionResult{} 481 } 482 se := newSpecExecutor(exampleSpec, mockRunner, mockHandler, errs, 0) 483 se.execute(true, false, true) 484 485 gotPreHookMessages := se.specResult.ProtoSpec.PreHookMessages 486 gotPostHookMessages := se.specResult.ProtoSpec.PostHookMessages 487 488 if len(gotPreHookMessages) != 1 { 489 t.Errorf("Expected 1 message, got : %d", len(gotPreHookMessages)) 490 } 491 if gotPreHookMessages[0] != "Before Spec Called" { 492 t.Errorf("Expected `Before Spec Called` message, got : %s", gotPreHookMessages[0]) 493 } 494 if len(gotPostHookMessages) != 1 { 495 t.Errorf("Expected 1 message, got : %d", len(gotPostHookMessages)) 496 } 497 if gotPostHookMessages[0] != "After Spec Called" { 498 t.Errorf("Expected `After Spec Called` message, got : %s", gotPostHookMessages[0]) 499 } 500 } 501 502 func TestExecuteAddsSpecHookExecutionScreenshots(t *testing.T) { 503 errs := gauge.NewBuildErrors() 504 mockRunner := &mockRunner{} 505 mockHandler := &mockPluginHandler{NotifyPluginsfunc: func(m *gauge_messages.Message) {}, GracefullyKillPluginsfunc: func() {}} 506 507 mockRunner.ExecuteAndGetStatusFunc = func(m *gauge_messages.Message) *gauge_messages.ProtoExecutionResult { 508 if m.MessageType == gauge_messages.Message_SpecExecutionEnding { 509 return &gauge_messages.ProtoExecutionResult{ 510 ScreenshotFiles: []string{"screenshot1.png", "screenshot2.png"}, 511 Failed: false, 512 ExecutionTime: 10, 513 } 514 } else if m.MessageType == gauge_messages.Message_SpecExecutionStarting { 515 return &gauge_messages.ProtoExecutionResult{ 516 ScreenshotFiles: []string{"screenshot3.png", "screenshot4.png"}, 517 Failed: false, 518 ExecutionTime: 10, 519 } 520 } 521 return &gauge_messages.ProtoExecutionResult{} 522 } 523 se := newSpecExecutor(exampleSpec, mockRunner, mockHandler, errs, 0) 524 se.execute(true, false, true) 525 526 beforeSpecScreenshots := se.specResult.ProtoSpec.PreHookScreenshotFiles 527 afterSpecScreenshots := se.specResult.ProtoSpec.PostHookScreenshotFiles 528 expectedAfterSpecScreenshots := []string{"screenshot1.png", "screenshot2.png"} 529 expectedBeforeSpecScreenshots := []string{"screenshot3.png", "screenshot4.png"} 530 531 if len(beforeSpecScreenshots) != len(expectedBeforeSpecScreenshots) { 532 t.Errorf("Expected 2 screenshots, got : %d", len(beforeSpecScreenshots)) 533 } 534 for i, e := range expectedBeforeSpecScreenshots { 535 if string(beforeSpecScreenshots[i]) != e { 536 t.Errorf("Expected `%s` screenshot, got : %s", e, beforeSpecScreenshots[i]) 537 } 538 } 539 if len(afterSpecScreenshots) != len(expectedAfterSpecScreenshots) { 540 t.Errorf("Expected 2 screenshots, got : %d", len(afterSpecScreenshots)) 541 } 542 for i, e := range expectedAfterSpecScreenshots { 543 if string(afterSpecScreenshots[i]) != e { 544 t.Errorf("Expected `%s` screenshot, got : %s", e, afterSpecScreenshots[i]) 545 } 546 } 547 } 548 549 func TestExecuteShouldNotifyAfterSpecEvent(t *testing.T) { 550 errs := gauge.NewBuildErrors() 551 r := &mockRunner{} 552 h := &mockPluginHandler{NotifyPluginsfunc: func(m *gauge_messages.Message) {}, GracefullyKillPluginsfunc: func() {}} 553 554 eventRaised := false 555 r.ExecuteAndGetStatusFunc = func(m *gauge_messages.Message) *gauge_messages.ProtoExecutionResult { 556 return &gauge_messages.ProtoExecutionResult{} 557 } 558 559 ch := make(chan event.ExecutionEvent) 560 event.InitRegistry() 561 event.Register(ch, event.SpecEnd) 562 wg := &sync.WaitGroup{} 563 wg.Add(1) 564 go func() { 565 for { 566 e := <-ch 567 t.Log(e.Topic) 568 if e.Topic == event.SpecEnd { 569 eventRaised = true 570 wg.Done() 571 } 572 } 573 }() 574 se := newSpecExecutor(exampleSpecWithScenarios, r, h, errs, 0) 575 se.execute(false, false, true) 576 577 wg.Wait() 578 if !eventRaised { 579 t.Error("Expected SpecEnd event to be raised") 580 } 581 event.InitRegistry() 582 } 583 584 type mockExecutor struct { 585 executeFunc func(i gauge.Item, r result.Result) 586 } 587 588 func (e *mockExecutor) execute(i gauge.Item, r result.Result) { 589 e.executeFunc(i, r) 590 } 591 592 func TestExecuteScenario(t *testing.T) { 593 MaxRetriesCount = 1 594 errs := gauge.NewBuildErrors() 595 r := &mockRunner{} 596 se := newSpecExecutor(exampleSpecWithScenarios, r, nil, errs, 0) 597 executedScenarios := make([]string, 0) 598 se.scenarioExecutor = &mockExecutor{ 599 executeFunc: func(i gauge.Item, r result.Result) { 600 executedScenarios = append(executedScenarios, i.(*gauge.Scenario).Heading.Value) 601 }, 602 } 603 se.execute(false, true, false) 604 got := len(executedScenarios) 605 if got != 2 { 606 t.Errorf("Expected 2 scenarios to be executed, got %d", got) 607 } 608 609 expected := []string{"Example Scenario 1", "Example Scenario 2"} 610 for i, s := range executedScenarios { 611 if s != expected[i] { 612 t.Errorf("Expected '%s' scenario to be executed. Got %s", s, executedScenarios) 613 } 614 } 615 } 616 617 func TestExecuteScenarioWithRetries(t *testing.T) { 618 MaxRetriesCount = 3 619 errs := gauge.NewBuildErrors() 620 r := &mockRunner{} 621 se := newSpecExecutor(exampleSpecWithScenarios, r, nil, errs, 0) 622 623 count := 1 624 se.scenarioExecutor = &mockExecutor{ 625 executeFunc: func(i gauge.Item, r result.Result) { 626 if count < MaxRetriesCount { 627 r.SetFailure() 628 } else { 629 r.(*result.ScenarioResult).ProtoScenario.ExecutionStatus = gauge_messages.ExecutionStatus_PASSED 630 } 631 632 count++ 633 }, 634 } 635 636 sceResult, _ := se.executeScenario(exampleSpecWithScenarios.Scenarios[0]) 637 638 if sceResult.GetFailed() { 639 t.Errorf("Expect sceResult.GetFailed() = false, got true") 640 } 641 } 642 643 var exampleSpecWithTags = &gauge.Specification{ 644 Heading: &gauge.Heading{Value: "Example Spec"}, 645 FileName: "example.spec", 646 Tags: &gauge.Tags{RawValues: [][]string{{"tagSpec"}}}, 647 Scenarios: []*gauge.Scenario{ 648 {Heading: &gauge.Heading{Value: "Example Scenario 1"}, Items: make([]gauge.Item, 0), Tags: &gauge.Tags{RawValues: [][]string{{"tagSce"}}}, Span: &gauge.Span{}}, 649 }, 650 } 651 652 func TestExecuteScenarioShouldNotRetryIfNotMatchTags(t *testing.T) { 653 MaxRetriesCount = 2 654 RetryOnlyTags = "tagN" 655 656 se := newSpecExecutorForTestsWithRetry() 657 sceResult, _ := se.executeScenario(exampleSpecWithTags.Scenarios[0]) 658 659 if !sceResult.GetFailed() { 660 t.Errorf("Expect sceResult.GetFailed() = true, got false") 661 } 662 } 663 664 func TestExecuteScenarioShouldRetryIfSpecificationMatchTags(t *testing.T) { 665 MaxRetriesCount = 2 666 RetryOnlyTags = "tagSpec" 667 668 se := newSpecExecutorForTestsWithRetry() 669 670 sceResult, _ := se.executeScenario(exampleSpecWithTags.Scenarios[0]) 671 672 if sceResult.GetFailed() { 673 t.Errorf("Expect sceResult.GetFailed() = false, got true") 674 } 675 } 676 677 func TestExecuteScenarioShouldRetryIfScenarioMatchTags(t *testing.T) { 678 MaxRetriesCount = 2 679 RetryOnlyTags = "tagSce" 680 681 se := newSpecExecutorForTestsWithRetry() 682 683 sceResult, _ := se.executeScenario(exampleSpecWithTags.Scenarios[0]) 684 685 if sceResult.GetFailed() { 686 t.Errorf("Expect sceResult.GetFailed() = false, got true") 687 } 688 } 689 690 func newSpecExecutorForTestsWithRetry() *specExecutor { 691 errs := gauge.NewBuildErrors() 692 r := &mockRunner{} 693 se := newSpecExecutor(exampleSpecWithTags, r, nil, errs, 0) 694 695 count := 1 696 se.scenarioExecutor = &mockExecutor{ 697 executeFunc: func(i gauge.Item, r result.Result) { 698 if count < MaxRetriesCount { 699 r.SetFailure() 700 } else { 701 r.(*result.ScenarioResult).ProtoScenario.ExecutionStatus = gauge_messages.ExecutionStatus_PASSED 702 } 703 704 count++ 705 }, 706 } 707 708 return se 709 } 710 711 func TestExecuteShouldMarkSpecAsSkippedWhenAllScenariosSkipped(t *testing.T) { 712 errs := gauge.NewBuildErrors() 713 r := &mockRunner{} 714 se := newSpecExecutor(exampleSpecWithScenarios, r, nil, errs, 0) 715 se.scenarioExecutor = &mockExecutor{ 716 executeFunc: func(i gauge.Item, r result.Result) { 717 r.(*result.ScenarioResult).ProtoScenario.ExecutionStatus = gauge_messages.ExecutionStatus_SKIPPED 718 }, 719 } 720 res := se.execute(false, true, false) 721 if !res.Skipped { 722 t.Error("Expect SpecResult.Skipped = true, got false") 723 } 724 } 725 726 func TestExecuteScenarioShoulHaveRetriesInfo(t *testing.T) { 727 MaxRetriesCount = 3 728 RetryOnlyTags = "tagSce" 729 730 se := newSpecExecutorForTestsWithRetry() 731 sceResult, _ := se.executeScenario(exampleSpecWithTags.Scenarios[0]) 732 733 if sceResult.GetFailed() { 734 t.Errorf("Expect sceResult.GetFailed() = false, got true") 735 } 736 if se.currentExecutionInfo.CurrentScenario.Retries.MaxRetries != int32(MaxRetriesCount - 1) { 737 t.Errorf("Expected MaxRetries %d, got %d", 738 int32(MaxRetriesCount - 1), 739 se.currentExecutionInfo.CurrentScenario.Retries.MaxRetries) 740 } 741 if se.currentExecutionInfo.CurrentScenario.Retries.CurrentRetry != int32(MaxRetriesCount - 1) { 742 t.Errorf("Expected CurrentRetry %d, got %d", 743 int32(MaxRetriesCount - 1), 744 se.currentExecutionInfo.CurrentScenario.Retries.CurrentRetry) 745 } 746 } 747