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  })