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  })