github.com/chenbh/concourse/v6@v6.4.2/atc/lidar/checker_test.go (about) 1 package lidar_test 2 3 import ( 4 "context" 5 "errors" 6 "time" 7 8 "code.cloudfoundry.org/lager/lagertest" 9 . "github.com/onsi/ginkgo" 10 . "github.com/onsi/gomega" 11 12 "github.com/chenbh/concourse/v6/atc/db" 13 "github.com/chenbh/concourse/v6/atc/db/dbfakes" 14 "github.com/chenbh/concourse/v6/atc/engine" 15 "github.com/chenbh/concourse/v6/atc/engine/enginefakes" 16 "github.com/chenbh/concourse/v6/atc/lidar" 17 "github.com/chenbh/concourse/v6/atc/lidar/lidarfakes" 18 "github.com/chenbh/concourse/v6/tracing" 19 "go.opentelemetry.io/otel/api/trace" 20 "go.opentelemetry.io/otel/api/trace/testtrace" 21 ) 22 23 type Checker interface { 24 Run(context.Context) error 25 } 26 27 var _ = Describe("Checker", func() { 28 var ( 29 err error 30 31 fakeCheckFactory *dbfakes.FakeCheckFactory 32 fakeEngine *enginefakes.FakeEngine 33 fakeRateCalculator *lidarfakes.FakeRateCalculator 34 fakeLimiter *lidarfakes.FakeLimiter 35 36 checker Checker 37 logger *lagertest.TestLogger 38 ) 39 40 BeforeEach(func() { 41 fakeCheckFactory = new(dbfakes.FakeCheckFactory) 42 fakeEngine = new(enginefakes.FakeEngine) 43 fakeRateCalculator = new(lidarfakes.FakeRateCalculator) 44 fakeLimiter = new(lidarfakes.FakeLimiter) 45 46 logger = lagertest.NewTestLogger("test") 47 }) 48 49 JustBeforeEach(func() { 50 checker = lidar.NewChecker( 51 logger, 52 fakeCheckFactory, 53 fakeEngine, 54 fakeRateCalculator, 55 ) 56 57 err = checker.Run(context.TODO()) 58 }) 59 60 Describe("Run", func() { 61 Context("when retrieving checks fails", func() { 62 BeforeEach(func() { 63 fakeCheckFactory.StartedChecksReturns(nil, errors.New("nope")) 64 }) 65 66 It("errors", func() { 67 Expect(err).To(HaveOccurred()) 68 }) 69 }) 70 71 Context("when tracing is configured", func() { 72 var ( 73 scanSpan trace.Span 74 fakeRunnable *enginefakes.FakeRunnable 75 ) 76 77 BeforeEach(func() { 78 tracing.ConfigureTraceProvider(&tracing.TestTraceProvider{}) 79 fakeCheck := new(dbfakes.FakeCheck) 80 fakeCheck.IDReturns(1) 81 var ctx context.Context 82 ctx, scanSpan = tracing.StartSpan(context.Background(), "fake-operation", nil) 83 fakeCheck.SpanContextReturns(db.NewSpanContext(ctx)) 84 85 fakeCheckFactory.StartedChecksReturns([]db.Check{ 86 fakeCheck, 87 }, nil) 88 89 fakeLimiter.WaitReturns(nil) 90 fakeRateCalculator.RateLimiterReturns(fakeLimiter, nil) 91 92 fakeRunnable = new(enginefakes.FakeRunnable) 93 fakeEngine.NewCheckReturns(fakeRunnable) 94 }) 95 96 AfterEach(func() { 97 tracing.Configured = false 98 }) 99 100 It("propagates span context to check step", func() { 101 Eventually(fakeRunnable.RunCallCount).Should(Equal(1)) 102 ctx := fakeRunnable.RunArgsForCall(0) 103 span, ok := tracing.FromContext(ctx).(*testtrace.Span) 104 Expect(ok).To(BeTrue(), "no testtrace.Span in context") 105 Expect(span.ParentSpanID()).To(Equal(scanSpan.SpanContext().SpanID)) 106 }) 107 }) 108 109 Context("when retrieving checks succeeds", func() { 110 var fakeCheck1, fakeCheck2, fakeCheck3 *dbfakes.FakeCheck 111 112 BeforeEach(func() { 113 fakeCheck1 = new(dbfakes.FakeCheck) 114 fakeCheck1.IDReturns(1) 115 fakeCheck2 = new(dbfakes.FakeCheck) 116 fakeCheck2.IDReturns(2) 117 fakeCheck3 = new(dbfakes.FakeCheck) 118 fakeCheck3.IDReturns(3) 119 120 fakeCheckFactory.StartedChecksReturns([]db.Check{ 121 fakeCheck1, 122 fakeCheck2, 123 fakeCheck3, 124 }, nil) 125 126 fakeEngine.NewCheckStub = func(check db.Check) engine.Runnable { 127 time.Sleep(time.Second) 128 return new(enginefakes.FakeRunnable) 129 } 130 }) 131 132 Context("when the rate limiter is fetched correctly", func() { 133 BeforeEach(func() { 134 fakeLimiter.WaitReturns(nil) 135 fakeRateCalculator.RateLimiterReturns(fakeLimiter, nil) 136 }) 137 138 It("succeeds", func() { 139 Expect(err).NotTo(HaveOccurred()) 140 }) 141 142 It("runs all pending checks", func() { 143 Eventually(fakeEngine.NewCheckCallCount).Should(Equal(3)) 144 }) 145 146 It("rate limits all the checks", func() { 147 Eventually(fakeLimiter.WaitCallCount()).Should(Equal(3)) 148 }) 149 150 Context("when there is a manually triggered check and the rate limiter is not allowing any checks to run", func() { 151 BeforeEach(func() { 152 fakeCheck1.ManuallyTriggeredReturns(true) 153 154 fakeLimiter.WaitReturns(errors.New("not-allowed")) 155 }) 156 157 It("runs the manually triggered check", func() { 158 Eventually(fakeEngine.NewCheckCallCount).Should(Equal(1)) 159 Expect(fakeEngine.NewCheckArgsForCall(0).ID()).To(Equal(fakeCheck1.ID())) 160 }) 161 }) 162 }) 163 164 Context("when calculating the rate limit fails", func() { 165 BeforeEach(func() { 166 fakeRateCalculator.RateLimiterReturns(nil, errors.New("disaster")) 167 }) 168 169 It("errors", func() { 170 Expect(err).To(HaveOccurred()) 171 }) 172 }) 173 }) 174 175 Context("when a check is already running", func() { 176 BeforeEach(func() { 177 fakeCheck := new(dbfakes.FakeCheck) 178 fakeCheck.IDReturns(1) 179 180 fakeEngine.NewCheckStub = func(build db.Check) engine.Runnable { 181 time.Sleep(time.Second) 182 return new(enginefakes.FakeRunnable) 183 } 184 185 fakeCheckFactory.StartedChecksReturns([]db.Check{ 186 fakeCheck, 187 fakeCheck, 188 }, nil) 189 190 fakeLimiter.WaitReturns(nil) 191 fakeRateCalculator.RateLimiterReturns(fakeLimiter, nil) 192 }) 193 194 It("succeeds", func() { 195 Expect(err).NotTo(HaveOccurred()) 196 }) 197 198 It("runs only one pending check", func() { 199 Eventually(fakeEngine.NewCheckCallCount).Should(Equal(1)) 200 }) 201 }) 202 203 Context("when check run panicing", func() { 204 var fakeRunnable *enginefakes.FakeRunnable 205 var fakeCheck *dbfakes.FakeCheck 206 207 BeforeEach(func() { 208 fakeCheck = new(dbfakes.FakeCheck) 209 fakeRunnable = new(enginefakes.FakeRunnable) 210 211 fakeEngine.NewCheckReturns(fakeRunnable) 212 213 fakeCheckFactory.StartedChecksReturns([]db.Check{ 214 fakeCheck, 215 }, nil) 216 217 fakeLimiter.WaitReturns(nil) 218 fakeRateCalculator.RateLimiterReturns(fakeLimiter, nil) 219 220 fakeRunnable.RunStub = func(context.Context) { 221 panic("something went wrong") 222 } 223 }) 224 225 It("tries to run the runnable", func() { 226 Expect(err).NotTo(HaveOccurred()) 227 Eventually(fakeRunnable.RunCallCount).Should(Equal(1)) 228 Eventually(fakeCheck.FinishWithErrorCallCount).Should(Equal(1)) 229 Eventually(fakeCheck.FinishWithErrorArgsForCall(0).Error).Should(ContainSubstring("something went wrong")) 230 }) 231 }) 232 }) 233 })