concourse/atc/db/team_test.go

2806 lines
87 KiB
Go

package db_test
import (
"database/sql"
"fmt"
"strconv"
"time"
"github.com/concourse/concourse/atc"
"github.com/concourse/concourse/atc/creds/credsfakes"
"github.com/concourse/concourse/atc/db"
"github.com/concourse/concourse/atc/event"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Team", func() {
var (
team db.Team
otherTeam db.Team
)
expectConfigsEqual := func(config, expectedConfig atc.Config) {
ExpectWithOffset(1, config.Groups).To(ConsistOf(expectedConfig.Groups))
ExpectWithOffset(1, config.Resources).To(ConsistOf(expectedConfig.Resources))
ExpectWithOffset(1, config.ResourceTypes).To(ConsistOf(expectedConfig.ResourceTypes))
ExpectWithOffset(1, config.Jobs).To(ConsistOf(expectedConfig.Jobs))
}
BeforeEach(func() {
var err error
team, err = teamFactory.CreateTeam(atc.Team{Name: "some-team"})
Expect(err).ToNot(HaveOccurred())
otherTeam, err = teamFactory.CreateTeam(atc.Team{Name: "some-other-team"})
Expect(err).ToNot(HaveOccurred())
})
Describe("Delete", func() {
var err error
var otherTeamPipeline db.Pipeline
BeforeEach(func() {
otherTeamPipeline, _, err = otherTeam.SavePipeline("fake-pipeline", atc.Config{
Jobs: atc.JobConfigs{
{Name: "job-name"},
},
}, db.ConfigVersion(1), db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
err = otherTeam.Delete()
Expect(err).ToNot(HaveOccurred())
})
It("deletes the team", func() {
team, found, err := teamFactory.FindTeam("some-other-team")
Expect(team).To(BeNil())
Expect(found).To(BeFalse())
Expect(err).ToNot(HaveOccurred())
})
It("drops the team_build_events_ID table", func() {
var exists bool
err := dbConn.QueryRow(fmt.Sprintf("SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'team_build_events_%d')", otherTeam.ID())).Scan(&exists)
Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeFalse())
})
It("drops the teams pipeline_build_events_ID table", func() {
var exists bool
err := dbConn.QueryRow(fmt.Sprintf("SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'pipeline_build_events_%d')", otherTeamPipeline.ID())).Scan(&exists)
Expect(err).ToNot(HaveOccurred())
Expect(exists).To(BeFalse())
})
})
Describe("Rename", func() {
JustBeforeEach(func() {
Expect(team.Rename("oopsies")).To(Succeed())
})
It("find the renamed team", func() {
_, found, _ := teamFactory.FindTeam("oopsies")
Expect(found).To(BeTrue())
})
})
Describe("SaveWorker", func() {
var (
team db.Team
otherTeam db.Team
atcWorker atc.Worker
err error
)
BeforeEach(func() {
postgresRunner.Truncate()
team, err = teamFactory.CreateTeam(atc.Team{Name: "team"})
Expect(err).ToNot(HaveOccurred())
otherTeam, err = teamFactory.CreateTeam(atc.Team{Name: "some-other-team"})
Expect(err).ToNot(HaveOccurred())
atcWorker = atc.Worker{
GardenAddr: "some-garden-addr",
BaggageclaimURL: "some-bc-url",
HTTPProxyURL: "some-http-proxy-url",
HTTPSProxyURL: "some-https-proxy-url",
NoProxy: "some-no-proxy",
ActiveContainers: 140,
ResourceTypes: []atc.WorkerResourceType{
{
Type: "some-resource-type",
Image: "some-image",
Version: "some-version",
},
{
Type: "other-resource-type",
Image: "other-image",
Version: "other-version",
},
},
Platform: "some-platform",
Tags: atc.Tags{"some", "tags"},
Name: "some-name",
StartTime: 55,
}
})
Context("the worker already exists", func() {
Context("the worker is not in stalled state", func() {
Context("the team_id of the new worker is the same", func() {
BeforeEach(func() {
_, err := team.SaveWorker(atcWorker, 5*time.Minute)
Expect(err).ToNot(HaveOccurred())
})
It("overwrites all the data", func() {
atcWorker.GardenAddr = "new-garden-addr"
savedWorker, err := team.SaveWorker(atcWorker, 5*time.Minute)
Expect(err).ToNot(HaveOccurred())
Expect(savedWorker.Name()).To(Equal("some-name"))
Expect(*savedWorker.GardenAddr()).To(Equal("new-garden-addr"))
Expect(savedWorker.State()).To(Equal(db.WorkerStateRunning))
})
})
Context("the team_id of the new worker is different", func() {
BeforeEach(func() {
_, err = otherTeam.SaveWorker(atcWorker, 5*time.Minute)
Expect(err).ToNot(HaveOccurred())
})
It("errors", func() {
_, err = team.SaveWorker(atcWorker, 5*time.Minute)
Expect(err).To(HaveOccurred())
})
})
})
})
})
Describe("Workers", func() {
var (
team db.Team
otherTeam db.Team
atcWorker atc.Worker
err error
)
BeforeEach(func() {
postgresRunner.Truncate()
team, err = teamFactory.CreateTeam(atc.Team{Name: "team"})
Expect(err).ToNot(HaveOccurred())
otherTeam, err = teamFactory.CreateTeam(atc.Team{Name: "some-other-team"})
Expect(err).ToNot(HaveOccurred())
atcWorker = atc.Worker{
GardenAddr: "some-garden-addr",
BaggageclaimURL: "some-bc-url",
HTTPProxyURL: "some-http-proxy-url",
HTTPSProxyURL: "some-https-proxy-url",
NoProxy: "some-no-proxy",
ActiveContainers: 140,
ResourceTypes: []atc.WorkerResourceType{
{
Type: "some-resource-type",
Image: "some-image",
Version: "some-version",
},
{
Type: "other-resource-type",
Image: "other-image",
Version: "other-version",
},
},
Platform: "some-platform",
Tags: atc.Tags{"some", "tags"},
Name: "some-name",
StartTime: 55,
}
})
Context("when there are global workers and workers for the team", func() {
BeforeEach(func() {
_, err = team.SaveWorker(atcWorker, 0)
Expect(err).ToNot(HaveOccurred())
atcWorker.Name = "some-new-worker"
atcWorker.GardenAddr = "some-other-garden-addr"
atcWorker.BaggageclaimURL = "some-other-bc-url"
_, err = workerFactory.SaveWorker(atcWorker, 0)
Expect(err).ToNot(HaveOccurred())
})
It("finds them without error", func() {
workers, err := team.Workers()
Expect(err).ToNot(HaveOccurred())
Expect(len(workers)).To(Equal(2))
Expect(workers[0].Name()).To(Equal("some-name"))
Expect(*workers[0].GardenAddr()).To(Equal("some-garden-addr"))
Expect(*workers[0].BaggageclaimURL()).To(Equal("some-bc-url"))
Expect(workers[1].Name()).To(Equal("some-new-worker"))
Expect(*workers[1].GardenAddr()).To(Equal("some-other-garden-addr"))
Expect(*workers[1].BaggageclaimURL()).To(Equal("some-other-bc-url"))
})
})
Context("when there are workers for another team", func() {
BeforeEach(func() {
atcWorker.Name = "some-other-team-worker"
atcWorker.GardenAddr = "some-other-garden-addr"
atcWorker.BaggageclaimURL = "some-other-bc-url"
_, err = otherTeam.SaveWorker(atcWorker, 5*time.Minute)
Expect(err).ToNot(HaveOccurred())
})
It("does not find the other team workers", func() {
workers, err := team.Workers()
Expect(err).ToNot(HaveOccurred())
Expect(len(workers)).To(Equal(0))
})
})
Context("when there are no workers", func() {
It("returns an error", func() {
workers, err := workerFactory.Workers()
Expect(err).ToNot(HaveOccurred())
Expect(workers).To(BeEmpty())
})
})
})
Describe("FindContainersByMetadata", func() {
var sampleMetadata []db.ContainerMetadata
var metaContainers map[db.ContainerMetadata][]db.Container
BeforeEach(func() {
baseMetadata := fullMetadata
diffType := fullMetadata
diffType.Type = db.ContainerTypeCheck
diffStepName := fullMetadata
diffStepName.StepName = fullMetadata.StepName + "-other"
diffAttempt := fullMetadata
diffAttempt.Attempt = fullMetadata.Attempt + ",2"
diffPipelineID := fullMetadata
diffPipelineID.PipelineID = fullMetadata.PipelineID + 1
diffJobID := fullMetadata
diffJobID.JobID = fullMetadata.JobID + 1
diffBuildID := fullMetadata
diffBuildID.BuildID = fullMetadata.BuildID + 1
diffWorkingDirectory := fullMetadata
diffWorkingDirectory.WorkingDirectory = fullMetadata.WorkingDirectory + "/other"
diffUser := fullMetadata
diffUser.User = fullMetadata.User + "-other"
sampleMetadata = []db.ContainerMetadata{
baseMetadata,
diffType,
diffStepName,
diffAttempt,
diffPipelineID,
diffJobID,
diffBuildID,
diffWorkingDirectory,
diffUser,
}
job, found, err := defaultPipeline.Job("some-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
build, err := job.CreateBuild()
Expect(err).ToNot(HaveOccurred())
metaContainers = make(map[db.ContainerMetadata][]db.Container)
for _, meta := range sampleMetadata {
firstContainerCreating, err := defaultWorker.CreateContainer(db.NewBuildStepContainerOwner(build.ID(), atc.PlanID("some-job"), defaultTeam.ID()), meta)
Expect(err).ToNot(HaveOccurred())
metaContainers[meta] = append(metaContainers[meta], firstContainerCreating)
secondContainerCreating, err := defaultWorker.CreateContainer(db.NewBuildStepContainerOwner(build.ID(), atc.PlanID("some-job"), defaultTeam.ID()), meta)
Expect(err).ToNot(HaveOccurred())
secondContainerCreated, err := secondContainerCreating.Created()
Expect(err).ToNot(HaveOccurred())
metaContainers[meta] = append(metaContainers[meta], secondContainerCreated)
thirdContainerCreating, err := defaultWorker.CreateContainer(db.NewBuildStepContainerOwner(build.ID(), atc.PlanID("some-job"), defaultTeam.ID()), meta)
Expect(err).ToNot(HaveOccurred())
thirdContainerCreated, err := thirdContainerCreating.Created()
Expect(err).ToNot(HaveOccurred())
// third container is not appended; we don't want Destroying containers
thirdContainerDestroying, err := thirdContainerCreated.Destroying()
Expect(err).ToNot(HaveOccurred())
metaContainers[meta] = append(metaContainers[meta], thirdContainerDestroying)
}
})
It("finds creating, created, and destroying containers for the team, matching the metadata in full", func() {
for _, meta := range sampleMetadata {
expectedHandles := []string{}
for _, c := range metaContainers[meta] {
expectedHandles = append(expectedHandles, c.Handle())
}
containers, err := defaultTeam.FindContainersByMetadata(meta)
Expect(err).ToNot(HaveOccurred())
foundHandles := []string{}
for _, c := range containers {
foundHandles = append(foundHandles, c.Handle())
}
// should always find a Creating container and a Created container
Expect(foundHandles).To(HaveLen(3))
Expect(foundHandles).To(ConsistOf(expectedHandles))
}
})
It("finds containers for the team, matching partial metadata", func() {
containers, err := defaultTeam.FindContainersByMetadata(db.ContainerMetadata{
Type: db.ContainerTypeTask,
})
Expect(err).ToNot(HaveOccurred())
Expect(containers).ToNot(BeEmpty())
foundHandles := []string{}
for _, c := range containers {
foundHandles = append(foundHandles, c.Handle())
}
var notFound int
for meta, cs := range metaContainers {
if meta.Type == db.ContainerTypeTask {
for _, c := range cs {
Expect(foundHandles).To(ContainElement(c.Handle()))
}
} else {
for _, c := range cs {
Expect(foundHandles).ToNot(ContainElement(c.Handle()))
notFound++
}
}
}
// just to assert test setup is valid
Expect(notFound).ToNot(BeZero())
})
It("finds all containers for the team when given empty metadata", func() {
containers, err := defaultTeam.FindContainersByMetadata(db.ContainerMetadata{})
Expect(err).ToNot(HaveOccurred())
Expect(containers).ToNot(BeEmpty())
foundHandles := []string{}
for _, c := range containers {
foundHandles = append(foundHandles, c.Handle())
}
for _, cs := range metaContainers {
for _, c := range cs {
Expect(foundHandles).To(ContainElement(c.Handle()))
}
}
})
It("does not find containers for other teams", func() {
for _, meta := range sampleMetadata {
containers, err := otherTeam.FindContainersByMetadata(meta)
Expect(err).ToNot(HaveOccurred())
Expect(containers).To(BeEmpty())
}
})
})
Describe("Containers", func() {
var (
fakeSecretManager *credsfakes.FakeSecrets
resourceContainer db.CreatingContainer
resourceConfigScope db.ResourceConfigScope
firstContainerCreating db.CreatingContainer
)
Context("when there is a task container and a check container", func() {
BeforeEach(func() {
fakeSecretManager = new(credsfakes.FakeSecrets)
fakeSecretManager.GetReturns("", nil, false, nil)
job, found, err := defaultPipeline.Job("some-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
build, err := job.CreateBuild()
Expect(err).ToNot(HaveOccurred())
firstContainerCreating, err = defaultWorker.CreateContainer(db.NewBuildStepContainerOwner(build.ID(), atc.PlanID("some-job"), defaultTeam.ID()), db.ContainerMetadata{Type: "task", StepName: "some-task"})
Expect(err).ToNot(HaveOccurred())
expiries := db.ContainerOwnerExpiries{
Min: 5 * time.Minute,
Max: 1 * time.Hour,
}
pipelineResourceTypes, err := defaultPipeline.ResourceTypes()
Expect(err).ToNot(HaveOccurred())
resourceConfigScope, err = defaultResource.SetResourceConfig(defaultResource.Source(), pipelineResourceTypes.Deserialize())
Expect(err).ToNot(HaveOccurred())
resourceContainer, err = defaultWorker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), expiries),
db.ContainerMetadata{},
)
Expect(err).ToNot(HaveOccurred())
})
It("finds all the containers", func() {
containers, err := defaultTeam.Containers()
Expect(err).ToNot(HaveOccurred())
Expect(containers).To(HaveLen(2))
Expect(containers).To(ConsistOf(firstContainerCreating, resourceContainer))
})
It("does not find containers for other teams", func() {
containers, err := otherTeam.Containers()
Expect(err).ToNot(HaveOccurred())
Expect(containers).To(BeEmpty())
})
})
Context("when there is a check container on a team worker", func() {
var resourceContainer db.Container
BeforeEach(func() {
atcWorker := atc.Worker{
ResourceTypes: []atc.WorkerResourceType{defaultWorkerResourceType},
Name: "default-team-worker",
GardenAddr: "3.4.5.6:7777",
BaggageclaimURL: "7.8.9.10:7878",
Team: defaultTeam.Name(),
}
worker, err := defaultTeam.SaveWorker(atcWorker, 0)
Expect(err).ToNot(HaveOccurred())
expiries := db.ContainerOwnerExpiries{
Min: 5 * time.Minute,
Max: 1 * time.Hour,
}
resourceConfigScope, err = defaultResource.SetResourceConfig(defaultResource.Source(), atc.VersionedResourceTypes{})
Expect(err).ToNot(HaveOccurred())
resourceContainer, err = worker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), expiries),
db.ContainerMetadata{
Type: "check",
},
)
Expect(err).ToNot(HaveOccurred())
})
It("finds the container", func() {
containers, err := defaultTeam.Containers()
Expect(err).ToNot(HaveOccurred())
Expect(containers).To(HaveLen(1))
Expect(containers).To(ConsistOf(resourceContainer))
})
Context("when there is another check container with the same resource config on a different team worker", func() {
var (
resource2Container db.Container
otherTeam db.Team
err error
)
BeforeEach(func() {
otherTeam, err = teamFactory.CreateTeam(atc.Team{Name: "other-team"})
Expect(err).NotTo(HaveOccurred())
otherPipeline, _, err := otherTeam.SavePipeline("other-pipeline", atc.Config{
Jobs: atc.JobConfigs{
{
Name: "some-job",
},
},
Resources: atc.ResourceConfigs{
{
Name: "some-resource",
Type: "some-base-resource-type",
Source: atc.Source{
"some": "source",
},
},
},
ResourceTypes: atc.ResourceTypes{
{
Name: "some-type",
Type: "some-base-resource-type",
Source: atc.Source{
"some-type": "source",
},
},
},
}, db.ConfigVersion(0), db.PipelineUnpaused)
Expect(err).NotTo(HaveOccurred())
otherResource, found, err := otherPipeline.Resource("some-resource")
Expect(err).NotTo(HaveOccurred())
Expect(found).To(BeTrue())
atcWorker := atc.Worker{
ResourceTypes: []atc.WorkerResourceType{defaultWorkerResourceType},
Name: "other-team-worker",
GardenAddr: "4.5.6.7:7777",
BaggageclaimURL: "8.9.10.11:7878",
Team: otherTeam.Name(),
}
worker, err := otherTeam.SaveWorker(atcWorker, 0)
Expect(err).ToNot(HaveOccurred())
expiries := db.ContainerOwnerExpiries{
Min: 5 * time.Minute,
Max: 1 * time.Hour,
}
resourceConfigScope, err = otherResource.SetResourceConfig(otherResource.Source(), atc.VersionedResourceTypes{})
Expect(err).ToNot(HaveOccurred())
resource2Container, err = worker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), expiries),
db.ContainerMetadata{
Type: "check",
},
)
Expect(err).ToNot(HaveOccurred())
})
It("returns the container only from the team", func() {
containers, err := otherTeam.Containers()
Expect(err).ToNot(HaveOccurred())
Expect(containers).To(HaveLen(1))
Expect(containers).To(ConsistOf(resource2Container))
})
})
Context("when there is a check container with the same resource config on a global worker", func() {
var (
globalResourceContainer db.Container
)
BeforeEach(func() {
expiries := db.ContainerOwnerExpiries{
Min: 5 * time.Minute,
Max: 1 * time.Hour,
}
resourceConfigScope, err := defaultResource.SetResourceConfig(defaultResource.Source(), atc.VersionedResourceTypes{})
Expect(err).ToNot(HaveOccurred())
globalResourceContainer, err = defaultWorker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), expiries),
db.ContainerMetadata{
Type: "check",
},
)
Expect(err).ToNot(HaveOccurred())
})
It("returns the container only from the team worker and global worker", func() {
containers, err := defaultTeam.Containers()
Expect(err).ToNot(HaveOccurred())
Expect(containers).To(HaveLen(2))
Expect(containers).To(ConsistOf(resourceContainer, globalResourceContainer))
})
})
})
Context("when there is a check container for a resource type", func() {
var resourceContainer db.Container
BeforeEach(func() {
expiries := db.ContainerOwnerExpiries{
Min: 5 * time.Minute,
Max: 1 * time.Hour,
}
resourceConfigScope, err := defaultResourceType.SetResourceConfig(defaultResourceType.Source(), atc.VersionedResourceTypes{})
Expect(err).ToNot(HaveOccurred())
resourceContainer, err = defaultWorker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), expiries),
db.ContainerMetadata{
Type: "check",
},
)
Expect(err).ToNot(HaveOccurred())
})
It("finds the container", func() {
containers, err := defaultTeam.Containers()
Expect(err).ToNot(HaveOccurred())
Expect(containers).To(HaveLen(1))
Expect(containers).To(ConsistOf(resourceContainer))
})
})
})
Describe("FindContainerByHandle", func() {
var createdContainer db.CreatedContainer
BeforeEach(func() {
job, found, err := defaultPipeline.Job("some-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
build, err := job.CreateBuild()
Expect(err).ToNot(HaveOccurred())
creatingContainer, err := defaultWorker.CreateContainer(db.NewBuildStepContainerOwner(build.ID(), atc.PlanID("some-job"), defaultTeam.ID()), db.ContainerMetadata{Type: "task", StepName: "some-task"})
Expect(err).ToNot(HaveOccurred())
createdContainer, err = creatingContainer.Created()
Expect(err).ToNot(HaveOccurred())
})
Context("when worker is no longer in database", func() {
BeforeEach(func() {
err := defaultWorker.Delete()
Expect(err).ToNot(HaveOccurred())
})
It("the container goes away from the db", func() {
_, found, err := defaultTeam.FindContainerByHandle(createdContainer.Handle())
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeFalse())
})
})
It("finds a container for the team", func() {
container, found, err := defaultTeam.FindContainerByHandle(createdContainer.Handle())
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(container).ToNot(BeNil())
Expect(container.Handle()).To(Equal(createdContainer.Handle()))
})
})
Describe("FindVolumeForWorkerArtifact", func() {
Context("when the artifact doesn't exist", func() {
It("returns not found", func() {
_, found, err := defaultTeam.FindVolumeForWorkerArtifact(12)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeFalse())
})
})
Context("when the artifact exists", func() {
BeforeEach(func() {
_, err := dbConn.Exec("INSERT INTO worker_artifacts (id, name) VALUES ($1, '')", 18)
Expect(err).NotTo(HaveOccurred())
})
Context("when the associated volume doesn't exist", func() {
It("returns not found", func() {
_, found, err := defaultTeam.FindVolumeForWorkerArtifact(18)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeFalse())
})
})
Context("when the associated volume exists", func() {
BeforeEach(func() {
_, 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)
Expect(err).NotTo(HaveOccurred())
})
It("returns the volume", func() {
volume, found, err := defaultTeam.FindVolumeForWorkerArtifact(18)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(volume.Handle()).To(Equal("some-handle"))
Expect(volume.WorkerArtifactID()).To(Equal(18))
})
})
})
})
Describe("FindWorkerForContainer", func() {
var containerMetadata db.ContainerMetadata
var defaultBuild db.Build
BeforeEach(func() {
var err error
containerMetadata = db.ContainerMetadata{
Type: "task",
StepName: "some-task",
}
defaultBuild, err = defaultTeam.CreateOneOffBuild()
Expect(err).ToNot(HaveOccurred())
})
Context("when there is a creating container", func() {
var container db.CreatingContainer
BeforeEach(func() {
var err error
container, err = defaultWorker.CreateContainer(db.NewBuildStepContainerOwner(defaultBuild.ID(), "some-plan", defaultTeam.ID()), containerMetadata)
Expect(err).ToNot(HaveOccurred())
})
It("returns it", func() {
worker, found, err := defaultTeam.FindWorkerForContainer(container.Handle())
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(worker).ToNot(BeNil())
Expect(worker.Name()).To(Equal(defaultWorker.Name()))
})
})
Context("when there is a created container", func() {
var container db.CreatedContainer
BeforeEach(func() {
creatingContainer, err := defaultWorker.CreateContainer(db.NewBuildStepContainerOwner(defaultBuild.ID(), "some-plan", defaultTeam.ID()), containerMetadata)
Expect(err).ToNot(HaveOccurred())
container, err = creatingContainer.Created()
Expect(err).ToNot(HaveOccurred())
})
It("returns it", func() {
worker, found, err := defaultTeam.FindWorkerForContainer(container.Handle())
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(worker).ToNot(BeNil())
Expect(worker.Name()).To(Equal(defaultWorker.Name()))
})
})
Context("when there is no container", func() {
It("returns nil", func() {
worker, found, err := defaultTeam.FindWorkerForContainer("bogus-handle")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeFalse())
Expect(worker).To(BeNil())
})
})
})
Describe("Updating Auth", func() {
var (
authProvider atc.TeamAuth
)
BeforeEach(func() {
authProvider = atc.TeamAuth{
"owner": {"users": []string{"local:username"}},
}
})
Describe("UpdateProviderAuth", func() {
It("saves auth team info to the existing team", func() {
err := team.UpdateProviderAuth(authProvider)
Expect(err).ToNot(HaveOccurred())
Expect(team.Auth()).To(Equal(authProvider))
})
It("resets legacy_auth to NULL", func() {
oldLegacyAuth := `{"basicauth": {"username": "u", "password": "p"}}`
_, err := dbConn.Exec("UPDATE teams SET legacy_auth = $1 WHERE id = $2", oldLegacyAuth, team.ID())
team.UpdateProviderAuth(authProvider)
var newLegacyAuth sql.NullString
err = dbConn.QueryRow("SELECT legacy_auth FROM teams WHERE id = $1", team.ID()).Scan(&newLegacyAuth)
Expect(err).ToNot(HaveOccurred())
value, err := newLegacyAuth.Value()
Expect(err).ToNot(HaveOccurred())
Expect(value).To(BeNil())
})
Context("when team auth is already set", func() {
BeforeEach(func() {
team.UpdateProviderAuth(atc.TeamAuth{
"owner": {"users": []string{"local:somebody"}},
"viewer": {"users": []string{"local:someone"}},
})
})
It("overrides the existing auth with the new config", func() {
err := team.UpdateProviderAuth(authProvider)
Expect(err).ToNot(HaveOccurred())
Expect(team.Auth()).To(Equal(authProvider))
})
})
})
})
Describe("Pipelines", func() {
var (
pipelines []db.Pipeline
pipeline1 db.Pipeline
pipeline2 db.Pipeline
)
JustBeforeEach(func() {
var err error
pipelines, err = team.Pipelines()
Expect(err).ToNot(HaveOccurred())
})
Context("when the team has configured pipelines", func() {
BeforeEach(func() {
var err error
pipeline1, _, err = team.SavePipeline("fake-pipeline", atc.Config{
Jobs: atc.JobConfigs{
{Name: "job-name"},
},
}, db.ConfigVersion(1), db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
pipeline2, _, err = team.SavePipeline("fake-pipeline-two", atc.Config{
Jobs: atc.JobConfigs{
{Name: "job-fake"},
},
}, db.ConfigVersion(1), db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
})
It("returns the pipelines", func() {
Expect(pipelines).To(Equal([]db.Pipeline{pipeline1, pipeline2}))
})
})
Context("when the team has no configured pipelines", func() {
It("returns no pipelines", func() {
Expect(pipelines).To(Equal([]db.Pipeline{}))
})
})
})
Describe("PublicPipelines", func() {
var (
pipelines []db.Pipeline
pipeline2 db.Pipeline
)
JustBeforeEach(func() {
var err error
pipelines, err = team.PublicPipelines()
Expect(err).ToNot(HaveOccurred())
})
Context("when the team has configured pipelines", func() {
BeforeEach(func() {
var err error
_, _, err = team.SavePipeline("fake-pipeline", atc.Config{
Jobs: atc.JobConfigs{
{Name: "job-name"},
},
}, db.ConfigVersion(1), db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
pipeline2, _, err = team.SavePipeline("fake-pipeline-two", atc.Config{
Jobs: atc.JobConfigs{
{Name: "job-fake"},
},
}, db.ConfigVersion(1), db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
err = pipeline2.Expose()
Expect(err).ToNot(HaveOccurred())
found, err := pipeline2.Reload()
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
})
It("returns the pipelines", func() {
Expect(pipelines).To(Equal([]db.Pipeline{pipeline2}))
})
})
Context("when the team has no configured pipelines", func() {
It("returns no pipelines", func() {
Expect(pipelines).To(Equal([]db.Pipeline{}))
})
})
})
Describe("VisiblePipelines", func() {
var (
pipelines []db.Pipeline
pipeline1 db.Pipeline
pipeline2 db.Pipeline
)
JustBeforeEach(func() {
var err error
pipelines, err = team.VisiblePipelines()
Expect(err).ToNot(HaveOccurred())
})
Context("when the team has configured pipelines", func() {
BeforeEach(func() {
var err error
pipeline1, _, err = team.SavePipeline("fake-pipeline", atc.Config{
Jobs: atc.JobConfigs{
{Name: "job-name"},
},
}, db.ConfigVersion(1), db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
pipeline2, _, err = otherTeam.SavePipeline("fake-pipeline-two", atc.Config{
Jobs: atc.JobConfigs{
{Name: "job-fake"},
},
}, db.ConfigVersion(1), db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
Expect(pipeline2.Expose()).To(Succeed())
Expect(pipeline2.Reload()).To(BeTrue())
})
It("returns the pipelines", func() {
Expect(pipelines).To(Equal([]db.Pipeline{pipeline1, pipeline2}))
})
Context("when the other team has a private pipeline", func() {
BeforeEach(func() {
var err error
_, _, err = otherTeam.SavePipeline("fake-pipeline-three", atc.Config{
Jobs: atc.JobConfigs{
{Name: "job-fake-again"},
},
}, db.ConfigVersion(1), db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
})
It("does not return the other team private pipeline", func() {
Expect(pipelines).To(Equal([]db.Pipeline{pipeline1, pipeline2}))
})
})
})
Context("when the team has no configured pipelines", func() {
It("returns no pipelines", func() {
Expect(pipelines).To(Equal([]db.Pipeline{}))
})
})
})
Describe("OrderPipelines", func() {
var pipeline1 db.Pipeline
var pipeline2 db.Pipeline
var otherPipeline1 db.Pipeline
var otherPipeline2 db.Pipeline
BeforeEach(func() {
var err error
pipeline1, _, err = team.SavePipeline("pipeline-name-a", atc.Config{}, 0, db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
pipeline2, _, err = team.SavePipeline("pipeline-name-b", atc.Config{}, 0, db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
otherPipeline1, _, err = otherTeam.SavePipeline("pipeline-name-a", atc.Config{}, 0, db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
otherPipeline2, _, err = otherTeam.SavePipeline("pipeline-name-b", atc.Config{}, 0, db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
})
It("orders pipelines that belong to team (case insensitive)", func() {
err := team.OrderPipelines([]string{"pipeline-name-b", "pipeline-name-a"})
Expect(err).ToNot(HaveOccurred())
err = otherTeam.OrderPipelines([]string{"pipeline-name-a", "pipeline-name-b"})
Expect(err).ToNot(HaveOccurred())
orderedPipelines, err := team.Pipelines()
Expect(err).ToNot(HaveOccurred())
Expect(orderedPipelines).To(HaveLen(2))
Expect(orderedPipelines[0].ID()).To(Equal(pipeline2.ID()))
Expect(orderedPipelines[1].ID()).To(Equal(pipeline1.ID()))
otherTeamOrderedPipelines, err := otherTeam.Pipelines()
Expect(err).ToNot(HaveOccurred())
Expect(otherTeamOrderedPipelines).To(HaveLen(2))
Expect(otherTeamOrderedPipelines[0].ID()).To(Equal(otherPipeline1.ID()))
Expect(otherTeamOrderedPipelines[1].ID()).To(Equal(otherPipeline2.ID()))
})
Context("when pipeline does not exist", func() {
It("returns error ", func() {
err := otherTeam.OrderPipelines([]string{"pipeline-name-a", "pipeline-does-not-exist"})
Expect(err).To(HaveOccurred())
})
})
})
Describe("CreateOneOffBuild", func() {
var (
oneOffBuild db.Build
err error
)
BeforeEach(func() {
oneOffBuild, err = team.CreateOneOffBuild()
Expect(err).ToNot(HaveOccurred())
})
It("can create one-off builds", func() {
Expect(oneOffBuild.ID()).ToNot(BeZero())
Expect(oneOffBuild.JobName()).To(BeZero())
Expect(oneOffBuild.PipelineName()).To(BeZero())
Expect(oneOffBuild.Name()).To(Equal(strconv.Itoa(oneOffBuild.ID())))
Expect(oneOffBuild.TeamName()).To(Equal(team.Name()))
Expect(oneOffBuild.Status()).To(Equal(db.BuildStatusPending))
Expect(oneOffBuild.CreateTime()).To(BeTemporally("~", time.Now(), 100*time.Millisecond))
})
})
Describe("CreateStartedBuild", func() {
var (
plan atc.Plan
startedBuild db.Build
err error
)
BeforeEach(func() {
plan = atc.Plan{
ID: atc.PlanID("56"),
Get: &atc.GetPlan{
Type: "some-type",
Name: "some-name",
Resource: "some-resource",
Source: atc.Source{"some": "source"},
Params: atc.Params{"some": "params"},
Version: &atc.Version{"some": "version"},
Tags: atc.Tags{"some-tags"},
VersionedResourceTypes: atc.VersionedResourceTypes{
{
ResourceType: atc.ResourceType{
Name: "some-name",
Source: atc.Source{"some": "source"},
Type: "some-type",
Privileged: true,
Tags: atc.Tags{"some-tags"},
},
Version: atc.Version{"some-resource-type": "version"},
},
},
},
}
startedBuild, err = team.CreateStartedBuild(plan)
Expect(err).ToNot(HaveOccurred())
})
It("can create started builds with plans", func() {
Expect(startedBuild.ID()).ToNot(BeZero())
Expect(startedBuild.JobName()).To(BeZero())
Expect(startedBuild.PipelineName()).To(BeZero())
Expect(startedBuild.Name()).To(Equal(strconv.Itoa(startedBuild.ID())))
Expect(startedBuild.TeamName()).To(Equal(team.Name()))
Expect(startedBuild.Status()).To(Equal(db.BuildStatusStarted))
})
It("saves the public plan", func() {
found, err := startedBuild.Reload()
Expect(err).NotTo(HaveOccurred())
Expect(found).To(BeTrue())
Expect(startedBuild.PublicPlan()).To(Equal(plan.Public()))
})
It("creates Start event", func() {
found, err := startedBuild.Reload()
Expect(err).NotTo(HaveOccurred())
Expect(found).To(BeTrue())
events, err := startedBuild.Events(0)
Expect(err).NotTo(HaveOccurred())
defer db.Close(events)
Expect(events.Next()).To(Equal(envelope(event.Status{
Status: atc.StatusStarted,
Time: startedBuild.StartTime().Unix(),
})))
})
})
Describe("PrivateAndPublicBuilds", func() {
Context("when there are no builds", func() {
It("returns an empty list of builds", func() {
builds, pagination, err := team.PrivateAndPublicBuilds(db.Page{Limit: 2})
Expect(err).ToNot(HaveOccurred())
Expect(pagination.Next).To(BeNil())
Expect(pagination.Previous).To(BeNil())
Expect(builds).To(BeEmpty())
})
})
Context("when there are builds", func() {
var allBuilds [5]db.Build
var pipeline db.Pipeline
var pipelineBuilds [2]db.Build
BeforeEach(func() {
for i := 0; i < 3; i++ {
build, err := team.CreateOneOffBuild()
Expect(err).ToNot(HaveOccurred())
allBuilds[i] = build
}
config := atc.Config{
Jobs: atc.JobConfigs{
{
Name: "some-job",
},
},
}
var err error
pipeline, _, err = team.SavePipeline("some-pipeline", config, db.ConfigVersion(1), db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
job, found, err := pipeline.Job("some-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
for i := 3; i < 5; i++ {
build, err := job.CreateBuild()
Expect(err).ToNot(HaveOccurred())
allBuilds[i] = build
pipelineBuilds[i-3] = build
}
})
It("returns all team builds with correct pagination", func() {
builds, pagination, err := team.PrivateAndPublicBuilds(db.Page{Limit: 2})
Expect(err).ToNot(HaveOccurred())
Expect(len(builds)).To(Equal(2))
Expect(builds[0]).To(Equal(allBuilds[4]))
Expect(builds[1]).To(Equal(allBuilds[3]))
Expect(pagination.Previous).To(BeNil())
Expect(pagination.Next).To(Equal(&db.Page{Since: allBuilds[3].ID(), Limit: 2}))
builds, pagination, err = team.PrivateAndPublicBuilds(*pagination.Next)
Expect(err).ToNot(HaveOccurred())
Expect(len(builds)).To(Equal(2))
Expect(builds[0]).To(Equal(allBuilds[2]))
Expect(builds[1]).To(Equal(allBuilds[1]))
Expect(pagination.Previous).To(Equal(&db.Page{Until: allBuilds[2].ID(), Limit: 2}))
Expect(pagination.Next).To(Equal(&db.Page{Since: allBuilds[1].ID(), Limit: 2}))
builds, pagination, err = team.PrivateAndPublicBuilds(*pagination.Next)
Expect(err).ToNot(HaveOccurred())
Expect(len(builds)).To(Equal(1))
Expect(builds[0]).To(Equal(allBuilds[0]))
Expect(pagination.Previous).To(Equal(&db.Page{Until: allBuilds[0].ID(), Limit: 2}))
Expect(pagination.Next).To(BeNil())
builds, pagination, err = team.PrivateAndPublicBuilds(*pagination.Previous)
Expect(err).ToNot(HaveOccurred())
Expect(len(builds)).To(Equal(2))
Expect(builds[0]).To(Equal(allBuilds[2]))
Expect(builds[1]).To(Equal(allBuilds[1]))
Expect(pagination.Previous).To(Equal(&db.Page{Until: allBuilds[2].ID(), Limit: 2}))
Expect(pagination.Next).To(Equal(&db.Page{Since: allBuilds[1].ID(), Limit: 2}))
})
Context("when there are builds that belong to different teams", func() {
var teamABuilds [3]db.Build
var teamBBuilds [3]db.Build
var caseInsensitiveTeamA db.Team
var caseInsensitiveTeamB db.Team
BeforeEach(func() {
_, err := teamFactory.CreateTeam(atc.Team{Name: "team-a"})
Expect(err).ToNot(HaveOccurred())
_, err = teamFactory.CreateTeam(atc.Team{Name: "team-b"})
Expect(err).ToNot(HaveOccurred())
var found bool
caseInsensitiveTeamA, found, err = teamFactory.FindTeam("team-A")
Expect(found).To(BeTrue())
Expect(err).ToNot(HaveOccurred())
caseInsensitiveTeamB, found, err = teamFactory.FindTeam("team-B")
Expect(found).To(BeTrue())
Expect(err).ToNot(HaveOccurred())
for i := 0; i < 3; i++ {
teamABuilds[i], err = caseInsensitiveTeamA.CreateOneOffBuild()
Expect(err).ToNot(HaveOccurred())
teamBBuilds[i], err = caseInsensitiveTeamB.CreateOneOffBuild()
Expect(err).ToNot(HaveOccurred())
}
})
Context("when other team builds are private", func() {
It("returns only builds for requested team", func() {
builds, _, err := caseInsensitiveTeamA.PrivateAndPublicBuilds(db.Page{Limit: 10})
Expect(err).ToNot(HaveOccurred())
Expect(len(builds)).To(Equal(3))
Expect(builds).To(ConsistOf(teamABuilds))
builds, _, err = caseInsensitiveTeamB.PrivateAndPublicBuilds(db.Page{Limit: 10})
Expect(err).ToNot(HaveOccurred())
Expect(len(builds)).To(Equal(3))
Expect(builds).To(ConsistOf(teamBBuilds))
})
})
Context("when other team builds are public", func() {
BeforeEach(func() {
err := pipeline.Expose()
Expect(err).ToNot(HaveOccurred())
})
It("returns builds for requested team and public builds", func() {
builds, _, err := caseInsensitiveTeamA.PrivateAndPublicBuilds(db.Page{Limit: 10})
Expect(err).ToNot(HaveOccurred())
Expect(builds).To(HaveLen(5))
expectedBuilds := []db.Build{}
for _, b := range teamABuilds {
expectedBuilds = append(expectedBuilds, b)
}
for _, b := range pipelineBuilds {
expectedBuilds = append(expectedBuilds, b)
}
Expect(builds).To(ConsistOf(expectedBuilds))
})
})
})
})
})
Describe("BuildsWithTime", func() {
var (
pipeline db.Pipeline
builds = make([]db.Build, 4)
)
BeforeEach(func() {
var (
err error
found bool
)
config := atc.Config{
Jobs: atc.JobConfigs{
{
Name: "some-job",
},
{
Name: "some-other-job",
},
},
}
pipeline, _, err = team.SavePipeline("some-pipeline", config, db.ConfigVersion(1), db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
job, found, err := pipeline.Job("some-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
for i := range builds {
builds[i], err = job.CreateBuild()
Expect(err).ToNot(HaveOccurred())
buildStart := time.Date(2020, 11, i+1, 0, 0, 0, 0, time.UTC)
_, err = dbConn.Exec("UPDATE builds SET start_time = to_timestamp($1) WHERE id = $2", buildStart.Unix(), builds[i].ID())
Expect(err).NotTo(HaveOccurred())
builds[i], found, err = job.Build(builds[i].Name())
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
}
})
Context("When not providing boundaries", func() {
Context("without a limit specified", func() {
It("returns no builds", func() {
returnedBuilds, _, err := team.BuildsWithTime(db.Page{})
Expect(err).NotTo(HaveOccurred())
Expect(returnedBuilds).To(BeEmpty())
})
})
Context("when a limit specified", func() {
It("returns a subset of the builds", func() {
returnedBuilds, _, err := team.BuildsWithTime(db.Page{
Limit: 2,
})
Expect(err).NotTo(HaveOccurred())
Expect(returnedBuilds).To(ConsistOf(builds[3], builds[2]))
})
})
})
Context("When providing boundaries", func() {
Context("only until", func() {
It("returns only those before until", func() {
returnedBuilds, _, err := team.BuildsWithTime(db.Page{
Until: int(builds[2].StartTime().Unix()),
Limit: 50,
})
Expect(err).NotTo(HaveOccurred())
Expect(returnedBuilds).To(ConsistOf(builds[0], builds[1], builds[2]))
})
})
Context("only since", func() {
It("returns only those after since", func() {
returnedBuilds, _, err := team.BuildsWithTime(db.Page{
Since: int(builds[1].StartTime().Unix()),
Limit: 50,
})
Expect(err).NotTo(HaveOccurred())
Expect(returnedBuilds).To(ConsistOf(builds[1], builds[2], builds[3]))
})
})
Context("since and until", func() {
It("returns only elements in the range", func() {
returnedBuilds, _, err := team.BuildsWithTime(db.Page{
Until: int(builds[2].StartTime().Unix()),
Since: int(builds[1].StartTime().Unix()),
Limit: 50,
})
Expect(err).NotTo(HaveOccurred())
Expect(returnedBuilds).To(ConsistOf(builds[1], builds[2]))
})
})
})
})
Describe("Builds", func() {
var (
expectedBuilds []db.Build
pipeline db.Pipeline
oneOffBuild, build, secondBuild, thirdBuild db.Build
)
BeforeEach(func() {
var err error
oneOffBuild, err = team.CreateOneOffBuild()
Expect(err).NotTo(HaveOccurred())
expectedBuilds = append(expectedBuilds, oneOffBuild)
config := atc.Config{
Jobs: atc.JobConfigs{
{
Name: "some-job",
},
{
Name: "some-other-job",
},
},
}
pipeline, _, err = team.SavePipeline("some-pipeline", config, db.ConfigVersion(1), db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
job, found, err := pipeline.Job("some-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
build, err = job.CreateBuild()
Expect(err).ToNot(HaveOccurred())
expectedBuilds = append(expectedBuilds, build)
secondBuild, err = job.CreateBuild()
Expect(err).ToNot(HaveOccurred())
expectedBuilds = append(expectedBuilds, secondBuild)
someOtherJob, found, err := pipeline.Job("some-other-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
thirdBuild, err = someOtherJob.CreateBuild()
Expect(err).ToNot(HaveOccurred())
expectedBuilds = append(expectedBuilds, thirdBuild)
})
It("returns builds for the current team", func() {
builds, _, err := team.Builds(db.Page{Limit: 10})
Expect(err).NotTo(HaveOccurred())
Expect(builds).To(ConsistOf(expectedBuilds))
})
Context("when limiting the range of build ids", func() {
Context("specifying only until", func() {
It("returns all builds after the specified id", func() {
builds, _, err := team.Builds(db.Page{Limit: 50, Until: secondBuild.ID()})
Expect(err).NotTo(HaveOccurred())
Expect(builds).To(ConsistOf(thirdBuild))
})
})
Context("specifying only since", func() {
It("returns all builds before the specified id", func() {
builds, _, err := team.Builds(db.Page{Limit: 50, Since: secondBuild.ID()})
Expect(err).NotTo(HaveOccurred())
Expect(builds).To(ConsistOf(oneOffBuild, build))
})
})
Context("specifying both since and until", func() {
It("returns all builds within range of ids", func() {
builds, _, err := team.Builds(db.Page{Limit: 50, Since: thirdBuild.ID(), Until: build.ID()})
Expect(err).NotTo(HaveOccurred())
Expect(builds).To(ConsistOf(secondBuild))
})
})
Context("specifying since greater than the biggest ID in the database", func() {
It("returns no rows error", func() {
builds, _, err := team.Builds(db.Page{Limit: 50, Until: thirdBuild.ID() + 1})
Expect(err).ToNot(HaveOccurred())
Expect(builds).To(BeEmpty())
})
})
Context("specifying invalid boundaries", func() {
It("should fail", func() {
_, _, err := team.Builds(db.Page{Limit: 50, Since: secondBuild.ID(), Until: thirdBuild.ID()})
Expect(err).To(HaveOccurred())
})
})
})
Context("when there are builds that belong to different teams", func() {
var teamABuilds [3]db.Build
var teamBBuilds [3]db.Build
var caseInsensitiveTeamA db.Team
var caseInsensitiveTeamB db.Team
BeforeEach(func() {
_, err := teamFactory.CreateTeam(atc.Team{Name: "team-a"})
Expect(err).ToNot(HaveOccurred())
_, err = teamFactory.CreateTeam(atc.Team{Name: "team-b"})
Expect(err).ToNot(HaveOccurred())
var found bool
caseInsensitiveTeamA, found, err = teamFactory.FindTeam("team-A")
Expect(found).To(BeTrue())
Expect(err).ToNot(HaveOccurred())
caseInsensitiveTeamB, found, err = teamFactory.FindTeam("team-B")
Expect(found).To(BeTrue())
Expect(err).ToNot(HaveOccurred())
for i := 0; i < 3; i++ {
teamABuilds[i], err = caseInsensitiveTeamA.CreateOneOffBuild()
Expect(err).ToNot(HaveOccurred())
teamBBuilds[i], err = caseInsensitiveTeamB.CreateOneOffBuild()
Expect(err).ToNot(HaveOccurred())
}
})
Context("when other team builds are private", func() {
It("returns only builds for requested team", func() {
builds, _, err := caseInsensitiveTeamA.Builds(db.Page{Limit: 10})
Expect(err).ToNot(HaveOccurred())
Expect(len(builds)).To(Equal(3))
Expect(builds).To(ConsistOf(teamABuilds))
builds, _, err = caseInsensitiveTeamB.Builds(db.Page{Limit: 10})
Expect(err).ToNot(HaveOccurred())
Expect(len(builds)).To(Equal(3))
Expect(builds).To(ConsistOf(teamBBuilds))
})
})
Context("when other team builds are public", func() {
BeforeEach(func() {
err := pipeline.Expose()
Expect(err).ToNot(HaveOccurred())
})
It("returns only builds for requested team", func() {
builds, _, err := caseInsensitiveTeamA.Builds(db.Page{Limit: 10})
Expect(err).ToNot(HaveOccurred())
Expect(len(builds)).To(Equal(3))
Expect(builds).To(ConsistOf(teamABuilds))
builds, _, err = caseInsensitiveTeamB.Builds(db.Page{Limit: 10})
Expect(err).ToNot(HaveOccurred())
Expect(len(builds)).To(Equal(3))
Expect(builds).To(ConsistOf(teamBBuilds))
})
})
})
})
Describe("SavePipeline", func() {
type SerialGroup struct {
JobID int
Name string
}
var (
config atc.Config
otherConfig atc.Config
pipelineName string
)
BeforeEach(func() {
config = atc.Config{
Groups: atc.GroupConfigs{
{
Name: "some-group",
Jobs: []string{"job-1", "job-2"},
Resources: []string{"resource-1", "resource-2"},
},
},
Resources: atc.ResourceConfigs{
{
Name: "some-resource",
Type: "some-type",
Source: atc.Source{
"source-config": "some-value",
},
},
},
ResourceTypes: atc.ResourceTypes{
{
Name: "some-resource-type",
Type: "some-type",
Source: atc.Source{
"source-config": "some-value",
},
},
},
Jobs: atc.JobConfigs{
{
Name: "some-job",
Public: true,
Serial: true,
SerialGroups: []string{"serial-group-1", "serial-group-2"},
Plan: atc.PlanSequence{
{
Get: "some-input",
Resource: "some-resource",
Params: atc.Params{
"some-param": "some-value",
},
Passed: []string{"job-1", "job-2"},
Trigger: true,
},
{
Task: "some-task",
Privileged: true,
TaskConfigPath: "some/config/path.yml",
TaskConfig: &atc.TaskConfig{
RootfsURI: "some-image",
},
},
{
Put: "some-resource",
Params: atc.Params{
"some-param": "some-value",
},
},
},
},
},
}
otherConfig = atc.Config{
Groups: atc.GroupConfigs{
{
Name: "some-group",
Jobs: []string{"some-other-job", "job-1", "job-2"},
Resources: []string{"resource-1", "resource-2"},
},
},
Resources: atc.ResourceConfigs{
{
Name: "some-other-resource",
Type: "some-type",
Source: atc.Source{
"source-config": "some-value",
},
},
},
Jobs: atc.JobConfigs{
{
Name: "some-other-job",
},
},
}
pipelineName = "some-pipeline"
})
It("returns true for created", func() {
_, created, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
Expect(created).To(BeTrue())
})
It("caches the team id", func() {
_, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
pipeline, found, err := team.Pipeline(pipelineName)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(pipeline.TeamID()).To(Equal(team.ID()))
})
It("can be saved as paused", func() {
_, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelinePaused)
Expect(err).ToNot(HaveOccurred())
pipeline, found, err := team.Pipeline(pipelineName)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(pipeline.Paused()).To(BeTrue())
})
It("can be saved as unpaused", func() {
_, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
pipeline, found, err := team.Pipeline(pipelineName)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(pipeline.Paused()).To(BeFalse())
})
It("defaults to paused", func() {
_, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
pipeline, found, err := team.Pipeline(pipelineName)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(pipeline.Paused()).To(BeTrue())
})
It("creates all of the resources from the pipeline in the database", func() {
savedPipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
resource, found, err := savedPipeline.Resource("some-resource")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(resource.Type()).To(Equal("some-type"))
Expect(resource.Source()).To(Equal(atc.Source{
"source-config": "some-value",
}))
})
It("updates resource config", func() {
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
config.Resources[0].Source = atc.Source{
"source-other-config": "some-other-value",
}
savedPipeline, _, err := team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
resource, found, err := savedPipeline.Resource("some-resource")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(resource.Type()).To(Equal("some-type"))
Expect(resource.Source()).To(Equal(atc.Source{
"source-other-config": "some-other-value",
}))
})
It("clears out api pinned version when resaving a pinned version on the pipeline config", func() {
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
resource, found, err := pipeline.Resource("some-resource")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
setupTx, err := dbConn.Begin()
Expect(err).ToNot(HaveOccurred())
brt := db.BaseResourceType{
Name: "some-type",
}
_, err = brt.FindOrCreate(setupTx, false)
Expect(err).NotTo(HaveOccurred())
Expect(setupTx.Commit()).To(Succeed())
rc, err := resource.SetResourceConfig(atc.Source{"source-config": "some-value"}, atc.VersionedResourceTypes{})
Expect(err).ToNot(HaveOccurred())
err = rc.SaveVersions([]atc.Version{
atc.Version{"version": "v1"},
atc.Version{"version": "v2"},
})
Expect(err).ToNot(HaveOccurred())
rcv, found, err := rc.FindVersion(atc.Version{"version": "v1"})
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
err = resource.PinVersion(rcv.ID())
Expect(err).ToNot(HaveOccurred())
reloaded, err := resource.Reload()
Expect(err).ToNot(HaveOccurred())
Expect(reloaded).To(BeTrue())
Expect(resource.APIPinnedVersion()).To(Equal(atc.Version{"version": "v1"}))
config.Resources[0].Version = atc.Version{
"version": "v2",
}
savedPipeline, _, err := team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
resource, found, err = savedPipeline.Resource("some-resource")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(resource.ConfigPinnedVersion()).To(Equal(atc.Version{"version": "v2"}))
Expect(resource.APIPinnedVersion()).To(BeNil())
})
It("does not clear the api pinned version when resaving pipeline config", func() {
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
resource, found, err := pipeline.Resource("some-resource")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
setupTx, err := dbConn.Begin()
Expect(err).ToNot(HaveOccurred())
brt := db.BaseResourceType{
Name: "some-type",
}
_, err = brt.FindOrCreate(setupTx, false)
Expect(err).NotTo(HaveOccurred())
Expect(setupTx.Commit()).To(Succeed())
rc, err := resource.SetResourceConfig(atc.Source{"source-config": "some-value"}, atc.VersionedResourceTypes{})
Expect(err).ToNot(HaveOccurred())
err = rc.SaveVersions([]atc.Version{
atc.Version{"version": "v1"},
atc.Version{"version": "v2"},
})
Expect(err).ToNot(HaveOccurred())
rcv, found, err := rc.FindVersion(atc.Version{"version": "v1"})
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
err = resource.PinVersion(rcv.ID())
Expect(err).ToNot(HaveOccurred())
reloaded, err := resource.Reload()
Expect(err).ToNot(HaveOccurred())
Expect(reloaded).To(BeTrue())
Expect(resource.APIPinnedVersion()).To(Equal(atc.Version{"version": "v1"}))
savedPipeline, _, err := team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
resource, found, err = savedPipeline.Resource("some-resource")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(resource.APIPinnedVersion()).To(Equal(atc.Version{"version": "v1"}))
})
It("marks resource as inactive if it is no longer in config", func() {
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
config.Resources = []atc.ResourceConfig{}
savedPipeline, _, err := team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
_, found, err := savedPipeline.Resource("some-resource")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeFalse())
})
It("creates all of the resource types from the pipeline in the database", func() {
savedPipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
resourceType, found, err := savedPipeline.ResourceType("some-resource-type")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(resourceType.Type()).To(Equal("some-type"))
Expect(resourceType.Source()).To(Equal(atc.Source{
"source-config": "some-value",
}))
})
It("updates resource type config from the pipeline in the database", func() {
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
config.ResourceTypes[0].Source = atc.Source{
"source-other-config": "some-other-value",
}
savedPipeline, _, err := team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
resourceType, found, err := savedPipeline.ResourceType("some-resource-type")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(resourceType.Type()).To(Equal("some-type"))
Expect(resourceType.Source()).To(Equal(atc.Source{
"source-other-config": "some-other-value",
}))
})
It("marks resource type as inactive if it is no longer in config", func() {
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
config.ResourceTypes = []atc.ResourceType{}
savedPipeline, _, err := team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
_, found, err := savedPipeline.ResourceType("some-resource-type")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeFalse())
})
It("creates all of the jobs from the pipeline in the database", func() {
savedPipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
job, found, err := savedPipeline.Job("some-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(job.Config()).To(Equal(config.Jobs[0]))
})
It("updates job config", func() {
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
config.Jobs[0].Public = false
_, _, err = team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
job, found, err := pipeline.Job("some-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(job.Public()).To(BeFalse())
})
It("marks job inactive when it is no longer in pipeline", func() {
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
config.Jobs = []atc.JobConfig{}
savedPipeline, _, err := team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
_, found, err := savedPipeline.Job("some-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeFalse())
})
Context("update job names but keeps history", func() {
BeforeEach(func() {
newJobConfig := atc.JobConfig{
Name: "new-job",
Public: true,
Serial: true,
SerialGroups: []string{"serial-group-1", "serial-group-2"},
Plan: atc.PlanSequence{
{
Get: "some-input",
Resource: "some-resource",
Params: atc.Params{
"some-param": "some-value",
},
Passed: []string{"job-1", "job-2"},
Trigger: true,
},
{
Task: "some-task",
Privileged: true,
TaskConfigPath: "some/config/path.yml",
TaskConfig: &atc.TaskConfig{
RootfsURI: "some-image",
},
},
{
Put: "some-resource",
Params: atc.Params{
"some-param": "some-value",
},
},
},
}
config.Jobs = append(config.Jobs, newJobConfig)
})
It("should handle when there are multiple name changes", func() {
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
job, _, _ := pipeline.Job("some-job")
otherJob, _, _ := pipeline.Job("new-job")
config.Jobs[0].Name = "new-job"
config.Jobs[0].OldName = "some-job"
config.Jobs[1].Name = "new-other-job"
config.Jobs[1].OldName = "new-job"
updatedPipeline, _, err := team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
updatedJob, _, _ := updatedPipeline.Job("new-job")
Expect(updatedJob.ID()).To(Equal(job.ID()))
otherUpdatedJob, _, _ := updatedPipeline.Job("new-other-job")
Expect(otherUpdatedJob.ID()).To(Equal(otherJob.ID()))
})
It("should return an error when there is a swap with job name", func() {
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
config.Jobs[0].Name = "new-job"
config.Jobs[0].OldName = "some-job"
config.Jobs[1].Name = "some-job"
config.Jobs[1].OldName = "new-job"
_, _, err = team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).To(HaveOccurred())
})
Context("when new job name is in database but is inactive", func() {
It("should successfully update job name", func() {
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
config.Jobs = config.Jobs[:len(config.Jobs)-1]
_, _, err = team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
config.Jobs[0].Name = "new-job"
config.Jobs[0].OldName = "some-job"
_, _, err = team.SavePipeline(pipelineName, config, pipeline.ConfigVersion()+1, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
})
})
})
It("removes task caches for jobs that are no longer in pipeline", func() {
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
job, found, err := pipeline.Job("some-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
_, err = taskCacheFactory.FindOrCreate(job.ID(), "some-task", "some-path")
Expect(err).ToNot(HaveOccurred())
_, found, err = taskCacheFactory.Find(job.ID(), "some-task", "some-path")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
config.Jobs = []atc.JobConfig{}
_, _, err = team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
_, found, err = taskCacheFactory.Find(job.ID(), "some-task", "some-path")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeFalse())
})
It("removes task caches for tasks that are no longer exist", func() {
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
job, found, err := pipeline.Job("some-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
_, err = taskCacheFactory.FindOrCreate(job.ID(), "some-task", "some-path")
Expect(err).ToNot(HaveOccurred())
_, found, err = taskCacheFactory.Find(job.ID(), "some-task", "some-path")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
config.Jobs = []atc.JobConfig{
{
Name: "some-job",
Plan: atc.PlanSequence{
{
Task: "some-other-task",
TaskConfigPath: "some/config/path.yml",
},
},
},
}
_, _, err = team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
_, found, err = taskCacheFactory.Find(job.ID(), "some-task", "some-path")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeFalse())
})
It("should not remove task caches in other pipeline", func() {
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
otherPipeline, _, err := team.SavePipeline("other-pipeline", config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
job, found, err := pipeline.Job("some-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
_, err = taskCacheFactory.FindOrCreate(job.ID(), "some-task", "some-path")
Expect(err).ToNot(HaveOccurred())
_, found, err = taskCacheFactory.Find(job.ID(), "some-task", "some-path")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
otherJob, found, err := otherPipeline.Job("some-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
_, err = taskCacheFactory.FindOrCreate(otherJob.ID(), "some-task", "some-path")
Expect(err).ToNot(HaveOccurred())
_, found, err = taskCacheFactory.Find(otherJob.ID(), "some-task", "some-path")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
config.Jobs = []atc.JobConfig{
{
Name: "some-job",
Plan: atc.PlanSequence{
{
Task: "some-other-task",
TaskConfigPath: "some/config/path.yml",
},
},
},
}
_, _, err = team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
_, found, err = taskCacheFactory.Find(job.ID(), "some-task", "some-path")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeFalse())
_, found, err = taskCacheFactory.Find(otherJob.ID(), "some-task", "some-path")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
})
It("creates all of the serial groups from the jobs in the database", func() {
savedPipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
serialGroups := []SerialGroup{}
rows, err := dbConn.Query("SELECT job_id, serial_group FROM jobs_serial_groups")
Expect(err).ToNot(HaveOccurred())
for rows.Next() {
var serialGroup SerialGroup
err = rows.Scan(&serialGroup.JobID, &serialGroup.Name)
Expect(err).ToNot(HaveOccurred())
serialGroups = append(serialGroups, serialGroup)
}
job, found, err := savedPipeline.Job("some-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(serialGroups).To(ConsistOf([]SerialGroup{
{
JobID: job.ID(),
Name: "serial-group-1",
},
{
JobID: job.ID(),
Name: "serial-group-2",
},
}))
})
It("saves tags in the jobs table", func() {
savedPipeline, _, err := team.SavePipeline(pipelineName, otherConfig, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
job, found, err := savedPipeline.Job("some-other-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(job.Tags()).To(Equal([]string{"some-group"}))
})
It("updates tags in the jobs table", func() {
savedPipeline, _, err := team.SavePipeline(pipelineName, otherConfig, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
job, found, err := savedPipeline.Job("some-other-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(job.Tags()).To(Equal([]string{"some-group"}))
otherConfig.Groups = atc.GroupConfigs{
{
Name: "some-other-group",
Jobs: []string{"job-1", "job-2", "some-other-job"},
},
{
Name: "some-another-group",
Jobs: []string{"some-other-job"},
},
}
savedPipeline, _, err = team.SavePipeline(pipelineName, otherConfig, savedPipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
job, found, err = savedPipeline.Job("some-other-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(job.Tags()).To(ConsistOf([]string{"some-another-group", "some-other-group"}))
})
It("it returns created as false when updated", func() {
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
_, created, err := team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
Expect(created).To(BeFalse())
})
It("updating from paused to unpaused", func() {
_, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelinePaused)
Expect(err).ToNot(HaveOccurred())
pipeline, found, err := team.Pipeline(pipelineName)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(pipeline.Paused()).To(BeTrue())
_, _, err = team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
pipeline, found, err = team.Pipeline(pipelineName)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(pipeline.Paused()).To(BeFalse())
})
It("updating from unpaused to paused", func() {
_, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
pipeline, found, err := team.Pipeline(pipelineName)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(pipeline.Paused()).To(BeFalse())
_, _, err = team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelinePaused)
Expect(err).ToNot(HaveOccurred())
pipeline, found, err = team.Pipeline(pipelineName)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(pipeline.Paused()).To(BeTrue())
})
Context("updating with no change", func() {
It("maintains paused if the pipeline is paused", func() {
_, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelinePaused)
Expect(err).ToNot(HaveOccurred())
pipeline, found, err := team.Pipeline(pipelineName)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(pipeline.Paused()).To(BeTrue())
_, _, err = team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
pipeline, found, err = team.Pipeline(pipelineName)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(pipeline.Paused()).To(BeTrue())
})
It("maintains unpaused if the pipeline is unpaused", func() {
_, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
pipeline, found, err := team.Pipeline(pipelineName)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(pipeline.Paused()).To(BeFalse())
_, _, err = team.SavePipeline(pipelineName, config, pipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
pipeline, found, err = team.Pipeline(pipelineName)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(pipeline.Paused()).To(BeFalse())
})
})
It("can lookup a pipeline by name", func() {
pipelineName := "a-pipeline-name"
otherPipelineName := "an-other-pipeline-name"
_, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
_, _, err = team.SavePipeline(otherPipelineName, otherConfig, 0, db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
pipeline, found, err := team.Pipeline(pipelineName)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(pipeline.Name()).To(Equal(pipelineName))
Expect(pipeline.ID()).ToNot(Equal(0))
resourceTypes, err := pipeline.ResourceTypes()
Expect(err).ToNot(HaveOccurred())
resources, err := pipeline.Resources()
Expect(err).ToNot(HaveOccurred())
jobs, err := pipeline.Jobs()
Expect(err).ToNot(HaveOccurred())
expectConfigsEqual(atc.Config{
Groups: pipeline.Groups(),
Resources: resources.Configs(),
ResourceTypes: resourceTypes.Configs(),
Jobs: jobs.Configs(),
}, config)
otherPipeline, found, err := team.Pipeline(otherPipelineName)
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(otherPipeline.Name()).To(Equal(otherPipelineName))
Expect(otherPipeline.ID()).ToNot(Equal(0))
otherResourceTypes, err := otherPipeline.ResourceTypes()
Expect(err).ToNot(HaveOccurred())
otherResources, err := otherPipeline.Resources()
Expect(err).ToNot(HaveOccurred())
otherJobs, err := otherPipeline.Jobs()
Expect(err).ToNot(HaveOccurred())
expectConfigsEqual(atc.Config{
Groups: otherPipeline.Groups(),
Resources: otherResources.Configs(),
ResourceTypes: otherResourceTypes.Configs(),
Jobs: otherJobs.Configs(),
}, otherConfig)
})
It("can manage multiple pipeline configurations", func() {
pipelineName := "a-pipeline-name"
otherPipelineName := "an-other-pipeline-name"
By("being able to save the config")
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
otherPipeline, _, err := team.SavePipeline(otherPipelineName, otherConfig, 0, db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
By("returning the saved config to later gets")
resourceTypes, err := pipeline.ResourceTypes()
Expect(err).ToNot(HaveOccurred())
resources, err := pipeline.Resources()
Expect(err).ToNot(HaveOccurred())
jobs, err := pipeline.Jobs()
Expect(err).ToNot(HaveOccurred())
expectConfigsEqual(atc.Config{
Groups: pipeline.Groups(),
Resources: resources.Configs(),
ResourceTypes: resourceTypes.Configs(),
Jobs: jobs.Configs(),
}, config)
otherResourceTypes, err := otherPipeline.ResourceTypes()
Expect(err).ToNot(HaveOccurred())
otherResources, err := otherPipeline.Resources()
Expect(err).ToNot(HaveOccurred())
otherJobs, err := otherPipeline.Jobs()
Expect(err).ToNot(HaveOccurred())
expectConfigsEqual(atc.Config{
Groups: otherPipeline.Groups(),
Resources: otherResources.Configs(),
ResourceTypes: otherResourceTypes.Configs(),
Jobs: otherJobs.Configs(),
}, otherConfig)
By("returning the saved groups")
returnedGroups := pipeline.Groups()
Expect(returnedGroups).To(Equal(config.Groups))
otherReturnedGroups := otherPipeline.Groups()
Expect(otherReturnedGroups).To(Equal(otherConfig.Groups))
updatedConfig := config
updatedConfig.Groups = append(config.Groups, atc.GroupConfig{
Name: "new-group",
Jobs: []string{"new-job-1", "new-job-2"},
})
updatedConfig.Resources = append(config.Resources, atc.ResourceConfig{
Name: "new-resource",
Type: "new-type",
Source: atc.Source{
"new-source-config": "new-value",
},
})
updatedConfig.Jobs = append(config.Jobs, atc.JobConfig{
Name: "new-job",
Plan: atc.PlanSequence{
{
Get: "new-input",
Resource: "new-resource",
Params: atc.Params{
"new-param": "new-value",
},
},
{
Task: "some-task",
TaskConfigPath: "new/config/path.yml",
},
},
})
By("not allowing non-sequential updates")
_, _, err = team.SavePipeline(pipelineName, updatedConfig, pipeline.ConfigVersion()-1, db.PipelineUnpaused)
Expect(err).To(Equal(db.ErrConfigComparisonFailed))
_, _, err = team.SavePipeline(pipelineName, updatedConfig, pipeline.ConfigVersion()+10, db.PipelineUnpaused)
Expect(err).To(Equal(db.ErrConfigComparisonFailed))
_, _, err = team.SavePipeline(otherPipelineName, updatedConfig, otherPipeline.ConfigVersion()-1, db.PipelineUnpaused)
Expect(err).To(Equal(db.ErrConfigComparisonFailed))
_, _, err = team.SavePipeline(otherPipelineName, updatedConfig, otherPipeline.ConfigVersion()+10, db.PipelineUnpaused)
Expect(err).To(Equal(db.ErrConfigComparisonFailed))
By("being able to update the config with a valid con")
pipeline, _, err = team.SavePipeline(pipelineName, updatedConfig, pipeline.ConfigVersion(), db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
otherPipeline, _, err = team.SavePipeline(otherPipelineName, updatedConfig, otherPipeline.ConfigVersion(), db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
By("returning the updated config")
resourceTypes, err = pipeline.ResourceTypes()
Expect(err).ToNot(HaveOccurred())
resources, err = pipeline.Resources()
Expect(err).ToNot(HaveOccurred())
jobs, err = pipeline.Jobs()
Expect(err).ToNot(HaveOccurred())
expectConfigsEqual(atc.Config{
Groups: pipeline.Groups(),
Resources: resources.Configs(),
ResourceTypes: resourceTypes.Configs(),
Jobs: jobs.Configs(),
}, updatedConfig)
otherResourceTypes, err = otherPipeline.ResourceTypes()
Expect(err).ToNot(HaveOccurred())
otherResources, err = otherPipeline.Resources()
Expect(err).ToNot(HaveOccurred())
otherJobs, err = otherPipeline.Jobs()
Expect(err).ToNot(HaveOccurred())
expectConfigsEqual(atc.Config{
Groups: otherPipeline.Groups(),
Resources: otherResources.Configs(),
ResourceTypes: otherResourceTypes.Configs(),
Jobs: otherJobs.Configs(),
}, updatedConfig)
By("returning the saved groups")
returnedGroups = pipeline.Groups()
Expect(returnedGroups).To(Equal(updatedConfig.Groups))
otherReturnedGroups = otherPipeline.Groups()
Expect(otherReturnedGroups).To(Equal(updatedConfig.Groups))
})
It("should return sorted resources and resource_types", func() {
config.ResourceTypes = append(config.ResourceTypes, atc.ResourceType{
Name: "new-resource-type",
Type: "new-type",
Source: atc.Source{
"new-source-config": "new-value",
},
})
config.Resources = append(config.Resources, atc.ResourceConfig{
Name: "new-resource",
Type: "new-type",
Source: atc.Source{
"new-source-config": "new-value",
},
})
pipelineName := "a-pipeline-name"
pipeline, _, err := team.SavePipeline(pipelineName, config, 0, db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
resourceTypes, err := pipeline.ResourceTypes()
Expect(err).ToNot(HaveOccurred())
rtConfigs := resourceTypes.Configs()
Expect(rtConfigs[0].Name).To(Equal(config.ResourceTypes[1].Name)) // "new-resource-type"
Expect(rtConfigs[1].Name).To(Equal(config.ResourceTypes[0].Name)) // "some-resource-type"
resources, err := pipeline.Resources()
Expect(err).ToNot(HaveOccurred())
rConfigs := resources.Configs()
Expect(rConfigs[0].Name).To(Equal(config.Resources[1].Name)) // "new-resource"
Expect(rConfigs[1].Name).To(Equal(config.Resources[0].Name)) // "some-resource"
})
Context("when there are multiple teams", func() {
It("can allow pipelines with the same name across teams", func() {
teamPipeline, _, err := team.SavePipeline("steve", config, 0, db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
By("allowing you to save a pipeline with the same name in another team")
otherTeamPipeline, _, err := otherTeam.SavePipeline("steve", otherConfig, 0, db.PipelineUnpaused)
Expect(err).ToNot(HaveOccurred())
By("updating the pipeline config for the correct team's pipeline")
teamPipeline, _, err = team.SavePipeline("steve", otherConfig, teamPipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
_, _, err = otherTeam.SavePipeline("steve", config, otherTeamPipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).ToNot(HaveOccurred())
By("pausing the correct team's pipeline")
_, _, err = team.SavePipeline("steve", otherConfig, teamPipeline.ConfigVersion(), db.PipelinePaused)
Expect(err).ToNot(HaveOccurred())
pausedPipeline, found, err := team.Pipeline("steve")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
unpausedPipeline, found, err := otherTeam.Pipeline("steve")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
Expect(pausedPipeline.Paused()).To(BeTrue())
Expect(unpausedPipeline.Paused()).To(BeFalse())
By("cannot cross update configs")
_, _, err = team.SavePipeline("steve", otherConfig, otherTeamPipeline.ConfigVersion(), db.PipelineNoChange)
Expect(err).To(HaveOccurred())
_, _, err = team.SavePipeline("steve", otherConfig, otherTeamPipeline.ConfigVersion(), db.PipelinePaused)
Expect(err).To(HaveOccurred())
})
})
})
Describe("FindCheckContainers", func() {
var (
fakeSecretManager *credsfakes.FakeSecrets
)
expiries := db.ContainerOwnerExpiries{
Min: 5 * time.Minute,
Max: 1 * time.Hour,
}
BeforeEach(func() {
fakeSecretManager = new(credsfakes.FakeSecrets)
fakeSecretManager.GetReturns("", nil, false, nil)
})
Context("when pipeline exists", func() {
Context("when resource exists", func() {
Context("when check container for resource exists", func() {
var resourceContainer db.CreatingContainer
var resourceConfig db.ResourceConfig
BeforeEach(func() {
pipelineResourceTypes, err := defaultPipeline.ResourceTypes()
Expect(err).ToNot(HaveOccurred())
resourceConfig, err = resourceConfigFactory.FindOrCreateResourceConfig(
defaultResource.Type(),
defaultResource.Source(),
pipelineResourceTypes.Deserialize(),
)
Expect(err).ToNot(HaveOccurred())
resourceContainer, err = defaultWorker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfig, expiries),
db.ContainerMetadata{},
)
Expect(err).ToNot(HaveOccurred())
})
It("returns check container for resource", func() {
containers, checkContainersExpiresAt, err := defaultTeam.FindCheckContainers("default-pipeline", "some-resource", fakeSecretManager)
Expect(err).ToNot(HaveOccurred())
Expect(containers).To(HaveLen(1))
Expect(containers[0].ID()).To(Equal(resourceContainer.ID()))
Expect(checkContainersExpiresAt).To(HaveLen(1))
Expect(checkContainersExpiresAt[resourceContainer.ID()]).ToNot(BeNil())
})
Context("when there are multiple resources with the same resource config", func() {
var (
otherPipeline db.Pipeline
otherResource db.Resource
otherResourceContainer db.CreatingContainer
found bool
err error
)
BeforeEach(func() {
otherPipeline, _, err = defaultTeam.SavePipeline("other-pipeline", atc.Config{
Resources: atc.ResourceConfigs{
{
Name: "some-resource",
Type: "some-base-resource-type",
Source: atc.Source{
"some": "source",
},
},
},
}, db.ConfigVersion(0), db.PipelineUnpaused)
Expect(err).NotTo(HaveOccurred())
otherResource, found, err = otherPipeline.Resource("some-resource")
Expect(err).NotTo(HaveOccurred())
Expect(found).To(BeTrue())
resourceConfig, err = resourceConfigFactory.FindOrCreateResourceConfig(
otherResource.Type(),
otherResource.Source(),
atc.VersionedResourceTypes{},
)
Expect(err).ToNot(HaveOccurred())
otherResourceContainer, _, err = defaultWorker.FindContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfig, expiries),
)
Expect(err).ToNot(HaveOccurred())
})
It("returns the same check container", func() {
containers, checkContainersExpiresAt, err := defaultTeam.FindCheckContainers("other-pipeline", "some-resource", fakeSecretManager)
Expect(err).ToNot(HaveOccurred())
Expect(containers).To(HaveLen(1))
Expect(containers[0].ID()).To(Equal(otherResourceContainer.ID()))
Expect(otherResourceContainer.ID()).To(Equal(resourceContainer.ID()))
Expect(checkContainersExpiresAt).To(HaveLen(1))
Expect(checkContainersExpiresAt[resourceContainer.ID()]).ToNot(BeNil())
})
})
})
Context("when check container does not exist", func() {
It("returns empty list", func() {
containers, checkContainersExpiresAt, err := defaultTeam.FindCheckContainers("default-pipeline", "some-resource", fakeSecretManager)
Expect(err).ToNot(HaveOccurred())
Expect(containers).To(BeEmpty())
Expect(checkContainersExpiresAt).To(BeEmpty())
})
})
})
Context("when resource does not exist", func() {
It("returns empty list", func() {
containers, checkContainersExpiresAt, err := defaultTeam.FindCheckContainers("default-pipeline", "non-existent-resource", fakeSecretManager)
Expect(err).ToNot(HaveOccurred())
Expect(containers).To(BeEmpty())
Expect(checkContainersExpiresAt).To(BeEmpty())
})
})
})
Context("when pipeline does not exist", func() {
It("returns empty list", func() {
containers, checkContainersExpiresAt, err := defaultTeam.FindCheckContainers("non-existent-pipeline", "some-resource", fakeSecretManager)
Expect(err).ToNot(HaveOccurred())
Expect(containers).To(BeEmpty())
Expect(checkContainersExpiresAt).To(BeEmpty())
})
})
})
Describe("IsContainerWithinTeam", func() {
Context("when the container is a check container", func() {
var resourceContainer db.Container
expiries := db.ContainerOwnerExpiries{
Min: 5 * time.Minute,
Max: 1 * time.Hour,
}
BeforeEach(func() {
resourceConfigScope, err := defaultResource.SetResourceConfig(
defaultResource.Source(),
atc.VersionedResourceTypes{},
)
Expect(err).ToNot(HaveOccurred())
resourceContainer, err = defaultWorker.CreateContainer(
db.NewResourceConfigCheckSessionContainerOwner(resourceConfigScope.ResourceConfig(), expiries),
db.ContainerMetadata{},
)
Expect(err).ToNot(HaveOccurred())
})
Context("when the container does belong on the team", func() {
var ok bool
BeforeEach(func() {
var err error
ok, err = defaultTeam.IsContainerWithinTeam(resourceContainer.Handle(), true)
Expect(err).ToNot(HaveOccurred())
})
It("finds the container for the team", func() {
Expect(ok).To(BeTrue())
})
})
Context("when the container does not belong on the team", func() {
var ok bool
BeforeEach(func() {
var err error
ok, err = team.IsContainerWithinTeam(resourceContainer.Handle(), true)
Expect(err).ToNot(HaveOccurred())
})
It("finds the container for the team", func() {
Expect(ok).To(BeFalse())
})
})
})
Context("when the container is owned by a team", func() {
var createdContainer db.Container
BeforeEach(func() {
job, found, err := defaultPipeline.Job("some-job")
Expect(err).ToNot(HaveOccurred())
Expect(found).To(BeTrue())
build, err := job.CreateBuild()
Expect(err).ToNot(HaveOccurred())
creatingContainer, err := defaultWorker.CreateContainer(db.NewBuildStepContainerOwner(build.ID(), atc.PlanID("some-job"), defaultTeam.ID()), db.ContainerMetadata{Type: "task", StepName: "some-task"})
Expect(err).ToNot(HaveOccurred())
createdContainer, err = creatingContainer.Created()
Expect(err).ToNot(HaveOccurred())
})
Context("when the container does belong on the team", func() {
var ok bool
BeforeEach(func() {
var err error
ok, err = defaultTeam.IsContainerWithinTeam(createdContainer.Handle(), false)
Expect(err).ToNot(HaveOccurred())
})
It("finds the container for the team", func() {
Expect(ok).To(BeTrue())
})
})
Context("when the container does not belong on the team", func() {
var ok bool
BeforeEach(func() {
var err error
ok, err = team.IsContainerWithinTeam(createdContainer.Handle(), false)
Expect(err).ToNot(HaveOccurred())
})
It("finds the container for the team", func() {
Expect(ok).To(BeFalse())
})
})
})
})
})