1package exec_test
2
3import (
4	"context"
5	"errors"
6
7	"github.com/concourse/concourse/atc/exec"
8	"github.com/concourse/concourse/atc/exec/build"
9	"github.com/concourse/concourse/atc/exec/execfakes"
10	. "github.com/onsi/ginkgo"
11	. "github.com/onsi/gomega"
12)
13
14var _ = Describe("On Failure Step", func() {
15	var (
16		ctx    context.Context
17		cancel func()
18
19		step *execfakes.FakeStep
20		hook *execfakes.FakeStep
21
22		repo  *build.Repository
23		state *execfakes.FakeRunState
24
25		onFailureStep exec.Step
26
27		stepErr error
28	)
29
30	BeforeEach(func() {
31		ctx, cancel = context.WithCancel(context.Background())
32
33		step = &execfakes.FakeStep{}
34		hook = &execfakes.FakeStep{}
35
36		repo = build.NewRepository()
37		state = new(execfakes.FakeRunState)
38		state.ArtifactRepositoryReturns(repo)
39
40		onFailureStep = exec.OnFailure(step, hook)
41	})
42
43	AfterEach(func() {
44		cancel()
45	})
46
47	JustBeforeEach(func() {
48		stepErr = onFailureStep.Run(ctx, state)
49	})
50
51	Context("when the step fails", func() {
52		BeforeEach(func() {
53			step.SucceededReturns(false)
54		})
55
56		It("runs the failure hook", func() {
57			Expect(step.RunCallCount()).To(Equal(1))
58			Expect(hook.RunCallCount()).To(Equal(1))
59		})
60
61		It("runs the hook with the run state", func() {
62			Expect(hook.RunCallCount()).To(Equal(1))
63
64			_, argsState := hook.RunArgsForCall(0)
65			Expect(argsState).To(Equal(state))
66		})
67
68		It("propagates the context to the hook", func() {
69			runCtx, _ := hook.RunArgsForCall(0)
70			Expect(runCtx).To(Equal(ctx))
71		})
72
73		It("succeeds", func() {
74			Expect(stepErr).ToNot(HaveOccurred())
75		})
76	})
77
78	Context("when the step errors", func() {
79		disaster := errors.New("disaster")
80
81		BeforeEach(func() {
82			step.RunReturns(disaster)
83		})
84
85		It("does not run the failure hook", func() {
86			Expect(step.RunCallCount()).To(Equal(1))
87			Expect(hook.RunCallCount()).To(Equal(0))
88		})
89
90		It("returns the error", func() {
91			Expect(stepErr).To(Equal(disaster))
92		})
93	})
94
95	Context("when the step succeeds", func() {
96		BeforeEach(func() {
97			step.SucceededReturns(true)
98		})
99
100		It("does not run the failure hook", func() {
101			Expect(step.RunCallCount()).To(Equal(1))
102			Expect(hook.RunCallCount()).To(Equal(0))
103		})
104
105		It("returns nil", func() {
106			Expect(stepErr).To(BeNil())
107		})
108	})
109
110	It("propagates the context to the step", func() {
111		runCtx, _ := step.RunArgsForCall(0)
112		Expect(runCtx).To(Equal(ctx))
113	})
114
115	Describe("Succeeded", func() {
116		Context("when step fails and hook fails", func() {
117			BeforeEach(func() {
118				step.SucceededReturns(false)
119				hook.SucceededReturns(false)
120			})
121
122			It("returns false", func() {
123				Expect(onFailureStep.Succeeded()).To(BeFalse())
124			})
125		})
126
127		Context("when step fails and hook succeeds", func() {
128			BeforeEach(func() {
129				step.SucceededReturns(false)
130				hook.SucceededReturns(true)
131			})
132
133			It("returns false", func() {
134				Expect(onFailureStep.Succeeded()).To(BeFalse())
135			})
136		})
137
138		Context("when step succeeds", func() {
139			BeforeEach(func() {
140				step.SucceededReturns(true)
141			})
142
143			It("returns true", func() {
144				Expect(onFailureStep.Succeeded()).To(BeTrue())
145			})
146		})
147	})
148})
149