github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/db/team_test.go (about) 1 package db_test 2 3 import ( 4 "database/sql" 5 "fmt" 6 "strconv" 7 "time" 8 9 "code.cloudfoundry.org/lager" 10 "code.cloudfoundry.org/lager/lagertest" 11 12 sq "github.com/Masterminds/squirrel" 13 "github.com/pf-qiu/concourse/v6/atc" 14 "github.com/pf-qiu/concourse/v6/atc/creds/credsfakes" 15 "github.com/pf-qiu/concourse/v6/atc/db" 16 "github.com/pf-qiu/concourse/v6/atc/db/dbtest" 17 "github.com/pf-qiu/concourse/v6/atc/event" 18 . "github.com/onsi/ginkgo" 19 . "github.com/onsi/gomega" 20 ) 21 22 var _ = Describe("Team", func() { 23 var ( 24 team db.Team 25 otherTeam db.Team 26 ) 27 28 expectConfigsEqual := func(config, expectedConfig atc.Config) { 29 ExpectWithOffset(1, config.Groups).To(ConsistOf(expectedConfig.Groups)) 30 ExpectWithOffset(1, config.Resources).To(ConsistOf(expectedConfig.Resources)) 31 ExpectWithOffset(1, config.ResourceTypes).To(ConsistOf(expectedConfig.ResourceTypes)) 32 ExpectWithOffset(1, config.Jobs).To(ConsistOf(expectedConfig.Jobs)) 33 } 34 35 BeforeEach(func() { 36 var err error 37 team, err = teamFactory.CreateTeam(atc.Team{Name: "some-team"}) 38 Expect(err).ToNot(HaveOccurred()) 39 otherTeam, err = teamFactory.CreateTeam(atc.Team{Name: "some-other-team"}) 40 Expect(err).ToNot(HaveOccurred()) 41 }) 42 43 Describe("Delete", func() { 44 var err error 45 46 BeforeEach(func() { 47 err = otherTeam.Delete() 48 Expect(err).ToNot(HaveOccurred()) 49 }) 50 51 It("deletes the team", func() { 52 team, found, err := teamFactory.FindTeam("some-other-team") 53 Expect(team).To(BeNil()) 54 Expect(found).To(BeFalse()) 55 Expect(err).ToNot(HaveOccurred()) 56 }) 57 58 It("drops the team_build_events_ID table", func() { 59 var exists bool 60 err := dbConn.QueryRow(fmt.Sprintf("SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'team_build_events_%d')", otherTeam.ID())).Scan(&exists) 61 Expect(err).ToNot(HaveOccurred()) 62 Expect(exists).To(BeFalse()) 63 }) 64 }) 65 66 Describe("Rename", func() { 67 JustBeforeEach(func() { 68 Expect(team.Rename("oopsies")).To(Succeed()) 69 }) 70 71 It("find the renamed team", func() { 72 _, found, _ := teamFactory.FindTeam("oopsies") 73 Expect(found).To(BeTrue()) 74 }) 75 }) 76 77 Describe("SaveWorker", func() { 78 var ( 79 team db.Team 80 otherTeam db.Team 81 atcWorker atc.Worker 82 err error 83 ) 84 85 BeforeEach(func() { 86 postgresRunner.Truncate() 87 team, err = teamFactory.CreateTeam(atc.Team{Name: "team"}) 88 Expect(err).ToNot(HaveOccurred()) 89 90 otherTeam, err = teamFactory.CreateTeam(atc.Team{Name: "some-other-team"}) 91 Expect(err).ToNot(HaveOccurred()) 92 atcWorker = atc.Worker{ 93 GardenAddr: "some-garden-addr", 94 BaggageclaimURL: "some-bc-url", 95 HTTPProxyURL: "some-http-proxy-url", 96 HTTPSProxyURL: "some-https-proxy-url", 97 NoProxy: "some-no-proxy", 98 ActiveContainers: 140, 99 ResourceTypes: []atc.WorkerResourceType{ 100 { 101 Type: "some-resource-type", 102 Image: "some-image", 103 Version: "some-version", 104 }, 105 { 106 Type: "other-resource-type", 107 Image: "other-image", 108 Version: "other-version", 109 }, 110 }, 111 Platform: "some-platform", 112 Tags: atc.Tags{"some", "tags"}, 113 Name: "some-name", 114 StartTime: 55, 115 } 116 }) 117 118 Context("the worker already exists", func() { 119 Context("the worker is not in stalled state", func() { 120 Context("the team_id of the new worker is the same", func() { 121 BeforeEach(func() { 122 _, err := team.SaveWorker(atcWorker, 5*time.Minute) 123 Expect(err).ToNot(HaveOccurred()) 124 }) 125 It("overwrites all the data", func() { 126 atcWorker.GardenAddr = "new-garden-addr" 127 savedWorker, err := team.SaveWorker(atcWorker, 5*time.Minute) 128 Expect(err).ToNot(HaveOccurred()) 129 Expect(savedWorker.Name()).To(Equal("some-name")) 130 Expect(*savedWorker.GardenAddr()).To(Equal("new-garden-addr")) 131 Expect(savedWorker.State()).To(Equal(db.WorkerStateRunning)) 132 }) 133 }) 134 Context("the team_id of the new worker is different", func() { 135 BeforeEach(func() { 136 _, err = otherTeam.SaveWorker(atcWorker, 5*time.Minute) 137 Expect(err).ToNot(HaveOccurred()) 138 }) 139 It("errors", func() { 140 _, err = team.SaveWorker(atcWorker, 5*time.Minute) 141 Expect(err).To(HaveOccurred()) 142 }) 143 }) 144 }) 145 }) 146 }) 147 148 Describe("Workers", func() { 149 var ( 150 team db.Team 151 otherTeam db.Team 152 atcWorker atc.Worker 153 err error 154 ) 155 156 BeforeEach(func() { 157 postgresRunner.Truncate() 158 team, err = teamFactory.CreateTeam(atc.Team{Name: "team"}) 159 Expect(err).ToNot(HaveOccurred()) 160 161 otherTeam, err = teamFactory.CreateTeam(atc.Team{Name: "some-other-team"}) 162 Expect(err).ToNot(HaveOccurred()) 163 atcWorker = atc.Worker{ 164 GardenAddr: "some-garden-addr", 165 BaggageclaimURL: "some-bc-url", 166 HTTPProxyURL: "some-http-proxy-url", 167 HTTPSProxyURL: "some-https-proxy-url", 168 NoProxy: "some-no-proxy", 169 ActiveContainers: 140, 170 ResourceTypes: []atc.WorkerResourceType{ 171 { 172 Type: "some-resource-type", 173 Image: "some-image", 174 Version: "some-version", 175 }, 176 { 177 Type: "other-resource-type", 178 Image: "other-image", 179 Version: "other-version", 180 }, 181 }, 182 Platform: "some-platform", 183 Tags: atc.Tags{"some", "tags"}, 184 Name: "some-name", 185 StartTime: 55, 186 } 187 }) 188 189 Context("when there are global workers and workers for the team", func() { 190 BeforeEach(func() { 191 _, err = team.SaveWorker(atcWorker, 0) 192 Expect(err).ToNot(HaveOccurred()) 193 194 atcWorker.Name = "some-new-worker" 195 atcWorker.GardenAddr = "some-other-garden-addr" 196 atcWorker.BaggageclaimURL = "some-other-bc-url" 197 _, err = workerFactory.SaveWorker(atcWorker, 0) 198 Expect(err).ToNot(HaveOccurred()) 199 }) 200 201 It("finds them without error", func() { 202 workers, err := team.Workers() 203 Expect(err).ToNot(HaveOccurred()) 204 Expect(len(workers)).To(Equal(2)) 205 206 Expect(workers[0].Name()).To(Equal("some-name")) 207 Expect(*workers[0].GardenAddr()).To(Equal("some-garden-addr")) 208 Expect(*workers[0].BaggageclaimURL()).To(Equal("some-bc-url")) 209 210 Expect(workers[1].Name()).To(Equal("some-new-worker")) 211 Expect(*workers[1].GardenAddr()).To(Equal("some-other-garden-addr")) 212 Expect(*workers[1].BaggageclaimURL()).To(Equal("some-other-bc-url")) 213 }) 214 }) 215 216 Context("when there are workers for another team", func() { 217 BeforeEach(func() { 218 atcWorker.Name = "some-other-team-worker" 219 atcWorker.GardenAddr = "some-other-garden-addr" 220 atcWorker.BaggageclaimURL = "some-other-bc-url" 221 _, err = otherTeam.SaveWorker(atcWorker, 5*time.Minute) 222 Expect(err).ToNot(HaveOccurred()) 223 }) 224 225 It("does not find the other team workers", func() { 226 workers, err := team.Workers() 227 Expect(err).ToNot(HaveOccurred()) 228 Expect(len(workers)).To(Equal(0)) 229 }) 230 }) 231 232 Context("when there are no workers", func() { 233 It("returns an error", func() { 234 workers, err := workerFactory.Workers() 235 Expect(err).ToNot(HaveOccurred()) 236 Expect(workers).To(BeEmpty()) 237 }) 238 }) 239 }) 240 241 Describe("FindContainersByMetadata", func() { 242 var sampleMetadata []db.ContainerMetadata 243 var metaContainers map[db.ContainerMetadata][]db.Container 244 245 BeforeEach(func() { 246 baseMetadata := fullMetadata 247 248 diffType := fullMetadata 249 diffType.Type = db.ContainerTypeCheck 250 251 diffStepName := fullMetadata 252 diffStepName.StepName = fullMetadata.StepName + "-other" 253 254 diffAttempt := fullMetadata 255 diffAttempt.Attempt = fullMetadata.Attempt + ",2" 256 257 diffPipelineID := fullMetadata 258 diffPipelineID.PipelineID = fullMetadata.PipelineID + 1 259 260 diffJobID := fullMetadata 261 diffJobID.JobID = fullMetadata.JobID + 1 262 263 diffBuildID := fullMetadata 264 diffBuildID.BuildID = fullMetadata.BuildID + 1 265 266 diffWorkingDirectory := fullMetadata 267 diffWorkingDirectory.WorkingDirectory = fullMetadata.WorkingDirectory + "/other" 268 269 diffUser := fullMetadata 270 diffUser.User = fullMetadata.User + "-other" 271 272 sampleMetadata = []db.ContainerMetadata{ 273 baseMetadata, 274 diffType, 275 diffStepName, 276 diffAttempt, 277 diffPipelineID, 278 diffJobID, 279 diffBuildID, 280 diffWorkingDirectory, 281 diffUser, 282 } 283 284 job, found, err := defaultPipeline.Job("some-job") 285 Expect(err).ToNot(HaveOccurred()) 286 Expect(found).To(BeTrue()) 287 288 build, err := job.CreateBuild() 289 Expect(err).ToNot(HaveOccurred()) 290 291 metaContainers = make(map[db.ContainerMetadata][]db.Container) 292 for _, meta := range sampleMetadata { 293 firstContainerCreating, err := defaultWorker.CreateContainer(db.NewBuildStepContainerOwner(build.ID(), atc.PlanID("some-job"), defaultTeam.ID()), meta) 294 Expect(err).ToNot(HaveOccurred()) 295 296 metaContainers[meta] = append(metaContainers[meta], firstContainerCreating) 297 298 secondContainerCreating, err := defaultWorker.CreateContainer(db.NewBuildStepContainerOwner(build.ID(), atc.PlanID("some-job"), defaultTeam.ID()), meta) 299 Expect(err).ToNot(HaveOccurred()) 300 301 secondContainerCreated, err := secondContainerCreating.Created() 302 Expect(err).ToNot(HaveOccurred()) 303 304 metaContainers[meta] = append(metaContainers[meta], secondContainerCreated) 305 306 thirdContainerCreating, err := defaultWorker.CreateContainer(db.NewBuildStepContainerOwner(build.ID(), atc.PlanID("some-job"), defaultTeam.ID()), meta) 307 Expect(err).ToNot(HaveOccurred()) 308 309 thirdContainerCreated, err := thirdContainerCreating.Created() 310 Expect(err).ToNot(HaveOccurred()) 311 312 // third container is not appended; we don't want Destroying containers 313 thirdContainerDestroying, err := thirdContainerCreated.Destroying() 314 Expect(err).ToNot(HaveOccurred()) 315 316 metaContainers[meta] = append(metaContainers[meta], thirdContainerDestroying) 317 } 318 }) 319 320 It("finds creating, created, and destroying containers for the team, matching the metadata in full", func() { 321 for _, meta := range sampleMetadata { 322 expectedHandles := []string{} 323 for _, c := range metaContainers[meta] { 324 expectedHandles = append(expectedHandles, c.Handle()) 325 } 326 327 containers, err := defaultTeam.FindContainersByMetadata(meta) 328 Expect(err).ToNot(HaveOccurred()) 329 330 foundHandles := []string{} 331 for _, c := range containers { 332 foundHandles = append(foundHandles, c.Handle()) 333 } 334 335 // should always find a Creating container and a Created container 336 Expect(foundHandles).To(HaveLen(3)) 337 Expect(foundHandles).To(ConsistOf(expectedHandles)) 338 } 339 }) 340 341 It("finds containers for the team, matching partial metadata", func() { 342 containers, err := defaultTeam.FindContainersByMetadata(db.ContainerMetadata{ 343 Type: db.ContainerTypeTask, 344 }) 345 Expect(err).ToNot(HaveOccurred()) 346 Expect(containers).ToNot(BeEmpty()) 347 348 foundHandles := []string{} 349 for _, c := range containers { 350 foundHandles = append(foundHandles, c.Handle()) 351 } 352 353 var notFound int 354 for meta, cs := range metaContainers { 355 if meta.Type == db.ContainerTypeTask { 356 for _, c := range cs { 357 Expect(foundHandles).To(ContainElement(c.Handle())) 358 } 359 } else { 360 for _, c := range cs { 361 Expect(foundHandles).ToNot(ContainElement(c.Handle())) 362 notFound++ 363 } 364 } 365 } 366 367 // just to assert test setup is valid 368 Expect(notFound).ToNot(BeZero()) 369 }) 370 371 It("finds all containers for the team when given empty metadata", func() { 372 containers, err := defaultTeam.FindContainersByMetadata(db.ContainerMetadata{}) 373 Expect(err).ToNot(HaveOccurred()) 374 Expect(containers).ToNot(BeEmpty()) 375 376 foundHandles := []string{} 377 for _, c := range containers { 378 foundHandles = append(foundHandles, c.Handle()) 379 } 380 381 for _, cs := range metaContainers { 382 for _, c := range cs { 383 Expect(foundHandles).To(ContainElement(c.Handle())) 384 } 385 } 386 }) 387 388 It("does not find containers for other teams", func() { 389 for _, meta := range sampleMetadata { 390 containers, err := otherTeam.FindContainersByMetadata(meta) 391 Expect(err).ToNot(HaveOccurred()) 392 Expect(containers).To(BeEmpty()) 393 } 394 }) 395 }) 396 397 Describe("Containers", func() { 398 var ( 399 fakeSecretManager *credsfakes.FakeSecrets 400 resourceContainer db.CreatingContainer 401 firstContainerCreating db.CreatingContainer 402 scenario *dbtest.Scenario 403 ) 404 405 Context("when there is a task container and a check container", func() { 406 BeforeEach(func() { 407 fakeSecretManager = new(credsfakes.FakeSecrets) 408 fakeSecretManager.GetReturns("", nil, false, nil) 409 410 scenario = dbtest.Setup( 411 builder.WithPipeline(atc.Config{ 412 Jobs: atc.JobConfigs{ 413 { 414 Name: "some-job", 415 }, 416 }, 417 Resources: atc.ResourceConfigs{ 418 { 419 Name: "some-resource", 420 Type: "some-base-resource-type", 421 Source: atc.Source{ 422 "some": "source", 423 }, 424 }, 425 }, 426 ResourceTypes: atc.ResourceTypes{ 427 { 428 Name: "some-type", 429 Type: "some-base-resource-type", 430 Source: atc.Source{ 431 "some-type": "source", 432 }, 433 }, 434 }, 435 }), 436 builder.WithWorker(atc.Worker{ 437 ResourceTypes: []atc.WorkerResourceType{defaultWorkerResourceType}, 438 Name: "some-default-worker", 439 GardenAddr: "3.4.5.6:7777", 440 BaggageclaimURL: "7.8.9.10:7878", 441 }), 442 builder.WithResourceVersions("some-resource"), 443 ) 444 445 build, err := scenario.Job("some-job").CreateBuild() 446 Expect(err).ToNot(HaveOccurred()) 447 448 firstContainerCreating, err = scenario.Workers[0].CreateContainer(db.NewBuildStepContainerOwner(build.ID(), atc.PlanID("some-job"), scenario.Team.ID()), db.ContainerMetadata{Type: "task", StepName: "some-task"}) 449 Expect(err).ToNot(HaveOccurred()) 450 451 expiries := db.ContainerOwnerExpiries{ 452 Min: 5 * time.Minute, 453 Max: 1 * time.Hour, 454 } 455 456 rc, found, err := resourceConfigFactory.FindResourceConfigByID(scenario.Resource("some-resource").ResourceConfigID()) 457 Expect(err).ToNot(HaveOccurred()) 458 Expect(found).To(BeTrue()) 459 460 resourceContainer, err = scenario.Workers[0].CreateContainer( 461 db.NewResourceConfigCheckSessionContainerOwner( 462 rc.ID(), 463 rc.OriginBaseResourceType().ID, 464 expiries, 465 ), 466 db.ContainerMetadata{}, 467 ) 468 Expect(err).ToNot(HaveOccurred()) 469 }) 470 471 It("finds all the containers", func() { 472 containers, err := scenario.Team.Containers() 473 Expect(err).ToNot(HaveOccurred()) 474 475 Expect(containers).To(HaveLen(2)) 476 Expect(containers).To(ConsistOf(firstContainerCreating, resourceContainer)) 477 }) 478 479 It("does not find containers for other teams", func() { 480 containers, err := otherTeam.Containers() 481 Expect(err).ToNot(HaveOccurred()) 482 Expect(containers).To(BeEmpty()) 483 }) 484 }) 485 486 Context("when there is a check container on a team worker", func() { 487 var resourceContainer db.Container 488 489 BeforeEach(func() { 490 scenario = dbtest.Setup( 491 builder.WithTeam("some-test-team"), 492 builder.WithPipeline(atc.Config{ 493 Jobs: atc.JobConfigs{ 494 { 495 Name: "some-job", 496 }, 497 }, 498 Resources: atc.ResourceConfigs{ 499 { 500 Name: "some-resource", 501 Type: "some-base-resource-type", 502 Source: atc.Source{ 503 "some": "source", 504 }, 505 }, 506 }, 507 ResourceTypes: atc.ResourceTypes{ 508 { 509 Name: "some-type", 510 Type: "some-base-resource-type", 511 Source: atc.Source{ 512 "some-type": "source", 513 }, 514 }, 515 }, 516 }), 517 builder.WithWorker(atc.Worker{ 518 Name: "default-team-worker", 519 Team: "some-test-team", 520 ResourceTypes: []atc.WorkerResourceType{defaultWorkerResourceType}, 521 GardenAddr: "3.4.5.6:7777", 522 BaggageclaimURL: "7.8.9.10:7878", 523 }), 524 builder.WithResourceVersions("some-resource"), 525 ) 526 527 expiries := db.ContainerOwnerExpiries{ 528 Min: 5 * time.Minute, 529 Max: 1 * time.Hour, 530 } 531 532 rc, found, err := resourceConfigFactory.FindResourceConfigByID(scenario.Resource("some-resource").ResourceConfigID()) 533 Expect(err).ToNot(HaveOccurred()) 534 Expect(found).To(BeTrue()) 535 536 resourceContainer, err = scenario.Workers[0].CreateContainer( 537 db.NewResourceConfigCheckSessionContainerOwner( 538 rc.ID(), 539 rc.OriginBaseResourceType().ID, 540 expiries, 541 ), 542 db.ContainerMetadata{ 543 Type: "check", 544 }, 545 ) 546 Expect(err).ToNot(HaveOccurred()) 547 }) 548 549 It("finds the container", func() { 550 containers, err := scenario.Team.Containers() 551 Expect(err).ToNot(HaveOccurred()) 552 553 Expect(containers).To(HaveLen(1)) 554 Expect(containers).To(ConsistOf(resourceContainer)) 555 }) 556 557 Context("when there is another check container with the same resource config on a different team worker", func() { 558 var ( 559 resource2Container db.Container 560 otherScenario *dbtest.Scenario 561 ) 562 563 BeforeEach(func() { 564 otherScenario = dbtest.Setup( 565 builder.WithTeam("other-team"), 566 builder.WithPipeline(atc.Config{ 567 Jobs: atc.JobConfigs{ 568 { 569 Name: "some-job", 570 }, 571 }, 572 Resources: atc.ResourceConfigs{ 573 { 574 Name: "some-resource", 575 Type: "some-base-resource-type", 576 Source: atc.Source{ 577 "some": "source", 578 }, 579 }, 580 }, 581 ResourceTypes: atc.ResourceTypes{ 582 { 583 Name: "some-type", 584 Type: "some-base-resource-type", 585 Source: atc.Source{ 586 "some-type": "source", 587 }, 588 }, 589 }, 590 }), 591 builder.WithWorker(atc.Worker{ 592 Name: "other-team-worker", 593 Team: "other-team", 594 ResourceTypes: []atc.WorkerResourceType{defaultWorkerResourceType}, 595 GardenAddr: "4.5.6.7:7777", 596 BaggageclaimURL: "8.9.10.11:7878", 597 }), 598 builder.WithResourceVersions("some-resource"), 599 ) 600 601 expiries := db.ContainerOwnerExpiries{ 602 Min: 5 * time.Minute, 603 Max: 1 * time.Hour, 604 } 605 606 rc, found, err := resourceConfigFactory.FindResourceConfigByID(otherScenario.Resource("some-resource").ResourceConfigID()) 607 Expect(err).ToNot(HaveOccurred()) 608 Expect(found).To(BeTrue()) 609 610 resource2Container, err = otherScenario.Workers[0].CreateContainer( 611 db.NewResourceConfigCheckSessionContainerOwner( 612 rc.ID(), 613 rc.OriginBaseResourceType().ID, 614 expiries, 615 ), 616 db.ContainerMetadata{ 617 Type: "check", 618 }, 619 ) 620 Expect(err).ToNot(HaveOccurred()) 621 }) 622 623 It("returns the container only from the team", func() { 624 containers, err := otherScenario.Team.Containers() 625 Expect(err).ToNot(HaveOccurred()) 626 627 Expect(containers).To(HaveLen(1)) 628 Expect(containers).To(ConsistOf(resource2Container)) 629 }) 630 }) 631 632 Context("when there is a check container with the same resource config on a global worker", func() { 633 var ( 634 globalResourceContainer db.Container 635 ) 636 637 BeforeEach(func() { 638 expiries := db.ContainerOwnerExpiries{ 639 Min: 5 * time.Minute, 640 Max: 1 * time.Hour, 641 } 642 643 rc, found, err := resourceConfigFactory.FindResourceConfigByID(scenario.Resource("some-resource").ResourceConfigID()) 644 Expect(err).ToNot(HaveOccurred()) 645 Expect(found).To(BeTrue()) 646 647 globalResourceContainer, err = scenario.Workers[0].CreateContainer( 648 db.NewResourceConfigCheckSessionContainerOwner( 649 rc.ID(), 650 rc.OriginBaseResourceType().ID, 651 expiries, 652 ), 653 db.ContainerMetadata{ 654 Type: "check", 655 }, 656 ) 657 Expect(err).ToNot(HaveOccurred()) 658 }) 659 660 It("returns the container only from the team worker and global worker", func() { 661 containers, err := scenario.Team.Containers() 662 Expect(err).ToNot(HaveOccurred()) 663 664 Expect(containers).To(HaveLen(2)) 665 Expect(containers).To(ConsistOf(resourceContainer, globalResourceContainer)) 666 }) 667 }) 668 }) 669 670 Context("when there is a check container for a resource type", func() { 671 var resourceContainer db.Container 672 673 BeforeEach(func() { 674 expiries := db.ContainerOwnerExpiries{ 675 Min: 5 * time.Minute, 676 Max: 1 * time.Hour, 677 } 678 679 scenario = dbtest.Setup( 680 builder.WithPipeline(atc.Config{ 681 ResourceTypes: atc.ResourceTypes{ 682 { 683 Name: "some-type", 684 Type: "some-base-resource-type", 685 Source: atc.Source{ 686 "some-type": "source", 687 }, 688 }, 689 }, 690 }), 691 builder.WithWorker(atc.Worker{ 692 ResourceTypes: []atc.WorkerResourceType{defaultWorkerResourceType}, 693 Name: "some-default-worker", 694 GardenAddr: "3.4.5.6:7777", 695 BaggageclaimURL: "7.8.9.10:7878", 696 }), 697 builder.WithResourceTypeVersions("some-type"), 698 ) 699 700 rc, err := resourceConfigFactory.FindOrCreateResourceConfig(scenario.ResourceType("some-type").Type(), scenario.ResourceType("some-type").Source(), nil) 701 Expect(err).ToNot(HaveOccurred()) 702 703 resourceContainer, err = scenario.Workers[0].CreateContainer( 704 db.NewResourceConfigCheckSessionContainerOwner( 705 rc.ID(), 706 rc.OriginBaseResourceType().ID, 707 expiries, 708 ), 709 db.ContainerMetadata{ 710 Type: "check", 711 }, 712 ) 713 Expect(err).ToNot(HaveOccurred()) 714 }) 715 716 It("finds the container", func() { 717 containers, err := scenario.Team.Containers() 718 Expect(err).ToNot(HaveOccurred()) 719 720 Expect(containers).To(HaveLen(1)) 721 Expect(containers).To(ConsistOf(resourceContainer)) 722 }) 723 }) 724 }) 725 726 Describe("FindContainerByHandle", func() { 727 var createdContainer db.CreatedContainer 728 729 BeforeEach(func() { 730 job, found, err := defaultPipeline.Job("some-job") 731 Expect(err).ToNot(HaveOccurred()) 732 Expect(found).To(BeTrue()) 733 734 build, err := job.CreateBuild() 735 Expect(err).ToNot(HaveOccurred()) 736 737 creatingContainer, err := defaultWorker.CreateContainer(db.NewBuildStepContainerOwner(build.ID(), atc.PlanID("some-job"), defaultTeam.ID()), db.ContainerMetadata{Type: "task", StepName: "some-task"}) 738 Expect(err).ToNot(HaveOccurred()) 739 740 createdContainer, err = creatingContainer.Created() 741 Expect(err).ToNot(HaveOccurred()) 742 }) 743 744 Context("when worker is no longer in database", func() { 745 BeforeEach(func() { 746 err := defaultWorker.Delete() 747 Expect(err).ToNot(HaveOccurred()) 748 }) 749 750 It("the container goes away from the db", func() { 751 _, found, err := defaultTeam.FindContainerByHandle(createdContainer.Handle()) 752 Expect(err).ToNot(HaveOccurred()) 753 Expect(found).To(BeFalse()) 754 }) 755 }) 756 757 It("finds a container for the team", func() { 758 container, found, err := defaultTeam.FindContainerByHandle(createdContainer.Handle()) 759 Expect(err).ToNot(HaveOccurred()) 760 Expect(found).To(BeTrue()) 761 Expect(container).ToNot(BeNil()) 762 Expect(container.Handle()).To(Equal(createdContainer.Handle())) 763 }) 764 }) 765 766 Describe("FindVolumeForWorkerArtifact", func() { 767 768 Context("when the artifact doesn't exist", func() { 769 It("returns not found", func() { 770 _, found, err := defaultTeam.FindVolumeForWorkerArtifact(12) 771 Expect(err).ToNot(HaveOccurred()) 772 Expect(found).To(BeFalse()) 773 }) 774 }) 775 776 Context("when the artifact exists", func() { 777 BeforeEach(func() { 778 _, err := dbConn.Exec("INSERT INTO worker_artifacts (id, name) VALUES ($1, '')", 18) 779 Expect(err).NotTo(HaveOccurred()) 780 }) 781 782 Context("when the associated volume doesn't exist", func() { 783 It("returns not found", func() { 784 _, found, err := defaultTeam.FindVolumeForWorkerArtifact(18) 785 Expect(err).ToNot(HaveOccurred()) 786 Expect(found).To(BeFalse()) 787 }) 788 }) 789 790 Context("when the associated volume exists", func() { 791 BeforeEach(func() { 792 _, err := dbConn.Exec("INSERT INTO volumes (handle, team_id, worker_name, worker_artifact_id, state) VALUES ('some-handle', $1, $2, $3, $4)", defaultTeam.ID(), defaultWorker.Name(), 18, db.VolumeStateCreated) 793 Expect(err).NotTo(HaveOccurred()) 794 }) 795 796 It("returns the volume", func() { 797 volume, found, err := defaultTeam.FindVolumeForWorkerArtifact(18) 798 Expect(err).ToNot(HaveOccurred()) 799 Expect(found).To(BeTrue()) 800 Expect(volume.Handle()).To(Equal("some-handle")) 801 Expect(volume.WorkerArtifactID()).To(Equal(18)) 802 }) 803 }) 804 }) 805 }) 806 807 Describe("FindWorkerForContainer", func() { 808 var containerMetadata db.ContainerMetadata 809 var defaultBuild db.Build 810 811 BeforeEach(func() { 812 var err error 813 containerMetadata = db.ContainerMetadata{ 814 Type: "task", 815 StepName: "some-task", 816 } 817 defaultBuild, err = defaultTeam.CreateOneOffBuild() 818 Expect(err).ToNot(HaveOccurred()) 819 }) 820 821 Context("when there is a creating container", func() { 822 var container db.CreatingContainer 823 824 BeforeEach(func() { 825 var err error 826 container, err = defaultWorker.CreateContainer(db.NewBuildStepContainerOwner(defaultBuild.ID(), "some-plan", defaultTeam.ID()), containerMetadata) 827 Expect(err).ToNot(HaveOccurred()) 828 }) 829 830 It("returns it", func() { 831 worker, found, err := defaultTeam.FindWorkerForContainer(container.Handle()) 832 Expect(err).ToNot(HaveOccurred()) 833 Expect(found).To(BeTrue()) 834 Expect(worker).ToNot(BeNil()) 835 Expect(worker.Name()).To(Equal(defaultWorker.Name())) 836 }) 837 }) 838 839 Context("when there is a created container", func() { 840 var container db.CreatedContainer 841 842 BeforeEach(func() { 843 creatingContainer, err := defaultWorker.CreateContainer(db.NewBuildStepContainerOwner(defaultBuild.ID(), "some-plan", defaultTeam.ID()), containerMetadata) 844 Expect(err).ToNot(HaveOccurred()) 845 846 container, err = creatingContainer.Created() 847 Expect(err).ToNot(HaveOccurred()) 848 }) 849 850 It("returns it", func() { 851 worker, found, err := defaultTeam.FindWorkerForContainer(container.Handle()) 852 Expect(err).ToNot(HaveOccurred()) 853 Expect(found).To(BeTrue()) 854 Expect(worker).ToNot(BeNil()) 855 Expect(worker.Name()).To(Equal(defaultWorker.Name())) 856 }) 857 }) 858 859 Context("when there is no container", func() { 860 It("returns nil", func() { 861 worker, found, err := defaultTeam.FindWorkerForContainer("bogus-handle") 862 Expect(err).ToNot(HaveOccurred()) 863 Expect(found).To(BeFalse()) 864 Expect(worker).To(BeNil()) 865 }) 866 }) 867 }) 868 869 Describe("Updating Auth", func() { 870 var ( 871 authProvider atc.TeamAuth 872 ) 873 874 BeforeEach(func() { 875 authProvider = atc.TeamAuth{ 876 "owner": {"users": []string{"local:username"}}, 877 } 878 }) 879 880 Describe("UpdateProviderAuth", func() { 881 It("saves auth team info to the existing team", func() { 882 err := team.UpdateProviderAuth(authProvider) 883 Expect(err).ToNot(HaveOccurred()) 884 885 Expect(team.Auth()).To(Equal(authProvider)) 886 }) 887 888 It("resets legacy_auth to NULL", func() { 889 oldLegacyAuth := `{"basicauth": {"username": "u", "password": "p"}}` 890 _, err := dbConn.Exec("UPDATE teams SET legacy_auth = $1 WHERE id = $2", oldLegacyAuth, team.ID()) 891 team.UpdateProviderAuth(authProvider) 892 893 var newLegacyAuth sql.NullString 894 err = dbConn.QueryRow("SELECT legacy_auth FROM teams WHERE id = $1", team.ID()).Scan(&newLegacyAuth) 895 Expect(err).ToNot(HaveOccurred()) 896 897 value, err := newLegacyAuth.Value() 898 Expect(err).ToNot(HaveOccurred()) 899 Expect(value).To(BeNil()) 900 }) 901 902 Context("when team auth is already set", func() { 903 BeforeEach(func() { 904 team.UpdateProviderAuth(atc.TeamAuth{ 905 "owner": {"users": []string{"local:somebody"}}, 906 "viewer": {"users": []string{"local:someone"}}, 907 }) 908 }) 909 910 It("overrides the existing auth with the new config", func() { 911 err := team.UpdateProviderAuth(authProvider) 912 Expect(err).ToNot(HaveOccurred()) 913 914 Expect(team.Auth()).To(Equal(authProvider)) 915 }) 916 }) 917 }) 918 }) 919 920 Describe("Pipelines", func() { 921 var ( 922 pipelines []db.Pipeline 923 pipeline1 db.Pipeline 924 pipeline2 db.Pipeline 925 pipeline3 db.Pipeline 926 ) 927 928 JustBeforeEach(func() { 929 var err error 930 pipelines, err = team.Pipelines() 931 Expect(err).ToNot(HaveOccurred()) 932 }) 933 934 Context("when the team has configured pipelines", func() { 935 BeforeEach(func() { 936 var err error 937 pipeline1, _, err = team.SavePipeline(atc.PipelineRef{Name: "fake-pipeline", InstanceVars: atc.InstanceVars{"branch": "master"}}, atc.Config{ 938 Jobs: atc.JobConfigs{ 939 {Name: "job-name"}, 940 }, 941 }, db.ConfigVersion(1), false) 942 Expect(err).ToNot(HaveOccurred()) 943 944 pipeline2, _, err = team.SavePipeline(atc.PipelineRef{Name: "fake-pipeline", InstanceVars: atc.InstanceVars{"branch": "feature/foo"}}, atc.Config{ 945 Jobs: atc.JobConfigs{ 946 {Name: "job-fake"}, 947 }, 948 }, db.ConfigVersion(1), false) 949 Expect(err).ToNot(HaveOccurred()) 950 951 pipeline3, _, err = team.SavePipeline(atc.PipelineRef{Name: "fake-pipeline-two"}, atc.Config{ 952 Jobs: atc.JobConfigs{ 953 {Name: "job-fake"}, 954 }, 955 }, db.ConfigVersion(1), false) 956 Expect(err).ToNot(HaveOccurred()) 957 }) 958 959 It("returns the pipelines", func() { 960 Expect(pipelines[0].Name()).To(Equal(pipeline1.Name())) 961 Expect(pipelines[0].InstanceVars()).To(Equal(pipeline1.InstanceVars())) 962 963 Expect(pipelines[1].Name()).To(Equal(pipeline2.Name())) 964 Expect(pipelines[1].InstanceVars()).To(Equal(pipeline2.InstanceVars())) 965 966 Expect(pipelines[2].Name()).To(Equal(pipeline3.Name())) 967 Expect(pipelines[2].InstanceVars()).To(BeNil()) 968 }) 969 }) 970 Context("when the team has no configured pipelines", func() { 971 It("returns no pipelines", func() { 972 Expect(pipelines).To(Equal([]db.Pipeline{})) 973 }) 974 }) 975 }) 976 977 Describe("PublicPipelines", func() { 978 var ( 979 pipelines []db.Pipeline 980 pipeline2 db.Pipeline 981 ) 982 983 JustBeforeEach(func() { 984 var err error 985 pipelines, err = team.PublicPipelines() 986 Expect(err).ToNot(HaveOccurred()) 987 }) 988 989 Context("when the team has configured pipelines", func() { 990 BeforeEach(func() { 991 var err error 992 _, _, err = team.SavePipeline(atc.PipelineRef{Name: "fake-pipeline"}, atc.Config{ 993 Jobs: atc.JobConfigs{ 994 {Name: "job-name"}, 995 }, 996 }, db.ConfigVersion(1), false) 997 Expect(err).ToNot(HaveOccurred()) 998 999 pipeline2, _, err = team.SavePipeline(atc.PipelineRef{Name: "fake-pipeline-two"}, atc.Config{ 1000 Jobs: atc.JobConfigs{ 1001 {Name: "job-fake"}, 1002 }, 1003 }, db.ConfigVersion(1), false) 1004 Expect(err).ToNot(HaveOccurred()) 1005 1006 err = pipeline2.Expose() 1007 Expect(err).ToNot(HaveOccurred()) 1008 1009 found, err := pipeline2.Reload() 1010 Expect(err).ToNot(HaveOccurred()) 1011 Expect(found).To(BeTrue()) 1012 }) 1013 1014 It("returns the pipelines", func() { 1015 Expect(pipelines).To(Equal([]db.Pipeline{pipeline2})) 1016 }) 1017 }) 1018 Context("when the team has no configured pipelines", func() { 1019 It("returns no pipelines", func() { 1020 Expect(pipelines).To(Equal([]db.Pipeline{})) 1021 }) 1022 }) 1023 }) 1024 1025 Describe("OrderPipelines", func() { 1026 var pipeline1 db.Pipeline 1027 var pipeline2 db.Pipeline 1028 var otherPipeline1 db.Pipeline 1029 var otherPipeline2 db.Pipeline 1030 1031 var masterPipelineRef atc.PipelineRef 1032 var branchPipelineRef atc.PipelineRef 1033 1034 BeforeEach(func() { 1035 var err error 1036 masterPipelineRef = atc.PipelineRef{Name: "pipeline-name", InstanceVars: atc.InstanceVars{"branch": "master"}} 1037 branchPipelineRef = atc.PipelineRef{Name: "pipeline-name", InstanceVars: atc.InstanceVars{"branch": "feature/foo"}} 1038 1039 pipeline1, _, err = team.SavePipeline(masterPipelineRef, atc.Config{}, 0, false) 1040 Expect(err).ToNot(HaveOccurred()) 1041 pipeline2, _, err = team.SavePipeline(branchPipelineRef, atc.Config{}, 0, false) 1042 Expect(err).ToNot(HaveOccurred()) 1043 1044 otherPipeline1, _, err = otherTeam.SavePipeline(masterPipelineRef, atc.Config{}, 0, false) 1045 Expect(err).ToNot(HaveOccurred()) 1046 otherPipeline2, _, err = otherTeam.SavePipeline(branchPipelineRef, atc.Config{}, 0, false) 1047 Expect(err).ToNot(HaveOccurred()) 1048 }) 1049 1050 It("orders pipelines that belong to team (case insensitive)", func() { 1051 err := team.OrderPipelines([]atc.PipelineRef{branchPipelineRef, masterPipelineRef}) 1052 Expect(err).ToNot(HaveOccurred()) 1053 1054 err = otherTeam.OrderPipelines([]atc.PipelineRef{masterPipelineRef, branchPipelineRef}) 1055 Expect(err).ToNot(HaveOccurred()) 1056 1057 orderedPipelines, err := team.Pipelines() 1058 1059 Expect(err).ToNot(HaveOccurred()) 1060 Expect(orderedPipelines).To(HaveLen(2)) 1061 Expect(orderedPipelines[0].ID()).To(Equal(pipeline2.ID())) 1062 Expect(orderedPipelines[1].ID()).To(Equal(pipeline1.ID())) 1063 1064 otherTeamOrderedPipelines, err := otherTeam.Pipelines() 1065 Expect(err).ToNot(HaveOccurred()) 1066 Expect(otherTeamOrderedPipelines).To(HaveLen(2)) 1067 Expect(otherTeamOrderedPipelines[0].ID()).To(Equal(otherPipeline1.ID())) 1068 Expect(otherTeamOrderedPipelines[1].ID()).To(Equal(otherPipeline2.ID())) 1069 }) 1070 1071 Context("when pipeline does not exist", func() { 1072 It("returns error ", func() { 1073 err := otherTeam.OrderPipelines([]atc.PipelineRef{masterPipelineRef, {Name: "pipeline-name", InstanceVars: atc.InstanceVars{"branch": "feature/bar"}}}) 1074 Expect(err).To(HaveOccurred()) 1075 }) 1076 }) 1077 }) 1078 1079 Describe("CreateOneOffBuild", func() { 1080 var ( 1081 oneOffBuild db.Build 1082 err error 1083 ) 1084 1085 BeforeEach(func() { 1086 oneOffBuild, err = team.CreateOneOffBuild() 1087 Expect(err).ToNot(HaveOccurred()) 1088 }) 1089 1090 It("can create one-off builds", func() { 1091 Expect(oneOffBuild.ID()).ToNot(BeZero()) 1092 Expect(oneOffBuild.JobName()).To(BeZero()) 1093 Expect(oneOffBuild.PipelineName()).To(BeZero()) 1094 Expect(oneOffBuild.Name()).To(Equal(strconv.Itoa(oneOffBuild.ID()))) 1095 Expect(oneOffBuild.TeamName()).To(Equal(team.Name())) 1096 Expect(oneOffBuild.Status()).To(Equal(db.BuildStatusPending)) 1097 }) 1098 }) 1099 1100 Describe("CreateStartedBuild", func() { 1101 var ( 1102 plan atc.Plan 1103 startedBuild db.Build 1104 err error 1105 ) 1106 1107 BeforeEach(func() { 1108 plan = atc.Plan{ 1109 ID: atc.PlanID("56"), 1110 Get: &atc.GetPlan{ 1111 Type: "some-type", 1112 Name: "some-name", 1113 Resource: "some-resource", 1114 Source: atc.Source{"some": "source"}, 1115 Params: atc.Params{"some": "params"}, 1116 Version: &atc.Version{"some": "version"}, 1117 Tags: atc.Tags{"some-tags"}, 1118 VersionedResourceTypes: atc.VersionedResourceTypes{ 1119 { 1120 ResourceType: atc.ResourceType{ 1121 Name: "some-name", 1122 Source: atc.Source{"some": "source"}, 1123 Type: "some-type", 1124 Privileged: true, 1125 Tags: atc.Tags{"some-tags"}, 1126 }, 1127 Version: atc.Version{"some-resource-type": "version"}, 1128 }, 1129 }, 1130 }, 1131 } 1132 1133 startedBuild, err = team.CreateStartedBuild(plan) 1134 Expect(err).ToNot(HaveOccurred()) 1135 }) 1136 1137 It("can create started builds with plans", func() { 1138 Expect(startedBuild.ID()).ToNot(BeZero()) 1139 Expect(startedBuild.JobName()).To(BeZero()) 1140 Expect(startedBuild.PipelineName()).To(BeZero()) 1141 Expect(startedBuild.Name()).To(Equal(strconv.Itoa(startedBuild.ID()))) 1142 Expect(startedBuild.TeamName()).To(Equal(team.Name())) 1143 Expect(startedBuild.Status()).To(Equal(db.BuildStatusStarted)) 1144 }) 1145 1146 It("saves the public plan", func() { 1147 found, err := startedBuild.Reload() 1148 Expect(err).NotTo(HaveOccurred()) 1149 Expect(found).To(BeTrue()) 1150 Expect(startedBuild.PublicPlan()).To(Equal(plan.Public())) 1151 }) 1152 1153 It("creates Start event", func() { 1154 found, err := startedBuild.Reload() 1155 Expect(err).NotTo(HaveOccurred()) 1156 Expect(found).To(BeTrue()) 1157 1158 events, err := startedBuild.Events(0) 1159 Expect(err).NotTo(HaveOccurred()) 1160 1161 defer db.Close(events) 1162 1163 Expect(events.Next()).To(Equal(envelope(event.Status{ 1164 Status: atc.StatusStarted, 1165 Time: startedBuild.StartTime().Unix(), 1166 }))) 1167 }) 1168 }) 1169 1170 Describe("PrivateAndPublicBuilds", func() { 1171 Context("when there are no builds", func() { 1172 It("returns an empty list of builds", func() { 1173 builds, pagination, err := team.PrivateAndPublicBuilds(db.Page{Limit: 2}) 1174 Expect(err).ToNot(HaveOccurred()) 1175 1176 Expect(pagination.Older).To(BeNil()) 1177 Expect(pagination.Newer).To(BeNil()) 1178 Expect(builds).To(BeEmpty()) 1179 }) 1180 }) 1181 1182 Context("when there are builds", func() { 1183 var allBuilds [5]db.Build 1184 var pipeline db.Pipeline 1185 var pipelineBuilds [2]db.Build 1186 1187 BeforeEach(func() { 1188 for i := 0; i < 3; i++ { 1189 build, err := team.CreateOneOffBuild() 1190 Expect(err).ToNot(HaveOccurred()) 1191 allBuilds[i] = build 1192 } 1193 1194 config := atc.Config{ 1195 Jobs: atc.JobConfigs{ 1196 { 1197 Name: "some-job", 1198 }, 1199 }, 1200 } 1201 var err error 1202 pipeline, _, err = team.SavePipeline(atc.PipelineRef{Name: "some-pipeline"}, config, db.ConfigVersion(1), false) 1203 Expect(err).ToNot(HaveOccurred()) 1204 1205 job, found, err := pipeline.Job("some-job") 1206 Expect(err).ToNot(HaveOccurred()) 1207 Expect(found).To(BeTrue()) 1208 1209 for i := 3; i < 5; i++ { 1210 build, err := job.CreateBuild() 1211 Expect(err).ToNot(HaveOccurred()) 1212 allBuilds[i] = build 1213 pipelineBuilds[i-3] = build 1214 } 1215 }) 1216 1217 It("returns all team builds with correct pagination", func() { 1218 builds, pagination, err := team.PrivateAndPublicBuilds(db.Page{Limit: 2}) 1219 Expect(err).ToNot(HaveOccurred()) 1220 1221 Expect(len(builds)).To(Equal(2)) 1222 Expect(builds[0]).To(Equal(allBuilds[4])) 1223 Expect(builds[1]).To(Equal(allBuilds[3])) 1224 1225 Expect(pagination.Newer).To(BeNil()) 1226 Expect(pagination.Older).To(Equal(&db.Page{To: db.NewIntPtr(allBuilds[2].ID()), Limit: 2})) 1227 1228 builds, pagination, err = team.PrivateAndPublicBuilds(*pagination.Older) 1229 Expect(err).ToNot(HaveOccurred()) 1230 1231 Expect(len(builds)).To(Equal(2)) 1232 1233 Expect(builds[0]).To(Equal(allBuilds[2])) 1234 Expect(builds[1]).To(Equal(allBuilds[1])) 1235 1236 Expect(pagination.Newer).To(Equal(&db.Page{From: db.NewIntPtr(allBuilds[3].ID()), Limit: 2})) 1237 Expect(pagination.Older).To(Equal(&db.Page{To: db.NewIntPtr(allBuilds[0].ID()), Limit: 2})) 1238 1239 builds, pagination, err = team.PrivateAndPublicBuilds(*pagination.Older) 1240 Expect(err).ToNot(HaveOccurred()) 1241 1242 Expect(len(builds)).To(Equal(1)) 1243 Expect(builds[0]).To(Equal(allBuilds[0])) 1244 1245 Expect(pagination.Newer).To(Equal(&db.Page{From: db.NewIntPtr(allBuilds[1].ID()), Limit: 2})) 1246 Expect(pagination.Older).To(BeNil()) 1247 1248 builds, pagination, err = team.PrivateAndPublicBuilds(*pagination.Newer) 1249 Expect(err).ToNot(HaveOccurred()) 1250 1251 Expect(len(builds)).To(Equal(2)) 1252 Expect(builds[0]).To(Equal(allBuilds[2])) 1253 Expect(builds[1]).To(Equal(allBuilds[1])) 1254 Expect(pagination.Newer).To(Equal(&db.Page{From: db.NewIntPtr(allBuilds[3].ID()), Limit: 2})) 1255 Expect(pagination.Older).To(Equal(&db.Page{To: db.NewIntPtr(allBuilds[0].ID()), Limit: 2})) 1256 }) 1257 1258 Context("when there are builds that belong to different teams", func() { 1259 var teamABuilds [3]db.Build 1260 var teamBBuilds [3]db.Build 1261 1262 var caseInsensitiveTeamA db.Team 1263 var caseInsensitiveTeamB db.Team 1264 1265 BeforeEach(func() { 1266 _, err := teamFactory.CreateTeam(atc.Team{Name: "team-a"}) 1267 Expect(err).ToNot(HaveOccurred()) 1268 1269 _, err = teamFactory.CreateTeam(atc.Team{Name: "team-b"}) 1270 Expect(err).ToNot(HaveOccurred()) 1271 1272 var found bool 1273 caseInsensitiveTeamA, found, err = teamFactory.FindTeam("team-A") 1274 Expect(found).To(BeTrue()) 1275 Expect(err).ToNot(HaveOccurred()) 1276 1277 caseInsensitiveTeamB, found, err = teamFactory.FindTeam("team-B") 1278 Expect(found).To(BeTrue()) 1279 Expect(err).ToNot(HaveOccurred()) 1280 1281 for i := 0; i < 3; i++ { 1282 teamABuilds[i], err = caseInsensitiveTeamA.CreateOneOffBuild() 1283 Expect(err).ToNot(HaveOccurred()) 1284 1285 teamBBuilds[i], err = caseInsensitiveTeamB.CreateOneOffBuild() 1286 Expect(err).ToNot(HaveOccurred()) 1287 } 1288 }) 1289 1290 Context("when other team builds are private", func() { 1291 It("returns only builds for requested team", func() { 1292 builds, _, err := caseInsensitiveTeamA.PrivateAndPublicBuilds(db.Page{Limit: 10}) 1293 Expect(err).ToNot(HaveOccurred()) 1294 1295 Expect(len(builds)).To(Equal(3)) 1296 Expect(builds).To(ConsistOf(teamABuilds)) 1297 1298 builds, _, err = caseInsensitiveTeamB.PrivateAndPublicBuilds(db.Page{Limit: 10}) 1299 Expect(err).ToNot(HaveOccurred()) 1300 1301 Expect(len(builds)).To(Equal(3)) 1302 Expect(builds).To(ConsistOf(teamBBuilds)) 1303 }) 1304 }) 1305 1306 Context("when other team builds are public", func() { 1307 BeforeEach(func() { 1308 err := pipeline.Expose() 1309 Expect(err).ToNot(HaveOccurred()) 1310 }) 1311 1312 It("returns builds for requested team and public builds", func() { 1313 builds, _, err := caseInsensitiveTeamA.PrivateAndPublicBuilds(db.Page{Limit: 10}) 1314 Expect(err).ToNot(HaveOccurred()) 1315 1316 Expect(builds).To(HaveLen(5)) 1317 expectedBuilds := []db.Build{} 1318 for _, b := range teamABuilds { 1319 expectedBuilds = append(expectedBuilds, b) 1320 } 1321 for _, b := range pipelineBuilds { 1322 expectedBuilds = append(expectedBuilds, b) 1323 } 1324 Expect(builds).To(ConsistOf(expectedBuilds)) 1325 }) 1326 }) 1327 }) 1328 }) 1329 }) 1330 1331 Describe("BuildsWithTime", func() { 1332 var ( 1333 pipeline db.Pipeline 1334 builds = make([]db.Build, 4) 1335 ) 1336 1337 BeforeEach(func() { 1338 var ( 1339 err error 1340 found bool 1341 ) 1342 1343 config := atc.Config{ 1344 Jobs: atc.JobConfigs{ 1345 { 1346 Name: "some-job", 1347 }, 1348 { 1349 Name: "some-other-job", 1350 }, 1351 }, 1352 } 1353 pipeline, _, err = team.SavePipeline(atc.PipelineRef{Name: "some-pipeline"}, config, db.ConfigVersion(1), false) 1354 Expect(err).ToNot(HaveOccurred()) 1355 1356 job, found, err := pipeline.Job("some-job") 1357 Expect(err).ToNot(HaveOccurred()) 1358 Expect(found).To(BeTrue()) 1359 1360 for i := range builds { 1361 builds[i], err = job.CreateBuild() 1362 Expect(err).ToNot(HaveOccurred()) 1363 1364 buildStart := time.Date(2020, 11, i+1, 0, 0, 0, 0, time.UTC) 1365 _, err = dbConn.Exec("UPDATE builds SET start_time = to_timestamp($1) WHERE id = $2", buildStart.Unix(), builds[i].ID()) 1366 Expect(err).NotTo(HaveOccurred()) 1367 1368 builds[i], found, err = job.Build(builds[i].Name()) 1369 Expect(err).ToNot(HaveOccurred()) 1370 Expect(found).To(BeTrue()) 1371 } 1372 }) 1373 1374 Context("When not providing boundaries", func() { 1375 Context("without a limit specified", func() { 1376 It("returns no builds", func() { 1377 returnedBuilds, _, err := team.BuildsWithTime(db.Page{}) 1378 Expect(err).NotTo(HaveOccurred()) 1379 1380 Expect(returnedBuilds).To(BeEmpty()) 1381 }) 1382 }) 1383 1384 Context("when a limit specified", func() { 1385 It("returns a subset of the builds", func() { 1386 returnedBuilds, _, err := team.BuildsWithTime(db.Page{ 1387 Limit: 2, 1388 }) 1389 Expect(err).NotTo(HaveOccurred()) 1390 Expect(returnedBuilds).To(ConsistOf(builds[3], builds[2])) 1391 }) 1392 }) 1393 1394 }) 1395 1396 Context("When providing boundaries", func() { 1397 Context("only to", func() { 1398 It("returns only those before to", func() { 1399 returnedBuilds, _, err := team.BuildsWithTime(db.Page{ 1400 To: db.NewIntPtr(int(builds[2].StartTime().Unix())), 1401 Limit: 50, 1402 }) 1403 1404 Expect(err).NotTo(HaveOccurred()) 1405 Expect(returnedBuilds).To(ConsistOf(builds[0], builds[1], builds[2])) 1406 }) 1407 }) 1408 1409 Context("only from", func() { 1410 It("returns only those after from", func() { 1411 returnedBuilds, _, err := team.BuildsWithTime(db.Page{ 1412 From: db.NewIntPtr(int(builds[1].StartTime().Unix())), 1413 Limit: 50, 1414 }) 1415 1416 Expect(err).NotTo(HaveOccurred()) 1417 Expect(returnedBuilds).To(ConsistOf(builds[1], builds[2], builds[3])) 1418 }) 1419 }) 1420 1421 Context("from and to", func() { 1422 It("returns only elements in the range", func() { 1423 returnedBuilds, _, err := team.BuildsWithTime(db.Page{ 1424 From: db.NewIntPtr(int(builds[1].StartTime().Unix())), 1425 To: db.NewIntPtr(int(builds[2].StartTime().Unix())), 1426 Limit: 50, 1427 }) 1428 Expect(err).NotTo(HaveOccurred()) 1429 Expect(returnedBuilds).To(ConsistOf(builds[1], builds[2])) 1430 }) 1431 }) 1432 }) 1433 }) 1434 1435 Describe("Builds", func() { 1436 var ( 1437 expectedBuilds []db.Build 1438 pipeline db.Pipeline 1439 oneOffBuild, build, secondBuild, thirdBuild db.Build 1440 ) 1441 1442 BeforeEach(func() { 1443 var err error 1444 1445 oneOffBuild, err = team.CreateOneOffBuild() 1446 Expect(err).NotTo(HaveOccurred()) 1447 expectedBuilds = append(expectedBuilds, oneOffBuild) 1448 1449 config := atc.Config{ 1450 Jobs: atc.JobConfigs{ 1451 { 1452 Name: "some-job", 1453 }, 1454 { 1455 Name: "some-other-job", 1456 }, 1457 }, 1458 } 1459 pipeline, _, err = team.SavePipeline(atc.PipelineRef{Name: "some-pipeline"}, config, db.ConfigVersion(1), false) 1460 Expect(err).ToNot(HaveOccurred()) 1461 1462 job, found, err := pipeline.Job("some-job") 1463 Expect(err).ToNot(HaveOccurred()) 1464 Expect(found).To(BeTrue()) 1465 1466 build, err = job.CreateBuild() 1467 Expect(err).ToNot(HaveOccurred()) 1468 expectedBuilds = append(expectedBuilds, build) 1469 1470 secondBuild, err = job.CreateBuild() 1471 Expect(err).ToNot(HaveOccurred()) 1472 expectedBuilds = append(expectedBuilds, secondBuild) 1473 1474 someOtherJob, found, err := pipeline.Job("some-other-job") 1475 Expect(err).ToNot(HaveOccurred()) 1476 Expect(found).To(BeTrue()) 1477 1478 thirdBuild, err = someOtherJob.CreateBuild() 1479 Expect(err).ToNot(HaveOccurred()) 1480 expectedBuilds = append(expectedBuilds, thirdBuild) 1481 }) 1482 1483 It("returns builds for the current team", func() { 1484 builds, _, err := team.Builds(db.Page{Limit: 10}) 1485 Expect(err).NotTo(HaveOccurred()) 1486 Expect(builds).To(ConsistOf(expectedBuilds)) 1487 }) 1488 1489 Context("when limiting the range of build ids", func() { 1490 Context("specifying only from", func() { 1491 It("returns all builds after and including the specified id", func() { 1492 builds, _, err := team.Builds(db.Page{Limit: 50, From: db.NewIntPtr(secondBuild.ID())}) 1493 Expect(err).NotTo(HaveOccurred()) 1494 Expect(builds).To(ConsistOf(secondBuild, thirdBuild)) 1495 }) 1496 }) 1497 1498 Context("specifying only to", func() { 1499 It("returns all builds before and including the specified id", func() { 1500 builds, _, err := team.Builds(db.Page{Limit: 50, To: db.NewIntPtr(secondBuild.ID())}) 1501 Expect(err).NotTo(HaveOccurred()) 1502 Expect(builds).To(ConsistOf(oneOffBuild, build, secondBuild)) 1503 }) 1504 }) 1505 1506 Context("specifying both from and to", func() { 1507 It("returns all builds within range of ids", func() { 1508 builds, _, err := team.Builds(db.Page{Limit: 50, From: db.NewIntPtr(build.ID()), To: db.NewIntPtr(thirdBuild.ID())}) 1509 Expect(err).NotTo(HaveOccurred()) 1510 Expect(builds).To(ConsistOf(build, secondBuild, thirdBuild)) 1511 }) 1512 }) 1513 1514 Context("specifying from greater than the biggest ID in the database", func() { 1515 It("returns no rows error", func() { 1516 builds, _, err := team.Builds(db.Page{Limit: 50, From: db.NewIntPtr(thirdBuild.ID() + 1)}) 1517 Expect(err).ToNot(HaveOccurred()) 1518 Expect(builds).To(BeEmpty()) 1519 }) 1520 }) 1521 1522 Context("specifying invalid boundaries", func() { 1523 It("should fail", func() { 1524 _, _, err := team.Builds(db.Page{Limit: 50, From: db.NewIntPtr(thirdBuild.ID()), To: db.NewIntPtr(secondBuild.ID())}) 1525 Expect(err).To(HaveOccurred()) 1526 }) 1527 }) 1528 }) 1529 1530 Context("when there are builds that belong to different teams", func() { 1531 var teamABuilds [3]db.Build 1532 var teamBBuilds [3]db.Build 1533 1534 var caseInsensitiveTeamA db.Team 1535 var caseInsensitiveTeamB db.Team 1536 1537 BeforeEach(func() { 1538 _, err := teamFactory.CreateTeam(atc.Team{Name: "team-a"}) 1539 Expect(err).ToNot(HaveOccurred()) 1540 1541 _, err = teamFactory.CreateTeam(atc.Team{Name: "team-b"}) 1542 Expect(err).ToNot(HaveOccurred()) 1543 1544 var found bool 1545 caseInsensitiveTeamA, found, err = teamFactory.FindTeam("team-A") 1546 Expect(found).To(BeTrue()) 1547 Expect(err).ToNot(HaveOccurred()) 1548 1549 caseInsensitiveTeamB, found, err = teamFactory.FindTeam("team-B") 1550 Expect(found).To(BeTrue()) 1551 Expect(err).ToNot(HaveOccurred()) 1552 1553 for i := 0; i < 3; i++ { 1554 teamABuilds[i], err = caseInsensitiveTeamA.CreateOneOffBuild() 1555 Expect(err).ToNot(HaveOccurred()) 1556 1557 teamBBuilds[i], err = caseInsensitiveTeamB.CreateOneOffBuild() 1558 Expect(err).ToNot(HaveOccurred()) 1559 } 1560 }) 1561 1562 Context("when other team builds are private", func() { 1563 It("returns only builds for requested team", func() { 1564 builds, _, err := caseInsensitiveTeamA.Builds(db.Page{Limit: 10}) 1565 Expect(err).ToNot(HaveOccurred()) 1566 1567 Expect(len(builds)).To(Equal(3)) 1568 Expect(builds).To(ConsistOf(teamABuilds)) 1569 1570 builds, _, err = caseInsensitiveTeamB.Builds(db.Page{Limit: 10}) 1571 Expect(err).ToNot(HaveOccurred()) 1572 1573 Expect(len(builds)).To(Equal(3)) 1574 Expect(builds).To(ConsistOf(teamBBuilds)) 1575 }) 1576 }) 1577 1578 Context("when other team builds are public", func() { 1579 BeforeEach(func() { 1580 err := pipeline.Expose() 1581 Expect(err).ToNot(HaveOccurred()) 1582 }) 1583 1584 It("returns only builds for requested team", func() { 1585 builds, _, err := caseInsensitiveTeamA.Builds(db.Page{Limit: 10}) 1586 Expect(err).ToNot(HaveOccurred()) 1587 1588 Expect(len(builds)).To(Equal(3)) 1589 Expect(builds).To(ConsistOf(teamABuilds)) 1590 1591 builds, _, err = caseInsensitiveTeamB.Builds(db.Page{Limit: 10}) 1592 Expect(err).ToNot(HaveOccurred()) 1593 1594 Expect(len(builds)).To(Equal(3)) 1595 Expect(builds).To(ConsistOf(teamBBuilds)) 1596 }) 1597 }) 1598 }) 1599 }) 1600 1601 Describe("Pipeline", func() { 1602 Context("when the team has instanced pipelines configured", func() { 1603 var ( 1604 instancedPipelineRef atc.PipelineRef 1605 instancedPipeline db.Pipeline 1606 ) 1607 1608 BeforeEach(func() { 1609 var err error 1610 instancedPipelineRef = atc.PipelineRef{ 1611 Name: "fake-pipeline", 1612 InstanceVars: atc.InstanceVars{"branch": "feature"}, 1613 } 1614 instancedPipeline, _, err = team.SavePipeline(instancedPipelineRef, atc.Config{}, db.ConfigVersion(0), false) 1615 Expect(err).ToNot(HaveOccurred()) 1616 }) 1617 1618 It("returns the pipeline when requesting by name and instance vars", func() { 1619 pipeline, found, err := team.Pipeline(instancedPipelineRef) 1620 Expect(err).ToNot(HaveOccurred()) 1621 Expect(found).To(BeTrue()) 1622 Expect(pipeline).To(Equal(instancedPipeline)) 1623 }) 1624 1625 It("returns nothing when requesting by name only", func() { 1626 pipeline, found, err := team.Pipeline(atc.PipelineRef{Name: "fake-pipeline"}) 1627 Expect(err).ToNot(HaveOccurred()) 1628 Expect(found).To(BeFalse()) 1629 Expect(pipeline).To(BeNil()) 1630 }) 1631 1632 Context("when the team has instanced and named pipelines configured with the same name", func() { 1633 var ( 1634 namedPipelineRef atc.PipelineRef 1635 namedPipeline db.Pipeline 1636 ) 1637 1638 BeforeEach(func() { 1639 var err error 1640 namedPipelineRef = atc.PipelineRef{Name: "fake-pipeline"} 1641 namedPipeline, _, err = team.SavePipeline(namedPipelineRef, atc.Config{}, db.ConfigVersion(0), false) 1642 Expect(err).ToNot(HaveOccurred()) 1643 }) 1644 1645 It("returns the named pipeline when requesting with name only", func() { 1646 pipeline, found, err := team.Pipeline(namedPipelineRef) 1647 Expect(err).ToNot(HaveOccurred()) 1648 Expect(found).To(BeTrue()) 1649 Expect(pipeline).To(Equal(namedPipeline)) 1650 }) 1651 }) 1652 }) 1653 }) 1654 1655 Describe("SavePipeline", func() { 1656 type SerialGroup struct { 1657 JobID int 1658 Name string 1659 } 1660 1661 var ( 1662 config atc.Config 1663 otherConfig atc.Config 1664 pipelineRef atc.PipelineRef 1665 pipelineName string 1666 ) 1667 1668 BeforeEach(func() { 1669 config = atc.Config{ 1670 Groups: atc.GroupConfigs{ 1671 { 1672 Name: "some-group", 1673 Jobs: []string{"job-1", "job-2"}, 1674 Resources: []string{"resource-1", "resource-2"}, 1675 }, 1676 }, 1677 1678 Resources: atc.ResourceConfigs{ 1679 { 1680 Name: "some-resource", 1681 Type: "some-type", 1682 Source: atc.Source{ 1683 "source-config": "some-value", 1684 }, 1685 }, 1686 }, 1687 1688 ResourceTypes: atc.ResourceTypes{ 1689 { 1690 Name: "some-resource-type", 1691 Type: "some-type", 1692 Source: atc.Source{ 1693 "source-config": "some-value", 1694 }, 1695 }, 1696 }, 1697 1698 Jobs: atc.JobConfigs{ 1699 { 1700 Name: "some-job", 1701 1702 Public: true, 1703 1704 Serial: true, 1705 SerialGroups: []string{"serial-group-1", "serial-group-2"}, 1706 1707 PlanSequence: []atc.Step{ 1708 { 1709 Config: &atc.GetStep{ 1710 Name: "some-input", 1711 Resource: "some-resource", 1712 Params: atc.Params{ 1713 "some-param": "some-value", 1714 }, 1715 Passed: []string{"job-1", "job-2"}, 1716 Trigger: true, 1717 }, 1718 }, 1719 { 1720 Config: &atc.TaskStep{ 1721 Name: "some-task", 1722 Privileged: true, 1723 ConfigPath: "some/config/path.yml", 1724 Config: &atc.TaskConfig{ 1725 RootfsURI: "some-image", 1726 }, 1727 }, 1728 }, 1729 { 1730 Config: &atc.PutStep{ 1731 Name: "some-resource", 1732 Params: atc.Params{ 1733 "some-param": "some-value", 1734 }, 1735 }, 1736 }, 1737 }, 1738 }, 1739 { 1740 Name: "job-1", 1741 }, 1742 { 1743 Name: "job-2", 1744 }, 1745 }, 1746 } 1747 1748 otherConfig = atc.Config{ 1749 Groups: atc.GroupConfigs{ 1750 { 1751 Name: "some-group", 1752 Jobs: []string{"some-other-job", "job-1", "job-2"}, 1753 Resources: []string{"resource-1", "resource-2"}, 1754 }, 1755 }, 1756 1757 Resources: atc.ResourceConfigs{ 1758 { 1759 Name: "some-other-resource", 1760 Type: "some-type", 1761 Source: atc.Source{ 1762 "source-config": "some-value", 1763 }, 1764 }, 1765 }, 1766 1767 Jobs: atc.JobConfigs{ 1768 { 1769 Name: "some-other-job", 1770 }, 1771 }, 1772 } 1773 1774 pipelineName = "some-pipeline" 1775 pipelineRef = atc.PipelineRef{Name: pipelineName} 1776 }) 1777 1778 It("returns true for created", func() { 1779 _, created, err := team.SavePipeline(pipelineRef, config, 0, false) 1780 Expect(err).ToNot(HaveOccurred()) 1781 Expect(created).To(BeTrue()) 1782 }) 1783 1784 It("caches the team id", func() { 1785 _, _, err := team.SavePipeline(pipelineRef, config, 0, false) 1786 Expect(err).ToNot(HaveOccurred()) 1787 1788 pipeline, found, err := team.Pipeline(pipelineRef) 1789 Expect(err).ToNot(HaveOccurred()) 1790 Expect(found).To(BeTrue()) 1791 Expect(pipeline.TeamID()).To(Equal(team.ID())) 1792 }) 1793 1794 It("can be saved as paused", func() { 1795 _, _, err := team.SavePipeline(pipelineRef, config, 0, true) 1796 Expect(err).ToNot(HaveOccurred()) 1797 1798 pipeline, found, err := team.Pipeline(pipelineRef) 1799 Expect(err).ToNot(HaveOccurred()) 1800 Expect(found).To(BeTrue()) 1801 1802 Expect(pipeline.Paused()).To(BeTrue()) 1803 }) 1804 1805 It("can be saved as unpaused", func() { 1806 _, _, err := team.SavePipeline(pipelineRef, config, 0, false) 1807 Expect(err).ToNot(HaveOccurred()) 1808 1809 pipeline, found, err := team.Pipeline(pipelineRef) 1810 Expect(err).ToNot(HaveOccurred()) 1811 Expect(found).To(BeTrue()) 1812 1813 Expect(pipeline.Paused()).To(BeFalse()) 1814 }) 1815 1816 It("is not archived by default", func() { 1817 _, _, err := team.SavePipeline(pipelineRef, config, 0, true) 1818 Expect(err).ToNot(HaveOccurred()) 1819 1820 pipeline, found, err := team.Pipeline(pipelineRef) 1821 Expect(err).ToNot(HaveOccurred()) 1822 Expect(found).To(BeTrue()) 1823 1824 Expect(pipeline.Archived()).To(BeFalse()) 1825 }) 1826 1827 It("requests schedule on the pipeline", func() { 1828 requestedPipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 1829 Expect(err).ToNot(HaveOccurred()) 1830 1831 otherPipeline, _, err := team.SavePipeline(atc.PipelineRef{Name: "other-pipeline"}, otherConfig, 0, false) 1832 Expect(err).ToNot(HaveOccurred()) 1833 1834 requestedJob, found, err := requestedPipeline.Job("some-job") 1835 Expect(err).ToNot(HaveOccurred()) 1836 Expect(found).To(BeTrue()) 1837 1838 otherJob, found, err := otherPipeline.Job("some-other-job") 1839 Expect(err).ToNot(HaveOccurred()) 1840 Expect(found).To(BeTrue()) 1841 1842 requestedSchedule1 := requestedJob.ScheduleRequestedTime() 1843 requestedSchedule2 := otherJob.ScheduleRequestedTime() 1844 1845 config.Resources[0].Source = atc.Source{ 1846 "source-other-config": "some-other-value", 1847 } 1848 1849 _, _, err = team.SavePipeline(pipelineRef, config, requestedPipeline.ConfigVersion(), false) 1850 Expect(err).ToNot(HaveOccurred()) 1851 1852 found, err = requestedJob.Reload() 1853 Expect(err).ToNot(HaveOccurred()) 1854 Expect(found).To(BeTrue()) 1855 1856 found, err = otherJob.Reload() 1857 Expect(err).ToNot(HaveOccurred()) 1858 Expect(found).To(BeTrue()) 1859 1860 Expect(requestedJob.ScheduleRequestedTime()).Should(BeTemporally(">", requestedSchedule1)) 1861 Expect(otherJob.ScheduleRequestedTime()).Should(BeTemporally("==", requestedSchedule2)) 1862 }) 1863 1864 It("creates all of the resources from the pipeline in the database", func() { 1865 savedPipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 1866 Expect(err).ToNot(HaveOccurred()) 1867 1868 resource, found, err := savedPipeline.Resource("some-resource") 1869 Expect(err).ToNot(HaveOccurred()) 1870 Expect(found).To(BeTrue()) 1871 Expect(resource.Type()).To(Equal("some-type")) 1872 Expect(resource.Source()).To(Equal(atc.Source{ 1873 "source-config": "some-value", 1874 })) 1875 }) 1876 1877 It("updates resource config", func() { 1878 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 1879 Expect(err).ToNot(HaveOccurred()) 1880 1881 config.Resources[0].Source = atc.Source{ 1882 "source-other-config": "some-other-value", 1883 } 1884 1885 savedPipeline, _, err := team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 1886 Expect(err).ToNot(HaveOccurred()) 1887 1888 resource, found, err := savedPipeline.Resource("some-resource") 1889 Expect(err).ToNot(HaveOccurred()) 1890 Expect(found).To(BeTrue()) 1891 Expect(resource.Type()).To(Equal("some-type")) 1892 Expect(resource.Source()).To(Equal(atc.Source{ 1893 "source-other-config": "some-other-value", 1894 })) 1895 }) 1896 1897 It("clears out api pinned version when resaving a pinned version on the pipeline config", func() { 1898 scenario := dbtest.Setup( 1899 builder.WithPipeline(config), 1900 builder.WithBaseResourceType(dbConn, "some-type"), 1901 builder.WithResourceVersions( 1902 "some-resource", 1903 atc.Version{"version": "v1"}, 1904 atc.Version{"version": "v2"}, 1905 ), 1906 builder.WithPinnedVersion("some-resource", atc.Version{"version": "v1"}), 1907 ) 1908 1909 Expect(scenario.Resource("some-resource").APIPinnedVersion()).To(Equal(atc.Version{"version": "v1"})) 1910 1911 config.Resources[0].Version = atc.Version{ 1912 "version": "v2", 1913 } 1914 1915 scenario.Run( 1916 builder.WithPipeline(config), 1917 ) 1918 1919 Expect(scenario.Resource("some-resource").ConfigPinnedVersion()).To(Equal(atc.Version{"version": "v2"})) 1920 Expect(scenario.Resource("some-resource").APIPinnedVersion()).To(BeNil()) 1921 }) 1922 1923 It("clears out config pinned version when it is removed", func() { 1924 config.Resources[0].Version = atc.Version{ 1925 "version": "v1", 1926 } 1927 1928 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 1929 Expect(err).ToNot(HaveOccurred()) 1930 1931 resource, found, err := pipeline.Resource("some-resource") 1932 Expect(err).ToNot(HaveOccurred()) 1933 Expect(found).To(BeTrue()) 1934 Expect(resource.ConfigPinnedVersion()).To(Equal(atc.Version{"version": "v1"})) 1935 Expect(resource.APIPinnedVersion()).To(BeNil()) 1936 1937 config.Resources[0].Version = nil 1938 1939 savedPipeline, _, err := team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 1940 Expect(err).ToNot(HaveOccurred()) 1941 1942 resource, found, err = savedPipeline.Resource("some-resource") 1943 Expect(err).ToNot(HaveOccurred()) 1944 Expect(found).To(BeTrue()) 1945 Expect(resource.ConfigPinnedVersion()).To(BeNil()) 1946 Expect(resource.APIPinnedVersion()).To(BeNil()) 1947 }) 1948 1949 It("does not clear the api pinned version when resaving pipeline config", func() { 1950 scenario := dbtest.Setup( 1951 builder.WithPipeline(config), 1952 builder.WithBaseResourceType(dbConn, "some-type"), 1953 builder.WithResourceVersions( 1954 "some-resource", 1955 atc.Version{"version": "v1"}, 1956 atc.Version{"version": "v2"}, 1957 ), 1958 builder.WithPinnedVersion("some-resource", atc.Version{"version": "v1"}), 1959 ) 1960 1961 Expect(scenario.Resource("some-resource").APIPinnedVersion()).To(Equal(atc.Version{"version": "v1"})) 1962 1963 scenario.Run( 1964 builder.WithPipeline(config), 1965 ) 1966 1967 Expect(scenario.Resource("some-resource").APIPinnedVersion()).To(Equal(atc.Version{"version": "v1"})) 1968 }) 1969 1970 It("marks resource as inactive if it is no longer in config", func() { 1971 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 1972 Expect(err).ToNot(HaveOccurred()) 1973 1974 config.Resources = []atc.ResourceConfig{} 1975 config.Jobs = atc.JobConfigs{ 1976 { 1977 Name: "some-job", 1978 1979 Public: true, 1980 1981 Serial: true, 1982 SerialGroups: []string{"serial-group-1", "serial-group-2"}, 1983 1984 PlanSequence: []atc.Step{ 1985 { 1986 Config: &atc.TaskStep{ 1987 Name: "some-task", 1988 Privileged: true, 1989 ConfigPath: "some/config/path.yml", 1990 Config: &atc.TaskConfig{ 1991 RootfsURI: "some-image", 1992 }, 1993 }, 1994 }, 1995 { 1996 Config: &atc.PutStep{ 1997 Name: "some-resource", 1998 Params: atc.Params{ 1999 "some-param": "some-value", 2000 }, 2001 }, 2002 }, 2003 }, 2004 }, 2005 { 2006 Name: "job-1", 2007 }, 2008 { 2009 Name: "job-2", 2010 }, 2011 } 2012 config.Resources = atc.ResourceConfigs{ 2013 { 2014 Name: "some-resource", 2015 Type: "some-type", 2016 }, 2017 } 2018 2019 savedPipeline, _, err := team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2020 Expect(err).ToNot(HaveOccurred()) 2021 2022 _, found, err := savedPipeline.Resource("some-other-resource") 2023 Expect(err).ToNot(HaveOccurred()) 2024 Expect(found).To(BeFalse()) 2025 }) 2026 2027 It("creates all of the resource types from the pipeline in the database", func() { 2028 savedPipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2029 Expect(err).ToNot(HaveOccurred()) 2030 2031 resourceType, found, err := savedPipeline.ResourceType("some-resource-type") 2032 Expect(err).ToNot(HaveOccurred()) 2033 Expect(found).To(BeTrue()) 2034 Expect(resourceType.Type()).To(Equal("some-type")) 2035 Expect(resourceType.Source()).To(Equal(atc.Source{ 2036 "source-config": "some-value", 2037 })) 2038 }) 2039 2040 It("updates resource type config from the pipeline in the database", func() { 2041 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2042 Expect(err).ToNot(HaveOccurred()) 2043 2044 config.ResourceTypes[0].Source = atc.Source{ 2045 "source-other-config": "some-other-value", 2046 } 2047 2048 savedPipeline, _, err := team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2049 Expect(err).ToNot(HaveOccurred()) 2050 2051 resourceType, found, err := savedPipeline.ResourceType("some-resource-type") 2052 Expect(err).ToNot(HaveOccurred()) 2053 Expect(found).To(BeTrue()) 2054 Expect(resourceType.Type()).To(Equal("some-type")) 2055 Expect(resourceType.Source()).To(Equal(atc.Source{ 2056 "source-other-config": "some-other-value", 2057 })) 2058 }) 2059 2060 It("marks resource type as inactive if it is no longer in config", func() { 2061 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2062 Expect(err).ToNot(HaveOccurred()) 2063 2064 config.ResourceTypes = []atc.ResourceType{} 2065 2066 savedPipeline, _, err := team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2067 Expect(err).ToNot(HaveOccurred()) 2068 2069 _, found, err := savedPipeline.ResourceType("some-resource-type") 2070 Expect(err).ToNot(HaveOccurred()) 2071 Expect(found).To(BeFalse()) 2072 }) 2073 2074 It("creates all of the jobs from the pipeline in the database", func() { 2075 savedPipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2076 Expect(err).ToNot(HaveOccurred()) 2077 2078 job, found, err := savedPipeline.Job("some-job") 2079 Expect(err).ToNot(HaveOccurred()) 2080 Expect(found).To(BeTrue()) 2081 Expect(job.Config()).To(Equal(config.Jobs[0])) 2082 }) 2083 2084 It("updates job config", func() { 2085 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2086 Expect(err).ToNot(HaveOccurred()) 2087 2088 config.Jobs[0].Public = false 2089 2090 _, _, err = team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2091 Expect(err).ToNot(HaveOccurred()) 2092 2093 job, found, err := pipeline.Job("some-job") 2094 Expect(err).ToNot(HaveOccurred()) 2095 Expect(found).To(BeTrue()) 2096 Expect(job.Public()).To(BeFalse()) 2097 }) 2098 2099 It("marks job inactive when it is no longer in pipeline", func() { 2100 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2101 Expect(err).ToNot(HaveOccurred()) 2102 2103 config.Jobs = []atc.JobConfig{} 2104 2105 savedPipeline, _, err := team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2106 Expect(err).ToNot(HaveOccurred()) 2107 2108 _, found, err := savedPipeline.Job("some-job") 2109 Expect(err).ToNot(HaveOccurred()) 2110 Expect(found).To(BeFalse()) 2111 }) 2112 2113 Context("update job names but keeps history", func() { 2114 BeforeEach(func() { 2115 newJobConfig := atc.JobConfig{ 2116 Name: "new-job", 2117 2118 Public: true, 2119 2120 Serial: true, 2121 SerialGroups: []string{"serial-group-1", "serial-group-2"}, 2122 2123 PlanSequence: []atc.Step{ 2124 { 2125 Config: &atc.GetStep{ 2126 Name: "some-input", 2127 Resource: "some-resource", 2128 Params: atc.Params{ 2129 "some-param": "some-value", 2130 }, 2131 Passed: []string{"job-1", "job-2"}, 2132 Trigger: true, 2133 }, 2134 }, 2135 { 2136 Config: &atc.TaskStep{ 2137 Name: "some-task", 2138 ConfigPath: "some/config/path.yml", 2139 }, 2140 }, 2141 { 2142 Config: &atc.PutStep{ 2143 Name: "some-resource", 2144 Params: atc.Params{ 2145 "some-param": "some-value", 2146 }, 2147 }, 2148 }, 2149 { 2150 Config: &atc.DoStep{ 2151 Steps: []atc.Step{ 2152 { 2153 Config: &atc.TaskStep{ 2154 Name: "some-nested-task", 2155 ConfigPath: "some/config/path.yml", 2156 }, 2157 }, 2158 }, 2159 }, 2160 }, 2161 }, 2162 } 2163 2164 config.Jobs = append(config.Jobs, newJobConfig) 2165 }) 2166 2167 It("should handle when there are multiple name changes", func() { 2168 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2169 Expect(err).ToNot(HaveOccurred()) 2170 2171 job, _, _ := pipeline.Job("some-job") 2172 otherJob, _, _ := pipeline.Job("new-job") 2173 2174 config.Jobs[0].Name = "new-job" 2175 config.Jobs[0].OldName = "some-job" 2176 2177 config.Jobs[3].Name = "new-other-job" 2178 config.Jobs[3].OldName = "new-job" 2179 2180 updatedPipeline, _, err := team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2181 Expect(err).ToNot(HaveOccurred()) 2182 2183 updatedJob, _, _ := updatedPipeline.Job("new-job") 2184 Expect(updatedJob.ID()).To(Equal(job.ID())) 2185 2186 otherUpdatedJob, _, _ := updatedPipeline.Job("new-other-job") 2187 Expect(otherUpdatedJob.ID()).To(Equal(otherJob.ID())) 2188 }) 2189 2190 It("should handle when old job has the same name as new job", func() { 2191 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2192 Expect(err).ToNot(HaveOccurred()) 2193 2194 job, _, _ := pipeline.Job("some-job") 2195 2196 config.Jobs[0].Name = "some-job" 2197 config.Jobs[0].OldName = "some-job" 2198 2199 updatedPipeline, _, err := team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2200 Expect(err).ToNot(HaveOccurred()) 2201 2202 updatedJob, _, _ := updatedPipeline.Job("some-job") 2203 Expect(updatedJob.ID()).To(Equal(job.ID())) 2204 }) 2205 2206 It("should return an error when there is a swap with job name", func() { 2207 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2208 Expect(err).ToNot(HaveOccurred()) 2209 2210 config.Jobs[0].Name = "new-job" 2211 config.Jobs[0].OldName = "some-job" 2212 2213 config.Jobs[1].Name = "some-job" 2214 config.Jobs[1].OldName = "new-job" 2215 2216 _, _, err = team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2217 Expect(err).To(HaveOccurred()) 2218 }) 2219 2220 Context("when new job name is in database but is inactive", func() { 2221 It("should successfully update job name", func() { 2222 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2223 Expect(err).ToNot(HaveOccurred()) 2224 2225 config.Jobs = config.Jobs[:len(config.Jobs)-1] 2226 2227 _, _, err = team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2228 Expect(err).ToNot(HaveOccurred()) 2229 2230 config.Jobs[0].Name = "new-job" 2231 config.Jobs[0].OldName = "some-job" 2232 2233 _, _, err = team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion()+1, false) 2234 Expect(err).ToNot(HaveOccurred()) 2235 }) 2236 }) 2237 }) 2238 2239 Context("update resource names but keeps data", func() { 2240 2241 BeforeEach(func() { 2242 2243 config.Resources = append(config.Resources, atc.ResourceConfig{ 2244 Name: "new-resource", 2245 Type: "some-type", 2246 Source: atc.Source{ 2247 "source-config": "some-value", 2248 }, 2249 }) 2250 }) 2251 2252 It("should successfully update resource name", func() { 2253 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2254 Expect(err).ToNot(HaveOccurred()) 2255 2256 resource, _, _ := pipeline.Resource("some-resource") 2257 2258 config.Resources[0].Name = "renamed-resource" 2259 config.Resources[0].OldName = "some-resource" 2260 2261 config.Jobs[0].PlanSequence = []atc.Step{ 2262 { 2263 Config: &atc.GetStep{ 2264 Name: "some-input", 2265 Resource: "renamed-resource", 2266 Params: atc.Params{ 2267 "some-param": "some-value", 2268 }, 2269 Passed: []string{"job-1", "job-2"}, 2270 Trigger: true, 2271 }, 2272 }, 2273 } 2274 2275 updatedPipeline, _, err := team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2276 Expect(err).ToNot(HaveOccurred()) 2277 2278 updatedResource, _, _ := updatedPipeline.Resource("renamed-resource") 2279 Expect(updatedResource.ID()).To(Equal(resource.ID())) 2280 }) 2281 2282 It("should handle when there are multiple name changes", func() { 2283 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2284 Expect(err).ToNot(HaveOccurred()) 2285 2286 resource, _, _ := pipeline.Resource("some-resource") 2287 otherResource, _, _ := pipeline.Resource("new-resource") 2288 2289 config.Resources[0].Name = "new-resource" 2290 config.Resources[0].OldName = "some-resource" 2291 2292 config.Resources[1].Name = "new-other-resource" 2293 config.Resources[1].OldName = "new-resource" 2294 2295 config.Jobs[0].PlanSequence = []atc.Step{ 2296 { 2297 Config: &atc.GetStep{ 2298 Name: "some-input", 2299 Resource: "new-resource", 2300 Params: atc.Params{ 2301 "some-param": "some-value", 2302 }, 2303 Passed: []string{"job-1", "job-2"}, 2304 Trigger: true, 2305 }, 2306 }, 2307 } 2308 2309 updatedPipeline, _, err := team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2310 Expect(err).ToNot(HaveOccurred()) 2311 2312 updatedResource, _, _ := updatedPipeline.Resource("new-resource") 2313 Expect(updatedResource.ID()).To(Equal(resource.ID())) 2314 2315 otherUpdatedResource, _, _ := updatedPipeline.Resource("new-other-resource") 2316 Expect(otherUpdatedResource.ID()).To(Equal(otherResource.ID())) 2317 }) 2318 2319 It("should handle when old resource has the same name as new resource", func() { 2320 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2321 Expect(err).ToNot(HaveOccurred()) 2322 2323 resource, _, _ := pipeline.Resource("some-resource") 2324 2325 config.Resources[0].Name = "some-resource" 2326 config.Resources[0].OldName = "some-resource" 2327 2328 updatedPipeline, _, err := team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2329 Expect(err).ToNot(HaveOccurred()) 2330 2331 updatedResource, _, _ := updatedPipeline.Resource("some-resource") 2332 Expect(updatedResource.ID()).To(Equal(resource.ID())) 2333 }) 2334 2335 It("should return an error when there is a swap with resource name", func() { 2336 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2337 Expect(err).ToNot(HaveOccurred()) 2338 2339 config.Resources[0].Name = "new-resource" 2340 config.Resources[0].OldName = "some-resource" 2341 2342 config.Resources[1].Name = "some-resource" 2343 config.Resources[1].OldName = "new-resource" 2344 2345 _, _, err = team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2346 Expect(err).To(HaveOccurred()) 2347 }) 2348 2349 Context("when new resource exists but is disabled", func() { 2350 var scenario *dbtest.Scenario 2351 var resource db.Resource 2352 2353 BeforeEach(func() { 2354 scenario = dbtest.Setup( 2355 builder.WithPipeline(config), 2356 builder.WithBaseResourceType(dbConn, "some-type"), 2357 builder.WithDisabledVersion("some-resource", atc.Version{"disabled": "version"}), 2358 ) 2359 2360 versions, _, found, err := scenario.Resource("some-resource").Versions(db.Page{Limit: 3}, nil) 2361 Expect(err).ToNot(HaveOccurred()) 2362 Expect(found).To(BeTrue()) 2363 Expect(versions).To(HaveLen(1)) 2364 Expect(versions[0].Version).To(Equal(atc.Version{"disabled": "version"})) 2365 Expect(versions[0].Enabled).To(BeFalse()) 2366 2367 resource = scenario.Resource("some-resource") 2368 }) 2369 2370 It("should not change the disabled version", func() { 2371 config.Resources[0].Name = "disabled-resource" 2372 config.Resources[0].OldName = "some-resource" 2373 config.Jobs[0].PlanSequence = []atc.Step{ 2374 { 2375 Config: &atc.GetStep{ 2376 Name: "some-input", 2377 Resource: "disabled-resource", 2378 Params: atc.Params{ 2379 "some-param": "some-value", 2380 }, 2381 Passed: []string{"job-1", "job-2"}, 2382 Trigger: true, 2383 }, 2384 }, 2385 } 2386 2387 scenario.Run( 2388 builder.WithPipeline(config), 2389 ) 2390 2391 updatedResource := scenario.Resource("disabled-resource") 2392 Expect(updatedResource.ID()).To(Equal(resource.ID())) 2393 2394 versions, _, found, err := updatedResource.Versions(db.Page{Limit: 3}, nil) 2395 Expect(err).ToNot(HaveOccurred()) 2396 Expect(found).To(BeTrue()) 2397 Expect(versions).To(HaveLen(1)) 2398 Expect(versions[0].Version).To(Equal(atc.Version{"disabled": "version"})) 2399 Expect(versions[0].Enabled).To(BeFalse()) 2400 }) 2401 }) 2402 2403 Context("when new resource exists but the version is pinned", func() { 2404 var scenario *dbtest.Scenario 2405 var resource db.Resource 2406 2407 BeforeEach(func() { 2408 scenario = dbtest.Setup( 2409 builder.WithPipeline(config), 2410 builder.WithBaseResourceType(dbConn, "some-type"), 2411 builder.WithResourceVersions( 2412 "some-resource", 2413 atc.Version{"version": "v1"}, 2414 atc.Version{"version": "v2"}, 2415 atc.Version{"version": "v3"}, 2416 ), 2417 builder.WithPinnedVersion("some-resource", atc.Version{"version": "v1"}), 2418 ) 2419 2420 resource = scenario.Resource("some-resource") 2421 }) 2422 2423 It("should not change the pinned version", func() { 2424 config.Resources[0].Name = "pinned-resource" 2425 config.Resources[0].OldName = "some-resource" 2426 config.Jobs[0].PlanSequence = []atc.Step{ 2427 { 2428 Config: &atc.GetStep{ 2429 Name: "some-input", 2430 Resource: "pinned-resource", 2431 Params: atc.Params{ 2432 "some-param": "some-value", 2433 }, 2434 Passed: []string{"job-1", "job-2"}, 2435 Trigger: true, 2436 }, 2437 }, 2438 } 2439 2440 scenario.Run( 2441 builder.WithPipeline(config), 2442 ) 2443 2444 updatedResource := scenario.Resource("pinned-resource") 2445 Expect(updatedResource.ID()).To(Equal(resource.ID())) 2446 Expect(updatedResource.APIPinnedVersion()).To(Equal(atc.Version{"version": "v1"})) 2447 }) 2448 }) 2449 }) 2450 2451 It("removes task caches for jobs that are no longer in pipeline", func() { 2452 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2453 Expect(err).ToNot(HaveOccurred()) 2454 2455 job, found, err := pipeline.Job("some-job") 2456 Expect(err).ToNot(HaveOccurred()) 2457 Expect(found).To(BeTrue()) 2458 2459 _, err = taskCacheFactory.FindOrCreate(job.ID(), "some-task", "some-path") 2460 Expect(err).ToNot(HaveOccurred()) 2461 2462 _, found, err = taskCacheFactory.Find(job.ID(), "some-task", "some-path") 2463 Expect(err).ToNot(HaveOccurred()) 2464 Expect(found).To(BeTrue()) 2465 2466 _, err = taskCacheFactory.FindOrCreate(job.ID(), "some-nested-task", "some-path") 2467 Expect(err).ToNot(HaveOccurred()) 2468 2469 _, found, err = taskCacheFactory.Find(job.ID(), "some-nested-task", "some-path") 2470 Expect(err).ToNot(HaveOccurred()) 2471 Expect(found).To(BeTrue()) 2472 2473 config.Jobs = []atc.JobConfig{} 2474 2475 _, _, err = team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2476 Expect(err).ToNot(HaveOccurred()) 2477 2478 _, found, err = taskCacheFactory.Find(job.ID(), "some-task", "some-path") 2479 Expect(err).ToNot(HaveOccurred()) 2480 Expect(found).To(BeFalse()) 2481 2482 _, found, err = taskCacheFactory.Find(job.ID(), "some-nested-task", "some-path") 2483 Expect(err).ToNot(HaveOccurred()) 2484 Expect(found).To(BeFalse()) 2485 }) 2486 2487 It("removes task caches for tasks that are no longer exist", func() { 2488 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2489 Expect(err).ToNot(HaveOccurred()) 2490 2491 job, found, err := pipeline.Job("some-job") 2492 Expect(err).ToNot(HaveOccurred()) 2493 Expect(found).To(BeTrue()) 2494 2495 _, err = taskCacheFactory.FindOrCreate(job.ID(), "some-task", "some-path") 2496 Expect(err).ToNot(HaveOccurred()) 2497 2498 _, found, err = taskCacheFactory.Find(job.ID(), "some-task", "some-path") 2499 Expect(err).ToNot(HaveOccurred()) 2500 Expect(found).To(BeTrue()) 2501 2502 _, err = taskCacheFactory.FindOrCreate(job.ID(), "some-nested-task", "some-path") 2503 Expect(err).ToNot(HaveOccurred()) 2504 2505 _, found, err = taskCacheFactory.Find(job.ID(), "some-nested-task", "some-path") 2506 Expect(err).ToNot(HaveOccurred()) 2507 Expect(found).To(BeTrue()) 2508 2509 config.Jobs = []atc.JobConfig{ 2510 { 2511 Name: "some-job", 2512 PlanSequence: []atc.Step{ 2513 { 2514 Config: &atc.TaskStep{ 2515 Name: "some-other-task", 2516 ConfigPath: "some/config/path.yml", 2517 }, 2518 }, 2519 }, 2520 }, 2521 } 2522 2523 _, _, err = team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2524 Expect(err).ToNot(HaveOccurred()) 2525 2526 _, found, err = taskCacheFactory.Find(job.ID(), "some-task", "some-path") 2527 Expect(err).ToNot(HaveOccurred()) 2528 Expect(found).To(BeFalse()) 2529 2530 _, found, err = taskCacheFactory.Find(job.ID(), "some-nested-task", "some-path") 2531 Expect(err).ToNot(HaveOccurred()) 2532 Expect(found).To(BeFalse()) 2533 }) 2534 2535 It("should not remove task caches in other pipeline", func() { 2536 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2537 Expect(err).ToNot(HaveOccurred()) 2538 2539 otherPipeline, _, err := team.SavePipeline(atc.PipelineRef{Name: "other-pipeline"}, config, 0, false) 2540 Expect(err).ToNot(HaveOccurred()) 2541 2542 job, found, err := pipeline.Job("some-job") 2543 Expect(err).ToNot(HaveOccurred()) 2544 Expect(found).To(BeTrue()) 2545 2546 _, err = taskCacheFactory.FindOrCreate(job.ID(), "some-task", "some-path") 2547 Expect(err).ToNot(HaveOccurred()) 2548 2549 _, found, err = taskCacheFactory.Find(job.ID(), "some-task", "some-path") 2550 Expect(err).ToNot(HaveOccurred()) 2551 Expect(found).To(BeTrue()) 2552 2553 otherJob, found, err := otherPipeline.Job("some-job") 2554 Expect(err).ToNot(HaveOccurred()) 2555 Expect(found).To(BeTrue()) 2556 2557 _, err = taskCacheFactory.FindOrCreate(otherJob.ID(), "some-task", "some-path") 2558 Expect(err).ToNot(HaveOccurred()) 2559 2560 _, found, err = taskCacheFactory.Find(otherJob.ID(), "some-task", "some-path") 2561 Expect(err).ToNot(HaveOccurred()) 2562 Expect(found).To(BeTrue()) 2563 2564 config.Jobs = []atc.JobConfig{ 2565 { 2566 Name: "some-job", 2567 PlanSequence: []atc.Step{ 2568 { 2569 Config: &atc.TaskStep{ 2570 Name: "some-other-task", 2571 ConfigPath: "some/config/path.yml", 2572 }, 2573 }, 2574 }, 2575 }, 2576 } 2577 2578 _, _, err = team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2579 Expect(err).ToNot(HaveOccurred()) 2580 2581 _, found, err = taskCacheFactory.Find(job.ID(), "some-task", "some-path") 2582 Expect(err).ToNot(HaveOccurred()) 2583 Expect(found).To(BeFalse()) 2584 2585 _, found, err = taskCacheFactory.Find(otherJob.ID(), "some-task", "some-path") 2586 Expect(err).ToNot(HaveOccurred()) 2587 Expect(found).To(BeTrue()) 2588 }) 2589 2590 It("creates all of the serial groups from the jobs in the database", func() { 2591 savedPipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2592 Expect(err).ToNot(HaveOccurred()) 2593 2594 serialGroups := []SerialGroup{} 2595 rows, err := dbConn.Query("SELECT job_id, serial_group FROM jobs_serial_groups") 2596 Expect(err).ToNot(HaveOccurred()) 2597 2598 for rows.Next() { 2599 var serialGroup SerialGroup 2600 err = rows.Scan(&serialGroup.JobID, &serialGroup.Name) 2601 Expect(err).ToNot(HaveOccurred()) 2602 serialGroups = append(serialGroups, serialGroup) 2603 } 2604 2605 job, found, err := savedPipeline.Job("some-job") 2606 Expect(err).ToNot(HaveOccurred()) 2607 Expect(found).To(BeTrue()) 2608 2609 Expect(serialGroups).To(ConsistOf([]SerialGroup{ 2610 { 2611 JobID: job.ID(), 2612 Name: "serial-group-1", 2613 }, 2614 { 2615 JobID: job.ID(), 2616 Name: "serial-group-2", 2617 }, 2618 })) 2619 }) 2620 2621 It("saves tags in the jobs table", func() { 2622 savedPipeline, _, err := team.SavePipeline(pipelineRef, otherConfig, 0, false) 2623 Expect(err).ToNot(HaveOccurred()) 2624 2625 job, found, err := savedPipeline.Job("some-other-job") 2626 Expect(err).ToNot(HaveOccurred()) 2627 Expect(found).To(BeTrue()) 2628 2629 Expect(job.Tags()).To(Equal([]string{"some-group"})) 2630 }) 2631 2632 It("saves tags in the jobs table based on globs", func() { 2633 otherConfig.Groups[0].Jobs = []string{"*-other-job"} 2634 savedPipeline, _, err := team.SavePipeline(pipelineRef, otherConfig, 0, false) 2635 Expect(err).ToNot(HaveOccurred()) 2636 2637 job, found, err := savedPipeline.Job("some-other-job") 2638 Expect(err).ToNot(HaveOccurred()) 2639 Expect(found).To(BeTrue()) 2640 2641 Expect(job.Tags()).To(Equal([]string{"some-group"})) 2642 }) 2643 2644 It("updates tags in the jobs table", func() { 2645 savedPipeline, _, err := team.SavePipeline(pipelineRef, otherConfig, 0, false) 2646 Expect(err).ToNot(HaveOccurred()) 2647 2648 job, found, err := savedPipeline.Job("some-other-job") 2649 Expect(err).ToNot(HaveOccurred()) 2650 Expect(found).To(BeTrue()) 2651 2652 Expect(job.Tags()).To(Equal([]string{"some-group"})) 2653 2654 otherConfig.Groups = atc.GroupConfigs{ 2655 { 2656 Name: "some-other-group", 2657 Jobs: []string{"job-1", "job-2", "some-other-job"}, 2658 }, 2659 { 2660 Name: "some-another-group", 2661 Jobs: []string{"*-other-job"}, 2662 }, 2663 } 2664 2665 savedPipeline, _, err = team.SavePipeline(pipelineRef, otherConfig, savedPipeline.ConfigVersion(), false) 2666 Expect(err).ToNot(HaveOccurred()) 2667 2668 job, found, err = savedPipeline.Job("some-other-job") 2669 Expect(err).ToNot(HaveOccurred()) 2670 Expect(found).To(BeTrue()) 2671 2672 Expect(job.Tags()).To(ConsistOf([]string{"some-another-group", "some-other-group"})) 2673 }) 2674 2675 It("it returns created as false when updated", func() { 2676 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 2677 Expect(err).ToNot(HaveOccurred()) 2678 2679 _, created, err := team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2680 Expect(err).ToNot(HaveOccurred()) 2681 Expect(created).To(BeFalse()) 2682 }) 2683 2684 It("deletes old job pipes and inserts new ones", func() { 2685 config = atc.Config{ 2686 Groups: atc.GroupConfigs{ 2687 { 2688 Name: "some-group", 2689 Jobs: []string{"job-1", "job-2"}, 2690 Resources: []string{"resource-1", "resource-2"}, 2691 }, 2692 }, 2693 2694 Resources: atc.ResourceConfigs{ 2695 { 2696 Name: "some-resource", 2697 Type: "some-type", 2698 Source: atc.Source{ 2699 "source-config": "some-value", 2700 }, 2701 }, 2702 }, 2703 2704 ResourceTypes: atc.ResourceTypes{ 2705 { 2706 Name: "some-resource-type", 2707 Type: "some-type", 2708 Source: atc.Source{ 2709 "source-config": "some-value", 2710 }, 2711 }, 2712 }, 2713 2714 Jobs: atc.JobConfigs{ 2715 { 2716 Name: "job-1", 2717 PlanSequence: []atc.Step{ 2718 { 2719 Config: &atc.GetStep{ 2720 Name: "some-resource", 2721 }, 2722 }, 2723 }, 2724 }, 2725 { 2726 Name: "job-2", 2727 PlanSequence: []atc.Step{ 2728 { 2729 Config: &atc.GetStep{ 2730 Name: "some-resource", 2731 }, 2732 }, 2733 }, 2734 }, 2735 { 2736 Name: "some-job", 2737 2738 Public: true, 2739 2740 Serial: true, 2741 SerialGroups: []string{"serial-group-1", "serial-group-2"}, 2742 2743 PlanSequence: []atc.Step{ 2744 { 2745 Config: &atc.DoStep{ 2746 Steps: []atc.Step{ 2747 { 2748 Config: &atc.GetStep{ 2749 Name: "other-input", 2750 Resource: "some-resource", 2751 }, 2752 }, 2753 }, 2754 }, 2755 }, 2756 { 2757 Config: &atc.GetStep{ 2758 Name: "some-input", 2759 Resource: "some-resource", 2760 Params: atc.Params{ 2761 "some-param": "some-value", 2762 }, 2763 Passed: []string{"job-1", "job-2"}, 2764 Trigger: true, 2765 }, 2766 }, 2767 { 2768 Config: &atc.TaskStep{ 2769 Name: "some-task", 2770 Privileged: true, 2771 ConfigPath: "some/config/path.yml", 2772 Config: &atc.TaskConfig{ 2773 RootfsURI: "some-image", 2774 }, 2775 }, 2776 }, 2777 { 2778 Config: &atc.PutStep{ 2779 Name: "some-resource", 2780 Params: atc.Params{ 2781 "some-param": "some-value", 2782 }, 2783 }, 2784 }, 2785 }, 2786 }, 2787 }, 2788 } 2789 2790 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, true) 2791 Expect(err).ToNot(HaveOccurred()) 2792 2793 rows, err := psql.Select("name", "job_id", "resource_id", "passed_job_id"). 2794 From("job_inputs"). 2795 Where(sq.Expr(`job_id in ( 2796 SELECT j.id 2797 FROM jobs j 2798 WHERE j.pipeline_id = $1 2799 )`, pipeline.ID())). 2800 RunWith(dbConn). 2801 Query() 2802 Expect(err).ToNot(HaveOccurred()) 2803 2804 type jobPipe struct { 2805 name string 2806 jobID int 2807 resourceID int 2808 passedJobID int 2809 } 2810 2811 var jobPipes []jobPipe 2812 for rows.Next() { 2813 var jp jobPipe 2814 var passedJob sql.NullInt64 2815 err = rows.Scan(&jp.name, &jp.jobID, &jp.resourceID, &passedJob) 2816 Expect(err).ToNot(HaveOccurred()) 2817 2818 if passedJob.Valid { 2819 jp.passedJobID = int(passedJob.Int64) 2820 } 2821 2822 jobPipes = append(jobPipes, jp) 2823 } 2824 2825 job1, found, err := pipeline.Job("job-1") 2826 Expect(err).ToNot(HaveOccurred()) 2827 Expect(found).To(BeTrue()) 2828 2829 job2, found, err := pipeline.Job("job-2") 2830 Expect(err).ToNot(HaveOccurred()) 2831 Expect(found).To(BeTrue()) 2832 2833 someJob, found, err := pipeline.Job("some-job") 2834 Expect(err).ToNot(HaveOccurred()) 2835 Expect(found).To(BeTrue()) 2836 2837 someResource, found, err := pipeline.Resource("some-resource") 2838 Expect(err).ToNot(HaveOccurred()) 2839 Expect(found).To(BeTrue()) 2840 2841 Expect(jobPipes).To(ConsistOf( 2842 jobPipe{ 2843 name: "some-resource", 2844 jobID: job1.ID(), 2845 resourceID: someResource.ID(), 2846 }, 2847 jobPipe{ 2848 name: "some-resource", 2849 jobID: job2.ID(), 2850 resourceID: someResource.ID(), 2851 }, 2852 jobPipe{ 2853 name: "other-input", 2854 jobID: someJob.ID(), 2855 resourceID: someResource.ID(), 2856 }, 2857 jobPipe{ 2858 name: "some-input", 2859 jobID: someJob.ID(), 2860 resourceID: someResource.ID(), 2861 passedJobID: job1.ID(), 2862 }, 2863 jobPipe{ 2864 name: "some-input", 2865 jobID: someJob.ID(), 2866 resourceID: someResource.ID(), 2867 passedJobID: job2.ID(), 2868 }, 2869 )) 2870 2871 config = atc.Config{ 2872 Resources: atc.ResourceConfigs{ 2873 { 2874 Name: "some-resource", 2875 Type: "some-type", 2876 Source: atc.Source{ 2877 "source-config": "some-value", 2878 }, 2879 }, 2880 }, 2881 2882 ResourceTypes: atc.ResourceTypes{ 2883 { 2884 Name: "some-resource-type", 2885 Type: "some-type", 2886 Source: atc.Source{ 2887 "source-config": "some-value", 2888 }, 2889 }, 2890 }, 2891 2892 Jobs: atc.JobConfigs{ 2893 { 2894 Name: "job-2", 2895 PlanSequence: []atc.Step{ 2896 { 2897 Config: &atc.GetStep{ 2898 Name: "some-resource", 2899 }, 2900 }, 2901 }, 2902 }, 2903 { 2904 Name: "some-job", 2905 2906 Public: true, 2907 2908 Serial: true, 2909 SerialGroups: []string{"serial-group-1", "serial-group-2"}, 2910 2911 PlanSequence: []atc.Step{ 2912 { 2913 Config: &atc.GetStep{ 2914 Name: "some-input", 2915 Resource: "some-resource", 2916 Params: atc.Params{ 2917 "some-param": "some-value", 2918 }, 2919 Passed: []string{"job-2"}, 2920 Trigger: true, 2921 }, 2922 }, 2923 { 2924 Config: &atc.TaskStep{ 2925 Name: "some-task", 2926 Privileged: true, 2927 ConfigPath: "some/config/path.yml", 2928 Config: &atc.TaskConfig{ 2929 RootfsURI: "some-image", 2930 }, 2931 }, 2932 }, 2933 { 2934 Config: &atc.PutStep{ 2935 Name: "some-resource", 2936 Params: atc.Params{ 2937 "some-param": "some-value", 2938 }, 2939 }, 2940 }, 2941 }, 2942 }, 2943 }, 2944 } 2945 2946 _, _, err = team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 2947 Expect(err).ToNot(HaveOccurred()) 2948 2949 rows, err = psql.Select("name", "job_id", "resource_id", "passed_job_id"). 2950 From("job_inputs"). 2951 Where(sq.Expr(`job_id in ( 2952 SELECT j.id 2953 FROM jobs j 2954 WHERE j.pipeline_id = $1 2955 )`, pipeline.ID())). 2956 RunWith(dbConn). 2957 Query() 2958 Expect(err).ToNot(HaveOccurred()) 2959 2960 var newJobPipes []jobPipe 2961 for rows.Next() { 2962 var jp jobPipe 2963 var passedJob sql.NullInt64 2964 err = rows.Scan(&jp.name, &jp.jobID, &jp.resourceID, &passedJob) 2965 Expect(err).ToNot(HaveOccurred()) 2966 2967 if passedJob.Valid { 2968 jp.passedJobID = int(passedJob.Int64) 2969 } 2970 2971 newJobPipes = append(newJobPipes, jp) 2972 } 2973 2974 Expect(newJobPipes).To(ConsistOf( 2975 jobPipe{ 2976 name: "some-resource", 2977 jobID: job2.ID(), 2978 resourceID: someResource.ID(), 2979 }, 2980 jobPipe{ 2981 name: "some-input", 2982 jobID: someJob.ID(), 2983 resourceID: someResource.ID(), 2984 passedJobID: job2.ID(), 2985 }, 2986 )) 2987 }) 2988 2989 Context("updating an existing pipeline", func() { 2990 It("maintains paused if the pipeline is paused", func() { 2991 _, _, err := team.SavePipeline(pipelineRef, config, 0, true) 2992 Expect(err).ToNot(HaveOccurred()) 2993 2994 pipeline, found, err := team.Pipeline(pipelineRef) 2995 Expect(err).ToNot(HaveOccurred()) 2996 Expect(found).To(BeTrue()) 2997 Expect(pipeline.Paused()).To(BeTrue()) 2998 2999 _, _, err = team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), false) 3000 Expect(err).ToNot(HaveOccurred()) 3001 3002 pipeline, found, err = team.Pipeline(pipelineRef) 3003 Expect(err).ToNot(HaveOccurred()) 3004 Expect(found).To(BeTrue()) 3005 Expect(pipeline.Paused()).To(BeTrue()) 3006 }) 3007 3008 It("maintains unpaused if the pipeline is unpaused", func() { 3009 _, _, err := team.SavePipeline(pipelineRef, config, 0, false) 3010 Expect(err).ToNot(HaveOccurred()) 3011 3012 pipeline, found, err := team.Pipeline(pipelineRef) 3013 Expect(err).ToNot(HaveOccurred()) 3014 Expect(found).To(BeTrue()) 3015 Expect(pipeline.Paused()).To(BeFalse()) 3016 3017 _, _, err = team.SavePipeline(pipelineRef, config, pipeline.ConfigVersion(), true) 3018 Expect(err).ToNot(HaveOccurred()) 3019 3020 pipeline, found, err = team.Pipeline(pipelineRef) 3021 Expect(err).ToNot(HaveOccurred()) 3022 Expect(found).To(BeTrue()) 3023 Expect(pipeline.Paused()).To(BeFalse()) 3024 }) 3025 3026 It("resets to unarchived", func() { 3027 team.SavePipeline(pipelineRef, config, 0, false) 3028 pipeline, _, _ := team.Pipeline(pipelineRef) 3029 pipeline.Archive() 3030 3031 team.SavePipeline(pipelineRef, config, db.ConfigVersion(0), true) 3032 pipeline.Reload() 3033 Expect(pipeline.Archived()).To(BeFalse(), "the pipeline remained archived") 3034 }) 3035 }) 3036 3037 It("can lookup a pipeline by name", func() { 3038 otherPipelineFilter := atc.PipelineRef{Name: "an-other-pipeline-name"} 3039 3040 _, _, err := team.SavePipeline(pipelineRef, config, 0, false) 3041 Expect(err).ToNot(HaveOccurred()) 3042 _, _, err = team.SavePipeline(otherPipelineFilter, otherConfig, 0, false) 3043 Expect(err).ToNot(HaveOccurred()) 3044 3045 pipeline, found, err := team.Pipeline(pipelineRef) 3046 Expect(err).ToNot(HaveOccurred()) 3047 Expect(found).To(BeTrue()) 3048 Expect(pipeline.Name()).To(Equal(pipelineName)) 3049 Expect(pipeline.ID()).ToNot(Equal(0)) 3050 resourceTypes, err := pipeline.ResourceTypes() 3051 Expect(err).ToNot(HaveOccurred()) 3052 resources, err := pipeline.Resources() 3053 Expect(err).ToNot(HaveOccurred()) 3054 jobs, err := pipeline.Jobs() 3055 Expect(err).ToNot(HaveOccurred()) 3056 jobConfigs, err := jobs.Configs() 3057 Expect(err).ToNot(HaveOccurred()) 3058 expectConfigsEqual(atc.Config{ 3059 Groups: pipeline.Groups(), 3060 Resources: resources.Configs(), 3061 ResourceTypes: resourceTypes.Configs(), 3062 Jobs: jobConfigs, 3063 }, config) 3064 3065 otherPipeline, found, err := team.Pipeline(otherPipelineFilter) 3066 Expect(err).ToNot(HaveOccurred()) 3067 Expect(found).To(BeTrue()) 3068 Expect(otherPipeline.Name()).To(Equal(otherPipelineFilter.Name)) 3069 Expect(otherPipeline.ID()).ToNot(Equal(0)) 3070 otherResourceTypes, err := otherPipeline.ResourceTypes() 3071 Expect(err).ToNot(HaveOccurred()) 3072 otherResources, err := otherPipeline.Resources() 3073 Expect(err).ToNot(HaveOccurred()) 3074 otherJobs, err := otherPipeline.Jobs() 3075 Expect(err).ToNot(HaveOccurred()) 3076 otherJobConfigs, err := otherJobs.Configs() 3077 Expect(err).ToNot(HaveOccurred()) 3078 expectConfigsEqual(atc.Config{ 3079 Groups: otherPipeline.Groups(), 3080 Resources: otherResources.Configs(), 3081 ResourceTypes: otherResourceTypes.Configs(), 3082 Jobs: otherJobConfigs, 3083 }, otherConfig) 3084 3085 }) 3086 3087 It("can manage multiple pipeline configurations", func() { 3088 otherPipelineFilter := atc.PipelineRef{Name: "an-other-pipeline-name"} 3089 3090 By("being able to save the config") 3091 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 3092 Expect(err).ToNot(HaveOccurred()) 3093 3094 otherPipeline, _, err := team.SavePipeline(otherPipelineFilter, otherConfig, 0, false) 3095 Expect(err).ToNot(HaveOccurred()) 3096 3097 By("returning the saved config to later gets") 3098 resourceTypes, err := pipeline.ResourceTypes() 3099 Expect(err).ToNot(HaveOccurred()) 3100 resources, err := pipeline.Resources() 3101 Expect(err).ToNot(HaveOccurred()) 3102 jobs, err := pipeline.Jobs() 3103 Expect(err).ToNot(HaveOccurred()) 3104 jobConfigs, err := jobs.Configs() 3105 Expect(err).ToNot(HaveOccurred()) 3106 expectConfigsEqual(atc.Config{ 3107 Groups: pipeline.Groups(), 3108 Resources: resources.Configs(), 3109 ResourceTypes: resourceTypes.Configs(), 3110 Jobs: jobConfigs, 3111 }, config) 3112 3113 otherResourceTypes, err := otherPipeline.ResourceTypes() 3114 Expect(err).ToNot(HaveOccurred()) 3115 otherResources, err := otherPipeline.Resources() 3116 Expect(err).ToNot(HaveOccurred()) 3117 otherJobs, err := otherPipeline.Jobs() 3118 Expect(err).ToNot(HaveOccurred()) 3119 otherJobConfigs, err := otherJobs.Configs() 3120 Expect(err).ToNot(HaveOccurred()) 3121 expectConfigsEqual(atc.Config{ 3122 Groups: otherPipeline.Groups(), 3123 Resources: otherResources.Configs(), 3124 ResourceTypes: otherResourceTypes.Configs(), 3125 Jobs: otherJobConfigs, 3126 }, otherConfig) 3127 3128 By("returning the saved groups") 3129 returnedGroups := pipeline.Groups() 3130 Expect(returnedGroups).To(Equal(config.Groups)) 3131 3132 otherReturnedGroups := otherPipeline.Groups() 3133 Expect(otherReturnedGroups).To(Equal(otherConfig.Groups)) 3134 3135 updatedConfig := config 3136 3137 updatedConfig.Groups = append(config.Groups, atc.GroupConfig{ 3138 Name: "new-group", 3139 Jobs: []string{"new-job-1", "new-job-2"}, 3140 }) 3141 3142 updatedConfig.Resources = append(config.Resources, atc.ResourceConfig{ 3143 Name: "new-resource", 3144 Type: "new-type", 3145 Source: atc.Source{ 3146 "new-source-config": "new-value", 3147 }, 3148 }) 3149 3150 updatedConfig.Jobs = append(config.Jobs, atc.JobConfig{ 3151 Name: "new-job", 3152 PlanSequence: []atc.Step{ 3153 { 3154 Config: &atc.GetStep{ 3155 Name: "new-input", 3156 Resource: "new-resource", 3157 Params: atc.Params{ 3158 "new-param": "new-value", 3159 }, 3160 }, 3161 }, 3162 { 3163 Config: &atc.TaskStep{ 3164 Name: "some-task", 3165 ConfigPath: "new/config/path.yml", 3166 }, 3167 }, 3168 }, 3169 }) 3170 3171 By("not allowing non-sequential updates") 3172 _, _, err = team.SavePipeline(pipelineRef, updatedConfig, pipeline.ConfigVersion()-1, false) 3173 Expect(err).To(Equal(db.ErrConfigComparisonFailed)) 3174 3175 _, _, err = team.SavePipeline(pipelineRef, updatedConfig, pipeline.ConfigVersion()+10, false) 3176 Expect(err).To(Equal(db.ErrConfigComparisonFailed)) 3177 3178 _, _, err = team.SavePipeline(otherPipelineFilter, updatedConfig, otherPipeline.ConfigVersion()-1, false) 3179 Expect(err).To(Equal(db.ErrConfigComparisonFailed)) 3180 3181 _, _, err = team.SavePipeline(otherPipelineFilter, updatedConfig, otherPipeline.ConfigVersion()+10, false) 3182 Expect(err).To(Equal(db.ErrConfigComparisonFailed)) 3183 3184 By("being able to update the config with a valid con") 3185 pipeline, _, err = team.SavePipeline(pipelineRef, updatedConfig, pipeline.ConfigVersion(), false) 3186 Expect(err).ToNot(HaveOccurred()) 3187 otherPipeline, _, err = team.SavePipeline(otherPipelineFilter, updatedConfig, otherPipeline.ConfigVersion(), false) 3188 Expect(err).ToNot(HaveOccurred()) 3189 3190 By("returning the updated config") 3191 resourceTypes, err = pipeline.ResourceTypes() 3192 Expect(err).ToNot(HaveOccurred()) 3193 resources, err = pipeline.Resources() 3194 Expect(err).ToNot(HaveOccurred()) 3195 jobs, err = pipeline.Jobs() 3196 Expect(err).ToNot(HaveOccurred()) 3197 jobConfigs, err = jobs.Configs() 3198 Expect(err).ToNot(HaveOccurred()) 3199 expectConfigsEqual(atc.Config{ 3200 Groups: pipeline.Groups(), 3201 Resources: resources.Configs(), 3202 ResourceTypes: resourceTypes.Configs(), 3203 Jobs: jobConfigs, 3204 }, updatedConfig) 3205 3206 otherResourceTypes, err = otherPipeline.ResourceTypes() 3207 Expect(err).ToNot(HaveOccurred()) 3208 otherResources, err = otherPipeline.Resources() 3209 Expect(err).ToNot(HaveOccurred()) 3210 otherJobs, err = otherPipeline.Jobs() 3211 Expect(err).ToNot(HaveOccurred()) 3212 otherJobConfigs, err = jobs.Configs() 3213 Expect(err).ToNot(HaveOccurred()) 3214 expectConfigsEqual(atc.Config{ 3215 Groups: otherPipeline.Groups(), 3216 Resources: otherResources.Configs(), 3217 ResourceTypes: otherResourceTypes.Configs(), 3218 Jobs: otherJobConfigs, 3219 }, updatedConfig) 3220 3221 By("returning the saved groups") 3222 returnedGroups = pipeline.Groups() 3223 Expect(returnedGroups).To(Equal(updatedConfig.Groups)) 3224 3225 otherReturnedGroups = otherPipeline.Groups() 3226 Expect(otherReturnedGroups).To(Equal(updatedConfig.Groups)) 3227 }) 3228 3229 It("should return sorted resources and resource_types", func() { 3230 config.ResourceTypes = append(config.ResourceTypes, atc.ResourceType{ 3231 Name: "new-resource-type", 3232 Type: "new-type", 3233 Source: atc.Source{ 3234 "new-source-config": "new-value", 3235 }, 3236 }) 3237 3238 config.Resources = append(config.Resources, atc.ResourceConfig{ 3239 Name: "new-resource", 3240 Type: "new-type", 3241 Source: atc.Source{ 3242 "new-source-config": "new-value", 3243 }, 3244 }) 3245 3246 pipeline, _, err := team.SavePipeline(pipelineRef, config, 0, false) 3247 Expect(err).ToNot(HaveOccurred()) 3248 3249 resourceTypes, err := pipeline.ResourceTypes() 3250 Expect(err).ToNot(HaveOccurred()) 3251 rtConfigs := resourceTypes.Configs() 3252 Expect(rtConfigs[0].Name).To(Equal(config.ResourceTypes[1].Name)) // "new-resource-type" 3253 Expect(rtConfigs[1].Name).To(Equal(config.ResourceTypes[0].Name)) // "some-resource-type" 3254 3255 resources, err := pipeline.Resources() 3256 Expect(err).ToNot(HaveOccurred()) 3257 rConfigs := resources.Configs() 3258 Expect(rConfigs[0].Name).To(Equal(config.Resources[1].Name)) // "new-resource" 3259 Expect(rConfigs[1].Name).To(Equal(config.Resources[0].Name)) // "some-resource" 3260 }) 3261 3262 Context("when there are multiple teams", func() { 3263 It("can allow pipelines with the same name across teams", func() { 3264 pipelineRef := atc.PipelineRef{Name: "steve"} 3265 3266 teamPipeline, _, err := team.SavePipeline(pipelineRef, config, 0, true) 3267 Expect(err).ToNot(HaveOccurred()) 3268 Expect(teamPipeline.Paused()).To(BeTrue()) 3269 3270 By("allowing you to save a pipeline with the same name in another team") 3271 otherTeamPipeline, _, err := otherTeam.SavePipeline(pipelineRef, otherConfig, 0, true) 3272 Expect(err).ToNot(HaveOccurred()) 3273 Expect(otherTeamPipeline.Paused()).To(BeTrue()) 3274 3275 By("updating the pipeline config for the correct team's pipeline") 3276 teamPipeline, _, err = team.SavePipeline(pipelineRef, otherConfig, teamPipeline.ConfigVersion(), false) 3277 Expect(err).ToNot(HaveOccurred()) 3278 3279 _, _, err = otherTeam.SavePipeline(pipelineRef, config, otherTeamPipeline.ConfigVersion(), false) 3280 Expect(err).ToNot(HaveOccurred()) 3281 3282 By("cannot cross update configs") 3283 _, _, err = team.SavePipeline(pipelineRef, otherConfig, otherTeamPipeline.ConfigVersion(), false) 3284 Expect(err).To(HaveOccurred()) 3285 3286 _, _, err = team.SavePipeline(pipelineRef, otherConfig, otherTeamPipeline.ConfigVersion(), true) 3287 Expect(err).To(HaveOccurred()) 3288 }) 3289 }) 3290 }) 3291 3292 Describe("FindCheckContainers", func() { 3293 var ( 3294 fakeSecretManager *credsfakes.FakeSecrets 3295 logger lager.Logger 3296 ) 3297 3298 expiries := db.ContainerOwnerExpiries{ 3299 Min: 5 * time.Minute, 3300 Max: 1 * time.Hour, 3301 } 3302 3303 BeforeEach(func() { 3304 fakeSecretManager = new(credsfakes.FakeSecrets) 3305 fakeSecretManager.GetReturns("", nil, false, nil) 3306 logger = lagertest.NewTestLogger("db-test") 3307 }) 3308 3309 Context("when pipeline exists", func() { 3310 Context("when resource exists", func() { 3311 Context("when check container for resource exists", func() { 3312 var resourceContainer db.CreatingContainer 3313 var resourceConfig db.ResourceConfig 3314 3315 BeforeEach(func() { 3316 pipelineResourceTypes, err := defaultPipeline.ResourceTypes() 3317 Expect(err).ToNot(HaveOccurred()) 3318 3319 resourceConfig, err = resourceConfigFactory.FindOrCreateResourceConfig( 3320 defaultResource.Type(), 3321 defaultResource.Source(), 3322 pipelineResourceTypes.Deserialize(), 3323 ) 3324 Expect(err).ToNot(HaveOccurred()) 3325 3326 resourceContainer, err = defaultWorker.CreateContainer( 3327 db.NewResourceConfigCheckSessionContainerOwner( 3328 resourceConfig.ID(), 3329 resourceConfig.OriginBaseResourceType().ID, 3330 expiries, 3331 ), 3332 db.ContainerMetadata{}, 3333 ) 3334 Expect(err).ToNot(HaveOccurred()) 3335 }) 3336 3337 It("returns check container for resource", func() { 3338 containers, checkContainersExpiresAt, err := defaultTeam.FindCheckContainers(logger, defaultPipelineRef, "some-resource", fakeSecretManager, fakeVarSourcePool) 3339 Expect(err).ToNot(HaveOccurred()) 3340 Expect(containers).To(HaveLen(1)) 3341 Expect(containers[0].ID()).To(Equal(resourceContainer.ID())) 3342 Expect(checkContainersExpiresAt).To(HaveLen(1)) 3343 Expect(checkContainersExpiresAt[resourceContainer.ID()]).ToNot(BeNil()) 3344 }) 3345 3346 Context("when there are multiple resources with the same resource config", func() { 3347 var ( 3348 otherPipeline db.Pipeline 3349 otherResource db.Resource 3350 otherResourceContainer db.CreatingContainer 3351 otherPipelineRef atc.PipelineRef 3352 found bool 3353 err error 3354 ) 3355 3356 BeforeEach(func() { 3357 otherPipelineRef = atc.PipelineRef{Name: "other-pipeline", InstanceVars: atc.InstanceVars{"branch": "master"}} 3358 otherPipeline, _, err = defaultTeam.SavePipeline(otherPipelineRef, atc.Config{ 3359 Resources: atc.ResourceConfigs{ 3360 { 3361 Name: "some-resource", 3362 Type: "some-base-resource-type", 3363 Source: atc.Source{ 3364 "some": "source", 3365 }, 3366 }, 3367 }, 3368 }, db.ConfigVersion(0), false) 3369 Expect(err).NotTo(HaveOccurred()) 3370 3371 otherResource, found, err = otherPipeline.Resource("some-resource") 3372 Expect(err).NotTo(HaveOccurred()) 3373 Expect(found).To(BeTrue()) 3374 3375 resourceConfig, err = resourceConfigFactory.FindOrCreateResourceConfig( 3376 otherResource.Type(), 3377 otherResource.Source(), 3378 atc.VersionedResourceTypes{}, 3379 ) 3380 Expect(err).ToNot(HaveOccurred()) 3381 3382 otherResourceContainer, _, err = defaultWorker.FindContainer( 3383 db.NewResourceConfigCheckSessionContainerOwner( 3384 resourceConfig.ID(), 3385 resourceConfig.OriginBaseResourceType().ID, 3386 expiries, 3387 ), 3388 ) 3389 Expect(err).ToNot(HaveOccurred()) 3390 }) 3391 3392 It("returns the same check container", func() { 3393 containers, checkContainersExpiresAt, err := defaultTeam.FindCheckContainers(logger, otherPipelineRef, "some-resource", fakeSecretManager, fakeVarSourcePool) 3394 Expect(err).ToNot(HaveOccurred()) 3395 Expect(containers).To(HaveLen(1)) 3396 Expect(containers[0].ID()).To(Equal(otherResourceContainer.ID())) 3397 Expect(otherResourceContainer.ID()).To(Equal(resourceContainer.ID())) 3398 Expect(checkContainersExpiresAt).To(HaveLen(1)) 3399 Expect(checkContainersExpiresAt[resourceContainer.ID()]).ToNot(BeNil()) 3400 }) 3401 }) 3402 }) 3403 3404 Context("when check container does not exist", func() { 3405 It("returns empty list", func() { 3406 containers, checkContainersExpiresAt, err := defaultTeam.FindCheckContainers(logger, defaultPipelineRef, "some-resource", fakeSecretManager, fakeVarSourcePool) 3407 Expect(err).ToNot(HaveOccurred()) 3408 Expect(containers).To(BeEmpty()) 3409 Expect(checkContainersExpiresAt).To(BeEmpty()) 3410 }) 3411 }) 3412 }) 3413 3414 Context("when resource does not exist", func() { 3415 It("returns empty list", func() { 3416 containers, checkContainersExpiresAt, err := defaultTeam.FindCheckContainers(logger, defaultPipelineRef, "non-existent-resource", fakeSecretManager, fakeVarSourcePool) 3417 Expect(err).ToNot(HaveOccurred()) 3418 Expect(containers).To(BeEmpty()) 3419 Expect(checkContainersExpiresAt).To(BeEmpty()) 3420 }) 3421 }) 3422 }) 3423 3424 Context("when pipeline does not exist", func() { 3425 It("returns empty list", func() { 3426 containers, checkContainersExpiresAt, err := defaultTeam.FindCheckContainers(logger, atc.PipelineRef{Name: "non-existent-pipeline"}, "some-resource", fakeSecretManager, fakeVarSourcePool) 3427 Expect(err).ToNot(HaveOccurred()) 3428 Expect(containers).To(BeEmpty()) 3429 Expect(checkContainersExpiresAt).To(BeEmpty()) 3430 }) 3431 }) 3432 }) 3433 3434 Describe("IsCheckContainer", func() { 3435 Context("when the container is associated with a resource config check session", func() { 3436 var resourceContainer db.Container 3437 var scenario *dbtest.Scenario 3438 3439 expiries := db.ContainerOwnerExpiries{ 3440 Min: 5 * time.Minute, 3441 Max: 1 * time.Hour, 3442 } 3443 3444 BeforeEach(func() { 3445 scenario = dbtest.Setup( 3446 builder.WithPipeline(atc.Config{ 3447 Jobs: atc.JobConfigs{ 3448 { 3449 Name: "some-job", 3450 }, 3451 }, 3452 Resources: atc.ResourceConfigs{ 3453 { 3454 Name: "some-resource", 3455 Type: "some-base-resource-type", 3456 Source: atc.Source{ 3457 "some": "source", 3458 }, 3459 }, 3460 }, 3461 }), 3462 builder.WithWorker(atc.Worker{ 3463 ResourceTypes: []atc.WorkerResourceType{defaultWorkerResourceType}, 3464 Name: "some-default-worker", 3465 GardenAddr: "3.4.5.6:7777", 3466 BaggageclaimURL: "7.8.9.10:7878", 3467 }), 3468 builder.WithResourceVersions("some-resource"), 3469 ) 3470 3471 rc, found, err := resourceConfigFactory.FindResourceConfigByID(scenario.Resource("some-resource").ResourceConfigID()) 3472 Expect(err).ToNot(HaveOccurred()) 3473 Expect(found).To(BeTrue()) 3474 3475 resourceContainer, err = scenario.Workers[0].CreateContainer( 3476 db.NewResourceConfigCheckSessionContainerOwner( 3477 rc.ID(), 3478 rc.OriginBaseResourceType().ID, 3479 expiries, 3480 ), 3481 db.ContainerMetadata{}, 3482 ) 3483 Expect(err).ToNot(HaveOccurred()) 3484 }) 3485 3486 It("returns true", func() { 3487 is, err := team.IsCheckContainer(resourceContainer.Handle()) 3488 Expect(err).ToNot(HaveOccurred()) 3489 Expect(is).To(BeTrue()) 3490 }) 3491 }) 3492 3493 Context("when the container is owned by a team", func() { 3494 var createdContainer db.Container 3495 var scenario *dbtest.Scenario 3496 3497 BeforeEach(func() { 3498 scenario = dbtest.Setup( 3499 builder.WithPipeline(atc.Config{ 3500 Jobs: atc.JobConfigs{ 3501 { 3502 Name: "some-job", 3503 }, 3504 }, 3505 }), 3506 builder.WithBaseWorker(), 3507 ) 3508 3509 build, err := scenario.Job("some-job").CreateBuild() 3510 Expect(err).ToNot(HaveOccurred()) 3511 3512 creatingContainer, err := scenario.Workers[0].CreateContainer( 3513 db.NewBuildStepContainerOwner( 3514 build.ID(), 3515 atc.PlanID("some-job"), 3516 scenario.Team.ID(), 3517 ), 3518 db.ContainerMetadata{Type: "task", StepName: "some-task"}, 3519 ) 3520 Expect(err).ToNot(HaveOccurred()) 3521 3522 createdContainer, err = creatingContainer.Created() 3523 Expect(err).ToNot(HaveOccurred()) 3524 }) 3525 3526 It("returns false", func() { 3527 is, err := team.IsCheckContainer(createdContainer.Handle()) 3528 Expect(err).ToNot(HaveOccurred()) 3529 Expect(is).To(BeFalse()) 3530 }) 3531 }) 3532 }) 3533 3534 Describe("IsContainerWithinTeam", func() { 3535 Context("when the container is a check container", func() { 3536 var resourceContainer db.Container 3537 var scenario *dbtest.Scenario 3538 3539 expiries := db.ContainerOwnerExpiries{ 3540 Min: 5 * time.Minute, 3541 Max: 1 * time.Hour, 3542 } 3543 3544 BeforeEach(func() { 3545 scenario = dbtest.Setup( 3546 builder.WithPipeline(atc.Config{ 3547 Jobs: atc.JobConfigs{ 3548 { 3549 Name: "some-job", 3550 }, 3551 }, 3552 Resources: atc.ResourceConfigs{ 3553 { 3554 Name: "some-resource", 3555 Type: "some-base-resource-type", 3556 Source: atc.Source{ 3557 "some": "source", 3558 }, 3559 }, 3560 }, 3561 }), 3562 builder.WithWorker(atc.Worker{ 3563 ResourceTypes: []atc.WorkerResourceType{defaultWorkerResourceType}, 3564 Name: "some-default-worker", 3565 GardenAddr: "3.4.5.6:7777", 3566 BaggageclaimURL: "7.8.9.10:7878", 3567 }), 3568 builder.WithResourceVersions("some-resource"), 3569 ) 3570 3571 rc, found, err := resourceConfigFactory.FindResourceConfigByID(scenario.Resource("some-resource").ResourceConfigID()) 3572 Expect(err).ToNot(HaveOccurred()) 3573 Expect(found).To(BeTrue()) 3574 3575 resourceContainer, err = scenario.Workers[0].CreateContainer( 3576 db.NewResourceConfigCheckSessionContainerOwner( 3577 rc.ID(), 3578 rc.OriginBaseResourceType().ID, 3579 expiries, 3580 ), 3581 db.ContainerMetadata{}, 3582 ) 3583 Expect(err).ToNot(HaveOccurred()) 3584 }) 3585 3586 Context("when the container does belong on the team", func() { 3587 var ok bool 3588 3589 BeforeEach(func() { 3590 var err error 3591 ok, err = scenario.Team.IsContainerWithinTeam(resourceContainer.Handle(), true) 3592 Expect(err).ToNot(HaveOccurred()) 3593 }) 3594 3595 It("finds the container for the team", func() { 3596 Expect(ok).To(BeTrue()) 3597 }) 3598 }) 3599 3600 Context("when the container does not belong on the team", func() { 3601 var ok bool 3602 3603 BeforeEach(func() { 3604 var err error 3605 ok, err = team.IsContainerWithinTeam(resourceContainer.Handle(), true) 3606 Expect(err).ToNot(HaveOccurred()) 3607 }) 3608 3609 It("finds the container for the team", func() { 3610 Expect(ok).To(BeFalse()) 3611 }) 3612 }) 3613 }) 3614 3615 Context("when the container is owned by a team", func() { 3616 var createdContainer db.Container 3617 var scenario *dbtest.Scenario 3618 3619 BeforeEach(func() { 3620 scenario = dbtest.Setup( 3621 builder.WithPipeline(atc.Config{ 3622 Jobs: atc.JobConfigs{ 3623 { 3624 Name: "some-job", 3625 }, 3626 }, 3627 }), 3628 builder.WithBaseWorker(), 3629 ) 3630 3631 build, err := scenario.Job("some-job").CreateBuild() 3632 Expect(err).ToNot(HaveOccurred()) 3633 3634 creatingContainer, err := scenario.Workers[0].CreateContainer(db.NewBuildStepContainerOwner(build.ID(), atc.PlanID("some-job"), scenario.Team.ID()), db.ContainerMetadata{Type: "task", StepName: "some-task"}) 3635 Expect(err).ToNot(HaveOccurred()) 3636 3637 createdContainer, err = creatingContainer.Created() 3638 Expect(err).ToNot(HaveOccurred()) 3639 }) 3640 3641 Context("when the container does belong on the team", func() { 3642 var ok bool 3643 3644 BeforeEach(func() { 3645 var err error 3646 ok, err = scenario.Team.IsContainerWithinTeam(createdContainer.Handle(), false) 3647 Expect(err).ToNot(HaveOccurred()) 3648 }) 3649 3650 It("finds the container for the team", func() { 3651 Expect(ok).To(BeTrue()) 3652 }) 3653 }) 3654 3655 Context("when the container does not belong on the team", func() { 3656 var ok bool 3657 3658 BeforeEach(func() { 3659 var err error 3660 ok, err = team.IsContainerWithinTeam(createdContainer.Handle(), false) 3661 Expect(err).ToNot(HaveOccurred()) 3662 }) 3663 3664 It("finds the container for the team", func() { 3665 Expect(ok).To(BeFalse()) 3666 }) 3667 }) 3668 }) 3669 }) 3670 })