github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/worker/db_worker_provider_test.go (about) 1 package worker_test 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net" 8 "net/http" 9 10 "code.cloudfoundry.org/garden/client" 11 "code.cloudfoundry.org/garden/client/connection" 12 gfakes "code.cloudfoundry.org/garden/gardenfakes" 13 "code.cloudfoundry.org/garden/server" 14 "code.cloudfoundry.org/lager/lagertest" 15 "github.com/concourse/baggageclaim" 16 "github.com/pf-qiu/concourse/v6/atc" 17 "github.com/pf-qiu/concourse/v6/atc/db" 18 "github.com/pf-qiu/concourse/v6/atc/db/dbfakes" 19 "github.com/pf-qiu/concourse/v6/atc/db/lock/lockfakes" 20 . "github.com/pf-qiu/concourse/v6/atc/worker" 21 "github.com/pf-qiu/concourse/v6/atc/worker/workerfakes" 22 "github.com/concourse/retryhttp/retryhttpfakes" 23 "github.com/cppforlife/go-semi-semantic/version" 24 25 "time" 26 27 . "github.com/onsi/ginkgo" 28 . "github.com/onsi/gomega" 29 "github.com/onsi/gomega/ghttp" 30 ) 31 32 var _ = Describe("DBProvider", func() { 33 var ( 34 fakeLockFactory *lockfakes.FakeLockFactory 35 36 logger *lagertest.TestLogger 37 38 fakeGardenBackend *gfakes.FakeBackend 39 gardenAddr string 40 baggageclaimURL string 41 wantWorkerVersion version.Version 42 baggageclaimServer *ghttp.Server 43 gardenServer *server.GardenServer 44 provider WorkerProvider 45 46 fakeFetcher *workerfakes.FakeFetcher 47 fakeImageFactory *workerfakes.FakeImageFactory 48 fakeDBVolumeRepository *dbfakes.FakeVolumeRepository 49 fakeDBWorkerFactory *dbfakes.FakeWorkerFactory 50 fakeDBTeamFactory *dbfakes.FakeTeamFactory 51 fakeDBWorkerBaseResourceTypeFactory *dbfakes.FakeWorkerBaseResourceTypeFactory 52 fakeDBWorkerTaskCacheFactory *dbfakes.FakeWorkerTaskCacheFactory 53 fakeDBTaskCacheFactory *dbfakes.FakeTaskCacheFactory 54 fakeDBResourceCacheFactory *dbfakes.FakeResourceCacheFactory 55 fakeDBResourceConfigFactory *dbfakes.FakeResourceConfigFactory 56 fakeCreatingContainer *dbfakes.FakeCreatingContainer 57 fakeCreatedContainer *dbfakes.FakeCreatedContainer 58 59 fakeDBTeam *dbfakes.FakeTeam 60 61 workers []Worker 62 workersErr error 63 64 fakeWorker1 *dbfakes.FakeWorker 65 fakeWorker2 *dbfakes.FakeWorker 66 ) 67 68 const ( 69 baggageclaimResponseHeaderTimeout = 10 * time.Minute 70 gardenRequestTimeout = 5 * time.Minute 71 ) 72 73 BeforeEach(func() { 74 var err error 75 76 baggageclaimServer = ghttp.NewServer() 77 78 baggageclaimServer.RouteToHandler("POST", "/volumes", ghttp.RespondWithJSONEncoded( 79 http.StatusCreated, 80 baggageclaim.VolumeResponse{Handle: "vol-handle"}, 81 )) 82 baggageclaimServer.RouteToHandler("PUT", "/volumes/vol-handle/ttl", ghttp.RespondWith( 83 http.StatusNoContent, 84 nil, 85 )) 86 baggageclaimServer.RouteToHandler("GET", "/volumes/vol-handle", ghttp.RespondWithJSONEncoded( 87 http.StatusOK, 88 baggageclaim.VolumeResponse{Handle: "vol-handle"}, 89 )) 90 baggageclaimServer.RouteToHandler("GET", "/volumes/certificates", ghttp.RespondWithJSONEncoded( 91 http.StatusOK, 92 baggageclaim.VolumeResponse{Handle: "certificates", Path: "/resource/certs"}, 93 )) 94 95 gardenAddr = fmt.Sprintf("0.0.0.0:%d", 8888+GinkgoParallelNode()) 96 fakeGardenBackend = new(gfakes.FakeBackend) 97 logger = lagertest.NewTestLogger("test") 98 gardenServer = server.New("tcp", gardenAddr, 0, fakeGardenBackend, logger) 99 100 go func() { 101 defer GinkgoRecover() 102 err = gardenServer.ListenAndServe() 103 Expect(err).NotTo(HaveOccurred()) 104 105 }() 106 107 apiClient := client.New(connection.New("tcp", gardenAddr)) 108 Eventually(apiClient.Ping).Should(Succeed()) 109 110 err = gardenServer.SetupBomberman() 111 Expect(err).NotTo(HaveOccurred()) 112 113 worker1Version := "1.2.3" 114 115 fakeWorker1 = new(dbfakes.FakeWorker) 116 fakeWorker1.NameReturns("some-worker") 117 fakeWorker1.GardenAddrReturns(&gardenAddr) 118 fakeWorker1.BaggageclaimURLReturns(&baggageclaimURL) 119 fakeWorker1.StateReturns(db.WorkerStateRunning) 120 fakeWorker1.ActiveContainersReturns(2) 121 fakeWorker1.ResourceTypesReturns([]atc.WorkerResourceType{ 122 {Type: "some-resource-a", Image: "some-image-a"}}) 123 124 fakeWorker1.VersionReturns(&worker1Version) 125 126 worker2Version := "1.2.4" 127 128 fakeWorker2 = new(dbfakes.FakeWorker) 129 fakeWorker2.NameReturns("some-other-worker") 130 fakeWorker2.GardenAddrReturns(&gardenAddr) 131 fakeWorker2.BaggageclaimURLReturns(&baggageclaimURL) 132 fakeWorker2.StateReturns(db.WorkerStateRunning) 133 fakeWorker2.ActiveContainersReturns(2) 134 fakeWorker2.ResourceTypesReturns([]atc.WorkerResourceType{ 135 {Type: "some-resource-b", Image: "some-image-b"}}) 136 137 fakeWorker2.VersionReturns(&worker2Version) 138 139 fakeFetcher = new(workerfakes.FakeFetcher) 140 fakeImageFactory = new(workerfakes.FakeImageFactory) 141 fakeImage := new(workerfakes.FakeImage) 142 fakeImage.FetchForContainerReturns(FetchedImage{}, nil) 143 fakeImageFactory.GetImageReturns(fakeImage, nil) 144 fakeDBTeamFactory = new(dbfakes.FakeTeamFactory) 145 fakeDBTeam = new(dbfakes.FakeTeam) 146 fakeDBTeam.IDReturns(1) 147 fakeDBTeamFactory.GetByIDReturns(fakeDBTeam) 148 fakeDBVolumeRepository = new(dbfakes.FakeVolumeRepository) 149 150 fakeBackOffFactory := new(retryhttpfakes.FakeBackOffFactory) 151 fakeBackOff := new(retryhttpfakes.FakeBackOff) 152 fakeBackOffFactory.NewBackOffReturns(fakeBackOff) 153 fakeDBResourceCacheFactory = new(dbfakes.FakeResourceCacheFactory) 154 fakeDBResourceConfigFactory = new(dbfakes.FakeResourceConfigFactory) 155 fakeDBWorkerBaseResourceTypeFactory = new(dbfakes.FakeWorkerBaseResourceTypeFactory) 156 fakeDBTaskCacheFactory = new(dbfakes.FakeTaskCacheFactory) 157 fakeDBWorkerTaskCacheFactory = new(dbfakes.FakeWorkerTaskCacheFactory) 158 fakeLock := new(lockfakes.FakeLock) 159 160 fakeLockFactory = new(lockfakes.FakeLockFactory) 161 fakeLockFactory.AcquireReturns(fakeLock, true, nil) 162 163 fakeDBWorkerFactory = new(dbfakes.FakeWorkerFactory) 164 165 wantWorkerVersion, err = version.NewVersionFromString("1.1.0") 166 Expect(err).ToNot(HaveOccurred()) 167 168 provider = NewDBWorkerProvider( 169 fakeLockFactory, 170 fakeBackOffFactory, 171 fakeFetcher, 172 fakeImageFactory, 173 fakeDBResourceCacheFactory, 174 fakeDBResourceConfigFactory, 175 fakeDBWorkerBaseResourceTypeFactory, 176 fakeDBTaskCacheFactory, 177 fakeDBWorkerTaskCacheFactory, 178 fakeDBVolumeRepository, 179 fakeDBTeamFactory, 180 fakeDBWorkerFactory, 181 wantWorkerVersion, 182 baggageclaimResponseHeaderTimeout, 183 gardenRequestTimeout, 184 ) 185 baggageclaimURL = baggageclaimServer.URL() 186 }) 187 188 AfterEach(func() { 189 gardenServer.Stop() 190 191 Eventually(func() error { 192 conn, err := net.Dial("tcp", gardenAddr) 193 if err == nil { 194 conn.Close() 195 } 196 197 return err 198 }).Should(HaveOccurred()) 199 200 baggageclaimServer.Close() 201 }) 202 203 Describe("RunningWorkers", func() { 204 JustBeforeEach(func() { 205 workers, workersErr = provider.RunningWorkers(logger) 206 }) 207 208 Context("when the database yields workers", func() { 209 BeforeEach(func() { 210 fakeDBWorkerFactory.WorkersReturns([]db.Worker{fakeWorker1, fakeWorker2}, nil) 211 fakeDBWorkerFactory.BuildContainersCountPerWorkerReturns(map[string]int{ 212 fakeWorker1.Name(): 57, 213 fakeWorker2.Name(): 68, 214 }, nil) 215 }) 216 217 It("succeeds", func() { 218 Expect(workersErr).NotTo(HaveOccurred()) 219 }) 220 221 It("returns a worker for each one", func() { 222 Expect(workers).To(HaveLen(2)) 223 }) 224 225 It("correctly populates the numBuildContainers field in each worker", func() { 226 Expect([]int{workers[0].BuildContainers(), workers[1].BuildContainers()}).To(ConsistOf(57, 68)) 227 }) 228 229 Context("when some of the workers returned are stalled or landing", func() { 230 BeforeEach(func() { 231 landingWorker := new(dbfakes.FakeWorker) 232 landingWorker.NameReturns("landing-worker") 233 landingWorker.GardenAddrReturns(&gardenAddr) 234 landingWorker.BaggageclaimURLReturns(&baggageclaimURL) 235 landingWorker.StateReturns(db.WorkerStateLanding) 236 landingWorker.ActiveContainersReturns(5) 237 landingWorker.ResourceTypesReturns([]atc.WorkerResourceType{ 238 {Type: "some-resource-b", Image: "some-image-b"}}) 239 240 stalledWorker := new(dbfakes.FakeWorker) 241 stalledWorker.NameReturns("stalled-worker") 242 stalledWorker.GardenAddrReturns(&gardenAddr) 243 stalledWorker.BaggageclaimURLReturns(&baggageclaimURL) 244 stalledWorker.StateReturns(db.WorkerStateStalled) 245 stalledWorker.ActiveContainersReturns(0) 246 stalledWorker.ResourceTypesReturns([]atc.WorkerResourceType{ 247 {Type: "some-resource-b", Image: "some-image-b"}}) 248 249 fakeDBWorkerFactory.WorkersReturns( 250 []db.Worker{ 251 fakeWorker1, 252 stalledWorker, 253 landingWorker, 254 }, nil) 255 }) 256 257 It("only returns workers for the running ones", func() { 258 Expect(workers).To(HaveLen(1)) 259 Expect(workersErr).NotTo(HaveOccurred()) 260 }) 261 }) 262 263 Context("when a worker's major version is higher or lower than the atc worker version", func() { 264 BeforeEach(func() { 265 worker1 := new(dbfakes.FakeWorker) 266 worker1.NameReturns("worker-1") 267 worker1.GardenAddrReturns(&gardenAddr) 268 worker1.BaggageclaimURLReturns(&baggageclaimURL) 269 worker1.StateReturns(db.WorkerStateRunning) 270 worker1.ActiveContainersReturns(5) 271 worker1.ResourceTypesReturns([]atc.WorkerResourceType{ 272 {Type: "some-resource-b", Image: "some-image-b"}}) 273 version1 := "1.1.0" 274 worker1.VersionReturns(&version1) 275 276 worker2 := new(dbfakes.FakeWorker) 277 worker2.NameReturns("worker-2") 278 worker2.GardenAddrReturns(&gardenAddr) 279 worker2.BaggageclaimURLReturns(&baggageclaimURL) 280 worker2.StateReturns(db.WorkerStateRunning) 281 worker2.ActiveContainersReturns(0) 282 worker2.ResourceTypesReturns([]atc.WorkerResourceType{ 283 {Type: "some-resource-b", Image: "some-image-b"}}) 284 version2 := "2.0.0" 285 worker2.VersionReturns(&version2) 286 287 worker3 := new(dbfakes.FakeWorker) 288 worker3.NameReturns("worker-2") 289 worker3.GardenAddrReturns(&gardenAddr) 290 worker3.BaggageclaimURLReturns(&baggageclaimURL) 291 worker3.StateReturns(db.WorkerStateRunning) 292 worker3.ActiveContainersReturns(0) 293 worker3.ResourceTypesReturns([]atc.WorkerResourceType{ 294 {Type: "some-resource-b", Image: "some-image-b"}}) 295 version3 := "0.0.0" 296 worker3.VersionReturns(&version3) 297 298 fakeDBWorkerFactory.WorkersReturns( 299 []db.Worker{ 300 worker3, 301 worker2, 302 worker1, 303 }, nil) 304 }) 305 306 It("only returns workers with same major version", func() { 307 Expect(workers).To(HaveLen(1)) 308 Expect(workers[0].Name()).To(Equal("worker-1")) 309 Expect(workersErr).NotTo(HaveOccurred()) 310 }) 311 }) 312 313 Context("when a worker's minor version is higher or lower than the atc worker version", func() { 314 BeforeEach(func() { 315 worker1 := new(dbfakes.FakeWorker) 316 worker1.NameReturns("worker-1") 317 worker1.GardenAddrReturns(&gardenAddr) 318 worker1.BaggageclaimURLReturns(&baggageclaimURL) 319 worker1.StateReturns(db.WorkerStateRunning) 320 worker1.ActiveContainersReturns(5) 321 worker1.ResourceTypesReturns([]atc.WorkerResourceType{ 322 {Type: "some-resource-b", Image: "some-image-b"}}) 323 version1 := "1.1.0" 324 worker1.VersionReturns(&version1) 325 326 worker2 := new(dbfakes.FakeWorker) 327 worker2.NameReturns("worker-2") 328 worker2.GardenAddrReturns(&gardenAddr) 329 worker2.BaggageclaimURLReturns(&baggageclaimURL) 330 worker2.StateReturns(db.WorkerStateRunning) 331 worker2.ActiveContainersReturns(0) 332 worker2.ResourceTypesReturns([]atc.WorkerResourceType{ 333 {Type: "some-resource-b", Image: "some-image-b"}}) 334 version2 := "1.2.0" 335 worker2.VersionReturns(&version2) 336 337 worker3 := new(dbfakes.FakeWorker) 338 worker3.NameReturns("worker-2") 339 worker3.GardenAddrReturns(&gardenAddr) 340 worker3.BaggageclaimURLReturns(&baggageclaimURL) 341 worker3.StateReturns(db.WorkerStateRunning) 342 worker3.ActiveContainersReturns(0) 343 worker3.ResourceTypesReturns([]atc.WorkerResourceType{ 344 {Type: "some-resource-b", Image: "some-image-b"}}) 345 version3 := "1.0.0" 346 worker3.VersionReturns(&version3) 347 348 fakeDBWorkerFactory.WorkersReturns( 349 []db.Worker{ 350 worker3, 351 worker2, 352 worker1, 353 }, nil) 354 }) 355 356 It("only returns workers with same or higher minor version", func() { 357 Expect(workers).To(HaveLen(2)) 358 Expect(workers[1].Name()).To(Equal("worker-1")) 359 Expect(workers[0].Name()).To(Equal("worker-2")) 360 Expect(workersErr).NotTo(HaveOccurred()) 361 }) 362 }) 363 364 Context("when a worker does not have a version (outdated)", func() { 365 BeforeEach(func() { 366 worker1 := new(dbfakes.FakeWorker) 367 worker1.NameReturns("worker-1") 368 worker1.GardenAddrReturns(&gardenAddr) 369 worker1.BaggageclaimURLReturns(&baggageclaimURL) 370 worker1.StateReturns(db.WorkerStateRunning) 371 worker1.ActiveContainersReturns(5) 372 worker1.ResourceTypesReturns([]atc.WorkerResourceType{ 373 {Type: "some-resource-b", Image: "some-image-b"}}) 374 375 fakeDBWorkerFactory.WorkersReturns( 376 []db.Worker{ 377 worker1, 378 }, nil) 379 }) 380 381 It("does not return the worker", func() { 382 Expect(workers).To(BeEmpty()) 383 Expect(workersErr).NotTo(HaveOccurred()) 384 }) 385 }) 386 387 Context("when a worker's version is incorretly formatted", func() { 388 BeforeEach(func() { 389 worker1 := new(dbfakes.FakeWorker) 390 worker1.NameReturns("worker-1") 391 worker1.GardenAddrReturns(&gardenAddr) 392 worker1.BaggageclaimURLReturns(&baggageclaimURL) 393 worker1.StateReturns(db.WorkerStateRunning) 394 worker1.ActiveContainersReturns(5) 395 worker1.ResourceTypesReturns([]atc.WorkerResourceType{ 396 {Type: "some-resource-b", Image: "some-image-b"}}) 397 version1 := "1.1..0.2-bogus=version" 398 worker1.VersionReturns(&version1) 399 400 fakeDBWorkerFactory.WorkersReturns( 401 []db.Worker{ 402 worker1, 403 }, nil) 404 }) 405 406 It("does not return the worker", func() { 407 Expect(workers).To(BeEmpty()) 408 Expect(workersErr).NotTo(HaveOccurred()) 409 }) 410 }) 411 412 Context("creating the connection to garden", func() { 413 var ( 414 containerSpec ContainerSpec 415 ) 416 417 JustBeforeEach(func() { 418 containerSpec = ContainerSpec{ 419 ImageSpec: ImageSpec{ 420 ResourceType: "some-resource-a", 421 }, 422 } 423 424 fakeContainer := new(gfakes.FakeContainer) 425 fakeContainer.HandleReturns("created-handle") 426 427 fakeGardenBackend.CreateReturns(fakeContainer, nil) 428 fakeGardenBackend.LookupReturns(fakeContainer, nil) 429 430 By("connecting to the worker") 431 fakeDBWorkerFactory.GetWorkerReturns(fakeWorker1, true, nil) 432 container, err := workers[0].FindOrCreateContainer( 433 context.TODO(), 434 logger, 435 db.NewBuildStepContainerOwner(42, atc.PlanID("some-plan-id"), 1), 436 db.ContainerMetadata{}, 437 containerSpec, 438 ) 439 Expect(err).NotTo(HaveOccurred()) 440 441 err = container.Destroy() 442 Expect(err).NotTo(HaveOccurred()) 443 444 By("restarting the worker with a new address") 445 gardenServer.Stop() 446 447 Eventually(func() error { 448 conn, err := net.Dial("tcp", gardenAddr) 449 if err == nil { 450 conn.Close() 451 } 452 453 return err 454 }).Should(HaveOccurred()) 455 456 gardenAddr = fmt.Sprintf("0.0.0.0:%d", 7777+GinkgoParallelNode()) 457 458 gardenServer = server.New("tcp", gardenAddr, 0, fakeGardenBackend, logger) 459 err = gardenServer.Start() 460 Expect(err).NotTo(HaveOccurred()) 461 }) 462 }) 463 464 Describe("a created container", func() { 465 BeforeEach(func() { 466 createdVolume := new(dbfakes.FakeCreatedVolume) 467 createdVolume.HandleReturns("vol-handle") 468 fakeDBWorkerFactory.GetWorkerReturns(fakeWorker1, true, nil) 469 fakeDBVolumeRepository.FindContainerVolumeReturns(nil, createdVolume, nil) 470 fakeDBVolumeRepository.FindBaseResourceTypeVolumeReturns(nil, createdVolume, nil) 471 472 fakeCreatingContainer = new(dbfakes.FakeCreatingContainer) 473 fakeCreatingContainer.HandleReturns("some-handle") 474 fakeCreatedContainer = new(dbfakes.FakeCreatedContainer) 475 fakeCreatingContainer.CreatedReturns(fakeCreatedContainer, nil) 476 fakeWorker1.CreateContainerReturns(fakeCreatingContainer, nil) 477 fakeWorker1.FindContainerReturns(fakeCreatingContainer, nil, nil) 478 479 workerBaseResourceType := &db.UsedWorkerBaseResourceType{ID: 42} 480 fakeDBWorkerBaseResourceTypeFactory.FindReturns(workerBaseResourceType, true, nil) 481 }) 482 483 It("calls through to garden", func() { 484 containerSpec := ContainerSpec{ 485 ImageSpec: ImageSpec{ 486 ResourceType: "some-resource-a", 487 }, 488 } 489 490 fakeContainer := new(gfakes.FakeContainer) 491 fakeContainer.HandleReturns("created-handle") 492 493 fakeGardenBackend.CreateReturns(fakeContainer, nil) 494 fakeGardenBackend.LookupReturns(fakeContainer, nil) 495 496 container, err := workers[0].FindOrCreateContainer( 497 context.TODO(), 498 logger, 499 db.NewBuildStepContainerOwner(42, atc.PlanID("some-plan-id"), 1), 500 db.ContainerMetadata{}, 501 containerSpec, 502 ) 503 Expect(err).NotTo(HaveOccurred()) 504 505 Expect(container.Handle()).To(Equal("created-handle")) 506 507 Expect(fakeGardenBackend.CreateCallCount()).To(Equal(1)) 508 509 err = container.Destroy() 510 Expect(err).NotTo(HaveOccurred()) 511 512 Expect(fakeGardenBackend.DestroyCallCount()).To(Equal(1)) 513 Expect(fakeGardenBackend.DestroyArgsForCall(0)).To(Equal("created-handle")) 514 }) 515 }) 516 }) 517 518 Context("when the database fails to return workers", func() { 519 disaster := errors.New("nope") 520 521 BeforeEach(func() { 522 fakeDBWorkerFactory.WorkersReturns(nil, disaster) 523 }) 524 525 It("returns the error", func() { 526 Expect(workersErr).To(Equal(disaster)) 527 }) 528 }) 529 }) 530 531 Describe("FindWorkerForContainer", func() { 532 var ( 533 foundWorker Worker 534 found bool 535 findErr error 536 ) 537 538 JustBeforeEach(func() { 539 foundWorker, found, findErr = provider.FindWorkerForContainer( 540 logger, 541 345278, 542 "some-handle", 543 ) 544 }) 545 546 Context("when the worker is found", func() { 547 var fakeExistingWorker *dbfakes.FakeWorker 548 549 BeforeEach(func() { 550 addr := "1.2.3.4:7777" 551 552 fakeExistingWorker = new(dbfakes.FakeWorker) 553 fakeExistingWorker.NameReturns("some-worker") 554 fakeExistingWorker.GardenAddrReturns(&addr) 555 workerVersion := "1.1.0" 556 fakeExistingWorker.VersionReturns(&workerVersion) 557 558 fakeDBTeam.FindWorkerForContainerReturns(fakeExistingWorker, true, nil) 559 }) 560 561 It("returns true", func() { 562 Expect(found).To(BeTrue()) 563 Expect(findErr).ToNot(HaveOccurred()) 564 }) 565 566 It("returns the worker", func() { 567 Expect(foundWorker).ToNot(BeNil()) 568 Expect(foundWorker.Name()).To(Equal("some-worker")) 569 }) 570 571 It("found the worker for the right handle", func() { 572 handle := fakeDBTeam.FindWorkerForContainerArgsForCall(0) 573 Expect(handle).To(Equal("some-handle")) 574 }) 575 576 It("found the right team", func() { 577 actualTeam := fakeDBTeamFactory.GetByIDArgsForCall(0) 578 Expect(actualTeam).To(Equal(345278)) 579 }) 580 581 Context("when the worker version is outdated", func() { 582 BeforeEach(func() { 583 fakeExistingWorker.VersionReturns(nil) 584 }) 585 586 It("returns an error", func() { 587 Expect(findErr).ToNot(HaveOccurred()) 588 Expect(foundWorker).To(BeNil()) 589 Expect(found).To(BeFalse()) 590 }) 591 }) 592 }) 593 594 Context("when the worker is not found", func() { 595 BeforeEach(func() { 596 fakeDBTeam.FindWorkerForContainerReturns(nil, false, nil) 597 }) 598 599 It("returns false", func() { 600 Expect(findErr).ToNot(HaveOccurred()) 601 Expect(foundWorker).To(BeNil()) 602 Expect(found).To(BeFalse()) 603 }) 604 }) 605 606 Context("when finding the worker fails", func() { 607 disaster := errors.New("nope") 608 609 BeforeEach(func() { 610 fakeDBTeam.FindWorkerForContainerReturns(nil, false, disaster) 611 }) 612 613 It("returns the error", func() { 614 Expect(findErr).To(Equal(disaster)) 615 Expect(foundWorker).To(BeNil()) 616 Expect(found).To(BeFalse()) 617 }) 618 }) 619 }) 620 621 Describe("FindWorkerForVolume", func() { 622 var ( 623 foundWorker Worker 624 found bool 625 findErr error 626 ) 627 628 JustBeforeEach(func() { 629 foundWorker, found, findErr = provider.FindWorkerForVolume( 630 logger, 631 345278, 632 "some-handle", 633 ) 634 }) 635 636 Context("when the worker is found", func() { 637 var fakeExistingWorker *dbfakes.FakeWorker 638 639 BeforeEach(func() { 640 addr := "1.2.3.4:7777" 641 642 fakeExistingWorker = new(dbfakes.FakeWorker) 643 fakeExistingWorker.NameReturns("some-worker") 644 fakeExistingWorker.GardenAddrReturns(&addr) 645 workerVersion := "1.1.0" 646 fakeExistingWorker.VersionReturns(&workerVersion) 647 648 fakeDBTeam.FindWorkerForVolumeReturns(fakeExistingWorker, true, nil) 649 }) 650 651 It("returns true", func() { 652 Expect(found).To(BeTrue()) 653 Expect(findErr).ToNot(HaveOccurred()) 654 }) 655 656 It("returns the worker", func() { 657 Expect(foundWorker).ToNot(BeNil()) 658 Expect(foundWorker.Name()).To(Equal("some-worker")) 659 }) 660 661 It("found the worker for the right handle", func() { 662 handle := fakeDBTeam.FindWorkerForVolumeArgsForCall(0) 663 Expect(handle).To(Equal("some-handle")) 664 }) 665 666 It("found the right team", func() { 667 actualTeam := fakeDBTeamFactory.GetByIDArgsForCall(0) 668 Expect(actualTeam).To(Equal(345278)) 669 }) 670 671 Context("when the worker version is outdated", func() { 672 BeforeEach(func() { 673 fakeExistingWorker.VersionReturns(nil) 674 }) 675 676 It("returns an error", func() { 677 Expect(findErr).ToNot(HaveOccurred()) 678 Expect(foundWorker).To(BeNil()) 679 Expect(found).To(BeFalse()) 680 }) 681 }) 682 }) 683 684 Context("when the worker is not found", func() { 685 BeforeEach(func() { 686 fakeDBTeam.FindWorkerForVolumeReturns(nil, false, nil) 687 }) 688 689 It("returns false", func() { 690 Expect(findErr).ToNot(HaveOccurred()) 691 Expect(foundWorker).To(BeNil()) 692 Expect(found).To(BeFalse()) 693 }) 694 }) 695 696 Context("when finding the worker fails", func() { 697 disaster := errors.New("nope") 698 699 BeforeEach(func() { 700 fakeDBTeam.FindWorkerForVolumeReturns(nil, false, disaster) 701 }) 702 703 It("returns the error", func() { 704 Expect(findErr).To(Equal(disaster)) 705 Expect(foundWorker).To(BeNil()) 706 Expect(found).To(BeFalse()) 707 }) 708 }) 709 }) 710 711 Describe("FindWorkersForContainerByOwner", func() { 712 var ( 713 fakeOwner *dbfakes.FakeContainerOwner 714 715 foundWorkers []Worker 716 findErr error 717 ) 718 719 BeforeEach(func() { 720 fakeOwner = new(dbfakes.FakeContainerOwner) 721 }) 722 723 JustBeforeEach(func() { 724 foundWorkers, findErr = provider.FindWorkersForContainerByOwner( 725 logger, 726 fakeOwner, 727 ) 728 }) 729 730 Context("when there is a worker", func() { 731 var fakeExistingWorker *dbfakes.FakeWorker 732 733 BeforeEach(func() { 734 addr := "1.2.3.4:7777" 735 736 fakeExistingWorker = new(dbfakes.FakeWorker) 737 fakeExistingWorker.NameReturns("some-worker") 738 fakeExistingWorker.GardenAddrReturns(&addr) 739 workerVersion := "1.1.0" 740 fakeExistingWorker.VersionReturns(&workerVersion) 741 742 fakeDBWorkerFactory.FindWorkersForContainerByOwnerReturns([]db.Worker{fakeExistingWorker}, nil) 743 }) 744 745 It("finds the worker", func() { 746 Expect(foundWorkers).To(HaveLen(1)) 747 Expect(foundWorkers[0].Name()).To(Equal("some-worker")) 748 Expect(findErr).ToNot(HaveOccurred()) 749 }) 750 751 It("found the worker for the right owner", func() { 752 owner := fakeDBWorkerFactory.FindWorkersForContainerByOwnerArgsForCall(0) 753 Expect(owner).To(Equal(fakeOwner)) 754 }) 755 756 Context("when the worker version is outdated", func() { 757 BeforeEach(func() { 758 fakeExistingWorker.VersionReturns(nil) 759 }) 760 761 It("returns an error", func() { 762 Expect(findErr).ToNot(HaveOccurred()) 763 Expect(foundWorkers).To(BeNil()) 764 }) 765 }) 766 }) 767 768 Context("when there are multiple workers", func() { 769 var fakeExistingWorker *dbfakes.FakeWorker 770 var fakeExistingWorker2 *dbfakes.FakeWorker 771 var fakeExistingWorker3 *dbfakes.FakeWorker 772 773 BeforeEach(func() { 774 addr := "1.2.3.4:7777" 775 776 fakeExistingWorker = new(dbfakes.FakeWorker) 777 fakeExistingWorker.NameReturns("some-worker") 778 fakeExistingWorker.GardenAddrReturns(&addr) 779 workerVersion := "1.1.0" 780 fakeExistingWorker.VersionReturns(&workerVersion) 781 782 addr2 := "1.2.3.5:7777" 783 fakeExistingWorker2 = new(dbfakes.FakeWorker) 784 fakeExistingWorker2.NameReturns("some-worker-2") 785 fakeExistingWorker2.GardenAddrReturns(&addr2) 786 fakeExistingWorker2.VersionReturns(&workerVersion) 787 788 addr3 := "1.2.3.6:7777" 789 fakeExistingWorker3 = new(dbfakes.FakeWorker) 790 fakeExistingWorker3.NameReturns("some-worker-3") 791 fakeExistingWorker3.GardenAddrReturns(&addr3) 792 fakeExistingWorker3.VersionReturns(&workerVersion) 793 794 fakeDBWorkerFactory.FindWorkersForContainerByOwnerReturns([]db.Worker{fakeExistingWorker, fakeExistingWorker2, fakeExistingWorker3}, nil) 795 }) 796 797 It("finds both the worker", func() { 798 Expect(foundWorkers).To(HaveLen(3)) 799 800 workerNames := []string{} 801 for _, w := range foundWorkers { 802 workerNames = append(workerNames, w.Name()) 803 } 804 805 Expect(workerNames).To(ConsistOf([]string{"some-worker", "some-worker-2", "some-worker-3"})) 806 Expect(findErr).ToNot(HaveOccurred()) 807 }) 808 809 Context("when one of the worker version is outdated", func() { 810 BeforeEach(func() { 811 workerVersionOld := "1.0.0" 812 fakeExistingWorker3.VersionReturns(&workerVersionOld) 813 }) 814 815 It("returns the other two workers", func() { 816 Expect(findErr).ToNot(HaveOccurred()) 817 Expect(foundWorkers).To(HaveLen(2)) 818 819 workerNames := []string{} 820 for _, w := range foundWorkers { 821 workerNames = append(workerNames, w.Name()) 822 } 823 824 Expect(workerNames).To(ConsistOf([]string{"some-worker", "some-worker-2"})) 825 }) 826 }) 827 }) 828 829 Context("when the worker is not found", func() { 830 BeforeEach(func() { 831 fakeDBWorkerFactory.FindWorkersForContainerByOwnerReturns([]db.Worker{}, nil) 832 }) 833 834 It("returns empty list of workers", func() { 835 Expect(findErr).ToNot(HaveOccurred()) 836 Expect(foundWorkers).To(BeNil()) 837 }) 838 }) 839 840 Context("when finding the worker fails", func() { 841 disaster := errors.New("nope") 842 843 BeforeEach(func() { 844 fakeDBWorkerFactory.FindWorkersForContainerByOwnerReturns(nil, disaster) 845 }) 846 847 It("returns the error", func() { 848 Expect(findErr).To(Equal(disaster)) 849 Expect(foundWorkers).To(BeNil()) 850 }) 851 }) 852 }) 853 })