github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/exec/retry_step_test.go (about) 1 package exec_test 2 3 import ( 4 "context" 5 "errors" 6 7 . "github.com/pf-qiu/concourse/v6/atc/exec" 8 "github.com/pf-qiu/concourse/v6/atc/exec/build" 9 "github.com/pf-qiu/concourse/v6/atc/exec/execfakes" 10 . "github.com/onsi/ginkgo" 11 . "github.com/onsi/gomega" 12 ) 13 14 var _ = Describe("Retry Step", func() { 15 var ( 16 ctx context.Context 17 cancel func() 18 19 attempt1 *execfakes.FakeStep 20 attempt2 *execfakes.FakeStep 21 attempt3 *execfakes.FakeStep 22 23 repo *build.Repository 24 state *execfakes.FakeRunState 25 26 step Step 27 ) 28 29 BeforeEach(func() { 30 ctx, cancel = context.WithCancel(context.Background()) 31 32 attempt1 = new(execfakes.FakeStep) 33 attempt2 = new(execfakes.FakeStep) 34 attempt3 = new(execfakes.FakeStep) 35 36 repo = build.NewRepository() 37 state = new(execfakes.FakeRunState) 38 state.ArtifactRepositoryReturns(repo) 39 40 step = Retry(attempt1, attempt2, attempt3) 41 }) 42 43 Describe("Run", func() { 44 var stepOk bool 45 var stepErr error 46 47 JustBeforeEach(func() { 48 stepOk, stepErr = step.Run(ctx, state) 49 }) 50 51 Context("when attempt 1 succeeds", func() { 52 BeforeEach(func() { 53 attempt1.RunReturns(true, nil) 54 }) 55 56 It("returns nil having only run the first attempt", func() { 57 Expect(stepErr).ToNot(HaveOccurred()) 58 59 Expect(attempt1.RunCallCount()).To(Equal(1)) 60 Expect(attempt2.RunCallCount()).To(Equal(0)) 61 Expect(attempt3.RunCallCount()).To(Equal(0)) 62 }) 63 64 It("succeeds", func() { 65 Expect(stepOk).To(BeTrue()) 66 }) 67 }) 68 69 Context("when attempt 1 fails, and attempt 2 succeeds", func() { 70 BeforeEach(func() { 71 attempt1.RunReturns(false, nil) 72 attempt2.RunReturns(true, nil) 73 }) 74 75 It("returns nil having only run the first and second attempts", func() { 76 Expect(stepErr).ToNot(HaveOccurred()) 77 78 Expect(attempt1.RunCallCount()).To(Equal(1)) 79 Expect(attempt2.RunCallCount()).To(Equal(1)) 80 Expect(attempt3.RunCallCount()).To(Equal(0)) 81 }) 82 83 It("succeeds", func() { 84 Expect(stepOk).To(BeTrue()) 85 }) 86 }) 87 88 Context("when attempt 1 errors, and attempt 2 succeeds", func() { 89 BeforeEach(func() { 90 attempt1.RunReturns(false, errors.New("nope")) 91 attempt2.RunReturns(true, nil) 92 }) 93 94 It("returns nil having only run the first and second attempts", func() { 95 Expect(stepErr).ToNot(HaveOccurred()) 96 97 Expect(attempt1.RunCallCount()).To(Equal(1)) 98 Expect(attempt2.RunCallCount()).To(Equal(1)) 99 Expect(attempt3.RunCallCount()).To(Equal(0)) 100 }) 101 102 It("succeeds", func() { 103 Expect(stepOk).To(BeTrue()) 104 }) 105 }) 106 107 Context("when attempt 1 errors, and attempt 2 is interrupted", func() { 108 BeforeEach(func() { 109 attempt1.RunReturns(false, errors.New("nope")) 110 attempt2.RunStub = func(c context.Context, r RunState) (bool, error) { 111 cancel() 112 return false, c.Err() 113 } 114 }) 115 116 It("returns the context error having only run the first and second attempts", func() { 117 Expect(stepErr).To(Equal(context.Canceled)) 118 119 Expect(attempt1.RunCallCount()).To(Equal(1)) 120 Expect(attempt2.RunCallCount()).To(Equal(1)) 121 Expect(attempt3.RunCallCount()).To(Equal(0)) 122 }) 123 124 It("fails", func() { 125 Expect(stepOk).To(BeFalse()) 126 }) 127 }) 128 129 Context("when attempt 1 errors, attempt 2 times out, and attempt 3 succeeds", func() { 130 BeforeEach(func() { 131 attempt1.RunReturns(false, errors.New("nope")) 132 attempt2.RunStub = func(c context.Context, r RunState) (bool, error) { 133 timeout, subCancel := context.WithTimeout(c, 0) 134 defer subCancel() 135 <-timeout.Done() 136 return false, timeout.Err() 137 } 138 attempt3.RunReturns(true, nil) 139 }) 140 141 It("returns nil after running all 3 steps", func() { 142 Expect(stepErr).ToNot(HaveOccurred()) 143 144 Expect(attempt1.RunCallCount()).To(Equal(1)) 145 Expect(attempt2.RunCallCount()).To(Equal(1)) 146 Expect(attempt3.RunCallCount()).To(Equal(1)) 147 }) 148 149 It("succeeds", func() { 150 Expect(stepOk).To(BeTrue()) 151 }) 152 }) 153 154 Context("when attempt 1 fails, attempt 2 fails, and attempt 3 succeeds", func() { 155 BeforeEach(func() { 156 attempt1.RunReturns(false, nil) 157 attempt2.RunReturns(false, nil) 158 attempt3.RunReturns(true, nil) 159 }) 160 161 It("returns nil after running all 3 steps", func() { 162 Expect(stepErr).ToNot(HaveOccurred()) 163 164 Expect(attempt1.RunCallCount()).To(Equal(1)) 165 Expect(attempt2.RunCallCount()).To(Equal(1)) 166 Expect(attempt3.RunCallCount()).To(Equal(1)) 167 }) 168 169 It("succeeds", func() { 170 Expect(stepOk).To(BeTrue()) 171 }) 172 }) 173 174 Context("when attempt 1 fails, attempt 2 fails, and attempt 3 errors", func() { 175 disaster := errors.New("nope") 176 177 BeforeEach(func() { 178 attempt1.RunReturns(false, nil) 179 attempt2.RunReturns(false, nil) 180 attempt3.RunReturns(false, disaster) 181 }) 182 183 It("returns the error", func() { 184 Expect(stepErr).To(Equal(disaster)) 185 186 Expect(attempt1.RunCallCount()).To(Equal(1)) 187 Expect(attempt2.RunCallCount()).To(Equal(1)) 188 Expect(attempt3.RunCallCount()).To(Equal(1)) 189 }) 190 191 It("fails", func() { 192 Expect(stepOk).To(BeFalse()) 193 }) 194 }) 195 196 Context("when attempt 1 fails, attempt 2 fails, and attempt 3 fails", func() { 197 BeforeEach(func() { 198 attempt1.RunReturns(false, nil) 199 attempt2.RunReturns(false, nil) 200 attempt3.RunReturns(false, nil) 201 }) 202 203 It("returns nil having only run the first and second attempts", func() { 204 Expect(stepErr).ToNot(HaveOccurred()) 205 206 Expect(attempt1.RunCallCount()).To(Equal(1)) 207 Expect(attempt2.RunCallCount()).To(Equal(1)) 208 Expect(attempt3.RunCallCount()).To(Equal(1)) 209 }) 210 211 It("fails", func() { 212 Expect(stepOk).To(BeFalse()) 213 }) 214 }) 215 }) 216 })