BeforeEach(func() { gardenClient.CreateReturns(fakeContainer, nil) gardenClient.ContainersReturns([]garden.Container{oldContainer}, nil) fakeContainer.RunReturns(fakeProcess, nil) fakeProcess.WaitReturns(0, nil) }) It("drives a container lifecycle", func() { err := gardenChecker.Healthcheck(logger) By("Fetching any pre-existing healthcheck containers") Expect(gardenClient.ContainersCallCount()).To(Equal(1)) By("Deleting all pre-existing-containers") //call count is two because we also expect to destroy the container we create Expect(gardenClient.DestroyCallCount()).To(Equal(2)) guid := gardenClient.DestroyArgsForCall(0) Expect(guid).To(Equal("old-guid")) By("Creates the container") Expect(gardenClient.CreateCallCount()).To(Equal(1)) containerSpec := gardenClient.CreateArgsForCall(0) Expect(containerSpec).To(Equal(garden.ContainerSpec{ Handle: "executor-healthcheck-abc-123", RootFSPath: rootfsPath, Properties: garden.Properties{ gardenstore.ContainerOwnerProperty: containerOwnerName, gardenstore.TagPropertyPrefix + gardenhealth.HealthcheckTag: gardenhealth.HealthcheckTagValue, }, }))
RootFSPath: "some-resource-image", Privileged: true, Properties: garden.Properties{ "concourse:ephemeral": "true", }, })) }) }) Describe("the created container", func() { It("can be destroyed", func() { err := createdContainer.Destroy() Expect(err).NotTo(HaveOccurred()) By("destroying via garden") Expect(fakeGardenClient.DestroyCallCount()).To(Equal(1)) Expect(fakeGardenClient.DestroyArgsForCall(0)).To(Equal("some-handle")) By("no longer heartbeating") fakeClock.Increment(30 * time.Second) Consistently(fakeContainer.SetGraceTimeCallCount).Should(Equal(1)) }) It("performs an initial heartbeat synchronously", func() { Expect(fakeContainer.SetGraceTimeCallCount()).To(Equal(1)) Expect(fakeGardenWorkerDB.UpdateExpiresAtOnContainerCallCount()).To(Equal(1)) }) Describe("every 30 seconds", func() { It("heartbeats to the database and the container", func() { fakeClock.Increment(30 * time.Second)
"concourse:check-source": "{\"some\":\"source\"}", "concourse:name": "some-name", "concourse:build-id": "42", "concourse:ephemeral": "true", }, })) }) }) Describe("the created container", func() { It("can be destroyed", func() { err := createdContainer.Destroy() Ω(err).ShouldNot(HaveOccurred()) By("destroying via garden") Ω(fakeGardenClient.DestroyCallCount()).Should(Equal(1)) Ω(fakeGardenClient.DestroyArgsForCall(0)).Should(Equal("some-handle")) By("no longer heartbeating") fakeClock.Increment(30 * time.Second) Consistently(fakeContainer.SetPropertyCallCount).Should(BeZero()) }) It("is kept alive by continuously setting a keepalive property until released", func() { Ω(fakeContainer.SetPropertyCallCount()).Should(Equal(0)) fakeClock.Increment(30 * time.Second) Eventually(fakeContainer.SetPropertyCallCount).Should(Equal(1)) name, value := fakeContainer.SetPropertyArgsForCall(0) Ω(name).Should(Equal("keepalive"))