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