Example #1
0
func jobService(database *dbSharedBehaviorInput) func() {
	return func() {
		Describe("Db/JobService", func() {
			var fakeDB *fakes.FakeJobServiceDB

			Describe("NewJobService", func() {
				BeforeEach(func() {
					fakeDB = new(fakes.FakeJobServiceDB)
				})

				It("sets the JobConfig and the DBJob", func() {
					dbJob := db.SavedJob{
						Job: db.Job{
							Name: "a-job",
						},
					}

					fakeDB.GetJobReturns(dbJob, nil)

					service, err := db.NewJobService(atc.JobConfig{}, fakeDB)
					Expect(err).NotTo(HaveOccurred())
					Expect(service).To(Equal(db.JobService{
						JobConfig: atc.JobConfig{},
						DBJob:     dbJob,
						DB:        fakeDB,
					}))

				})

				Context("when the GetJob lookup fails", func() {
					It("returns an error", func() {
						fakeDB.GetJobReturns(db.SavedJob{}, errors.New("disaster"))
						_, err := db.NewJobService(atc.JobConfig{}, fakeDB)
						Expect(err).To(HaveOccurred())
					})
				})
			})

			Describe("CanBuildBeScheduled", func() {
				BeforeEach(func() {
					fakeDB = new(fakes.FakeJobServiceDB)
				})

				Context("When the job is paused", func() {
					It("Returns false", func() {
						dbJob := db.SavedJob{
							Paused: true,
						}

						fakeDB.GetJobReturns(dbJob, nil)
						service, err := db.NewJobService(atc.JobConfig{}, fakeDB)
						Expect(err).NotTo(HaveOccurred())

						canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(db.Build{})
						Expect(err).NotTo(HaveOccurred())
						Expect(reason).To(Equal("job-paused"))
						Expect(canBuildBeScheduled).To(BeFalse())
					})
				})

				Context("When the job is not paused", func() {
					var dbJob db.SavedJob
					var service db.JobService

					BeforeEach(func() {
						var err error
						dbJob.Paused = false
						dbJob.Name = "a-job"
						fakeDB.GetJobReturns(
							dbJob,
							nil,
						)

						service, err = db.NewJobService(atc.JobConfig{}, fakeDB)
						Expect(err).NotTo(HaveOccurred())
					})

					It("returns true if the build status is pending", func() {
						canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(db.Build{
							Status: db.StatusPending,
						})

						Expect(err).NotTo(HaveOccurred())
						Expect(reason).To(Equal("can-be-scheduled"))
						Expect(canBuildBeScheduled).To(BeTrue())
					})

					It("returns false if the build status is not pending", func() {
						canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(db.Build{
							Status: db.StatusStarted,
						})

						Expect(err).NotTo(HaveOccurred())
						Expect(reason).To(Equal("build-not-pending"))
						Expect(canBuildBeScheduled).To(BeFalse())
					})

					Context("When the job is serial", func() {
						var service db.JobService
						var dbBuild db.Build

						BeforeEach(func() {
							var err error
							service, err = db.NewJobService(atc.JobConfig{
								Serial: true,
							}, fakeDB)

							Expect(err).NotTo(HaveOccurred())
							dbBuild = db.Build{
								Status: db.StatusPending,
							}
						})

						Context("When the call to get running builds throws an error", func() {
							BeforeEach(func() {
								fakeDB.GetRunningBuildsBySerialGroupReturns([]db.Build{}, errors.New("disaster"))
							})

							It("returns the error", func() {
								canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)
								Expect(err).To(HaveOccurred())
								Expect(reason).To(Equal("db-failed"))
								Expect(canBuildBeScheduled).To(BeFalse())
							})
						})

						Context("When another build with the same job is running", func() {
							BeforeEach(func() {
								fakeDB.GetRunningBuildsBySerialGroupReturns([]db.Build{
									{
										Name: "Some-build",
									},
								}, nil)
							})

							It("returns false and the error", func() {
								canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)
								Expect(err).NotTo(HaveOccurred())
								Expect(reason).To(Equal("max-in-flight-reached"))
								Expect(canBuildBeScheduled).To(BeFalse())
							})
						})

						Context("When no other builds are running", func() {
							BeforeEach(func() {
								fakeDB.GetRunningBuildsBySerialGroupReturns([]db.Build{}, nil)
							})

							Context("When the call to get next pending build fails", func() {
								BeforeEach(func() {
									fakeDB.GetNextPendingBuildBySerialGroupReturns(db.Build{}, false, errors.New("disaster"))
								})

								It("returns false and the error", func() {
									canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)
									Expect(err).To(HaveOccurred())
									Expect(reason).To(Equal("db-failed"))
									Expect(canBuildBeScheduled).To(BeFalse())
								})
							})

							Context("When it is not the next most pending build", func() {
								BeforeEach(func() {
									fakeDB.GetNextPendingBuildBySerialGroupReturns(db.Build{ID: 3}, true, nil)
								})

								It("returns false", func() {
									canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)
									Expect(err).NotTo(HaveOccurred())
									Expect(reason).To(Equal("not-next-most-pending"))
									Expect(canBuildBeScheduled).To(BeFalse())
								})
							})

							Context("When there is no pending build", func() {
								BeforeEach(func() {
									fakeDB.GetNextPendingBuildBySerialGroupReturns(db.Build{}, false, nil)
								})

								It("returns false", func() {
									canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)
									Expect(err).NotTo(HaveOccurred())
									Expect(reason).To(Equal("no-pending-build"))
									Expect(canBuildBeScheduled).To(BeFalse())
								})
							})

							Context("When it is the next most pending build", func() {
								BeforeEach(func() {
									fakeDB.GetNextPendingBuildBySerialGroupReturns(db.Build{ID: dbBuild.ID}, true, nil)
								})

								It("returns true", func() {
									canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)

									Expect(err).NotTo(HaveOccurred())
									Expect(reason).To(Equal("can-be-scheduled"))
									Expect(canBuildBeScheduled).To(BeTrue())
								})
							})
						})
					})

					Context("When the job has a max-in-flight of 3", func() {
						var service db.JobService
						var dbBuild db.Build

						BeforeEach(func() {
							var err error
							service, err = db.NewJobService(atc.JobConfig{
								RawMaxInFlight: 3,
							}, fakeDB)

							Expect(err).NotTo(HaveOccurred())
							dbBuild = db.Build{
								Status: db.StatusPending,
							}
						})

						Context("When the call to get running builds throws an error", func() {
							BeforeEach(func() {
								fakeDB.GetRunningBuildsBySerialGroupReturns([]db.Build{}, errors.New("disaster"))
							})

							It("returns the error", func() {
								canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)
								Expect(err).To(HaveOccurred())
								Expect(reason).To(Equal("db-failed"))
								Expect(canBuildBeScheduled).To(BeFalse())
							})
						})

						Context("When 1 build is running", func() {
							BeforeEach(func() {
								fakeDB.GetRunningBuildsBySerialGroupReturns([]db.Build{
									{
										Name: "Some-build",
									},
								}, nil)
							})

							Context("when the build is the next in line", func() {
								BeforeEach(func() {
									fakeDB.GetNextPendingBuildBySerialGroupReturns(db.Build{ID: dbBuild.ID}, true, nil)
								})

								It("returns true", func() {
									canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)

									Expect(err).NotTo(HaveOccurred())
									Expect(reason).To(Equal("can-be-scheduled"))
									Expect(canBuildBeScheduled).To(BeTrue())
								})
							})

							Context("when the build is not next in line", func() {
								BeforeEach(func() {
									fakeDB.GetNextPendingBuildBySerialGroupReturns(db.Build{ID: dbBuild.ID - 1}, true, nil)
								})

								It("returns false", func() {
									canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)
									Expect(err).NotTo(HaveOccurred())
									Expect(reason).To(Equal("not-next-most-pending"))
									Expect(canBuildBeScheduled).To(BeFalse())
								})
							})

							Context("When there is no pending build", func() {
								BeforeEach(func() {
									fakeDB.GetNextPendingBuildBySerialGroupReturns(db.Build{}, false, nil)
								})

								It("returns false", func() {
									canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)
									Expect(err).NotTo(HaveOccurred())
									Expect(reason).To(Equal("no-pending-build"))
									Expect(canBuildBeScheduled).To(BeFalse())
								})
							})
						})

						Context("When 2 builds are running", func() {
							BeforeEach(func() {
								fakeDB.GetRunningBuildsBySerialGroupReturns([]db.Build{
									{
										Name: "Some-build",
									},
									{
										Name: "Some-other-build",
									},
								}, nil)
							})

							Context("when the build is the next in line", func() {
								BeforeEach(func() {
									fakeDB.GetNextPendingBuildBySerialGroupReturns(db.Build{ID: dbBuild.ID}, true, nil)
								})

								It("returns true", func() {
									canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)

									Expect(err).NotTo(HaveOccurred())
									Expect(reason).To(Equal("can-be-scheduled"))
									Expect(canBuildBeScheduled).To(BeTrue())
								})
							})

							Context("when the build is not next in line", func() {
								BeforeEach(func() {
									fakeDB.GetNextPendingBuildBySerialGroupReturns(db.Build{ID: dbBuild.ID - 1}, true, nil)
								})

								It("returns false", func() {
									canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)
									Expect(err).NotTo(HaveOccurred())
									Expect(reason).To(Equal("not-next-most-pending"))
									Expect(canBuildBeScheduled).To(BeFalse())
								})
							})

							Context("When there is no pending build", func() {
								BeforeEach(func() {
									fakeDB.GetNextPendingBuildBySerialGroupReturns(db.Build{}, false, nil)
								})

								It("returns false", func() {
									canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)
									Expect(err).NotTo(HaveOccurred())
									Expect(reason).To(Equal("no-pending-build"))
									Expect(canBuildBeScheduled).To(BeFalse())
								})
							})
						})

						Context("When the max-in-flight is already reached", func() {
							BeforeEach(func() {
								fakeDB.GetRunningBuildsBySerialGroupReturns([]db.Build{
									{
										Name: "Some-build",
									},
									{
										Name: "Some-other-build",
									},
									{
										Name: "Some-other-other-build",
									},
								}, nil)
							})

							It("returns false and the error", func() {
								canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)

								Expect(err).NotTo(HaveOccurred())
								Expect(reason).To(Equal("max-in-flight-reached"))
								Expect(canBuildBeScheduled).To(BeFalse())
							})
						})

						Context("When no other builds are running", func() {
							BeforeEach(func() {
								fakeDB.GetRunningBuildsBySerialGroupReturns([]db.Build{}, nil)
							})

							Context("When the call to get next pending build fails", func() {
								BeforeEach(func() {
									fakeDB.GetNextPendingBuildBySerialGroupReturns(db.Build{}, false, errors.New("disaster"))
								})

								It("returns false and the error", func() {
									canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)
									Expect(err).To(HaveOccurred())
									Expect(reason).To(Equal("db-failed"))
									Expect(canBuildBeScheduled).To(BeFalse())
								})
							})

							Context("When it is not the next most pending build", func() {
								BeforeEach(func() {
									fakeDB.GetNextPendingBuildBySerialGroupReturns(db.Build{ID: 3}, true, nil)
								})

								It("returns false", func() {
									canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)
									Expect(err).NotTo(HaveOccurred())
									Expect(reason).To(Equal("not-next-most-pending"))
									Expect(canBuildBeScheduled).To(BeFalse())
								})
							})

							Context("When there is no pending build", func() {
								BeforeEach(func() {
									fakeDB.GetNextPendingBuildBySerialGroupReturns(db.Build{}, false, nil)
								})

								It("returns false", func() {
									canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)
									Expect(err).NotTo(HaveOccurred())
									Expect(reason).To(Equal("no-pending-build"))
									Expect(canBuildBeScheduled).To(BeFalse())
								})
							})

							Context("When it is the next most pending build", func() {
								BeforeEach(func() {
									fakeDB.GetNextPendingBuildBySerialGroupReturns(db.Build{ID: dbBuild.ID}, true, nil)
								})

								It("returns true", func() {
									canBuildBeScheduled, reason, err := service.CanBuildBeScheduled(dbBuild)

									Expect(err).NotTo(HaveOccurred())
									Expect(reason).To(Equal("can-be-scheduled"))
									Expect(canBuildBeScheduled).To(BeTrue())
								})
							})
						})
					})
				})
			})
		})
	}
}
Example #2
0
			BeforeEach(func() {
				fakeDB.IsPausedReturns(false, nil)
			})

			It("marks the build prep paused pipeline to not blocking", func() {
				Expect(err).NotTo(HaveOccurred())

				Expect(fakeDB.UpdateBuildPreparationCallCount()).To(BeNumerically(">=", 1))
				buildPrep = fakeDB.UpdateBuildPreparationArgsForCall(0)
				Expect(buildPrep.PausedPipeline).To(Equal(db.BuildPreparationStatusNotBlocking))
			})

			Context("when the build is not marked as scheduled", func() {
				Context("when the job is paused", func() {
					BeforeEach(func() {
						dbSavedJob.Paused = true
					})

					It("returns false", func() {
						Expect(err).NotTo(HaveOccurred())
						Expect(reason).To(Equal("job-paused"))
						Expect(canBuildBeScheduled).To(BeFalse())
					})

					It("marks the build prep paused job to blocking", func() {
						Expect(err).NotTo(HaveOccurred())

						Expect(fakeDB.UpdateBuildPreparationCallCount()).To(BeNumerically(">=", 2))
						buildPrep = fakeDB.UpdateBuildPreparationArgsForCall(1)
						Expect(buildPrep.PausedJob).To(Equal(db.BuildPreparationStatusBlocking))
					})