github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/apiv3/route/service_test.go (about) 1 package route 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "net/http/httptest" 9 "net/url" 10 "testing" 11 "time" 12 13 "github.com/evergreen-ci/evergreen/apiv3" 14 "github.com/evergreen-ci/evergreen/apiv3/model" 15 "github.com/evergreen-ci/evergreen/apiv3/servicecontext" 16 serviceModel "github.com/evergreen-ci/evergreen/model" 17 "github.com/evergreen-ci/evergreen/model/host" 18 "github.com/evergreen-ci/evergreen/model/task" 19 "github.com/evergreen-ci/evergreen/model/user" 20 "github.com/evergreen-ci/evergreen/util" 21 "github.com/gorilla/context" 22 "github.com/gorilla/mux" 23 . "github.com/smartystreets/goconvey/convey" 24 ) 25 26 func TestHostParseAndValidate(t *testing.T) { 27 Convey("With a hostGetHandler and request", t, func() { 28 testStatus := "testStatus" 29 hgh := &hostGetHandler{} 30 hgh, ok := hgh.Handler().(*hostGetHandler) 31 So(ok, ShouldBeTrue) 32 u := url.URL{ 33 RawQuery: fmt.Sprintf("status=%s", testStatus), 34 } 35 r := http.Request{ 36 URL: &u, 37 } 38 Convey("parsing request should fetch status", func() { 39 err := hgh.ParseAndValidate(&r) 40 So(err, ShouldBeNil) 41 hga, ok := hgh.PaginationExecutor.Args.(hostGetArgs) 42 So(ok, ShouldBeTrue) 43 So(hga.status, ShouldEqual, testStatus) 44 }) 45 }) 46 } 47 48 func TestHostPaginator(t *testing.T) { 49 numHostsInDB := 300 50 Convey("When paginating with a ServiceContext", t, func() { 51 serviceContext := servicecontext.MockServiceContext{} 52 Convey("and there are hosts to be found", func() { 53 cachedHosts := []host.Host{} 54 for i := 0; i < numHostsInDB; i++ { 55 nextHost := host.Host{ 56 Id: fmt.Sprintf("host%d", i), 57 } 58 cachedHosts = append(cachedHosts, nextHost) 59 } 60 serviceContext.MockHostConnector.CachedHosts = cachedHosts 61 Convey("then finding a key in the middle of the set should produce"+ 62 " a full next and previous page and a full set of models", func() { 63 hostToStartAt := 100 64 limit := 100 65 expectedHosts := []model.Model{} 66 for i := hostToStartAt; i < hostToStartAt+limit; i++ { 67 nextModelHost := &model.APIHost{ 68 Id: model.APIString(fmt.Sprintf("host%d", i)), 69 } 70 expectedHosts = append(expectedHosts, nextModelHost) 71 } 72 expectedPages := &PageResult{ 73 Next: &Page{ 74 Key: fmt.Sprintf("host%d", hostToStartAt+limit), 75 Limit: limit, 76 Relation: "next", 77 }, 78 Prev: &Page{ 79 Key: fmt.Sprintf("host%d", hostToStartAt-limit), 80 Limit: limit, 81 Relation: "prev", 82 }, 83 } 84 checkPaginatorResultMatches(hostPaginator, fmt.Sprintf("host%d", hostToStartAt), 85 limit, &serviceContext, hostGetArgs{}, expectedPages, expectedHosts, nil) 86 87 }) 88 Convey("then finding a key in the near the end of the set should produce"+ 89 " a limited next and full previous page and a full set of models", func() { 90 hostToStartAt := 150 91 limit := 100 92 expectedHosts := []model.Model{} 93 for i := hostToStartAt; i < hostToStartAt+limit; i++ { 94 nextModelHost := &model.APIHost{ 95 Id: model.APIString(fmt.Sprintf("host%d", i)), 96 } 97 expectedHosts = append(expectedHosts, nextModelHost) 98 } 99 expectedPages := &PageResult{ 100 Next: &Page{ 101 Key: fmt.Sprintf("host%d", hostToStartAt+limit), 102 Limit: 50, 103 Relation: "next", 104 }, 105 Prev: &Page{ 106 Key: fmt.Sprintf("host%d", hostToStartAt-limit), 107 Limit: limit, 108 Relation: "prev", 109 }, 110 } 111 checkPaginatorResultMatches(hostPaginator, fmt.Sprintf("host%d", hostToStartAt), 112 limit, &serviceContext, hostGetArgs{}, expectedPages, expectedHosts, nil) 113 114 }) 115 Convey("then finding a key in the near the beginning of the set should produce"+ 116 " a full next and a limited previous page and a full set of models", func() { 117 hostToStartAt := 50 118 limit := 100 119 expectedHosts := []model.Model{} 120 for i := hostToStartAt; i < hostToStartAt+limit; i++ { 121 nextModelHost := &model.APIHost{ 122 Id: model.APIString(fmt.Sprintf("host%d", i)), 123 } 124 expectedHosts = append(expectedHosts, nextModelHost) 125 } 126 expectedPages := &PageResult{ 127 Next: &Page{ 128 Key: fmt.Sprintf("host%d", hostToStartAt+limit), 129 Limit: limit, 130 Relation: "next", 131 }, 132 Prev: &Page{ 133 Key: fmt.Sprintf("host%d", 0), 134 Limit: 50, 135 Relation: "prev", 136 }, 137 } 138 checkPaginatorResultMatches(hostPaginator, fmt.Sprintf("host%d", hostToStartAt), 139 limit, &serviceContext, hostGetArgs{}, expectedPages, expectedHosts, nil) 140 141 }) 142 Convey("then finding a key in the last page should produce only a previous"+ 143 " page and a limited set of models", func() { 144 hostToStartAt := 299 145 limit := 100 146 expectedHosts := []model.Model{} 147 for i := hostToStartAt; i < numHostsInDB; i++ { 148 nextModelHost := &model.APIHost{ 149 Id: model.APIString(fmt.Sprintf("host%d", i)), 150 } 151 expectedHosts = append(expectedHosts, nextModelHost) 152 } 153 expectedPages := &PageResult{ 154 Prev: &Page{ 155 Key: fmt.Sprintf("host%d", hostToStartAt-limit), 156 Limit: limit, 157 Relation: "prev", 158 }, 159 } 160 checkPaginatorResultMatches(hostPaginator, fmt.Sprintf("host%d", hostToStartAt), 161 limit, &serviceContext, hostGetArgs{}, expectedPages, expectedHosts, nil) 162 163 }) 164 Convey("then finding the first key should produce only a next"+ 165 " page and a full set of models", func() { 166 hostToStartAt := 0 167 limit := 100 168 expectedHosts := []model.Model{} 169 for i := hostToStartAt; i < hostToStartAt+limit; i++ { 170 nextModelHost := &model.APIHost{ 171 Id: model.APIString(fmt.Sprintf("host%d", i)), 172 } 173 expectedHosts = append(expectedHosts, nextModelHost) 174 } 175 expectedPages := &PageResult{ 176 Next: &Page{ 177 Key: fmt.Sprintf("host%d", hostToStartAt+limit), 178 Limit: limit, 179 Relation: "next", 180 }, 181 } 182 checkPaginatorResultMatches(hostPaginator, fmt.Sprintf("host%d", hostToStartAt), 183 limit, &serviceContext, hostGetArgs{}, expectedPages, expectedHosts, nil) 184 185 }) 186 }) 187 }) 188 } 189 190 func TestTasksByProjectAndCommitPaginator(t *testing.T) { 191 numTasks := 300 192 projectName := "project_1" 193 commit := "commit_1" 194 Convey("When paginating with a ServiceContext", t, func() { 195 serviceContext := servicecontext.MockServiceContext{} 196 Convey("and there are tasks to be found", func() { 197 cachedTasks := []task.Task{} 198 for i := 0; i < numTasks; i++ { 199 nextTask := task.Task{ 200 Id: fmt.Sprintf("task_%d", i), 201 Revision: commit, 202 Project: projectName, 203 } 204 cachedTasks = append(cachedTasks, nextTask) 205 } 206 serviceContext.MockTaskConnector.CachedTasks = cachedTasks 207 Convey("then finding a key in the middle of the set should produce"+ 208 " a full next and previous page and a full set of models", func() { 209 taskToStartAt := 100 210 limit := 100 211 expectedTasks := []model.Model{} 212 for i := taskToStartAt; i < taskToStartAt+limit; i++ { 213 nextModelTask := &model.APITask{ 214 Id: model.APIString(fmt.Sprintf("task_%d", i)), 215 Revision: model.APIString(commit), 216 Branch: model.APIString(projectName), 217 } 218 err := nextModelTask.BuildFromService("") 219 So(err, ShouldBeNil) 220 expectedTasks = append(expectedTasks, nextModelTask) 221 } 222 expectedPages := &PageResult{ 223 Next: &Page{ 224 Key: fmt.Sprintf("task_%d", taskToStartAt+limit), 225 Limit: limit, 226 Relation: "next", 227 }, 228 Prev: &Page{ 229 Key: fmt.Sprintf("task_%d", taskToStartAt-limit), 230 Limit: limit, 231 Relation: "prev", 232 }, 233 } 234 tphArgs := tasksByProjectArgs{ 235 projectId: projectName, 236 commitHash: commit, 237 } 238 checkPaginatorResultMatches(tasksByProjectPaginator, fmt.Sprintf("task_%d", taskToStartAt), 239 limit, &serviceContext, tphArgs, expectedPages, expectedTasks, nil) 240 241 }) 242 Convey("then finding a key in the near the end of the set should produce"+ 243 " a limited next and full previous page and a full set of models", func() { 244 taskToStartAt := 150 245 limit := 100 246 expectedTasks := []model.Model{} 247 for i := taskToStartAt; i < taskToStartAt+limit; i++ { 248 nextModelTask := &model.APITask{ 249 Id: model.APIString(fmt.Sprintf("task_%d", i)), 250 Revision: model.APIString(commit), 251 Branch: model.APIString(projectName), 252 } 253 err := nextModelTask.BuildFromService("") 254 So(err, ShouldBeNil) 255 expectedTasks = append(expectedTasks, nextModelTask) 256 } 257 expectedPages := &PageResult{ 258 Next: &Page{ 259 Key: fmt.Sprintf("task_%d", taskToStartAt+limit), 260 Limit: 50, 261 Relation: "next", 262 }, 263 Prev: &Page{ 264 Key: fmt.Sprintf("task_%d", taskToStartAt-limit), 265 Limit: limit, 266 Relation: "prev", 267 }, 268 } 269 tphArgs := tasksByProjectArgs{ 270 projectId: projectName, 271 commitHash: commit, 272 } 273 checkPaginatorResultMatches(tasksByProjectPaginator, fmt.Sprintf("task_%d", taskToStartAt), 274 limit, &serviceContext, tphArgs, expectedPages, expectedTasks, nil) 275 276 }) 277 Convey("then finding a key in the near the beginning of the set should produce"+ 278 " a full next and a limited previous page and a full set of models", func() { 279 taskToStartAt := 50 280 limit := 100 281 expectedTasks := []model.Model{} 282 for i := taskToStartAt; i < taskToStartAt+limit; i++ { 283 nextModelTask := &model.APITask{ 284 Id: model.APIString(fmt.Sprintf("task_%d", i)), 285 Revision: model.APIString(commit), 286 Branch: model.APIString(projectName), 287 } 288 err := nextModelTask.BuildFromService("") 289 So(err, ShouldBeNil) 290 expectedTasks = append(expectedTasks, nextModelTask) 291 } 292 expectedPages := &PageResult{ 293 Next: &Page{ 294 Key: fmt.Sprintf("task_%d", taskToStartAt+limit), 295 Limit: limit, 296 Relation: "next", 297 }, 298 Prev: &Page{ 299 Key: fmt.Sprintf("task_%d", 0), 300 Limit: 50, 301 Relation: "prev", 302 }, 303 } 304 tphArgs := tasksByProjectArgs{ 305 projectId: projectName, 306 commitHash: commit, 307 } 308 checkPaginatorResultMatches(tasksByProjectPaginator, fmt.Sprintf("task_%d", taskToStartAt), 309 limit, &serviceContext, tphArgs, expectedPages, expectedTasks, nil) 310 311 }) 312 Convey("then finding a key in the last page should produce only a previous"+ 313 " page and a limited set of models", func() { 314 taskToStartAt := 299 315 limit := 100 316 expectedTasks := []model.Model{} 317 for i := taskToStartAt; i < numTasks; i++ { 318 nextModelTask := &model.APITask{ 319 Id: model.APIString(fmt.Sprintf("task_%d", i)), 320 Revision: model.APIString(commit), 321 Branch: model.APIString(projectName), 322 } 323 err := nextModelTask.BuildFromService("") 324 So(err, ShouldBeNil) 325 expectedTasks = append(expectedTasks, nextModelTask) 326 } 327 expectedPages := &PageResult{ 328 Prev: &Page{ 329 Key: fmt.Sprintf("task_%d", taskToStartAt-limit), 330 Limit: limit, 331 Relation: "prev", 332 }, 333 } 334 tphArgs := tasksByProjectArgs{ 335 projectId: projectName, 336 commitHash: commit, 337 } 338 checkPaginatorResultMatches(tasksByProjectPaginator, fmt.Sprintf("task_%d", taskToStartAt), 339 limit, &serviceContext, tphArgs, expectedPages, expectedTasks, nil) 340 341 }) 342 Convey("then finding the first key should produce only a next"+ 343 " page and a full set of models", func() { 344 taskToStartAt := 0 345 limit := 100 346 expectedTasks := []model.Model{} 347 for i := taskToStartAt; i < taskToStartAt+limit; i++ { 348 nextModelTask := &model.APITask{ 349 Id: model.APIString(fmt.Sprintf("task_%d", i)), 350 Revision: model.APIString(commit), 351 Branch: model.APIString(projectName), 352 } 353 err := nextModelTask.BuildFromService("") 354 So(err, ShouldBeNil) 355 expectedTasks = append(expectedTasks, nextModelTask) 356 } 357 expectedPages := &PageResult{ 358 Next: &Page{ 359 Key: fmt.Sprintf("task_%d", taskToStartAt+limit), 360 Limit: limit, 361 Relation: "next", 362 }, 363 } 364 tphArgs := tasksByProjectArgs{ 365 projectId: projectName, 366 commitHash: commit, 367 } 368 checkPaginatorResultMatches(tasksByProjectPaginator, fmt.Sprintf("task_%d", taskToStartAt), 369 limit, &serviceContext, tphArgs, expectedPages, expectedTasks, nil) 370 }) 371 Convey("when APIError is returned from DB, should percolate upward", func() { 372 expectedErr := apiv3.APIError{ 373 StatusCode: http.StatusNotFound, 374 Message: "not found", 375 } 376 serviceContext.MockTaskConnector.StoredError = &expectedErr 377 checkPaginatorResultMatches(tasksByProjectPaginator, "", 378 0, &serviceContext, tasksByProjectArgs{}, nil, nil, &expectedErr) 379 380 }) 381 }) 382 }) 383 } 384 385 func TestTaskByBuildPaginator(t *testing.T) { 386 numTasks := 300 387 Convey("When paginating with a ServiceContext", t, func() { 388 serviceContext := servicecontext.MockServiceContext{} 389 Convey("and there are tasks to be found", func() { 390 cachedTasks := []task.Task{} 391 for i := 0; i < numTasks; i++ { 392 nextTask := task.Task{ 393 Id: fmt.Sprintf("build%d", i), 394 } 395 cachedTasks = append(cachedTasks, nextTask) 396 } 397 serviceContext.MockTaskConnector.CachedTasks = cachedTasks 398 Convey("then finding a key in the middle of the set should produce"+ 399 " a full next and previous page and a full set of models", func() { 400 taskToStartAt := 100 401 limit := 100 402 expectedTasks := []model.Model{} 403 for i := taskToStartAt; i < taskToStartAt+limit; i++ { 404 nextModelTask := &model.APITask{ 405 Id: model.APIString(fmt.Sprintf("build%d", i)), 406 } 407 err := nextModelTask.BuildFromService("") 408 So(err, ShouldBeNil) 409 expectedTasks = append(expectedTasks, nextModelTask) 410 } 411 expectedPages := &PageResult{ 412 Next: &Page{ 413 Key: fmt.Sprintf("build%d", taskToStartAt+limit), 414 Limit: limit, 415 Relation: "next", 416 }, 417 Prev: &Page{ 418 Key: fmt.Sprintf("build%d", taskToStartAt-limit), 419 Limit: limit, 420 Relation: "prev", 421 }, 422 } 423 checkPaginatorResultMatches(tasksByBuildPaginator, fmt.Sprintf("build%d", taskToStartAt), 424 limit, &serviceContext, tasksByBuildArgs{}, expectedPages, expectedTasks, nil) 425 426 }) 427 Convey("then finding a key in the near the end of the set should produce"+ 428 " a limited next and full previous page and a full set of models", func() { 429 taskToStartAt := 150 430 limit := 100 431 expectedTasks := []model.Model{} 432 for i := taskToStartAt; i < taskToStartAt+limit; i++ { 433 nextModelTask := &model.APITask{ 434 Id: model.APIString(fmt.Sprintf("build%d", i)), 435 } 436 err := nextModelTask.BuildFromService("") 437 So(err, ShouldBeNil) 438 expectedTasks = append(expectedTasks, nextModelTask) 439 } 440 expectedPages := &PageResult{ 441 Next: &Page{ 442 Key: fmt.Sprintf("build%d", taskToStartAt+limit), 443 Limit: 50, 444 Relation: "next", 445 }, 446 Prev: &Page{ 447 Key: fmt.Sprintf("build%d", taskToStartAt-limit), 448 Limit: limit, 449 Relation: "prev", 450 }, 451 } 452 checkPaginatorResultMatches(tasksByBuildPaginator, fmt.Sprintf("build%d", taskToStartAt), 453 limit, &serviceContext, tasksByBuildArgs{}, expectedPages, expectedTasks, nil) 454 455 }) 456 Convey("then finding a key in the near the beginning of the set should produce"+ 457 " a full next and a limited previous page and a full set of models", func() { 458 taskToStartAt := 50 459 limit := 100 460 expectedTasks := []model.Model{} 461 for i := taskToStartAt; i < taskToStartAt+limit; i++ { 462 nextModelTask := &model.APITask{ 463 Id: model.APIString(fmt.Sprintf("build%d", i)), 464 } 465 err := nextModelTask.BuildFromService("") 466 So(err, ShouldBeNil) 467 expectedTasks = append(expectedTasks, nextModelTask) 468 } 469 expectedPages := &PageResult{ 470 Next: &Page{ 471 Key: fmt.Sprintf("build%d", taskToStartAt+limit), 472 Limit: limit, 473 Relation: "next", 474 }, 475 Prev: &Page{ 476 Key: fmt.Sprintf("build%d", 0), 477 Limit: 50, 478 Relation: "prev", 479 }, 480 } 481 checkPaginatorResultMatches(tasksByBuildPaginator, fmt.Sprintf("build%d", taskToStartAt), 482 limit, &serviceContext, tasksByBuildArgs{}, expectedPages, expectedTasks, nil) 483 484 }) 485 Convey("then finding a key in the last page should produce only a previous"+ 486 " page and a limited set of models", func() { 487 taskToStartAt := 299 488 limit := 100 489 expectedTasks := []model.Model{} 490 for i := taskToStartAt; i < numTasks; i++ { 491 nextModelTask := &model.APITask{ 492 Id: model.APIString(fmt.Sprintf("build%d", i)), 493 } 494 err := nextModelTask.BuildFromService("") 495 So(err, ShouldBeNil) 496 expectedTasks = append(expectedTasks, nextModelTask) 497 } 498 expectedPages := &PageResult{ 499 Prev: &Page{ 500 Key: fmt.Sprintf("build%d", taskToStartAt-limit), 501 Limit: limit, 502 Relation: "prev", 503 }, 504 } 505 checkPaginatorResultMatches(tasksByBuildPaginator, fmt.Sprintf("build%d", taskToStartAt), 506 limit, &serviceContext, tasksByBuildArgs{}, expectedPages, expectedTasks, nil) 507 508 }) 509 Convey("then finding the first key should produce only a next"+ 510 " page and a full set of models", func() { 511 taskToStartAt := 0 512 limit := 100 513 expectedTasks := []model.Model{} 514 for i := taskToStartAt; i < taskToStartAt+limit; i++ { 515 nextModelTask := &model.APITask{ 516 Id: model.APIString(fmt.Sprintf("build%d", i)), 517 } 518 err := nextModelTask.BuildFromService("") 519 So(err, ShouldBeNil) 520 expectedTasks = append(expectedTasks, nextModelTask) 521 } 522 expectedPages := &PageResult{ 523 Next: &Page{ 524 Key: fmt.Sprintf("build%d", taskToStartAt+limit), 525 Limit: limit, 526 Relation: "next", 527 }, 528 } 529 checkPaginatorResultMatches(tasksByBuildPaginator, fmt.Sprintf("build%d", taskToStartAt), 530 limit, &serviceContext, tasksByBuildArgs{}, expectedPages, expectedTasks, nil) 531 532 }) 533 }) 534 }) 535 } 536 537 func TestTestPaginator(t *testing.T) { 538 numTests := 300 539 Convey("When paginating with a ServiceContext", t, func() { 540 serviceContext := servicecontext.MockServiceContext{} 541 Convey("and there are tasks with tests to be found", func() { 542 cachedTests := []task.TestResult{} 543 for i := 0; i < numTests; i++ { 544 status := "pass" 545 if i%2 == 0 { 546 status = "fail" 547 } 548 nextTest := task.TestResult{ 549 TestFile: fmt.Sprintf("test%d", i), 550 Status: status, 551 } 552 cachedTests = append(cachedTests, nextTest) 553 } 554 serviceContext.MockTestConnector.CachedTests = cachedTests 555 Convey("then finding a key in the middle of the set should produce"+ 556 " a full next and previous page and a full set of models", func() { 557 testToStartAt := 100 558 limit := 100 559 expectedTests := []model.Model{} 560 for i := testToStartAt; i < testToStartAt+limit; i++ { 561 status := "pass" 562 if i%2 == 0 { 563 status = "fail" 564 } 565 nextModelTest := &model.APITest{ 566 TestFile: model.APIString(fmt.Sprintf("test%d", i)), 567 StartTime: model.APITime(time.Unix(0, 0)), 568 EndTime: model.APITime(time.Unix(0, 0)), 569 Status: model.APIString(status), 570 } 571 expectedTests = append(expectedTests, nextModelTest) 572 } 573 expectedPages := &PageResult{ 574 Next: &Page{ 575 Key: fmt.Sprintf("test%d", testToStartAt+limit), 576 Limit: limit, 577 Relation: "next", 578 }, 579 Prev: &Page{ 580 Key: fmt.Sprintf("test%d", testToStartAt-limit), 581 Limit: limit, 582 Relation: "prev", 583 }, 584 } 585 args := testGetHandlerArgs{} 586 checkPaginatorResultMatches(testPaginator, fmt.Sprintf("test%d", testToStartAt), 587 limit, &serviceContext, args, expectedPages, expectedTests, nil) 588 589 }) 590 Convey("then finding a key in the near the end of the set should produce"+ 591 " a limited next and full previous page and a full set of models", func() { 592 testToStartAt := 150 593 limit := 100 594 expectedTests := []model.Model{} 595 for i := testToStartAt; i < testToStartAt+limit; i++ { 596 status := "pass" 597 if i%2 == 0 { 598 status = "fail" 599 } 600 nextModelTest := &model.APITest{ 601 TestFile: model.APIString(fmt.Sprintf("test%d", i)), 602 StartTime: model.APITime(time.Unix(0, 0)), 603 EndTime: model.APITime(time.Unix(0, 0)), 604 Status: model.APIString(status), 605 } 606 expectedTests = append(expectedTests, nextModelTest) 607 } 608 expectedPages := &PageResult{ 609 Next: &Page{ 610 Key: fmt.Sprintf("test%d", testToStartAt+limit), 611 Limit: 50, 612 Relation: "next", 613 }, 614 Prev: &Page{ 615 Key: fmt.Sprintf("test%d", testToStartAt-limit), 616 Limit: limit, 617 Relation: "prev", 618 }, 619 } 620 args := testGetHandlerArgs{} 621 checkPaginatorResultMatches(testPaginator, fmt.Sprintf("test%d", testToStartAt), 622 limit, &serviceContext, args, expectedPages, expectedTests, nil) 623 624 }) 625 Convey("then finding a key in the near the beginning of the set should produce"+ 626 " a full next and a limited previous page and a full set of models", func() { 627 testToStartAt := 50 628 limit := 100 629 expectedTests := []model.Model{} 630 for i := testToStartAt; i < testToStartAt+limit; i++ { 631 status := "pass" 632 if i%2 == 0 { 633 status = "fail" 634 } 635 nextModelTest := &model.APITest{ 636 TestFile: model.APIString(fmt.Sprintf("test%d", i)), 637 StartTime: model.APITime(time.Unix(0, 0)), 638 EndTime: model.APITime(time.Unix(0, 0)), 639 Status: model.APIString(status), 640 } 641 expectedTests = append(expectedTests, nextModelTest) 642 } 643 expectedPages := &PageResult{ 644 Next: &Page{ 645 Key: fmt.Sprintf("test%d", testToStartAt+limit), 646 Limit: limit, 647 Relation: "next", 648 }, 649 Prev: &Page{ 650 Key: fmt.Sprintf("test%d", 0), 651 Limit: 50, 652 Relation: "prev", 653 }, 654 } 655 args := testGetHandlerArgs{} 656 checkPaginatorResultMatches(testPaginator, fmt.Sprintf("test%d", testToStartAt), 657 limit, &serviceContext, args, expectedPages, expectedTests, nil) 658 659 }) 660 Convey("then finding a key in the last page should produce only a previous"+ 661 " page and a limited set of models", func() { 662 testToStartAt := 299 663 limit := 100 664 expectedTests := []model.Model{} 665 for i := testToStartAt; i < numTests; i++ { 666 status := "pass" 667 if i%2 == 0 { 668 status = "fail" 669 } 670 nextModelTest := &model.APITest{ 671 TestFile: model.APIString(fmt.Sprintf("test%d", i)), 672 StartTime: model.APITime(time.Unix(0, 0)), 673 EndTime: model.APITime(time.Unix(0, 0)), 674 Status: model.APIString(status), 675 } 676 expectedTests = append(expectedTests, nextModelTest) 677 } 678 expectedPages := &PageResult{ 679 Prev: &Page{ 680 Key: fmt.Sprintf("test%d", testToStartAt-limit), 681 Limit: limit, 682 Relation: "prev", 683 }, 684 } 685 args := testGetHandlerArgs{} 686 checkPaginatorResultMatches(testPaginator, fmt.Sprintf("test%d", testToStartAt), 687 limit, &serviceContext, args, expectedPages, expectedTests, nil) 688 689 }) 690 Convey("then finding the first key should produce only a next"+ 691 " page and a full set of models", func() { 692 testToStartAt := 0 693 limit := 100 694 expectedTests := []model.Model{} 695 for i := testToStartAt; i < testToStartAt+limit; i++ { 696 status := "pass" 697 if i%2 == 0 { 698 status = "fail" 699 } 700 nextModelTest := &model.APITest{ 701 TestFile: model.APIString(fmt.Sprintf("test%d", i)), 702 StartTime: model.APITime(time.Unix(0, 0)), 703 EndTime: model.APITime(time.Unix(0, 0)), 704 Status: model.APIString(status), 705 } 706 expectedTests = append(expectedTests, nextModelTest) 707 } 708 expectedPages := &PageResult{ 709 Next: &Page{ 710 Key: fmt.Sprintf("test%d", testToStartAt+limit), 711 Limit: limit, 712 Relation: "next", 713 }, 714 } 715 args := testGetHandlerArgs{} 716 checkPaginatorResultMatches(testPaginator, fmt.Sprintf("test%d", testToStartAt), 717 limit, &serviceContext, args, expectedPages, expectedTests, nil) 718 }) 719 }) 720 }) 721 } 722 723 func TestTaskExecutionPatchPrepare(t *testing.T) { 724 Convey("With handler and a project context and user", t, func() { 725 tep := &TaskExecutionPatchHandler{} 726 727 projCtx := serviceModel.Context{ 728 Task: &task.Task{ 729 Id: "testTaskId", 730 Priority: 0, 731 Activated: false, 732 }, 733 } 734 u := user.DBUser{ 735 Id: "testUser", 736 } 737 Convey("then should error on empty body", func() { 738 req, err := http.NewRequest("PATCH", "task/testTaskId", &bytes.Buffer{}) 739 So(err, ShouldBeNil) 740 context.Set(req, RequestUser, &u) 741 context.Set(req, RequestContext, &projCtx) 742 err = tep.ParseAndValidate(req) 743 So(err, ShouldNotBeNil) 744 expectedErr := apiv3.APIError{ 745 Message: "No request body sent", 746 StatusCode: http.StatusBadRequest, 747 } 748 So(err, ShouldResemble, expectedErr) 749 }) 750 Convey("then should error on body with wrong type", func() { 751 str := "nope" 752 badBod := &struct { 753 Activated *string 754 }{ 755 Activated: &str, 756 } 757 res, err := json.Marshal(badBod) 758 So(err, ShouldBeNil) 759 buf := bytes.NewBuffer(res) 760 761 req, err := http.NewRequest("PATCH", "task/testTaskId", buf) 762 So(err, ShouldBeNil) 763 context.Set(req, RequestUser, &u) 764 context.Set(req, RequestContext, &projCtx) 765 err = tep.ParseAndValidate(req) 766 So(err, ShouldNotBeNil) 767 expectedErr := apiv3.APIError{ 768 Message: fmt.Sprintf("Incorrect type given, expecting '%s' "+ 769 "but receieved '%s'", 770 "bool", "string"), 771 StatusCode: http.StatusBadRequest, 772 } 773 So(err, ShouldResemble, expectedErr) 774 }) 775 Convey("then should error when fields not set", func() { 776 badBod := &struct { 777 Activated *string 778 }{} 779 res, err := json.Marshal(badBod) 780 So(err, ShouldBeNil) 781 buf := bytes.NewBuffer(res) 782 783 req, err := http.NewRequest("PATCH", "task/testTaskId", buf) 784 So(err, ShouldBeNil) 785 context.Set(req, RequestUser, &u) 786 context.Set(req, RequestContext, &projCtx) 787 err = tep.ParseAndValidate(req) 788 So(err, ShouldNotBeNil) 789 expectedErr := apiv3.APIError{ 790 Message: "Must set 'activated' or 'priority'", 791 StatusCode: http.StatusBadRequest, 792 } 793 So(err, ShouldResemble, expectedErr) 794 }) 795 Convey("then should set it's Activated and Priority field when set", func() { 796 goodBod := &struct { 797 Activated bool 798 Priority int 799 }{ 800 Activated: true, 801 Priority: 100, 802 } 803 res, err := json.Marshal(goodBod) 804 So(err, ShouldBeNil) 805 buf := bytes.NewBuffer(res) 806 807 req, err := http.NewRequest("PATCH", "task/testTaskId", buf) 808 So(err, ShouldBeNil) 809 context.Set(req, RequestUser, &u) 810 context.Set(req, RequestContext, &projCtx) 811 err = tep.ParseAndValidate(req) 812 So(err, ShouldBeNil) 813 So(*tep.Activated, ShouldBeTrue) 814 So(*tep.Priority, ShouldEqual, 100) 815 816 Convey("and task and user should be set", func() { 817 So(tep.task, ShouldNotBeNil) 818 So(tep.task.Id, ShouldEqual, "testTaskId") 819 So(tep.user.Username(), ShouldEqual, "testUser") 820 }) 821 }) 822 }) 823 } 824 825 func TestTaskExecutionPatchExecute(t *testing.T) { 826 Convey("With a task in the DB and a ServiceContext", t, func() { 827 sc := servicecontext.MockServiceContext{} 828 testTask := task.Task{ 829 Id: "testTaskId", 830 Activated: false, 831 Priority: 10, 832 } 833 sc.MockTaskConnector.CachedTasks = append(sc.MockTaskConnector.CachedTasks, testTask) 834 835 Convey("then setting priority should change it's priority", func() { 836 act := true 837 var prio int64 = 100 838 839 tep := &TaskExecutionPatchHandler{ 840 Activated: &act, 841 Priority: &prio, 842 task: &task.Task{ 843 Id: "testTaskId", 844 }, 845 user: &user.DBUser{ 846 Id: "testUser", 847 }, 848 } 849 res, err := tep.Execute(&sc) 850 So(err, ShouldBeNil) 851 So(len(res.Result), ShouldEqual, 1) 852 resModel := res.Result[0] 853 resTask, ok := resModel.(*model.APITask) 854 So(ok, ShouldBeTrue) 855 So(resTask.Priority, ShouldEqual, int64(100)) 856 So(resTask.Activated, ShouldBeTrue) 857 So(resTask.ActivatedBy, ShouldEqual, "testUser") 858 }) 859 }) 860 } 861 862 func TestTaskResetPrepare(t *testing.T) { 863 Convey("With handler and a project context and user", t, func() { 864 trh := &TaskRestartHandler{} 865 866 projCtx := serviceModel.Context{ 867 Task: &task.Task{ 868 Id: "testTaskId", 869 Priority: 0, 870 Activated: false, 871 }, 872 Project: &serviceModel.Project{}, 873 } 874 u := user.DBUser{ 875 Id: "testUser", 876 } 877 Convey("should error on empty project", func() { 878 projCtx.Project = nil 879 req, err := http.NewRequest("POST", "task/testTaskId/restart", &bytes.Buffer{}) 880 So(err, ShouldBeNil) 881 context.Set(req, RequestUser, &u) 882 context.Set(req, RequestContext, &projCtx) 883 err = trh.ParseAndValidate(req) 884 So(err, ShouldNotBeNil) 885 expectedErr := fmt.Errorf("Unable to fetch associated project") 886 So(err, ShouldResemble, expectedErr) 887 }) 888 Convey("then should error on empty task", func() { 889 projCtx.Task = nil 890 req, err := http.NewRequest("POST", "task/testTaskId/restart", &bytes.Buffer{}) 891 So(err, ShouldBeNil) 892 context.Set(req, RequestUser, &u) 893 context.Set(req, RequestContext, &projCtx) 894 err = trh.ParseAndValidate(req) 895 So(err, ShouldNotBeNil) 896 expectedErr := apiv3.APIError{ 897 Message: "Task not found", 898 StatusCode: http.StatusNotFound, 899 } 900 901 So(err, ShouldResemble, expectedErr) 902 }) 903 }) 904 } 905 906 func TestTaskGetHandler(t *testing.T) { 907 Convey("With test server with a handler and mock servicecontext", t, func() { 908 rm := getTaskRouteManager("/tasks/{task_id}", 2) 909 sc := &servicecontext.MockServiceContext{} 910 sc.SetPrefix("rest") 911 r := mux.NewRouter() 912 913 Convey("and task is in the service context", func() { 914 sc.MockTaskConnector.CachedTasks = []task.Task{ 915 {Id: "testTaskId"}, 916 } 917 rm.Register(r, sc) 918 Convey("a request with a user should then return no error and a task should"+ 919 " should be returned", func() { 920 req, err := http.NewRequest("GET", "/rest/v2/tasks/testTaskId", nil) 921 So(err, ShouldBeNil) 922 req.Header.Add("Api-Key", "Key") 923 req.Header.Add("Api-User", "User") 924 925 sc.MockUserConnector.CachedUsers = map[string]*user.DBUser{ 926 "User": &user.DBUser{ 927 APIKey: "Key", 928 Id: "User", 929 }, 930 } 931 932 rr := httptest.NewRecorder() 933 r.ServeHTTP(rr, req) 934 So(rr.Code, ShouldEqual, http.StatusOK) 935 936 res := model.APITask{} 937 err = json.Unmarshal(rr.Body.Bytes(), &res) 938 So(err, ShouldBeNil) 939 So(res.Id, ShouldEqual, "testTaskId") 940 }) 941 Convey("a request without a user should then return a 404 error and a task should"+ 942 " should be not returned", func() { 943 req, err := http.NewRequest("GET", "/rest/v2/tasks/testTaskId", nil) 944 So(err, ShouldBeNil) 945 req.Header.Add("Api-Key", "Key") 946 req.Header.Add("Api-User", "User") 947 948 rr := httptest.NewRecorder() 949 r.ServeHTTP(rr, req) 950 So(rr.Code, ShouldEqual, http.StatusNotFound) 951 }) 952 }) 953 }) 954 } 955 956 func TestTaskResetExecute(t *testing.T) { 957 Convey("With a task returned by the ServiceContext", t, func() { 958 sc := servicecontext.MockServiceContext{} 959 timeNow := time.Now() 960 testTask := task.Task{ 961 Id: "testTaskId", 962 Activated: false, 963 Secret: "initialSecret", 964 DispatchTime: timeNow, 965 } 966 sc.MockTaskConnector.CachedTasks = append(sc.MockTaskConnector.CachedTasks, testTask) 967 Convey("and an error from the service function", func() { 968 sc.MockTaskConnector.StoredError = fmt.Errorf("could not reset task") 969 970 trh := &TaskRestartHandler{ 971 taskId: "testTaskId", 972 project: &serviceModel.Project{}, 973 username: "testUser", 974 } 975 976 _, err := trh.Execute(&sc) 977 So(err, ShouldNotBeNil) 978 apiErr, ok := err.(apiv3.APIError) 979 So(ok, ShouldBeTrue) 980 So(apiErr.StatusCode, ShouldEqual, http.StatusBadRequest) 981 982 }) 983 984 Convey("calling TryReset should reset the task", func() { 985 986 trh := &TaskRestartHandler{ 987 taskId: "testTaskId", 988 project: &serviceModel.Project{}, 989 username: "testUser", 990 } 991 992 res, err := trh.Execute(&sc) 993 So(err, ShouldBeNil) 994 So(len(res.Result), ShouldEqual, 1) 995 resModel := res.Result[0] 996 resTask, ok := resModel.(*model.APITask) 997 So(ok, ShouldBeTrue) 998 So(resTask.Activated, ShouldBeTrue) 999 So(time.Time(resTask.DispatchTime), ShouldResemble, util.ZeroTime) 1000 dbTask, err := sc.FindTaskById("testTaskId") 1001 So(err, ShouldBeNil) 1002 So(string(dbTask.Secret), ShouldNotResemble, "initialSecret") 1003 }) 1004 }) 1005 1006 } 1007 1008 func checkPaginatorResultMatches(paginator PaginatorFunc, key string, limit int, 1009 sc servicecontext.ServiceContext, args interface{}, expectedPages *PageResult, 1010 expectedModels []model.Model, expectedErr error) { 1011 res, pages, err := paginator(key, limit, args, sc) 1012 So(err, ShouldResemble, expectedErr) 1013 So(len(res), ShouldEqual, len(expectedModels)) 1014 for ix := range expectedModels { 1015 So(res[ix], ShouldResemble, expectedModels[ix]) 1016 } 1017 So(pages, ShouldResemble, expectedPages) 1018 }