github.com/chenbh/concourse/v6@v6.4.2/fly/integration/workers_test.go (about) 1 package integration_test 2 3 import ( 4 "os/exec" 5 "time" 6 7 "github.com/chenbh/concourse/v6/atc" 8 "github.com/chenbh/concourse/v6/fly/ui" 9 "github.com/fatih/color" 10 . "github.com/onsi/ginkgo" 11 . "github.com/onsi/gomega" 12 "github.com/onsi/gomega/gbytes" 13 "github.com/onsi/gomega/gexec" 14 "github.com/onsi/gomega/ghttp" 15 ) 16 17 const second = 1 18 const minute = 60 * second 19 const hour = minute * 60 20 const day = hour * 24 21 22 var _ = Describe("Fly CLI", func() { 23 Describe("workers", func() { 24 var ( 25 flyCmd *exec.Cmd 26 worker1StartTime int64 27 worker2StartTime int64 28 worker3StartTime int64 29 worker4StartTime int64 30 worker5StartTime int64 31 worker6StartTime int64 32 worker7StartTime int64 33 ) 34 35 BeforeEach(func() { 36 flyCmd = exec.Command(flyPath, "-t", targetName, "workers") 37 }) 38 39 Context("when workers are returned from the API", func() { 40 JustBeforeEach(func() { 41 atcServer.AppendHandlers( 42 ghttp.CombineHandlers( 43 ghttp.VerifyRequest("GET", "/api/v1/workers"), 44 ghttp.RespondWithJSONEncoded(200, []atc.Worker{ 45 { 46 Name: "worker-2", 47 GardenAddr: "1.2.3.4:7777", 48 ActiveContainers: 0, 49 ActiveTasks: 1, 50 Platform: "platform2", 51 Tags: []string{"tag2", "tag3"}, 52 ResourceTypes: []atc.WorkerResourceType{ 53 {Type: "resource-1", Image: "/images/resource-1"}, 54 }, 55 Team: "team-1", 56 State: "running", 57 Version: "4.5.6", 58 StartTime: worker2StartTime, 59 }, 60 { 61 Name: "worker-6", 62 GardenAddr: "5.5.5.5:7777", 63 ActiveContainers: 0, 64 ActiveTasks: 1, 65 Platform: "platform2", 66 Tags: []string{"tag1"}, 67 Team: "team-1", 68 State: "running", 69 Version: "1.2.3", 70 Ephemeral: true, 71 StartTime: worker6StartTime, 72 }, 73 { 74 Name: "worker-7", 75 GardenAddr: "7.7.7.7:7777", 76 ActiveContainers: 0, 77 ActiveTasks: 0, 78 Platform: "platform2", 79 Tags: []string{"tag1"}, 80 Team: "team-1", 81 State: "running", 82 Version: "", 83 StartTime: worker7StartTime, 84 }, 85 { 86 Name: "worker-1", 87 GardenAddr: "2.2.3.4:7777", 88 BaggageclaimURL: "http://2.2.3.4:7788", 89 ActiveContainers: 1, 90 ActiveTasks: 1, 91 Platform: "platform1", 92 Tags: []string{"tag1"}, 93 ResourceTypes: []atc.WorkerResourceType{ 94 {Type: "resource-1", Image: "/images/resource-1"}, 95 {Type: "resource-2", Image: "/images/resource-2"}, 96 }, 97 Team: "team-1", 98 State: "landing", 99 Version: "4.5.6", 100 StartTime: worker1StartTime, 101 }, 102 { 103 Name: "worker-3", 104 GardenAddr: "3.2.3.4:7777", 105 ActiveContainers: 10, 106 ActiveTasks: 1, 107 Platform: "platform3", 108 Tags: []string{}, 109 State: "landed", 110 Version: "4.5.6", 111 StartTime: worker3StartTime, 112 }, 113 { 114 Name: "worker-4", 115 GardenAddr: "", 116 ActiveContainers: 7, 117 ActiveTasks: 1, 118 Platform: "platform4", 119 Tags: []string{"tag1"}, 120 Team: "team-1", 121 State: "stalled", 122 Version: "4.5.6", 123 StartTime: worker4StartTime, 124 }, 125 { 126 Name: "worker-5", 127 GardenAddr: "3.2.3.4:7777", 128 ActiveContainers: 5, 129 ActiveTasks: 1, 130 Platform: "platform5", 131 Tags: []string{}, 132 State: "retiring", 133 Version: "4.5.6", 134 StartTime: worker5StartTime, 135 }, 136 }), 137 ), 138 ) 139 }) 140 141 BeforeEach(func() { 142 worker1StartTime = time.Now().Unix() - 2*day - 90*second 143 worker2StartTime = time.Now().Unix() - 1*day - 90*second 144 worker3StartTime = time.Now().Unix() - 10*hour - 3*minute - 50*second 145 worker4StartTime = time.Now().Unix() - 8*hour - 30*minute - 50*second 146 worker5StartTime = 0 147 worker6StartTime = 0 148 worker7StartTime = time.Now().Unix() + 700*second 149 }) 150 151 It("lists them to the user, ordered by name, with outdated and stalled workers grouped together", func() { 152 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 153 Expect(err).NotTo(HaveOccurred()) 154 155 Eventually(sess).Should(gexec.Exit(0)) 156 Expect(sess.Out).To(PrintTable(ui.Table{ 157 Headers: ui.TableRow{ 158 {Contents: "name", Color: color.New(color.Bold)}, 159 {Contents: "containers", Color: color.New(color.Bold)}, 160 {Contents: "platform", Color: color.New(color.Bold)}, 161 {Contents: "tags", Color: color.New(color.Bold)}, 162 {Contents: "team", Color: color.New(color.Bold)}, 163 {Contents: "state", Color: color.New(color.Bold)}, 164 {Contents: "version", Color: color.New(color.Bold)}, 165 {Contents: "age", Color: color.New(color.Bold)}, 166 }, 167 Data: []ui.TableRow{ 168 {{Contents: "worker-1"}, {Contents: "1"}, {Contents: "platform1"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "landing"}, {Contents: "4.5.6"}, {Contents: "2d"}}, 169 {{Contents: "worker-2"}, {Contents: "0"}, {Contents: "platform2"}, {Contents: "tag2, tag3"}, {Contents: "team-1"}, {Contents: "running"}, {Contents: "4.5.6"}, {Contents: "1d"}}, 170 {{Contents: "worker-3"}, {Contents: "10"}, {Contents: "platform3"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "landed"}, {Contents: "4.5.6"}, {Contents: "10h3m"}}, 171 {{Contents: "worker-5"}, {Contents: "5"}, {Contents: "platform5"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "retiring"}, {Contents: "4.5.6"}, {Contents: "n/a", Color: color.New(color.Faint)}}, 172 {{Contents: "worker-6"}, {Contents: "0"}, {Contents: "platform2"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "running"}, {Contents: "1.2.3", Color: color.New(color.FgRed)}, {Contents: "n/a", Color: color.New(color.Faint)}}, 173 {{Contents: "worker-7"}, {Contents: "0"}, {Contents: "platform2"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "running"}, {Contents: "none", Color: color.New(color.FgRed)}, {Contents: "n/a", Color: color.New(color.Faint)}}, 174 {{Contents: "worker-4"}, {Contents: "7"}, {Contents: "platform4"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "stalled"}, {Contents: "4.5.6"}, {Contents: "8h30m"}}, 175 }, 176 })) 177 }) 178 179 Context("when --json is given", func() { 180 BeforeEach(func() { 181 flyCmd.Args = append(flyCmd.Args, "--json") 182 worker1StartTime = 0 183 worker2StartTime = 0 184 worker3StartTime = 0 185 worker4StartTime = 0 186 worker5StartTime = 0 187 worker6StartTime = 0 188 worker7StartTime = 0 189 }) 190 191 It("prints response in json as stdout", func() { 192 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 193 Expect(err).NotTo(HaveOccurred()) 194 195 Eventually(sess).Should(gexec.Exit(0)) 196 Expect(sess.Out.Contents()).To(MatchJSON(`[ 197 { 198 "addr": "1.2.3.4:7777", 199 "baggageclaim_url": "", 200 "active_containers": 0, 201 "active_volumes": 0, 202 "active_tasks": 1, 203 "resource_types": [ 204 { 205 "type": "resource-1", 206 "image": "/images/resource-1", 207 "version": "", 208 "privileged": false, 209 "unique_version_history": false 210 } 211 ], 212 "platform": "platform2", 213 "tags": [ 214 "tag2", 215 "tag3" 216 ], 217 "team": "team-1", 218 "name": "worker-2", 219 "version": "4.5.6", 220 "start_time": 0, 221 "state": "running", 222 "ephemeral": false 223 }, 224 { 225 "addr": "5.5.5.5:7777", 226 "baggageclaim_url": "", 227 "active_containers": 0, 228 "active_volumes": 0, 229 "active_tasks": 1, 230 "resource_types": null, 231 "platform": "platform2", 232 "tags": [ 233 "tag1" 234 ], 235 "team": "team-1", 236 "name": "worker-6", 237 "version": "1.2.3", 238 "start_time": 0, 239 "state": "running", 240 "ephemeral": true 241 }, 242 { 243 "addr": "7.7.7.7:7777", 244 "baggageclaim_url": "", 245 "active_containers": 0, 246 "active_volumes": 0, 247 "active_tasks": 0, 248 "resource_types": null, 249 "platform": "platform2", 250 "tags": [ 251 "tag1" 252 ], 253 "team": "team-1", 254 "name": "worker-7", 255 "version": "", 256 "start_time": 0, 257 "state": "running", 258 "ephemeral": false 259 }, 260 { 261 "addr": "2.2.3.4:7777", 262 "baggageclaim_url": "http://2.2.3.4:7788", 263 "active_containers": 1, 264 "active_volumes": 0, 265 "active_tasks": 1, 266 "resource_types": [ 267 { 268 "type": "resource-1", 269 "image": "/images/resource-1", 270 "version": "", 271 "privileged": false, 272 "unique_version_history": false 273 }, 274 { 275 "type": "resource-2", 276 "image": "/images/resource-2", 277 "version": "", 278 "privileged": false, 279 "unique_version_history": false 280 } 281 ], 282 "platform": "platform1", 283 "tags": [ 284 "tag1" 285 ], 286 "team": "team-1", 287 "name": "worker-1", 288 "version": "4.5.6", 289 "start_time": 0, 290 "state": "landing", 291 "ephemeral": false 292 }, 293 { 294 "addr": "3.2.3.4:7777", 295 "baggageclaim_url": "", 296 "active_containers": 10, 297 "active_volumes": 0, 298 "active_tasks": 1, 299 "resource_types": null, 300 "platform": "platform3", 301 "tags": [], 302 "team": "", 303 "name": "worker-3", 304 "version": "4.5.6", 305 "start_time": 0, 306 "state": "landed", 307 "ephemeral": false 308 }, 309 { 310 "addr": "", 311 "baggageclaim_url": "", 312 "active_containers": 7, 313 "active_volumes": 0, 314 "active_tasks": 1, 315 "resource_types": null, 316 "platform": "platform4", 317 "tags": [ 318 "tag1" 319 ], 320 "team": "team-1", 321 "name": "worker-4", 322 "version": "4.5.6", 323 "start_time": 0, 324 "state": "stalled", 325 "ephemeral": false 326 }, 327 { 328 "addr": "3.2.3.4:7777", 329 "baggageclaim_url": "", 330 "active_containers": 5, 331 "active_volumes": 0, 332 "active_tasks": 1, 333 "resource_types": null, 334 "platform": "platform5", 335 "tags": [], 336 "team": "", 337 "name": "worker-5", 338 "version": "4.5.6", 339 "start_time": 0, 340 "state": "retiring", 341 "ephemeral": false 342 } 343 ]`)) 344 }) 345 }) 346 347 Context("when --details is given", func() { 348 BeforeEach(func() { 349 flyCmd.Args = append(flyCmd.Args, "--details") 350 worker1StartTime = 0 351 worker2StartTime = 0 352 worker3StartTime = 0 353 worker4StartTime = 0 354 worker5StartTime = 0 355 worker6StartTime = 0 356 worker7StartTime = 0 357 }) 358 359 It("lists them to the user, ordered by name", func() { 360 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 361 Expect(err).NotTo(HaveOccurred()) 362 363 Eventually(sess).Should(gexec.Exit(0)) 364 Expect(sess.Out).To(PrintTable(ui.Table{ 365 Headers: ui.TableRow{ 366 {Contents: "name", Color: color.New(color.Bold)}, 367 {Contents: "containers", Color: color.New(color.Bold)}, 368 {Contents: "platform", Color: color.New(color.Bold)}, 369 {Contents: "tags", Color: color.New(color.Bold)}, 370 {Contents: "team", Color: color.New(color.Bold)}, 371 {Contents: "state", Color: color.New(color.Bold)}, 372 {Contents: "version", Color: color.New(color.Bold)}, 373 {Contents: "age", Color: color.New(color.Bold)}, 374 {Contents: "garden address", Color: color.New(color.Bold)}, 375 {Contents: "baggageclaim url", Color: color.New(color.Bold)}, 376 {Contents: "active tasks", Color: color.New(color.Bold)}, 377 {Contents: "resource types", Color: color.New(color.Bold)}, 378 }, 379 Data: []ui.TableRow{ 380 {{Contents: "worker-1"}, {Contents: "1"}, {Contents: "platform1"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "landing"}, {Contents: "4.5.6"}, {Contents: "n/a", Color: color.New(color.Faint)}, {Contents: "2.2.3.4:7777"}, {Contents: "http://2.2.3.4:7788"}, {Contents: "1"}, {Contents: "resource-1, resource-2"}}, 381 {{Contents: "worker-2"}, {Contents: "0"}, {Contents: "platform2"}, {Contents: "tag2, tag3"}, {Contents: "team-1"}, {Contents: "running"}, {Contents: "4.5.6"}, {Contents: "n/a", Color: color.New(color.Faint)}, {Contents: "1.2.3.4:7777"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "1"}, {Contents: "resource-1"}}, 382 {{Contents: "worker-3"}, {Contents: "10"}, {Contents: "platform3"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "landed"}, {Contents: "4.5.6"}, {Contents: "n/a", Color: color.New(color.Faint)}, {Contents: "3.2.3.4:7777"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "1"}, {Contents: "none", Color: color.New(color.Faint)}}, 383 {{Contents: "worker-5"}, {Contents: "5"}, {Contents: "platform5"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "retiring"}, {Contents: "4.5.6"}, {Contents: "n/a", Color: color.New(color.Faint)}, {Contents: "3.2.3.4:7777"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "1"}, {Contents: "none", Color: color.New(color.Faint)}}, 384 {{Contents: "worker-6"}, {Contents: "0"}, {Contents: "platform2"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "running"}, {Contents: "1.2.3", Color: color.New(color.FgRed)}, {Contents: "n/a", Color: color.New(color.Faint)}, {Contents: "5.5.5.5:7777", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "1"}, {Contents: "none", Color: color.New(color.Faint)}}, 385 {{Contents: "worker-7"}, {Contents: "0"}, {Contents: "platform2"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "running"}, {Contents: "none", Color: color.New(color.FgRed)}, {Contents: "n/a", Color: color.New(color.Faint)}, {Contents: "7.7.7.7:7777", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "0"}, {Contents: "none", Color: color.New(color.Faint)}}, 386 {{Contents: "worker-4"}, {Contents: "7"}, {Contents: "platform4"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "stalled"}, {Contents: "4.5.6"}, {Contents: "n/a", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "1"}, {Contents: "none", Color: color.New(color.Faint)}}, 387 }, 388 })) 389 }) 390 }) 391 }) 392 393 Context("when API does not return stalled or outdated workers", func() { 394 BeforeEach(func() { 395 atcServer.AppendHandlers( 396 ghttp.CombineHandlers( 397 ghttp.VerifyRequest("GET", "/api/v1/workers"), 398 ghttp.RespondWithJSONEncoded(200, []atc.Worker{ 399 { 400 Name: "worker-2", 401 GardenAddr: "1.2.3.4:7777", 402 ActiveContainers: 0, 403 Platform: "platform2", 404 Tags: []string{"tag1"}, 405 Team: "team-1", 406 State: "running", 407 Version: "4.5.6", 408 StartTime: 0, 409 }, 410 { 411 Name: "worker-1", 412 GardenAddr: "3.2.3.4:7777", 413 ActiveContainers: 10, 414 Platform: "platform1", 415 Tags: []string{}, 416 Team: "team-1", 417 State: "landing", 418 Version: "4.5.6", 419 StartTime: 0, 420 }, 421 { 422 Name: "worker-3", 423 GardenAddr: "3.2.3.4:7777", 424 ActiveContainers: 5, 425 Platform: "platform3", 426 Tags: []string{}, 427 State: "retiring", 428 Version: "4.5.6", 429 StartTime: 0, 430 }, 431 }), 432 ), 433 ) 434 }) 435 436 It("does not print second table", func() { 437 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 438 Expect(err).NotTo(HaveOccurred()) 439 440 Eventually(sess).Should(gexec.Exit(0)) 441 Expect(sess.Out).To(PrintTable(ui.Table{ 442 Headers: ui.TableRow{ 443 {Contents: "name", Color: color.New(color.Bold)}, 444 {Contents: "containers", Color: color.New(color.Bold)}, 445 {Contents: "platform", Color: color.New(color.Bold)}, 446 {Contents: "tags", Color: color.New(color.Bold)}, 447 {Contents: "team", Color: color.New(color.Bold)}, 448 {Contents: "state", Color: color.New(color.Bold)}, 449 {Contents: "version", Color: color.New(color.Bold)}, 450 {Contents: "age", Color: color.New(color.Bold)}, 451 }, 452 Data: []ui.TableRow{ 453 {{Contents: "worker-1"}, {Contents: "10"}, {Contents: "platform1"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "team-1"}, {Contents: "landing"}, {Contents: "4.5.6", Color: color.New(color.Faint)}, {Contents: "n/a", Color: color.New(color.Faint)}}, 454 {{Contents: "worker-2"}, {Contents: "0"}, {Contents: "platform2"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "running"}, {Contents: "4.5.6", Color: color.New(color.Faint)}, {Contents: "n/a", Color: color.New(color.Faint)}}, 455 {{Contents: "worker-3"}, {Contents: "5"}, {Contents: "platform3"}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "none", Color: color.New(color.Faint)}, {Contents: "retiring"}, {Contents: "4.5.6", Color: color.New(color.Faint)}, {Contents: "n/a", Color: color.New(color.Faint)}}, 456 }, 457 })) 458 Expect(sess.Out).NotTo(PrintTable(ui.Table{ 459 Headers: ui.TableRow{ 460 {Contents: "name", Color: color.New(color.Bold)}, 461 {Contents: "containers", Color: color.New(color.Bold)}, 462 {Contents: "platform", Color: color.New(color.Bold)}, 463 {Contents: "tags", Color: color.New(color.Bold)}, 464 {Contents: "team", Color: color.New(color.Bold)}, 465 {Contents: "state", Color: color.New(color.Bold)}, 466 {Contents: "version", Color: color.New(color.Bold)}, 467 {Contents: "age", Color: color.New(color.Bold)}, 468 }, 469 Data: []ui.TableRow{ 470 {{Contents: "worker-4"}, {Contents: "7"}, {Contents: "platform4"}, {Contents: "tag1"}, {Contents: "team-1"}, {Contents: "stalled"}, {Contents: "4.5.6"}, {Contents: "n/a", Color: color.New(color.Faint)}}, 471 }, 472 })) 473 }) 474 }) 475 476 Context("and the api returns an internal server error", func() { 477 BeforeEach(func() { 478 atcServer.AppendHandlers( 479 ghttp.CombineHandlers( 480 ghttp.VerifyRequest("GET", "/api/v1/workers"), 481 ghttp.RespondWith(500, ""), 482 ), 483 ) 484 }) 485 486 It("writes an error message to stderr", func() { 487 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 488 Expect(err).NotTo(HaveOccurred()) 489 490 Eventually(sess).Should(gexec.Exit(1)) 491 Eventually(sess.Err).Should(gbytes.Say("Unexpected Response")) 492 }) 493 }) 494 }) 495 })