github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/db/worker_test.go (about) 1 package db_test 2 3 import ( 4 "database/sql" 5 "fmt" 6 "time" 7 8 "github.com/pf-qiu/concourse/v6/atc" 9 . "github.com/pf-qiu/concourse/v6/atc/db" 10 11 . "github.com/onsi/ginkgo" 12 . "github.com/onsi/ginkgo/extensions/table" 13 . "github.com/onsi/gomega" 14 . "github.com/onsi/gomega/types" 15 ) 16 17 var _ = Describe("Worker", func() { 18 var ( 19 atcWorker atc.Worker 20 worker Worker 21 ) 22 23 BeforeEach(func() { 24 atcWorker = atc.Worker{ 25 GardenAddr: "some-garden-addr", 26 BaggageclaimURL: "some-bc-url", 27 HTTPProxyURL: "some-http-proxy-url", 28 HTTPSProxyURL: "some-https-proxy-url", 29 NoProxy: "some-no-proxy", 30 Ephemeral: true, 31 ActiveContainers: 140, 32 ResourceTypes: []atc.WorkerResourceType{ 33 { 34 Type: "some-resource-type", 35 Image: "some-image", 36 Version: "some-version", 37 }, 38 { 39 Type: "other-resource-type", 40 Image: "other-image", 41 Version: "other-version", 42 }, 43 }, 44 Platform: "some-platform", 45 Tags: atc.Tags{"some", "tags"}, 46 Name: "some-name", 47 StartTime: 55912945, 48 } 49 }) 50 51 Describe("Land", func() { 52 BeforeEach(func() { 53 var err error 54 worker, err = workerFactory.SaveWorker(atcWorker, 5*time.Minute) 55 Expect(err).NotTo(HaveOccurred()) 56 }) 57 58 Context("when the worker is present", func() { 59 It("marks the worker as `landing`", func() { 60 err := worker.Land() 61 Expect(err).NotTo(HaveOccurred()) 62 63 _, err = worker.Reload() 64 Expect(err).NotTo(HaveOccurred()) 65 Expect(worker.Name()).To(Equal(atcWorker.Name)) 66 Expect(worker.State()).To(Equal(WorkerStateLanding)) 67 }) 68 69 Context("when worker is already landed", func() { 70 BeforeEach(func() { 71 err := worker.Land() 72 Expect(err).NotTo(HaveOccurred()) 73 _, err = workerLifecycle.LandFinishedLandingWorkers() 74 Expect(err).NotTo(HaveOccurred()) 75 }) 76 77 It("keeps worker state as landed", func() { 78 err := worker.Land() 79 Expect(err).NotTo(HaveOccurred()) 80 _, err = worker.Reload() 81 Expect(err).NotTo(HaveOccurred()) 82 83 Expect(worker.Name()).To(Equal(atcWorker.Name)) 84 Expect(worker.State()).To(Equal(WorkerStateLanded)) 85 }) 86 }) 87 }) 88 89 Context("when the worker is not present", func() { 90 It("returns an error", func() { 91 err := worker.Delete() 92 Expect(err).NotTo(HaveOccurred()) 93 94 err = worker.Land() 95 Expect(err).To(HaveOccurred()) 96 Expect(err).To(Equal(ErrWorkerNotPresent)) 97 }) 98 }) 99 }) 100 101 Describe("Retire", func() { 102 BeforeEach(func() { 103 var err error 104 worker, err = workerFactory.SaveWorker(atcWorker, 5*time.Minute) 105 Expect(err).NotTo(HaveOccurred()) 106 }) 107 108 Context("when the worker is present", func() { 109 It("marks the worker as `retiring`", func() { 110 err := worker.Retire() 111 Expect(err).NotTo(HaveOccurred()) 112 113 _, err = worker.Reload() 114 Expect(err).NotTo(HaveOccurred()) 115 Expect(worker.Name()).To(Equal(atcWorker.Name)) 116 Expect(worker.State()).To(Equal(WorkerStateRetiring)) 117 }) 118 }) 119 120 Context("when the worker is not present", func() { 121 BeforeEach(func() { 122 err := worker.Delete() 123 Expect(err).NotTo(HaveOccurred()) 124 }) 125 126 It("returns an error", func() { 127 err := worker.Retire() 128 Expect(err).To(HaveOccurred()) 129 Expect(err).To(Equal(ErrWorkerNotPresent)) 130 }) 131 }) 132 }) 133 134 Describe("Delete", func() { 135 BeforeEach(func() { 136 var err error 137 worker, err = workerFactory.SaveWorker(atcWorker, 5*time.Minute) 138 Expect(err).NotTo(HaveOccurred()) 139 }) 140 141 It("deletes the record for the worker", func() { 142 err := worker.Delete() 143 Expect(err).NotTo(HaveOccurred()) 144 145 _, found, err := workerFactory.GetWorker(atcWorker.Name) 146 Expect(err).ToNot(HaveOccurred()) 147 Expect(found).To(BeFalse()) 148 }) 149 }) 150 151 Describe("Prune", func() { 152 Context("when worker exists", func() { 153 DescribeTable("worker in state", 154 func(workerState string, errMatch GomegaMatcher) { 155 worker, err := workerFactory.SaveWorker(atc.Worker{ 156 Name: "worker-to-prune", 157 GardenAddr: "1.2.3.4", 158 State: workerState, 159 }, 5*time.Minute) 160 Expect(err).NotTo(HaveOccurred()) 161 162 err = worker.Prune() 163 Expect(err).To(errMatch) 164 }, 165 166 Entry("running", "running", Equal(ErrCannotPruneRunningWorker)), 167 Entry("landing", "landing", BeNil()), 168 Entry("retiring", "retiring", BeNil()), 169 ) 170 171 Context("when worker is stalled", func() { 172 var pruneErr error 173 BeforeEach(func() { 174 worker, err := workerFactory.SaveWorker(atc.Worker{ 175 Name: "worker-to-prune", 176 GardenAddr: "1.2.3.4", 177 State: "running", 178 }, -5*time.Minute) 179 Expect(err).NotTo(HaveOccurred()) 180 181 _, err = workerLifecycle.StallUnresponsiveWorkers() 182 Expect(err).NotTo(HaveOccurred()) 183 pruneErr = worker.Prune() 184 }) 185 186 It("does not return error", func() { 187 Expect(pruneErr).NotTo(HaveOccurred()) 188 }) 189 }) 190 }) 191 192 Context("when worker does not exist", func() { 193 BeforeEach(func() { 194 var err error 195 worker, err = workerFactory.SaveWorker(atcWorker, 5*time.Minute) 196 Expect(err).NotTo(HaveOccurred()) 197 err = worker.Delete() 198 Expect(err).NotTo(HaveOccurred()) 199 }) 200 201 It("raises ErrWorkerNotPresent", func() { 202 err := worker.Prune() 203 Expect(err).To(Equal(ErrWorkerNotPresent)) 204 }) 205 }) 206 }) 207 208 Describe("FindContainer/CreateContainer", func() { 209 var ( 210 containerMetadata ContainerMetadata 211 containerOwner ContainerOwner 212 213 foundCreatingContainer CreatingContainer 214 foundCreatedContainer CreatedContainer 215 worker Worker 216 ) 217 218 expiries := ContainerOwnerExpiries{ 219 Min: 5 * time.Minute, 220 Max: 1 * time.Hour, 221 } 222 223 BeforeEach(func() { 224 containerMetadata = ContainerMetadata{ 225 Type: "check", 226 } 227 228 var err error 229 worker, err = workerFactory.SaveWorker(atcWorker, 5*time.Minute) 230 Expect(err).NotTo(HaveOccurred()) 231 232 atcWorker2 := atcWorker 233 atcWorker2.Name = "some-name2" 234 atcWorker2.GardenAddr = "some-garden-addr-other" 235 otherWorker, err = workerFactory.SaveWorker(atcWorker2, 5*time.Minute) 236 Expect(err).NotTo(HaveOccurred()) 237 238 resourceConfig, err := resourceConfigFactory.FindOrCreateResourceConfig( 239 "some-resource-type", 240 atc.Source{"some": "source"}, 241 atc.VersionedResourceTypes{}, 242 ) 243 Expect(err).ToNot(HaveOccurred()) 244 245 containerOwner = NewResourceConfigCheckSessionContainerOwner( 246 resourceConfig.ID(), 247 resourceConfig.OriginBaseResourceType().ID, 248 expiries, 249 ) 250 }) 251 252 JustBeforeEach(func() { 253 var err error 254 foundCreatingContainer, foundCreatedContainer, err = worker.FindContainer(containerOwner) 255 Expect(err).ToNot(HaveOccurred()) 256 }) 257 258 Context("when there is a creating container", func() { 259 var creatingContainer CreatingContainer 260 261 BeforeEach(func() { 262 var err error 263 creatingContainer, err = worker.CreateContainer(containerOwner, containerMetadata) 264 Expect(err).ToNot(HaveOccurred()) 265 }) 266 267 It("returns it", func() { 268 Expect(foundCreatedContainer).To(BeNil()) 269 Expect(foundCreatingContainer).ToNot(BeNil()) 270 }) 271 272 Context("when finding on another worker", func() { 273 BeforeEach(func() { 274 worker = otherWorker 275 }) 276 277 It("does not find it", func() { 278 Expect(foundCreatingContainer).To(BeNil()) 279 Expect(foundCreatedContainer).To(BeNil()) 280 }) 281 }) 282 283 Context("when there is a created container", func() { 284 BeforeEach(func() { 285 _, err := creatingContainer.Created() 286 Expect(err).ToNot(HaveOccurred()) 287 }) 288 289 It("returns it", func() { 290 Expect(foundCreatedContainer).ToNot(BeNil()) 291 Expect(foundCreatingContainer).To(BeNil()) 292 }) 293 294 Context("when finding on another worker", func() { 295 BeforeEach(func() { 296 worker = otherWorker 297 }) 298 299 It("does not find it", func() { 300 Expect(foundCreatingContainer).To(BeNil()) 301 Expect(foundCreatedContainer).To(BeNil()) 302 }) 303 }) 304 }) 305 306 Context("when the creating container is failed and gced", func() { 307 BeforeEach(func() { 308 var err error 309 _, err = creatingContainer.Failed() 310 Expect(err).ToNot(HaveOccurred()) 311 312 containerRepository := NewContainerRepository(dbConn) 313 containersDestroyed, err := containerRepository.DestroyFailedContainers() 314 Expect(containersDestroyed).To(Equal(1)) 315 Expect(err).ToNot(HaveOccurred()) 316 317 var checkSessions int 318 err = dbConn.QueryRow("SELECT COUNT(*) FROM resource_config_check_sessions").Scan(&checkSessions) 319 Expect(err).ToNot(HaveOccurred()) 320 Expect(checkSessions).To(Equal(1)) 321 }) 322 323 Context("and we create a new container", func() { 324 BeforeEach(func() { 325 _, err := worker.CreateContainer(containerOwner, containerMetadata) 326 Expect(err).ToNot(HaveOccurred()) 327 }) 328 329 It("does not duplicate the resource config check session", func() { 330 var checkSessions int 331 err := dbConn.QueryRow("SELECT COUNT(*) FROM resource_config_check_sessions").Scan(&checkSessions) 332 Expect(err).ToNot(HaveOccurred()) 333 Expect(checkSessions).To(Equal(1)) 334 }) 335 }) 336 }) 337 }) 338 339 Context("when there is no container", func() { 340 It("returns nil", func() { 341 Expect(foundCreatedContainer).To(BeNil()) 342 Expect(foundCreatingContainer).To(BeNil()) 343 }) 344 }) 345 346 Context("when the container has a meta type", func() { 347 var container CreatingContainer 348 349 Context("when the meta type is check", func() { 350 BeforeEach(func() { 351 containerMetadata = ContainerMetadata{ 352 Type: "check", 353 } 354 355 var err error 356 container, err = worker.CreateContainer(containerOwner, containerMetadata) 357 Expect(err).ToNot(HaveOccurred()) 358 }) 359 360 It("returns a container with empty team id", func() { 361 var teamID sql.NullString 362 363 err := dbConn.QueryRow(fmt.Sprintf("SELECT team_id FROM containers WHERE id='%d'", container.ID())).Scan(&teamID) 364 Expect(err).ToNot(HaveOccurred()) 365 Expect(teamID.Valid).To(BeFalse()) 366 }) 367 }) 368 369 Context("when the meta type is not check", func() { 370 BeforeEach(func() { 371 containerMetadata = ContainerMetadata{ 372 Type: "get", 373 } 374 375 oneOffBuild, err := defaultTeam.CreateOneOffBuild() 376 Expect(err).ToNot(HaveOccurred()) 377 378 container, err = worker.CreateContainer(NewBuildStepContainerOwner(oneOffBuild.ID(), atc.PlanID("1"), 1), containerMetadata) 379 Expect(err).ToNot(HaveOccurred()) 380 }) 381 382 It("returns a container with a team id", func() { 383 var teamID sql.NullString 384 385 err := dbConn.QueryRow(fmt.Sprintf("SELECT team_id FROM containers WHERE id='%d'", container.ID())).Scan(&teamID) 386 Expect(err).ToNot(HaveOccurred()) 387 Expect(teamID.Valid).To(BeTrue()) 388 }) 389 }) 390 }) 391 }) 392 393 Describe("Active tasks", func() { 394 BeforeEach(func() { 395 var err error 396 worker, err = workerFactory.SaveWorker(atcWorker, 5*time.Minute) 397 Expect(err).NotTo(HaveOccurred()) 398 }) 399 400 Context("when the worker registers", func() { 401 It("has no active tasks", func() { 402 at, err := worker.ActiveTasks() 403 Expect(err).ToNot(HaveOccurred()) 404 Expect(at).To(Equal(0)) 405 }) 406 }) 407 408 Context("when the active task is increased", func() { 409 BeforeEach(func() { 410 err := worker.IncreaseActiveTasks() 411 Expect(err).ToNot(HaveOccurred()) 412 }) 413 414 It("increase the active tasks counter", func() { 415 at, err := worker.ActiveTasks() 416 Expect(err).ToNot(HaveOccurred()) 417 Expect(at).To(Equal(1)) 418 }) 419 Context("when the active task is decreased", func() { 420 BeforeEach(func() { 421 err := worker.DecreaseActiveTasks() 422 Expect(err).ToNot(HaveOccurred()) 423 }) 424 It("reset the active tasks to 0", func() { 425 at, err := worker.ActiveTasks() 426 Expect(err).ToNot(HaveOccurred()) 427 Expect(at).To(Equal(0)) 428 }) 429 }) 430 }) 431 432 Context("when the active task is decreased below 0", func() { 433 It("raise an error", func() { 434 err := worker.DecreaseActiveTasks() 435 Expect(err).To(HaveOccurred()) 436 }) 437 }) 438 }) 439 })