github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/api/resources_test.go (about) 1 package api_test 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "io/ioutil" 9 "net/http" 10 "time" 11 12 . "github.com/onsi/ginkgo" 13 . "github.com/onsi/gomega" 14 15 "github.com/pf-qiu/concourse/v6/atc" 16 "github.com/pf-qiu/concourse/v6/atc/creds" 17 "github.com/pf-qiu/concourse/v6/atc/db" 18 "github.com/pf-qiu/concourse/v6/atc/db/dbfakes" 19 . "github.com/pf-qiu/concourse/v6/atc/testhelpers" 20 "github.com/pf-qiu/concourse/v6/vars" 21 ) 22 23 var _ = Describe("Resources API", func() { 24 var ( 25 fakePipeline *dbfakes.FakePipeline 26 resource1 *dbfakes.FakeResource 27 variables vars.Variables 28 ) 29 30 BeforeEach(func() { 31 fakePipeline = new(dbfakes.FakePipeline) 32 dbTeamFactory.FindTeamReturns(dbTeam, true, nil) 33 dbTeam.PipelineReturns(fakePipeline, true, nil) 34 }) 35 36 Describe("GET /api/v1/resources", func() { 37 var response *http.Response 38 39 JustBeforeEach(func() { 40 var err error 41 42 response, err = client.Get(server.URL + "/api/v1/resources") 43 Expect(err).NotTo(HaveOccurred()) 44 }) 45 46 Context("when getting the dashboard resources succeeds", func() { 47 BeforeEach(func() { 48 resource1 = new(dbfakes.FakeResource) 49 resource1.IDReturns(1) 50 resource1.PipelineIDReturns(1) 51 resource1.PipelineNameReturns("a-pipeline") 52 resource1.TeamNameReturns("some-team") 53 resource1.NameReturns("resource-1") 54 resource1.TypeReturns("type-1") 55 resource1.LastCheckEndTimeReturns(time.Unix(1513364881, 0)) 56 57 resource2 := new(dbfakes.FakeResource) 58 resource2.IDReturns(2) 59 resource2.PipelineIDReturns(1) 60 resource2.PipelineNameReturns("a-pipeline") 61 resource2.TeamNameReturns("other-team") 62 resource2.NameReturns("resource-2") 63 resource2.TypeReturns("type-2") 64 resource2.BuildSummaryReturns(&atc.BuildSummary{ 65 ID: 123, 66 Name: "123", 67 Status: atc.StatusSucceeded, 68 StartTime: 456, 69 EndTime: 789, 70 TeamName: "some-team", 71 PipelineID: 99, 72 PipelineName: "some-pipeline", 73 PipelineInstanceVars: atc.InstanceVars{"foo": 1}, 74 }) 75 76 resource3 := new(dbfakes.FakeResource) 77 resource3.IDReturns(3) 78 resource3.TeamNameReturns("some-team") 79 resource3.PipelineIDReturns(2) 80 resource3.PipelineNameReturns("some-pipeline") 81 resource3.PipelineInstanceVarsReturns(atc.InstanceVars{"branch": "master"}) 82 resource3.TeamNameReturns("another-team") 83 resource3.NameReturns("resource-3") 84 resource3.TypeReturns("type-3") 85 86 dbResourceFactory.VisibleResourcesReturns([]db.Resource{ 87 resource1, resource2, resource3, 88 }, nil) 89 }) 90 91 It("returns 200 OK", func() { 92 Expect(response.StatusCode).To(Equal(http.StatusOK)) 93 }) 94 95 It("returns Content-Type 'application/json'", func() { 96 expectedHeaderEntries := map[string]string{ 97 "Content-Type": "application/json", 98 } 99 Expect(response).Should(IncludeHeaderEntries(expectedHeaderEntries)) 100 }) 101 102 It("returns each resource, including their build", func() { 103 body, err := ioutil.ReadAll(response.Body) 104 Expect(err).NotTo(HaveOccurred()) 105 106 Expect(body).To(MatchJSON(`[ 107 { 108 "name": "resource-1", 109 "pipeline_id": 1, 110 "pipeline_name": "a-pipeline", 111 "team_name": "some-team", 112 "type": "type-1", 113 "last_checked": 1513364881 114 }, 115 { 116 "name": "resource-2", 117 "pipeline_id": 1, 118 "pipeline_name": "a-pipeline", 119 "team_name": "other-team", 120 "type": "type-2", 121 "build": { 122 "id": 123, 123 "name": "123", 124 "status": "succeeded", 125 "start_time": 456, 126 "end_time": 789, 127 "team_name": "some-team", 128 "pipeline_id": 99, 129 "pipeline_name": "some-pipeline", 130 "pipeline_instance_vars": { 131 "foo": 1 132 } 133 } 134 }, 135 { 136 "name": "resource-3", 137 "pipeline_id": 2, 138 "pipeline_name": "some-pipeline", 139 "pipeline_instance_vars": { 140 "branch": "master" 141 }, 142 "team_name": "another-team", 143 "type": "type-3" 144 } 145 ]`)) 146 }) 147 148 Context("when getting the resource config fails", func() { 149 BeforeEach(func() { 150 dbResourceFactory.VisibleResourcesReturns(nil, errors.New("nope")) 151 }) 152 153 It("returns 500", func() { 154 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 155 }) 156 }) 157 158 Context("when there are no visible resources", func() { 159 BeforeEach(func() { 160 dbResourceFactory.VisibleResourcesReturns(nil, nil) 161 }) 162 163 It("returns empty array", func() { 164 body, err := ioutil.ReadAll(response.Body) 165 Expect(err).NotTo(HaveOccurred()) 166 167 Expect(body).To(MatchJSON(`[]`)) 168 }) 169 }) 170 171 Context("when not authenticated", func() { 172 It("populates resource factory with no team names", func() { 173 Expect(dbResourceFactory.VisibleResourcesCallCount()).To(Equal(1)) 174 Expect(dbResourceFactory.VisibleResourcesArgsForCall(0)).To(BeEmpty()) 175 }) 176 }) 177 178 Context("when authenticated", func() { 179 BeforeEach(func() { 180 fakeAccess.TeamNamesReturns([]string{"some-team"}) 181 }) 182 183 It("constructs job factory with provided team names", func() { 184 Expect(dbResourceFactory.VisibleResourcesCallCount()).To(Equal(1)) 185 Expect(dbResourceFactory.VisibleResourcesArgsForCall(0)).To(ContainElement("some-team")) 186 }) 187 188 Context("when user has admin privilege", func() { 189 BeforeEach(func() { 190 fakeAccess.IsAdminReturns(true) 191 }) 192 193 It("returns all resources", func() { 194 Expect(dbResourceFactory.AllResourcesCallCount()).To(Equal(1)) 195 }) 196 }) 197 }) 198 }) 199 }) 200 201 Describe("GET /api/v1/teams/:team_name/pipelines/:pipeline_name/resources", func() { 202 var response *http.Response 203 204 JustBeforeEach(func() { 205 var err error 206 207 response, err = client.Get(server.URL + "/api/v1/teams/a-team/pipelines/a-pipeline/resources") 208 Expect(err).NotTo(HaveOccurred()) 209 }) 210 211 Context("when getting the dashboard resources succeeds", func() { 212 BeforeEach(func() { 213 resource1 = new(dbfakes.FakeResource) 214 resource1.IDReturns(1) 215 resource1.TeamNameReturns("a-team") 216 resource1.PipelineIDReturns(1) 217 resource1.PipelineNameReturns("a-pipeline") 218 resource1.NameReturns("resource-1") 219 resource1.TypeReturns("type-1") 220 resource1.LastCheckEndTimeReturns(time.Unix(1513364881, 0)) 221 222 resource2 := new(dbfakes.FakeResource) 223 resource2.IDReturns(2) 224 resource2.TeamNameReturns("a-team") 225 resource2.PipelineIDReturns(1) 226 resource2.PipelineNameReturns("a-pipeline") 227 resource2.NameReturns("resource-2") 228 resource2.TypeReturns("type-2") 229 230 resource3 := new(dbfakes.FakeResource) 231 resource3.IDReturns(3) 232 resource3.TeamNameReturns("a-team") 233 resource3.PipelineIDReturns(2) 234 resource3.PipelineNameReturns("some-pipeline") 235 resource3.PipelineInstanceVarsReturns(atc.InstanceVars{"branch": "master"}) 236 resource3.NameReturns("resource-3") 237 resource3.TypeReturns("type-3") 238 239 fakePipeline.ResourcesReturns([]db.Resource{ 240 resource1, resource2, resource3, 241 }, nil) 242 }) 243 244 Context("when not authenticated and not authorized", func() { 245 BeforeEach(func() { 246 fakeAccess.IsAuthenticatedReturns(false) 247 fakeAccess.IsAuthorizedReturns(false) 248 }) 249 250 Context("and the pipeline is private", func() { 251 BeforeEach(func() { 252 fakePipeline.PublicReturns(false) 253 }) 254 255 It("returns 401", func() { 256 Expect(response.StatusCode).To(Equal(http.StatusUnauthorized)) 257 }) 258 }) 259 260 Context("and the pipeline is public", func() { 261 BeforeEach(func() { 262 fakePipeline.PublicReturns(true) 263 }) 264 265 It("returns 200 OK", func() { 266 Expect(response.StatusCode).To(Equal(http.StatusOK)) 267 }) 268 269 It("returns Content-Type 'application/json'", func() { 270 expectedHeaderEntries := map[string]string{ 271 "Content-Type": "application/json", 272 } 273 Expect(response).Should(IncludeHeaderEntries(expectedHeaderEntries)) 274 }) 275 276 It("returns each resource", func() { 277 body, err := ioutil.ReadAll(response.Body) 278 Expect(err).NotTo(HaveOccurred()) 279 280 Expect(body).To(MatchJSON(`[ 281 { 282 "name": "resource-1", 283 "pipeline_id": 1, 284 "pipeline_name": "a-pipeline", 285 "team_name": "a-team", 286 "type": "type-1", 287 "last_checked": 1513364881 288 }, 289 { 290 "name": "resource-2", 291 "pipeline_id": 1, 292 "pipeline_name": "a-pipeline", 293 "team_name": "a-team", 294 "type": "type-2" 295 }, 296 { 297 "name": "resource-3", 298 "pipeline_id": 2, 299 "pipeline_name": "some-pipeline", 300 "pipeline_instance_vars": { 301 "branch": "master" 302 }, 303 "team_name": "a-team", 304 "type": "type-3" 305 } 306 ]`)) 307 }) 308 }) 309 }) 310 311 Context("when authorized", func() { 312 BeforeEach(func() { 313 fakeAccess.IsAuthenticatedReturns(true) 314 fakeAccess.IsAuthorizedReturns(true) 315 }) 316 317 It("returns 200 OK", func() { 318 Expect(response.StatusCode).To(Equal(http.StatusOK)) 319 }) 320 321 It("returns Content-Type 'application/json'", func() { 322 expectedHeaderEntries := map[string]string{ 323 "Content-Type": "application/json", 324 } 325 Expect(response).Should(IncludeHeaderEntries(expectedHeaderEntries)) 326 }) 327 328 It("returns each resource", func() { 329 body, err := ioutil.ReadAll(response.Body) 330 Expect(err).NotTo(HaveOccurred()) 331 332 Expect(body).To(MatchJSON(`[ 333 { 334 "name": "resource-1", 335 "pipeline_id": 1, 336 "pipeline_name": "a-pipeline", 337 "team_name": "a-team", 338 "type": "type-1", 339 "last_checked": 1513364881 340 }, 341 { 342 "name": "resource-2", 343 "pipeline_id": 1, 344 "pipeline_name": "a-pipeline", 345 "team_name": "a-team", 346 "type": "type-2" 347 }, 348 { 349 "name": "resource-3", 350 "pipeline_id": 2, 351 "pipeline_name": "some-pipeline", 352 "pipeline_instance_vars": { 353 "branch": "master" 354 }, 355 "team_name": "a-team", 356 "type": "type-3" 357 } 358 ]`)) 359 }) 360 361 Context("when the pipeline has no resources", func() { 362 BeforeEach(func() { 363 fakePipeline.ResourcesReturns(nil, nil) 364 }) 365 366 It("returns an empty list", func() { 367 body, err := ioutil.ReadAll(response.Body) 368 Expect(err).NotTo(HaveOccurred()) 369 370 Expect(body).To(MatchJSON(`[]`)) 371 }) 372 }) 373 374 Context("when getting the resource config fails", func() { 375 Context("when the resources are not found", func() { 376 BeforeEach(func() { 377 fakePipeline.ResourcesReturns(nil, nil) 378 }) 379 380 It("returns 200", func() { 381 Expect(response.StatusCode).To(Equal(http.StatusOK)) 382 }) 383 }) 384 385 Context("with an unknown error", func() { 386 BeforeEach(func() { 387 fakePipeline.ResourcesReturns(nil, errors.New("oh no!")) 388 }) 389 390 It("returns 500", func() { 391 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 392 }) 393 }) 394 }) 395 }) 396 }) 397 }) 398 399 Describe("PUT /api/v1/teams/:team_name/pipelines/:pipeline_name/resources/:resource_name/unpin", func() { 400 var response *http.Response 401 var fakeResource *dbfakes.FakeResource 402 403 JustBeforeEach(func() { 404 var err error 405 406 request, err := http.NewRequest("PUT", server.URL+"/api/v1/teams/a-team/pipelines/a-pipeline/resources/resource-name/unpin", nil) 407 Expect(err).NotTo(HaveOccurred()) 408 409 response, err = client.Do(request) 410 Expect(err).NotTo(HaveOccurred()) 411 }) 412 413 Context("when authenticated ", func() { 414 BeforeEach(func() { 415 fakeAccess.IsAuthenticatedReturns(true) 416 }) 417 418 Context("when authorized", func() { 419 BeforeEach(func() { 420 fakeAccess.IsAuthorizedReturns(true) 421 }) 422 423 It("tries to find the resource", func() { 424 resourceName := fakePipeline.ResourceArgsForCall(0) 425 Expect(resourceName).To(Equal("resource-name")) 426 }) 427 428 Context("when finding the resource succeeds", func() { 429 BeforeEach(func() { 430 fakeResource = new(dbfakes.FakeResource) 431 fakeResource.IDReturns(1) 432 fakePipeline.ResourceReturns(fakeResource, true, nil) 433 }) 434 435 Context("when unpinning the resource version succeeds", func() { 436 BeforeEach(func() { 437 fakeResource.UnpinVersionReturns(nil) 438 }) 439 440 It("returns 200", func() { 441 Expect(response.StatusCode).To(Equal(http.StatusOK)) 442 }) 443 }) 444 445 Context("when unpinning the resource fails", func() { 446 BeforeEach(func() { 447 fakeResource.UnpinVersionReturns(errors.New("welp")) 448 }) 449 450 It("returns 500", func() { 451 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 452 }) 453 }) 454 }) 455 456 Context("when it fails to find the resource", func() { 457 BeforeEach(func() { 458 fakePipeline.ResourceReturns(nil, false, errors.New("welp")) 459 }) 460 461 It("returns Internal Server Error", func() { 462 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 463 }) 464 }) 465 466 Context("when the resource is not found", func() { 467 BeforeEach(func() { 468 fakePipeline.ResourceReturns(nil, false, nil) 469 }) 470 471 It("returns not found", func() { 472 Expect(response.StatusCode).To(Equal(http.StatusNotFound)) 473 }) 474 }) 475 }) 476 Context("when not authorized", func() { 477 BeforeEach(func() { 478 fakeAccess.IsAuthorizedReturns(false) 479 }) 480 481 It("returns Forbidden", func() { 482 Expect(response.StatusCode).To(Equal(http.StatusForbidden)) 483 }) 484 }) 485 }) 486 Context("when not authenticated", func() { 487 BeforeEach(func() { 488 fakeAccess.IsAuthenticatedReturns(false) 489 }) 490 491 It("returns Unauthorized", func() { 492 Expect(response.StatusCode).To(Equal(http.StatusUnauthorized)) 493 }) 494 }) 495 }) 496 497 Describe("PUT /api/v1/teams/:team_name/pipelines/:pipeline_name/resources/:resource_name/pin_comment", func() { 498 var response *http.Response 499 var pinCommentRequestBody atc.SetPinCommentRequestBody 500 var fakeResource *dbfakes.FakeResource 501 502 BeforeEach(func() { 503 pinCommentRequestBody = atc.SetPinCommentRequestBody{} 504 }) 505 506 JustBeforeEach(func() { 507 reqPayload, err := json.Marshal(pinCommentRequestBody) 508 Expect(err).NotTo(HaveOccurred()) 509 510 request, err := http.NewRequest("PUT", server.URL+"/api/v1/teams/a-team/pipelines/a-pipeline/resources/resource-name/pin_comment", bytes.NewBuffer(reqPayload)) 511 Expect(err).NotTo(HaveOccurred()) 512 513 response, err = client.Do(request) 514 Expect(err).NotTo(HaveOccurred()) 515 }) 516 517 Context("when not authenticated", func() { 518 BeforeEach(func() { 519 fakeAccess.IsAuthenticatedReturns(false) 520 }) 521 522 It("returns Unauthorized", func() { 523 Expect(response.StatusCode).To(Equal(http.StatusUnauthorized)) 524 }) 525 }) 526 527 Context("when authenticated ", func() { 528 BeforeEach(func() { 529 fakeAccess.IsAuthenticatedReturns(true) 530 }) 531 532 Context("when authorized", func() { 533 BeforeEach(func() { 534 fakeAccess.IsAuthorizedReturns(true) 535 }) 536 537 It("tries to find the resource", func() { 538 resourceName := fakePipeline.ResourceArgsForCall(0) 539 Expect(resourceName).To(Equal("resource-name")) 540 }) 541 542 Context("when finding the resource succeeds", func() { 543 BeforeEach(func() { 544 fakeResource = new(dbfakes.FakeResource) 545 fakeResource.IDReturns(1) 546 fakePipeline.ResourceReturns(fakeResource, true, nil) 547 pinCommentRequestBody.PinComment = "I am a pin comment" 548 }) 549 550 It("Tries to set the pin comment", func() { 551 Expect(fakeResource.SetPinCommentCallCount()).To(Equal(1)) 552 comment := fakeResource.SetPinCommentArgsForCall(0) 553 Expect(comment).To(Equal("I am a pin comment")) 554 }) 555 556 Context("when setting the pin comment succeeds", func() { 557 BeforeEach(func() { 558 fakeResource.SetPinCommentReturns(nil) 559 }) 560 561 It("returns 200", func() { 562 Expect(response.StatusCode).To(Equal(http.StatusOK)) 563 }) 564 }) 565 566 Context("when setting the pin comment fails", func() { 567 BeforeEach(func() { 568 fakeResource.SetPinCommentReturns(errors.New("welp")) 569 }) 570 571 It("returns 500", func() { 572 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 573 }) 574 }) 575 }) 576 577 Context("when it fails to find the resource", func() { 578 BeforeEach(func() { 579 fakePipeline.ResourceReturns(nil, false, errors.New("welp")) 580 }) 581 582 It("returns Internal Server Error", func() { 583 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 584 }) 585 }) 586 587 Context("when the resource is not found", func() { 588 BeforeEach(func() { 589 fakePipeline.ResourceReturns(nil, false, nil) 590 }) 591 592 It("returns not found", func() { 593 Expect(response.StatusCode).To(Equal(http.StatusNotFound)) 594 }) 595 }) 596 }) 597 Context("when not authorized", func() { 598 BeforeEach(func() { 599 fakeAccess.IsAuthorizedReturns(false) 600 }) 601 602 It("returns Forbidden", func() { 603 Expect(response.StatusCode).To(Equal(http.StatusForbidden)) 604 }) 605 }) 606 }) 607 }) 608 609 Describe("POST /api/v1/teams/:team_name/pipelines/:pipeline_name/resources/:resource_name/check", func() { 610 var checkRequestBody atc.CheckRequestBody 611 var response *http.Response 612 613 BeforeEach(func() { 614 checkRequestBody = atc.CheckRequestBody{} 615 }) 616 617 JustBeforeEach(func() { 618 reqPayload, err := json.Marshal(checkRequestBody) 619 Expect(err).NotTo(HaveOccurred()) 620 621 request, err := http.NewRequest("POST", server.URL+"/api/v1/teams/a-team/pipelines/a-pipeline/resources/resource-name/check", bytes.NewBuffer(reqPayload)) 622 Expect(err).NotTo(HaveOccurred()) 623 request.Header.Set("Content-Type", "application/json") 624 625 response, err = client.Do(request) 626 Expect(err).NotTo(HaveOccurred()) 627 }) 628 629 Context("when authorized", func() { 630 BeforeEach(func() { 631 fakeAccess.IsAuthenticatedReturns(true) 632 fakeAccess.IsAuthorizedReturns(true) 633 }) 634 635 Context("when looking up the resource fails", func() { 636 BeforeEach(func() { 637 fakePipeline.ResourceReturns(nil, false, errors.New("nope")) 638 }) 639 It("returns 500", func() { 640 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 641 }) 642 }) 643 644 Context("when the resource is not found", func() { 645 BeforeEach(func() { 646 fakePipeline.ResourceReturns(nil, false, nil) 647 }) 648 It("returns 404", func() { 649 Expect(response.StatusCode).To(Equal(http.StatusNotFound)) 650 }) 651 }) 652 653 Context("when it finds the resource", func() { 654 var fakeResource *dbfakes.FakeResource 655 656 BeforeEach(func() { 657 fakeResource = new(dbfakes.FakeResource) 658 fakeResource.IDReturns(1) 659 fakePipeline.ResourceReturns(fakeResource, true, nil) 660 }) 661 662 Context("when looking up the resource types fails", func() { 663 BeforeEach(func() { 664 fakePipeline.ResourceTypesReturns(nil, errors.New("nope")) 665 }) 666 It("returns 500", func() { 667 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 668 }) 669 }) 670 671 Context("when looking up the resource types succeeds", func() { 672 var fakeResourceTypes db.ResourceTypes 673 674 BeforeEach(func() { 675 fakeResourceTypes = db.ResourceTypes{} 676 fakePipeline.ResourceTypesReturns(fakeResourceTypes, nil) 677 }) 678 679 It("checks with no version specified", func() { 680 Expect(dbCheckFactory.TryCreateCheckCallCount()).To(Equal(1)) 681 _, actualResource, actualResourceTypes, actualFromVersion, manuallyTriggered := dbCheckFactory.TryCreateCheckArgsForCall(0) 682 Expect(actualResource).To(Equal(fakeResource)) 683 Expect(actualResourceTypes).To(Equal(fakeResourceTypes)) 684 Expect(actualFromVersion).To(BeNil()) 685 Expect(manuallyTriggered).To(BeTrue()) 686 }) 687 688 Context("when checking with a version specified", func() { 689 BeforeEach(func() { 690 checkRequestBody = atc.CheckRequestBody{ 691 From: atc.Version{ 692 "some-version-key": "some-version-value", 693 }, 694 } 695 }) 696 697 It("checks with the version specified", func() { 698 Expect(dbCheckFactory.TryCreateCheckCallCount()).To(Equal(1)) 699 _, actualResource, actualResourceTypes, actualFromVersion, manuallyTriggered := dbCheckFactory.TryCreateCheckArgsForCall(0) 700 Expect(actualResource).To(Equal(fakeResource)) 701 Expect(actualResourceTypes).To(Equal(fakeResourceTypes)) 702 Expect(actualFromVersion).To(Equal(checkRequestBody.From)) 703 Expect(manuallyTriggered).To(BeTrue()) 704 }) 705 }) 706 707 Context("when checking fails", func() { 708 BeforeEach(func() { 709 dbCheckFactory.TryCreateCheckReturns(nil, false, errors.New("nope")) 710 }) 711 712 It("returns 500", func() { 713 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 714 }) 715 }) 716 717 Context("when checking does not create a new check", func() { 718 BeforeEach(func() { 719 dbCheckFactory.TryCreateCheckReturns(nil, false, nil) 720 }) 721 722 It("returns 500", func() { 723 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 724 }) 725 }) 726 727 Context("when checking creates a new check", func() { 728 var fakeBuild *dbfakes.FakeBuild 729 730 BeforeEach(func() { 731 fakeBuild = new(dbfakes.FakeBuild) 732 fakeBuild.IDReturns(10) 733 fakeBuild.NameReturns("some-name") 734 fakeBuild.TeamNameReturns("some-team") 735 fakeBuild.StatusReturns("started") 736 fakeBuild.StartTimeReturns(time.Date(2001, 01, 01, 0, 0, 0, 0, time.UTC)) 737 fakeBuild.EndTimeReturns(time.Date(2002, 01, 01, 0, 0, 0, 0, time.UTC)) 738 739 dbCheckFactory.TryCreateCheckReturns(fakeBuild, true, nil) 740 }) 741 742 It("returns 201", func() { 743 Expect(response.StatusCode).To(Equal(http.StatusCreated)) 744 Expect(ioutil.ReadAll(response.Body)).To(MatchJSON(`{ 745 "id": 10, 746 "name": "some-name", 747 "team_name": "some-team", 748 "status": "started", 749 "api_url": "/api/v1/builds/10", 750 "start_time": 978307200, 751 "end_time": 1009843200 752 }`)) 753 }) 754 }) 755 }) 756 }) 757 }) 758 759 Context("when not authenticated", func() { 760 BeforeEach(func() { 761 fakeAccess.IsAuthenticatedReturns(false) 762 }) 763 764 It("returns Unauthorized", func() { 765 Expect(response.StatusCode).To(Equal(http.StatusUnauthorized)) 766 }) 767 }) 768 }) 769 770 Describe("GET /api/v1/teams/:team_name/pipelines/:pipeline_name/resource-types", func() { 771 var response *http.Response 772 773 JustBeforeEach(func() { 774 var err error 775 776 response, err = client.Get(server.URL + "/api/v1/teams/a-team/pipelines/a-pipeline/resource-types") 777 Expect(err).NotTo(HaveOccurred()) 778 }) 779 780 Context("when getting the resource types succeeds", func() { 781 BeforeEach(func() { 782 resourceType1 := new(dbfakes.FakeResourceType) 783 resourceType1.IDReturns(1) 784 resourceType1.NameReturns("resource-type-1") 785 resourceType1.TypeReturns("type-1") 786 resourceType1.SourceReturns(map[string]interface{}{"source-key-1": "source-value-1"}) 787 resourceType1.PrivilegedReturns(false) 788 resourceType1.TagsReturns([]string{"tag1"}) 789 resourceType1.ParamsReturns(map[string]interface{}{"param-key-1": "param-value-1"}) 790 resourceType1.VersionReturns(map[string]string{ 791 "version-key-1": "version-value-1", 792 "version-key-2": "version-value-2", 793 }) 794 795 resourceType2 := new(dbfakes.FakeResourceType) 796 resourceType2.IDReturns(2) 797 resourceType2.NameReturns("resource-type-2") 798 resourceType2.TypeReturns("type-2") 799 resourceType2.SourceReturns(map[string]interface{}{"source-key-2": "source-value-2"}) 800 resourceType2.PrivilegedReturns(true) 801 resourceType2.CheckEveryReturns("10ms") 802 resourceType2.TagsReturns([]string{"tag1", "tag2"}) 803 resourceType2.ParamsReturns(map[string]interface{}{"param-key-2": "param-value-2"}) 804 resourceType2.VersionReturns(map[string]string{ 805 "version-key-2": "version-value-2", 806 }) 807 808 fakePipeline.ResourceTypesReturns(db.ResourceTypes{ 809 resourceType1, resourceType2, 810 }, nil) 811 }) 812 813 Context("when not authorized", func() { 814 BeforeEach(func() { 815 fakeAccess.IsAuthenticatedReturns(false) 816 fakeAccess.IsAuthorizedReturns(false) 817 }) 818 819 Context("and the pipeline is private", func() { 820 BeforeEach(func() { 821 fakePipeline.PublicReturns(false) 822 }) 823 824 It("returns 401", func() { 825 Expect(response.StatusCode).To(Equal(http.StatusUnauthorized)) 826 }) 827 }) 828 829 Context("and the pipeline is public", func() { 830 BeforeEach(func() { 831 fakePipeline.PublicReturns(true) 832 }) 833 834 It("returns 200 OK", func() { 835 Expect(response.StatusCode).To(Equal(http.StatusOK)) 836 }) 837 838 It("returns application/json", func() { 839 expectedHeaderEntries := map[string]string{ 840 "Content-Type": "application/json", 841 } 842 Expect(response).Should(IncludeHeaderEntries(expectedHeaderEntries)) 843 }) 844 845 It("returns each resource type", func() { 846 body, err := ioutil.ReadAll(response.Body) 847 Expect(err).NotTo(HaveOccurred()) 848 849 Expect(body).To(MatchJSON(`[ 850 { 851 "name": "resource-type-1", 852 "type": "type-1", 853 "tags": ["tag1"], 854 "params": {"param-key-1": "param-value-1"}, 855 "source": {"source-key-1": "source-value-1"}, 856 "version": { 857 "version-key-1": "version-value-1", 858 "version-key-2": "version-value-2" 859 } 860 }, 861 { 862 "name": "resource-type-2", 863 "type": "type-2", 864 "tags": ["tag1", "tag2"], 865 "privileged": true, 866 "check_every": "10ms", 867 "params": {"param-key-2": "param-value-2"}, 868 "source": {"source-key-2": "source-value-2"}, 869 "version": { 870 "version-key-2": "version-value-2" 871 } 872 } 873 ]`)) 874 }) 875 }) 876 }) 877 878 Context("when authorized", func() { 879 BeforeEach(func() { 880 fakeAccess.IsAuthenticatedReturns(true) 881 fakeAccess.IsAuthorizedReturns(true) 882 }) 883 884 It("returns 200 OK", func() { 885 Expect(response.StatusCode).To(Equal(http.StatusOK)) 886 }) 887 888 It("returns application/json", func() { 889 expectedHeaderEntries := map[string]string{ 890 "Content-Type": "application/json", 891 } 892 Expect(response).Should(IncludeHeaderEntries(expectedHeaderEntries)) 893 }) 894 895 It("returns each resource type", func() { 896 body, err := ioutil.ReadAll(response.Body) 897 Expect(err).NotTo(HaveOccurred()) 898 899 Expect(body).To(MatchJSON(`[ 900 { 901 "name": "resource-type-1", 902 "type": "type-1", 903 "tags": ["tag1"], 904 "params": {"param-key-1": "param-value-1"}, 905 "source": {"source-key-1": "source-value-1"}, 906 "version": { 907 "version-key-1": "version-value-1", 908 "version-key-2": "version-value-2" 909 } 910 }, 911 { 912 "name": "resource-type-2", 913 "type": "type-2", 914 "tags": ["tag1", "tag2"], 915 "privileged": true, 916 "check_every": "10ms", 917 "params": {"param-key-2": "param-value-2"}, 918 "source": {"source-key-2": "source-value-2"}, 919 "version": { 920 "version-key-2": "version-value-2" 921 } 922 } 923 ]`)) 924 }) 925 926 Context("when getting the resource type fails", func() { 927 Context("when the resource type are not found", func() { 928 BeforeEach(func() { 929 fakePipeline.ResourceTypesReturns(nil, nil) 930 }) 931 932 It("returns 200", func() { 933 Expect(response.StatusCode).To(Equal(http.StatusOK)) 934 }) 935 936 It("returns application/json", func() { 937 expectedHeaderEntries := map[string]string{ 938 "Content-Type": "application/json", 939 } 940 Expect(response).Should(IncludeHeaderEntries(expectedHeaderEntries)) 941 }) 942 }) 943 944 Context("with an unknown error", func() { 945 BeforeEach(func() { 946 fakePipeline.ResourceTypesReturns(nil, errors.New("oh no!")) 947 }) 948 949 It("returns 500", func() { 950 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 951 }) 952 }) 953 }) 954 }) 955 }) 956 }) 957 958 Describe("GET /api/v1/teams/:team_name/pipelines/:pipeline_name/resources/:resource_name", func() { 959 var response *http.Response 960 var resourceName string 961 BeforeEach(func() { 962 resourceName = "some-resource" 963 }) 964 965 JustBeforeEach(func() { 966 var err error 967 968 request, err := http.NewRequest("GET", fmt.Sprintf("%s/api/v1/teams/a-team/pipelines/a-pipeline/resources/%s", server.URL, resourceName), nil) 969 Expect(err).NotTo(HaveOccurred()) 970 971 response, err = client.Do(request) 972 Expect(err).NotTo(HaveOccurred()) 973 }) 974 975 Context("when not authenticated and not authorized", func() { 976 BeforeEach(func() { 977 fakeAccess.IsAuthenticatedReturns(false) 978 fakeAccess.IsAuthorizedReturns(false) 979 }) 980 981 Context("and the pipeline is private", func() { 982 BeforeEach(func() { 983 fakePipeline.PublicReturns(false) 984 }) 985 986 It("returns 401", func() { 987 Expect(response.StatusCode).To(Equal(http.StatusUnauthorized)) 988 }) 989 }) 990 991 Context("and the pipeline is public", func() { 992 BeforeEach(func() { 993 fakePipeline.PublicReturns(true) 994 resourceName = "resource-1" 995 996 resource1 := new(dbfakes.FakeResource) 997 resource1.TeamNameReturns("a-team") 998 resource1.PipelineIDReturns(1) 999 resource1.PipelineNameReturns("a-pipeline") 1000 resource1.NameReturns("resource-1") 1001 resource1.TypeReturns("type-1") 1002 resource1.LastCheckEndTimeReturns(time.Unix(1513364881, 0)) 1003 resource1.BuildSummaryReturns(&atc.BuildSummary{ 1004 ID: 123, 1005 Name: "123", 1006 Status: atc.StatusSucceeded, 1007 StartTime: 456, 1008 EndTime: 789, 1009 TeamName: "some-team", 1010 PipelineID: 99, 1011 PipelineName: "some-pipeline", 1012 PipelineInstanceVars: atc.InstanceVars{"foo": 1}, 1013 }) 1014 1015 fakePipeline.ResourceReturns(resource1, true, nil) 1016 }) 1017 1018 It("returns 200 OK", func() { 1019 Expect(response.StatusCode).To(Equal(http.StatusOK)) 1020 }) 1021 1022 It("returns Content-Type 'application/json'", func() { 1023 expectedHeaderEntries := map[string]string{ 1024 "Content-Type": "application/json", 1025 } 1026 Expect(response).Should(IncludeHeaderEntries(expectedHeaderEntries)) 1027 }) 1028 1029 It("returns the resource json", func() { 1030 body, err := ioutil.ReadAll(response.Body) 1031 Expect(err).NotTo(HaveOccurred()) 1032 1033 Expect(body).To(MatchJSON(` 1034 { 1035 "name": "resource-1", 1036 "pipeline_id": 1, 1037 "pipeline_name": "a-pipeline", 1038 "team_name": "a-team", 1039 "type": "type-1", 1040 "last_checked": 1513364881, 1041 "build": { 1042 "id": 123, 1043 "name": "123", 1044 "status": "succeeded", 1045 "start_time": 456, 1046 "end_time": 789, 1047 "team_name": "some-team", 1048 "pipeline_id": 99, 1049 "pipeline_name": "some-pipeline", 1050 "pipeline_instance_vars": { 1051 "foo": 1 1052 } 1053 } 1054 }`)) 1055 }) 1056 }) 1057 }) 1058 1059 Context("when authorized", func() { 1060 BeforeEach(func() { 1061 fakeAccess.IsAuthenticatedReturns(true) 1062 fakeAccess.IsAuthorizedReturns(true) 1063 }) 1064 1065 It("looks it up in the database", func() { 1066 Expect(fakePipeline.ResourceCallCount()).To(Equal(1)) 1067 Expect(fakePipeline.ResourceArgsForCall(0)).To(Equal("some-resource")) 1068 }) 1069 1070 Context("when the resource cannot be found in the database", func() { 1071 BeforeEach(func() { 1072 resourceName = "resource-in-config-but-not-db" 1073 }) 1074 1075 It("returns a 404", func() { 1076 Expect(response.StatusCode).To(Equal(http.StatusNotFound)) 1077 }) 1078 }) 1079 1080 Context("when the call to the db returns an error", func() { 1081 BeforeEach(func() { 1082 fakePipeline.ResourceReturns(nil, false, errors.New("Oh no!")) 1083 }) 1084 1085 It("returns a 500 error", func() { 1086 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 1087 }) 1088 }) 1089 1090 Context("when the call to get a resource succeeds", func() { 1091 Context("when the resource version is pinned via pipeline config", func() { 1092 BeforeEach(func() { 1093 resource1 := new(dbfakes.FakeResource) 1094 resource1.TeamNameReturns("a-team") 1095 resource1.PipelineIDReturns(1) 1096 resource1.PipelineNameReturns("a-pipeline") 1097 resource1.NameReturns("resource-1") 1098 resource1.TypeReturns("type-1") 1099 resource1.LastCheckEndTimeReturns(time.Unix(1513364881, 0)) 1100 resource1.ConfigPinnedVersionReturns(atc.Version{"version": "v1"}) 1101 1102 fakePipeline.ResourceReturns(resource1, true, nil) 1103 }) 1104 1105 It("returns 200 ok", func() { 1106 Expect(response.StatusCode).To(Equal(http.StatusOK)) 1107 }) 1108 1109 It("returns Content-Type 'application/json'", func() { 1110 expectedHeaderEntries := map[string]string{ 1111 "Content-Type": "application/json", 1112 } 1113 Expect(response).Should(IncludeHeaderEntries(expectedHeaderEntries)) 1114 }) 1115 1116 It("returns the resource json", func() { 1117 body, err := ioutil.ReadAll(response.Body) 1118 Expect(err).NotTo(HaveOccurred()) 1119 1120 Expect(body).To(MatchJSON(` 1121 { 1122 "name": "resource-1", 1123 "pipeline_id": 1, 1124 "pipeline_name": "a-pipeline", 1125 "team_name": "a-team", 1126 "type": "type-1", 1127 "last_checked": 1513364881, 1128 "pinned_version": {"version": "v1"}, 1129 "pinned_in_config": true 1130 }`)) 1131 }) 1132 }) 1133 1134 Context("when the resource version is pinned via the API", func() { 1135 BeforeEach(func() { 1136 resource1 := new(dbfakes.FakeResource) 1137 resource1.TeamNameReturns("a-team") 1138 resource1.PipelineIDReturns(1) 1139 resource1.PipelineNameReturns("a-pipeline") 1140 resource1.NameReturns("resource-1") 1141 resource1.TypeReturns("type-1") 1142 resource1.LastCheckEndTimeReturns(time.Unix(1513364881, 0)) 1143 resource1.APIPinnedVersionReturns(atc.Version{"version": "v1"}) 1144 1145 fakePipeline.ResourceReturns(resource1, true, nil) 1146 }) 1147 1148 It("returns 200 ok", func() { 1149 Expect(response.StatusCode).To(Equal(http.StatusOK)) 1150 }) 1151 1152 It("returns Content-Type 'application/json'", func() { 1153 expectedHeaderEntries := map[string]string{ 1154 "Content-Type": "application/json", 1155 } 1156 Expect(response).Should(IncludeHeaderEntries(expectedHeaderEntries)) 1157 }) 1158 1159 It("returns the resource json describing the pinned version", func() { 1160 body, err := ioutil.ReadAll(response.Body) 1161 Expect(err).NotTo(HaveOccurred()) 1162 1163 Expect(body).To(MatchJSON(` 1164 { 1165 "name": "resource-1", 1166 "pipeline_id": 1, 1167 "pipeline_name": "a-pipeline", 1168 "team_name": "a-team", 1169 "type": "type-1", 1170 "last_checked": 1513364881, 1171 "pinned_version": {"version": "v1"} 1172 }`)) 1173 }) 1174 }) 1175 1176 Context("when the resource has a pin comment", func() { 1177 BeforeEach(func() { 1178 resource1 := new(dbfakes.FakeResource) 1179 resource1.TeamNameReturns("a-team") 1180 resource1.PipelineIDReturns(1) 1181 resource1.PipelineNameReturns("a-pipeline") 1182 resource1.NameReturns("resource-1") 1183 resource1.TypeReturns("type-1") 1184 resource1.LastCheckEndTimeReturns(time.Unix(1513364881, 0)) 1185 resource1.APIPinnedVersionReturns(atc.Version{"version": "v1"}) 1186 resource1.PinCommentReturns("a pin comment") 1187 fakePipeline.ResourceReturns(resource1, true, nil) 1188 }) 1189 1190 It("returns the pin comment in the response json", func() { 1191 body, err := ioutil.ReadAll(response.Body) 1192 Expect(err).NotTo(HaveOccurred()) 1193 1194 Expect(body).To(MatchJSON(` 1195 { 1196 "name": "resource-1", 1197 "pipeline_id": 1, 1198 "pipeline_name": "a-pipeline", 1199 "team_name": "a-team", 1200 "type": "type-1", 1201 "last_checked": 1513364881, 1202 "pinned_version": {"version": "v1"}, 1203 "pin_comment": "a pin comment" 1204 }`)) 1205 }) 1206 }) 1207 }) 1208 }) 1209 1210 Context("when authenticated but not authorized", func() { 1211 BeforeEach(func() { 1212 fakeAccess.IsAuthenticatedReturns(true) 1213 fakeAccess.IsAuthorizedReturns(false) 1214 }) 1215 1216 Context("and the pipeline is private", func() { 1217 BeforeEach(func() { 1218 fakePipeline.PublicReturns(false) 1219 }) 1220 1221 It("returns 403", func() { 1222 Expect(response.StatusCode).To(Equal(http.StatusForbidden)) 1223 }) 1224 }) 1225 1226 Context("and the pipeline is public", func() { 1227 BeforeEach(func() { 1228 fakePipeline.PublicReturns(true) 1229 resourceName = "resource-1" 1230 1231 resource1 := new(dbfakes.FakeResource) 1232 resource1.TeamNameReturns("a-team") 1233 resource1.PipelineIDReturns(1) 1234 resource1.PipelineNameReturns("a-pipeline") 1235 resource1.NameReturns("resource-1") 1236 resource1.TypeReturns("type-1") 1237 resource1.LastCheckEndTimeReturns(time.Unix(1513364881, 0)) 1238 1239 fakePipeline.ResourceReturns(resource1, true, nil) 1240 }) 1241 1242 It("returns 200 OK", func() { 1243 Expect(response.StatusCode).To(Equal(http.StatusOK)) 1244 }) 1245 1246 It("returns Content-Type 'application/json'", func() { 1247 expectedHeaderEntries := map[string]string{ 1248 "Content-Type": "application/json", 1249 } 1250 Expect(response).Should(IncludeHeaderEntries(expectedHeaderEntries)) 1251 }) 1252 1253 It("returns the resource json", func() { 1254 body, err := ioutil.ReadAll(response.Body) 1255 Expect(err).NotTo(HaveOccurred()) 1256 1257 Expect(body).To(MatchJSON(` 1258 { 1259 "name": "resource-1", 1260 "pipeline_id": 1, 1261 "pipeline_name": "a-pipeline", 1262 "team_name": "a-team", 1263 "type": "type-1", 1264 "last_checked": 1513364881 1265 }`)) 1266 }) 1267 }) 1268 }) 1269 }) 1270 1271 Describe("POST /api/v1/teams/:team_name/pipelines/:pipeline_name/resource-types/:resource_type_name/check", func() { 1272 var checkRequestBody atc.CheckRequestBody 1273 var response *http.Response 1274 1275 BeforeEach(func() { 1276 checkRequestBody = atc.CheckRequestBody{} 1277 }) 1278 1279 JustBeforeEach(func() { 1280 reqPayload, err := json.Marshal(checkRequestBody) 1281 Expect(err).NotTo(HaveOccurred()) 1282 1283 request, err := http.NewRequest("POST", server.URL+"/api/v1/teams/a-team/pipelines/a-pipeline/resource-types/resource-type-name/check", bytes.NewBuffer(reqPayload)) 1284 Expect(err).NotTo(HaveOccurred()) 1285 request.Header.Set("Content-Type", "application/json") 1286 1287 response, err = client.Do(request) 1288 Expect(err).NotTo(HaveOccurred()) 1289 }) 1290 1291 Context("when not authenticated", func() { 1292 BeforeEach(func() { 1293 fakeAccess.IsAuthenticatedReturns(false) 1294 }) 1295 1296 It("returns Unauthorized", func() { 1297 Expect(response.StatusCode).To(Equal(http.StatusUnauthorized)) 1298 }) 1299 }) 1300 1301 Context("when not authorized", func() { 1302 BeforeEach(func() { 1303 fakeAccess.IsAuthenticatedReturns(true) 1304 fakeAccess.IsAuthorizedReturns(false) 1305 }) 1306 1307 It("returns Forbidden", func() { 1308 Expect(response.StatusCode).To(Equal(http.StatusForbidden)) 1309 }) 1310 }) 1311 1312 Context("when authenticated and authorized", func() { 1313 1314 BeforeEach(func() { 1315 fakeAccess.IsAuthenticatedReturns(true) 1316 fakeAccess.IsAuthorizedReturns(true) 1317 }) 1318 1319 Context("when looking up the resource type fails", func() { 1320 BeforeEach(func() { 1321 fakePipeline.ResourceTypeReturns(nil, false, errors.New("nope")) 1322 }) 1323 It("returns 500", func() { 1324 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 1325 }) 1326 }) 1327 1328 Context("when the resource type is not found", func() { 1329 BeforeEach(func() { 1330 fakePipeline.ResourceTypeReturns(nil, false, nil) 1331 }) 1332 It("returns 404", func() { 1333 Expect(response.StatusCode).To(Equal(http.StatusNotFound)) 1334 }) 1335 }) 1336 1337 Context("when it finds the resource type", func() { 1338 var fakeResourceType *dbfakes.FakeResourceType 1339 1340 BeforeEach(func() { 1341 fakeResourceType = new(dbfakes.FakeResourceType) 1342 fakeResourceType.IDReturns(1) 1343 fakePipeline.ResourceTypeReturns(fakeResourceType, true, nil) 1344 }) 1345 1346 Context("when looking up the resource types fails", func() { 1347 BeforeEach(func() { 1348 fakePipeline.ResourceTypesReturns(nil, errors.New("nope")) 1349 }) 1350 1351 It("returns 500", func() { 1352 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 1353 }) 1354 }) 1355 1356 Context("when looking up the resource types succeeds", func() { 1357 var fakeResourceTypes db.ResourceTypes 1358 1359 BeforeEach(func() { 1360 fakeResourceTypes = db.ResourceTypes{} 1361 fakePipeline.ResourceTypesReturns(fakeResourceTypes, nil) 1362 }) 1363 1364 It("checks with no version specified", func() { 1365 Expect(dbCheckFactory.TryCreateCheckCallCount()).To(Equal(1)) 1366 _, actualResourceType, actualResourceTypes, actualFromVersion, manuallyTriggered := dbCheckFactory.TryCreateCheckArgsForCall(0) 1367 Expect(actualResourceType).To(Equal(fakeResourceType)) 1368 Expect(actualResourceTypes).To(Equal(fakeResourceTypes)) 1369 Expect(actualFromVersion).To(BeNil()) 1370 Expect(manuallyTriggered).To(BeTrue()) 1371 }) 1372 1373 Context("when checking with a version specified", func() { 1374 BeforeEach(func() { 1375 checkRequestBody = atc.CheckRequestBody{ 1376 From: atc.Version{ 1377 "some-version-key": "some-version-value", 1378 }, 1379 } 1380 }) 1381 1382 It("checks with no version specified", func() { 1383 Expect(dbCheckFactory.TryCreateCheckCallCount()).To(Equal(1)) 1384 _, actualResourceType, actualResourceTypes, actualFromVersion, manuallyTriggered := dbCheckFactory.TryCreateCheckArgsForCall(0) 1385 Expect(actualResourceType).To(Equal(fakeResourceType)) 1386 Expect(actualResourceTypes).To(Equal(fakeResourceTypes)) 1387 Expect(actualFromVersion).To(Equal(checkRequestBody.From)) 1388 Expect(manuallyTriggered).To(BeTrue()) 1389 }) 1390 }) 1391 1392 Context("when checking fails", func() { 1393 BeforeEach(func() { 1394 dbCheckFactory.TryCreateCheckReturns(nil, false, errors.New("nope")) 1395 }) 1396 1397 It("returns 500", func() { 1398 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 1399 }) 1400 }) 1401 1402 Context("when checking does not create a new check", func() { 1403 BeforeEach(func() { 1404 dbCheckFactory.TryCreateCheckReturns(nil, false, nil) 1405 }) 1406 1407 It("returns 500", func() { 1408 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 1409 }) 1410 }) 1411 1412 Context("when checking creates a new check", func() { 1413 var fakeBuild *dbfakes.FakeBuild 1414 1415 BeforeEach(func() { 1416 fakeBuild = new(dbfakes.FakeBuild) 1417 fakeBuild.IDReturns(10) 1418 fakeBuild.NameReturns("some-name") 1419 fakeBuild.TeamNameReturns("some-team") 1420 fakeBuild.StatusReturns("started") 1421 fakeBuild.StartTimeReturns(time.Date(2001, 01, 01, 0, 0, 0, 0, time.UTC)) 1422 fakeBuild.EndTimeReturns(time.Date(2002, 01, 01, 0, 0, 0, 0, time.UTC)) 1423 1424 dbCheckFactory.TryCreateCheckReturns(fakeBuild, true, nil) 1425 }) 1426 1427 It("returns 201", func() { 1428 Expect(response.StatusCode).To(Equal(http.StatusCreated)) 1429 Expect(ioutil.ReadAll(response.Body)).To(MatchJSON(`{ 1430 "id": 10, 1431 "name": "some-name", 1432 "team_name": "some-team", 1433 "status": "started", 1434 "api_url": "/api/v1/builds/10", 1435 "start_time": 978307200, 1436 "end_time": 1009843200 1437 }`)) 1438 }) 1439 }) 1440 1441 }) 1442 }) 1443 }) 1444 }) 1445 1446 Describe("POST /api/v1/teams/:team_name/pipelines/:pipeline_name/resources/:resource_name/check/webhook", func() { 1447 var ( 1448 checkRequestBody atc.CheckRequestBody 1449 response *http.Response 1450 fakeResource *dbfakes.FakeResource 1451 ) 1452 1453 BeforeEach(func() { 1454 checkRequestBody = atc.CheckRequestBody{} 1455 1456 fakeResource = new(dbfakes.FakeResource) 1457 fakeResource.NameReturns("resource-name") 1458 fakeResource.IDReturns(10) 1459 }) 1460 1461 JustBeforeEach(func() { 1462 reqPayload, err := json.Marshal(checkRequestBody) 1463 Expect(err).NotTo(HaveOccurred()) 1464 1465 request, err := http.NewRequest("POST", server.URL+"/api/v1/teams/a-team/pipelines/a-pipeline/resources/resource-name/check/webhook?webhook_token=fake-token", bytes.NewBuffer(reqPayload)) 1466 Expect(err).NotTo(HaveOccurred()) 1467 request.Header.Set("Content-Type", "application/json") 1468 1469 response, err = client.Do(request) 1470 Expect(err).NotTo(HaveOccurred()) 1471 }) 1472 1473 Context("when authorized", func() { 1474 BeforeEach(func() { 1475 variables = vars.StaticVariables{ 1476 "webhook-token": "fake-token", 1477 } 1478 token, err := creds.NewString(variables, "((webhook-token))").Evaluate() 1479 Expect(err).NotTo(HaveOccurred()) 1480 fakeResource.WebhookTokenReturns(token) 1481 fakePipeline.ResourceReturns(fakeResource, true, nil) 1482 fakeResource.ResourceConfigIDReturns(1) 1483 fakeResource.ResourceConfigScopeIDReturns(2) 1484 }) 1485 1486 It("injects the proper pipelineDB", func() { 1487 Expect(dbTeam.PipelineCallCount()).To(Equal(1)) 1488 resourceName := fakePipeline.ResourceArgsForCall(0) 1489 Expect(resourceName).To(Equal("resource-name")) 1490 }) 1491 1492 It("tries to find the resource", func() { 1493 Expect(fakePipeline.ResourceCallCount()).To(Equal(1)) 1494 Expect(fakePipeline.ResourceArgsForCall(0)).To(Equal("resource-name")) 1495 }) 1496 1497 Context("when finding the resource succeeds", func() { 1498 BeforeEach(func() { 1499 fakePipeline.ResourceReturns(fakeResource, true, nil) 1500 }) 1501 1502 Context("when finding the resource types fails", func() { 1503 BeforeEach(func() { 1504 fakePipeline.ResourceTypesReturns(nil, errors.New("oops")) 1505 }) 1506 1507 It("returns 500", func() { 1508 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 1509 }) 1510 }) 1511 1512 Context("when finding the resource types succeeds", func() { 1513 var fakeResourceTypes db.ResourceTypes 1514 1515 BeforeEach(func() { 1516 fakeResourceTypes = db.ResourceTypes{} 1517 fakePipeline.ResourceTypesReturns(fakeResourceTypes, nil) 1518 }) 1519 1520 It("checks with a nil version", func() { 1521 Expect(dbCheckFactory.TryCreateCheckCallCount()).To(Equal(1)) 1522 _, actualResource, actualResourceTypes, actualFromVersion, manuallyTriggered := dbCheckFactory.TryCreateCheckArgsForCall(0) 1523 Expect(actualResource).To(Equal(fakeResource)) 1524 Expect(actualResourceTypes).To(Equal(fakeResourceTypes)) 1525 Expect(actualFromVersion).To(BeNil()) 1526 Expect(manuallyTriggered).To(BeTrue()) 1527 }) 1528 1529 Context("when checking fails", func() { 1530 BeforeEach(func() { 1531 dbCheckFactory.TryCreateCheckReturns(nil, false, errors.New("nope")) 1532 }) 1533 1534 It("returns 500", func() { 1535 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 1536 }) 1537 }) 1538 1539 Context("when checking does not create a new check", func() { 1540 BeforeEach(func() { 1541 dbCheckFactory.TryCreateCheckReturns(nil, false, nil) 1542 }) 1543 1544 It("returns 500", func() { 1545 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 1546 }) 1547 }) 1548 1549 Context("when checking creates a new check", func() { 1550 var fakeBuild *dbfakes.FakeBuild 1551 1552 BeforeEach(func() { 1553 fakeBuild = new(dbfakes.FakeBuild) 1554 fakeBuild.IDReturns(10) 1555 fakeBuild.NameReturns("some-name") 1556 fakeBuild.TeamNameReturns("some-team") 1557 fakeBuild.StatusReturns("started") 1558 fakeBuild.StartTimeReturns(time.Date(2001, 01, 01, 0, 0, 0, 0, time.UTC)) 1559 fakeBuild.EndTimeReturns(time.Date(2002, 01, 01, 0, 0, 0, 0, time.UTC)) 1560 1561 dbCheckFactory.TryCreateCheckReturns(fakeBuild, true, nil) 1562 }) 1563 1564 It("returns 201", func() { 1565 Expect(response.StatusCode).To(Equal(http.StatusCreated)) 1566 Expect(ioutil.ReadAll(response.Body)).To(MatchJSON(`{ 1567 "id": 10, 1568 "name": "some-name", 1569 "team_name": "some-team", 1570 "status": "started", 1571 "api_url": "/api/v1/builds/10", 1572 "start_time": 978307200, 1573 "end_time": 1009843200 1574 }`)) 1575 }) 1576 }) 1577 }) 1578 }) 1579 1580 Context("when finding the resource fails", func() { 1581 BeforeEach(func() { 1582 fakePipeline.ResourceReturns(nil, false, errors.New("oops")) 1583 }) 1584 1585 It("returns 500", func() { 1586 Expect(response.StatusCode).To(Equal(http.StatusInternalServerError)) 1587 }) 1588 }) 1589 1590 Context("when the resource is not found", func() { 1591 BeforeEach(func() { 1592 fakePipeline.ResourceReturns(nil, false, nil) 1593 }) 1594 1595 It("returns 404", func() { 1596 Expect(response.StatusCode).To(Equal(http.StatusNotFound)) 1597 }) 1598 }) 1599 }) 1600 1601 Context("when unauthorized", func() { 1602 BeforeEach(func() { 1603 fakeResource.WebhookTokenReturns("wrong-token") 1604 fakePipeline.ResourceReturns(fakeResource, true, nil) 1605 }) 1606 It("returns 401", func() { 1607 Expect(response.StatusCode).To(Equal(http.StatusUnauthorized)) 1608 }) 1609 }) 1610 }) 1611 })