github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/exec/retry_error_step_test.go (about) 1 package exec_test 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net" 8 "net/url" 9 10 . "github.com/pf-qiu/concourse/v6/atc/exec" 11 "github.com/pf-qiu/concourse/v6/atc/exec/build" 12 "github.com/pf-qiu/concourse/v6/atc/exec/execfakes" 13 "github.com/pf-qiu/concourse/v6/atc/worker/transport" 14 . "github.com/onsi/ginkgo" 15 . "github.com/onsi/gomega" 16 ) 17 18 var _ = Describe("RetryErrorStep", func() { 19 var ( 20 ctx context.Context 21 cancel func() 22 23 fakeStep *execfakes.FakeStep 24 25 fakeDelegate *execfakes.FakeBuildStepDelegate 26 fakeDelegateFactory *execfakes.FakeBuildStepDelegateFactory 27 28 repo *build.Repository 29 state *execfakes.FakeRunState 30 31 step Step 32 ) 33 34 BeforeEach(func() { 35 ctx, cancel = context.WithCancel(context.Background()) 36 37 fakeStep = new(execfakes.FakeStep) 38 fakeDelegate = new(execfakes.FakeBuildStepDelegate) 39 fakeDelegateFactory = new(execfakes.FakeBuildStepDelegateFactory) 40 fakeDelegateFactory.BuildStepDelegateReturns(fakeDelegate) 41 42 repo = build.NewRepository() 43 state = new(execfakes.FakeRunState) 44 state.ArtifactRepositoryReturns(repo) 45 46 step = RetryError(fakeStep, fakeDelegateFactory) 47 }) 48 49 AfterEach(func() { 50 cancel() 51 }) 52 53 Describe("Run", func() { 54 var runOk bool 55 var runErr error 56 57 JustBeforeEach(func() { 58 runOk, runErr = step.Run(ctx, state) 59 }) 60 61 Context("when the inner step does not error", func() { 62 BeforeEach(func() { 63 fakeStep.RunReturns(true, nil) 64 }) 65 66 It("returns nil", func() { 67 Expect(runErr).To(BeNil()) 68 }) 69 70 It("does not log", func() { 71 Expect(fakeDelegate.ErroredCallCount()).To(Equal(0)) 72 }) 73 }) 74 75 Context("when aborted", func() { 76 BeforeEach(func() { 77 fakeStep.RunReturns(false, context.Canceled) 78 }) 79 80 It("propagates the error", func() { 81 Expect(runErr).To(Equal(context.Canceled)) 82 }) 83 }) 84 85 Context("when worker disappeared", func() { 86 cause := transport.WorkerMissingError{WorkerName: "some-worker"} 87 BeforeEach(func() { 88 fakeStep.RunReturns(false, cause) 89 }) 90 91 It("should return retriable", func() { 92 Expect(runErr).To(Equal(Retriable{cause})) 93 }) 94 95 It("logs 'timeout exceeded'", func() { 96 Expect(fakeDelegate.ErroredCallCount()).To(Equal(1)) 97 _, message := fakeDelegate.ErroredArgsForCall(0) 98 Expect(message).To(Equal(fmt.Sprintf("%s, will retry ...", cause.Error()))) 99 }) 100 101 Context("when build aborted", func(){ 102 BeforeEach(func(){ 103 cancel() 104 }) 105 106 It("should not retry", func(){ 107 Expect(runErr).To(Equal(cause)) 108 }) 109 }) 110 }) 111 112 Context("when url.Error error happened", func() { 113 cause := &url.Error{Op: "error", URL: "err", Err: errors.New("error")} 114 BeforeEach(func() { 115 fakeStep.RunReturns(false, cause) 116 }) 117 118 It("should return retriable", func() { 119 Expect(runErr).To(Equal(Retriable{cause})) 120 }) 121 }) 122 123 Context("when net.Error error happened", func() { 124 cause := &net.OpError{Op: "read", Net: "test", Source: nil, Addr: nil, Err: errors.New("test")} 125 BeforeEach(func() { 126 fakeStep.RunReturns(false, cause) 127 }) 128 129 It("should return retriable", func() { 130 Expect(runErr).To(Equal(Retriable{cause})) 131 }) 132 }) 133 134 Context("when the inner step returns any other error", func() { 135 disaster := errors.New("disaster") 136 137 BeforeEach(func() { 138 fakeStep.RunReturns(false, disaster) 139 }) 140 141 It("propagates the error", func() { 142 Expect(runErr).To(Equal(disaster)) 143 }) 144 }) 145 146 Context("when the wrapped step has succeeded", func() { 147 BeforeEach(func() { 148 fakeStep.RunReturns(true, nil) 149 }) 150 151 It("returns true", func() { 152 Expect(runOk).Should(BeTrue()) 153 }) 154 }) 155 156 Context("when the wrapped step has failed", func() { 157 BeforeEach(func() { 158 fakeStep.RunReturns(false, nil) 159 }) 160 161 It("returns true", func() { 162 Expect(runOk).Should(BeFalse()) 163 }) 164 }) 165 }) 166 })