github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/engine/check_delegate_test.go (about) 1 package engine_test 2 3 import ( 4 "context" 5 "errors" 6 "time" 7 8 . "github.com/onsi/ginkgo" 9 . "github.com/onsi/gomega" 10 11 "code.cloudfoundry.org/clock/fakeclock" 12 "code.cloudfoundry.org/lager" 13 "github.com/pf-qiu/concourse/v6/atc" 14 "github.com/pf-qiu/concourse/v6/atc/db" 15 "github.com/pf-qiu/concourse/v6/atc/db/dbfakes" 16 "github.com/pf-qiu/concourse/v6/atc/db/lock" 17 "github.com/pf-qiu/concourse/v6/atc/db/lock/lockfakes" 18 "github.com/pf-qiu/concourse/v6/atc/engine" 19 "github.com/pf-qiu/concourse/v6/atc/engine/enginefakes" 20 "github.com/pf-qiu/concourse/v6/atc/exec" 21 "github.com/pf-qiu/concourse/v6/atc/policy/policyfakes" 22 "github.com/pf-qiu/concourse/v6/vars" 23 ) 24 25 var _ = Describe("CheckDelegate", func() { 26 var ( 27 fakeBuild *dbfakes.FakeBuild 28 fakeClock *fakeclock.FakeClock 29 fakeRateLimiter *enginefakes.FakeRateLimiter 30 fakePolicyChecker *policyfakes.FakeChecker 31 32 state exec.RunState 33 34 now = time.Date(1991, 6, 3, 5, 30, 0, 0, time.UTC) 35 36 plan atc.Plan 37 delegate exec.CheckDelegate 38 39 fakeResourceConfig *dbfakes.FakeResourceConfig 40 fakeResourceConfigScope *dbfakes.FakeResourceConfigScope 41 ) 42 43 BeforeEach(func() { 44 fakeBuild = new(dbfakes.FakeBuild) 45 fakeClock = fakeclock.NewFakeClock(now) 46 fakeRateLimiter = new(enginefakes.FakeRateLimiter) 47 credVars := vars.StaticVariables{ 48 "source-param": "super-secret-source", 49 "git-key": "{\n123\n456\n789\n}\n", 50 } 51 state = exec.NewRunState(noopStepper, credVars, true) 52 53 plan = atc.Plan{ 54 ID: "some-plan-id", 55 Check: &atc.CheckPlan{}, 56 } 57 58 fakePolicyChecker = new(policyfakes.FakeChecker) 59 60 delegate = engine.NewCheckDelegate(fakeBuild, plan, state, fakeClock, fakeRateLimiter, fakePolicyChecker) 61 62 fakeResourceConfig = new(dbfakes.FakeResourceConfig) 63 fakeResourceConfigScope = new(dbfakes.FakeResourceConfigScope) 64 fakeResourceConfig.FindOrCreateScopeReturns(fakeResourceConfigScope, nil) 65 }) 66 67 Describe("FindOrCreateScope", func() { 68 var saveErr error 69 var scope db.ResourceConfigScope 70 71 BeforeEach(func() { 72 saveErr = nil 73 }) 74 75 JustBeforeEach(func() { 76 scope, saveErr = delegate.FindOrCreateScope(fakeResourceConfig) 77 }) 78 79 Context("without a resource", func() { 80 BeforeEach(func() { 81 plan.Check.Resource = "" 82 }) 83 84 It("succeeds", func() { 85 Expect(saveErr).ToNot(HaveOccurred()) 86 }) 87 88 It("finds or creates a global scope", func() { 89 Expect(fakeResourceConfig.FindOrCreateScopeCallCount()).To(Equal(1)) 90 resource := fakeResourceConfig.FindOrCreateScopeArgsForCall(0) 91 Expect(resource).To(BeNil()) 92 }) 93 94 It("returns the scope", func() { 95 Expect(scope).To(Equal(fakeResourceConfigScope)) 96 }) 97 }) 98 99 Context("with a resource", func() { 100 var ( 101 fakePipeline *dbfakes.FakePipeline 102 fakeResource *dbfakes.FakeResource 103 ) 104 105 BeforeEach(func() { 106 plan.Check.Resource = "some-resource" 107 108 fakePipeline = new(dbfakes.FakePipeline) 109 fakeBuild.PipelineReturns(fakePipeline, true, nil) 110 111 fakeResource = new(dbfakes.FakeResource) 112 fakePipeline.ResourceReturns(fakeResource, true, nil) 113 }) 114 115 It("succeeds", func() { 116 Expect(saveErr).ToNot(HaveOccurred()) 117 }) 118 119 It("looks up the resource on the pipeline", func() { 120 Expect(fakePipeline.ResourceCallCount()).To(Equal(1)) 121 resourceName := fakePipeline.ResourceArgsForCall(0) 122 Expect(resourceName).To(Equal("some-resource")) 123 }) 124 125 It("finds or creates a scope for the resource", func() { 126 Expect(fakeResourceConfig.FindOrCreateScopeCallCount()).To(Equal(1)) 127 resource := fakeResourceConfig.FindOrCreateScopeArgsForCall(0) 128 Expect(resource).To(Equal(fakeResource)) 129 }) 130 131 It("returns the scope", func() { 132 Expect(scope).To(Equal(fakeResourceConfigScope)) 133 }) 134 135 Context("when the pipeline is not found", func() { 136 BeforeEach(func() { 137 fakeBuild.PipelineReturns(nil, false, nil) 138 }) 139 140 It("returns an error", func() { 141 Expect(saveErr).To(HaveOccurred()) 142 }) 143 144 It("does not create a scope", func() { 145 Expect(fakeResourceConfig.FindOrCreateScopeCallCount()).To(BeZero()) 146 }) 147 }) 148 149 Context("when the resource is not found", func() { 150 BeforeEach(func() { 151 fakePipeline.ResourceReturns(nil, false, nil) 152 }) 153 154 It("returns an error", func() { 155 Expect(saveErr).To(HaveOccurred()) 156 }) 157 158 It("does not create a scope", func() { 159 Expect(fakeResourceConfig.FindOrCreateScopeCallCount()).To(BeZero()) 160 }) 161 }) 162 }) 163 }) 164 165 Describe("WaitToRun", func() { 166 var runLock lock.Lock 167 var run bool 168 var runErr error 169 170 BeforeEach(func() { 171 run = false 172 }) 173 174 JustBeforeEach(func() { 175 runLock, run, runErr = delegate.WaitToRun(context.TODO(), fakeResourceConfigScope) 176 }) 177 178 Context("when the build is manually triggered", func() { 179 BeforeEach(func() { 180 fakeBuild.IsManuallyTriggeredReturns(true) 181 }) 182 183 It("returns true", func() { 184 Expect(run).To(BeTrue()) 185 }) 186 }) 187 188 Context("with an interval configured", func() { 189 var interval time.Duration = time.Minute 190 191 BeforeEach(func() { 192 plan.Check.Interval = interval.String() 193 }) 194 195 Context("when the interval has not elapsed since the last check", func() { 196 BeforeEach(func() { 197 fakeResourceConfigScope.LastCheckEndTimeReturns(now.Add(-(interval - 1)), nil) 198 }) 199 200 It("returns false", func() { 201 Expect(run).To(BeFalse()) 202 }) 203 }) 204 205 Context("when the interval has elapsed since the last check", func() { 206 BeforeEach(func() { 207 fakeResourceConfigScope.LastCheckEndTimeReturns(now.Add(-interval), nil) 208 }) 209 210 It("returns true", func() { 211 Expect(run).To(BeTrue()) 212 }) 213 }) 214 }) 215 216 Context("when running for a resource", func() { 217 var fakeLock *lockfakes.FakeLock 218 219 BeforeEach(func() { 220 plan.Check.Resource = "some-resource" 221 222 fakeLock = new(lockfakes.FakeLock) 223 fakeResourceConfigScope.AcquireResourceCheckingLockReturns(fakeLock, true, nil) 224 }) 225 226 It("returns a lock", func() { 227 Expect(runLock).To(Equal(fakeLock)) 228 }) 229 230 Context("before acquiring the lock", func() { 231 BeforeEach(func() { 232 fakeResourceConfigScope.AcquireResourceCheckingLockStub = func(lager.Logger) (lock.Lock, bool, error) { 233 Expect(fakeRateLimiter.WaitCallCount()).To(Equal(1)) 234 return fakeLock, true, nil 235 } 236 }) 237 238 It("rate limits", func() { 239 Expect(fakeRateLimiter.WaitCallCount()).To(Equal(1)) 240 }) 241 }) 242 243 Context("when the build is manually triggered", func() { 244 BeforeEach(func() { 245 fakeBuild.IsManuallyTriggeredReturns(true) 246 }) 247 248 It("does not rate limit", func() { 249 Expect(fakeRateLimiter.WaitCallCount()).To(Equal(0)) 250 }) 251 }) 252 253 Context("when getting the last check end time errors", func() { 254 BeforeEach(func() { 255 fakeResourceConfigScope.LastCheckEndTimeReturns(time.Time{}, errors.New("oh no")) 256 }) 257 258 It("returns an error", func() { 259 Expect(runErr).To(HaveOccurred()) 260 }) 261 262 It("releases the lock", func() { 263 Expect(fakeLock.ReleaseCallCount()).To(Equal(1)) 264 }) 265 }) 266 267 Context("with an interval configured", func() { 268 var interval time.Duration = time.Minute 269 270 BeforeEach(func() { 271 plan.Check.Interval = interval.String() 272 }) 273 274 Context("when the interval has not elapsed since the last check", func() { 275 BeforeEach(func() { 276 fakeResourceConfigScope.LastCheckEndTimeReturns(now.Add(-(interval - 1)), nil) 277 }) 278 279 It("returns false", func() { 280 Expect(run).To(BeFalse()) 281 }) 282 283 It("releases the lock", func() { 284 Expect(fakeLock.ReleaseCallCount()).To(Equal(1)) 285 }) 286 }) 287 }) 288 }) 289 290 Context("when not running for a resource", func() { 291 BeforeEach(func() { 292 plan.Check.Resource = "" 293 }) 294 295 It("does not rate limit", func() { 296 Expect(fakeRateLimiter.WaitCallCount()).To(Equal(0)) 297 }) 298 299 It("does not acquire a lock", func() { 300 Expect(fakeResourceConfigScope.AcquireResourceCheckingLockCallCount()).To(Equal(0)) 301 }) 302 303 It("returns a no-op lock", func() { 304 Expect(runLock).To(Equal(lock.NoopLock{})) 305 }) 306 }) 307 }) 308 309 Describe("PointToCheckedConfig", func() { 310 var pointErr error 311 312 BeforeEach(func() { 313 pointErr = nil 314 }) 315 316 JustBeforeEach(func() { 317 pointErr = delegate.PointToCheckedConfig(fakeResourceConfigScope) 318 }) 319 320 Context("when not checking for a resource or resource type", func() { 321 It("succeeds", func() { 322 Expect(pointErr).ToNot(HaveOccurred()) 323 }) 324 }) 325 326 Context("when checking for a resource", func() { 327 var ( 328 fakePipeline *dbfakes.FakePipeline 329 fakeResource *dbfakes.FakeResource 330 ) 331 332 BeforeEach(func() { 333 plan.Check.Resource = "some-resource" 334 335 fakePipeline = new(dbfakes.FakePipeline) 336 fakeBuild.PipelineReturns(fakePipeline, true, nil) 337 338 fakeResource = new(dbfakes.FakeResource) 339 fakePipeline.ResourceReturns(fakeResource, true, nil) 340 }) 341 342 It("succeeds", func() { 343 Expect(pointErr).ToNot(HaveOccurred()) 344 }) 345 346 It("looks up the resource on the pipeline", func() { 347 Expect(fakePipeline.ResourceCallCount()).To(Equal(1)) 348 resourceName := fakePipeline.ResourceArgsForCall(0) 349 Expect(resourceName).To(Equal("some-resource")) 350 }) 351 352 It("sets the resource config scope", func() { 353 Expect(fakeResource.SetResourceConfigScopeCallCount()).To(Equal(1)) 354 scope := fakeResource.SetResourceConfigScopeArgsForCall(0) 355 Expect(scope).To(Equal(fakeResourceConfigScope)) 356 }) 357 358 Context("when the pipeline is not found", func() { 359 BeforeEach(func() { 360 fakeBuild.PipelineReturns(nil, false, nil) 361 }) 362 363 It("returns an error", func() { 364 Expect(pointErr).To(HaveOccurred()) 365 }) 366 }) 367 368 Context("when the resource is not found", func() { 369 BeforeEach(func() { 370 fakePipeline.ResourceReturns(nil, false, nil) 371 }) 372 373 It("returns an error", func() { 374 Expect(pointErr).To(HaveOccurred()) 375 }) 376 }) 377 }) 378 379 Context("when checking for a resource type", func() { 380 var ( 381 fakePipeline *dbfakes.FakePipeline 382 fakeResourceType *dbfakes.FakeResourceType 383 ) 384 385 BeforeEach(func() { 386 plan.Check.ResourceType = "some-resource-type" 387 388 fakePipeline = new(dbfakes.FakePipeline) 389 fakeBuild.PipelineReturns(fakePipeline, true, nil) 390 391 fakeResourceType = new(dbfakes.FakeResourceType) 392 fakePipeline.ResourceTypeReturns(fakeResourceType, true, nil) 393 }) 394 395 It("succeeds", func() { 396 Expect(pointErr).ToNot(HaveOccurred()) 397 }) 398 399 It("looks up the resource type on the pipeline", func() { 400 Expect(fakePipeline.ResourceTypeCallCount()).To(Equal(1)) 401 resourceName := fakePipeline.ResourceTypeArgsForCall(0) 402 Expect(resourceName).To(Equal("some-resource-type")) 403 }) 404 405 It("assigns the scope to the resource type", func() { 406 Expect(fakeResourceType.SetResourceConfigScopeCallCount()).To(Equal(1)) 407 408 scope := fakeResourceType.SetResourceConfigScopeArgsForCall(0) 409 Expect(scope).To(Equal(fakeResourceConfigScope)) 410 }) 411 412 Context("when the pipeline is not found", func() { 413 BeforeEach(func() { 414 fakeBuild.PipelineReturns(nil, false, nil) 415 }) 416 417 It("returns an error", func() { 418 Expect(pointErr).To(HaveOccurred()) 419 }) 420 }) 421 422 Context("when the resource is not found", func() { 423 BeforeEach(func() { 424 fakePipeline.ResourceTypeReturns(nil, false, nil) 425 }) 426 427 It("returns an error", func() { 428 Expect(pointErr).To(HaveOccurred()) 429 }) 430 }) 431 }) 432 }) 433 })