logger = lagertest.NewTestLogger("test") }) JustBeforeEach(func() { step = steps.NewEmitProgress(subStep, startMessage, successMessage, failureMessage, fakeStreamer, logger) }) Context("running", func() { Context("when there is a start message", func() { BeforeEach(func() { startMessage = "STARTING" }) It("should emit the start message before performing", func() { err := step.Perform() Expect(err).NotTo(HaveOccurred()) Expect(stdoutBuffer.String()).To(Equal("STARTING\nRUNNING\n")) }) }) Context("when there is no start or success message", func() { It("should not emit the start message (i.e. a newline) before performing", func() { err := step.Perform() Expect(err).NotTo(HaveOccurred()) Expect(stdoutBuffer.String()).To(Equal("RUNNING\n")) }) }) Context("when the substep succeeds and there is a success message", func() { BeforeEach(func() {
<-doneChan return nil } checkFunc = func() steps.Step { return fakeStep } }) AfterEach(func() { step.Cancel() }) It("throttles concurrent health check", func() { for i := 0; i < 5; i++ { go step.Perform() } Consistently(fakeStep.PerformCallCount).Should(Equal(0)) clock.Increment(501 * time.Millisecond) Eventually(func() int { return len(throttleChan) }).Should(Equal(numOfConcurrentMonitorSteps)) Consistently(func() int { return len(throttleChan) }).Should(Equal(numOfConcurrentMonitorSteps)) Eventually(fakeStep.PerformCallCount).Should(Equal(numOfConcurrentMonitorSteps)) doneChan <- struct{}{}
thingHappened <- true return nil }, CancelStub: func() { cancelled <- true }, } }) Describe("Perform", func() { JustBeforeEach(func() { step = steps.NewCodependent([]steps.Step{subStep1, subStep2}, errorOnExit) }) It("performs its substeps in parallel", func() { err := step.Perform() Expect(err).NotTo(HaveOccurred()) Eventually(thingHappened).Should(Receive()) Eventually(thingHappened).Should(Receive()) }) Context("when one of the substeps fails", func() { disaster := errors.New("oh no!") BeforeEach(func() { subStep1 = &fakes.FakeStep{ PerformStub: func() error { return disaster }, }
return nil }, CancelStub: func() { cancelled <- true }, } }) JustBeforeEach(func() { step = steps.NewParallel([]steps.Step{subStep1, subStep2}) }) It("performs its substeps in parallel", func(done Done) { defer close(done) err := step.Perform() Expect(err).NotTo(HaveOccurred()) Eventually(thingHappened).Should(Receive()) Eventually(thingHappened).Should(Receive()) }, 2) Context("when one of the substeps fails", func() { disaster := errors.New("oh no!") var triggerStep2 chan struct{} var step2Completed chan struct{} BeforeEach(func() { triggerStep2 = make(chan struct{}) step2Completed = make(chan struct{})
container, runAction, fakeStreamer, logger, externalIP, portMappings, exportNetworkEnvVars, fakeClock, ) }) Describe("Perform", func() { var stepErr error JustBeforeEach(func() { stepErr = step.Perform() }) Context("when the script succeeds", func() { BeforeEach(func() { spawnedProcess.WaitReturns(0, nil) }) It("does not return an error", func() { Expect(stepErr).NotTo(HaveOccurred()) }) It("executes the command in the passed-in container", func() { ranHandle, spec, _ := gardenClient.Connection.RunArgsForCall(0) Expect(ranHandle).To(Equal(handle)) Expect(spec.Path).To(Equal("sudo"))
func (store *GardenStore) runStepProcess( logger lager.Logger, step steps.Step, hasStartedRunning <-chan struct{}, gardenContainer garden.Container, guid string, ) { process := ifrit.Invoke(ifrit.RunFunc(func(signals <-chan os.Signal, ready chan<- struct{}) error { logger := logger.Session("run-step-process") logger.Info("started") defer logger.Info("finished") seqComplete := make(chan error) close(ready) go func() { seqComplete <- step.Perform() }() result := executor.ContainerRunResult{} toldToStop := false OUTER_LOOP: for { select { case <-signals: signals = nil toldToStop = true logger.Info("signaled") step.Cancel() case <-hasStartedRunning: hasStartedRunning = nil logger.Info("transitioning-to-running") err := store.transitionToRunning(logger, gardenContainer) if err != nil { logger.Error("failed-transitioning-to-running", err) result.Failed = true result.FailureReason = err.Error() break OUTER_LOOP } logger.Info("succeeded-transitioning-to-running") case err := <-seqComplete: if err == nil { logger.Info("step-finished-normally") } else if toldToStop { logger.Info("step-cancelled") result.Stopped = true } else { logger.Info("step-finished-with-error", lager.Data{"error": err.Error()}) result.Failed = true result.FailureReason = err.Error() } break OUTER_LOOP } } logger.Info("transitioning-to-complete") err := store.transitionToComplete(logger, gardenContainer, result) if err != nil { logger.Error("failed-transitioning-to-complete", err) return nil } logger.Info("succeeded-transitioning-to-complete") return nil })) store.processesL.Lock() store.runningProcesses[guid] = process numProcesses := len(store.runningProcesses) store.processesL.Unlock() logger.Info("stored-step-process", lager.Data{"num-step-processes": numProcesses}) }
JustBeforeEach(func() { container, err := gardenClient.Create(garden.ContainerSpec{ Handle: handle, }) Expect(err).NotTo(HaveOccurred()) step = steps.NewDownload( container, downloadAction, cache, rateLimiter, fakeStreamer, logger, ) stepErr = step.Perform() }) var tarReader *tar.Reader It("downloads via the cache with a tar transformer", func() { Expect(cache.FetchCallCount()).To(Equal(1)) url, cacheKey, transformer, cancelChan := cache.FetchArgsForCall(0) Expect(url.Host).To(ContainSubstring("mr_jones")) Expect(cacheKey).To(Equal("the-cache-key")) Expect(cancelChan).NotTo(BeNil()) tVal := reflect.ValueOf(transformer) expectedVal := reflect.ValueOf(cacheddownloader.TarTransform)