github.com/franc20/ayesa_sap@v7.0.0-beta.28.0.20200124003224-302d4d52fa6c+incompatible/command/v7/shared/app_summary_displayer_test.go (about) 1 package shared_test 2 3 import ( 4 "time" 5 6 "code.cloudfoundry.org/cli/actor/v7action" 7 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 8 . "code.cloudfoundry.org/cli/command/v7/shared" 9 "code.cloudfoundry.org/cli/integration/helpers" 10 "code.cloudfoundry.org/cli/types" 11 "code.cloudfoundry.org/cli/util/ui" 12 . "github.com/onsi/ginkgo" 13 . "github.com/onsi/gomega" 14 . "github.com/onsi/gomega/gbytes" 15 ) 16 17 var _ = Describe("app summary displayer", func() { 18 var ( 19 appSummaryDisplayer *AppSummaryDisplayer 20 output *Buffer 21 testUI *ui.UI 22 ) 23 24 BeforeEach(func() { 25 output = NewBuffer() 26 testUI = ui.NewTestUI(nil, output, NewBuffer()) 27 28 appSummaryDisplayer = NewAppSummaryDisplayer(testUI) 29 }) 30 31 Describe("AppDisplay", func() { 32 var ( 33 summary v7action.DetailedApplicationSummary 34 displayStartCommand bool 35 ) 36 37 JustBeforeEach(func() { 38 appSummaryDisplayer.AppDisplay(summary, displayStartCommand) 39 }) 40 41 When("the app has instances", func() { 42 When("the process instances are running", func() { 43 var uptime time.Duration 44 45 BeforeEach(func() { 46 uptime = time.Since(time.Unix(267321600, 0)) 47 summary = v7action.DetailedApplicationSummary{ 48 ApplicationSummary: v7action.ApplicationSummary{ 49 Application: v7action.Application{ 50 GUID: "some-app-guid", 51 State: constant.ApplicationStarted, 52 }, 53 ProcessSummaries: v7action.ProcessSummaries{ 54 { 55 Process: v7action.Process{ 56 Type: constant.ProcessTypeWeb, 57 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 58 DiskInMB: types.NullUint64{Value: 1024, IsSet: true}, 59 }, 60 Sidecars: []v7action.Sidecar{}, 61 InstanceDetails: []v7action.ProcessInstance{ 62 v7action.ProcessInstance{ 63 Index: 0, 64 State: constant.ProcessInstanceRunning, 65 MemoryUsage: 1000000, 66 DiskUsage: 1000000, 67 MemoryQuota: 33554432, 68 DiskQuota: 2000000, 69 Uptime: uptime, 70 Details: "Some Details 1", 71 }, 72 v7action.ProcessInstance{ 73 Index: 1, 74 State: constant.ProcessInstanceRunning, 75 MemoryUsage: 2000000, 76 DiskUsage: 2000000, 77 MemoryQuota: 33554432, 78 DiskQuota: 4000000, 79 Uptime: time.Since(time.Unix(330480000, 0)), 80 Details: "Some Details 2", 81 }, 82 v7action.ProcessInstance{ 83 Index: 2, 84 State: constant.ProcessInstanceRunning, 85 MemoryUsage: 3000000, 86 DiskUsage: 3000000, 87 MemoryQuota: 33554432, 88 DiskQuota: 6000000, 89 Uptime: time.Since(time.Unix(1277164800, 0)), 90 }, 91 }, 92 }, 93 { 94 Process: v7action.Process{ 95 Type: "console", 96 MemoryInMB: types.NullUint64{Value: 16, IsSet: true}, 97 DiskInMB: types.NullUint64{Value: 512, IsSet: true}, 98 }, 99 Sidecars: []v7action.Sidecar{}, 100 InstanceDetails: []v7action.ProcessInstance{ 101 v7action.ProcessInstance{ 102 Index: 0, 103 State: constant.ProcessInstanceRunning, 104 MemoryUsage: 1000000, 105 DiskUsage: 1000000, 106 MemoryQuota: 33554432, 107 DiskQuota: 8000000, 108 Uptime: time.Since(time.Unix(167572800, 0)), 109 }, 110 }, 111 }, 112 }, 113 }, 114 } 115 }) 116 117 It("lists information for each of the processes", func() { 118 processTable := helpers.ParseV3AppProcessTable(output.Contents()) 119 Expect(len(processTable.Processes)).To(Equal(2)) 120 121 webProcessSummary := processTable.Processes[0] 122 Expect(webProcessSummary.Type).To(Equal("web")) 123 Expect(webProcessSummary.Sidecars).To(Equal("")) 124 Expect(webProcessSummary.InstanceCount).To(Equal("3/3")) 125 Expect(webProcessSummary.MemUsage).To(Equal("32M")) 126 127 Expect(webProcessSummary.Instances[0].Memory).To(Equal("976.6K of 32M")) 128 Expect(webProcessSummary.Instances[0].Since).To(MatchRegexp(`\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z`)) 129 Expect(time.Parse(time.RFC3339, webProcessSummary.Instances[0].Since)).To(BeTemporally("~", time.Now().Add(-uptime), 2*time.Second)) 130 Expect(webProcessSummary.Instances[0].Disk).To(Equal("976.6K of 1.9M")) 131 Expect(webProcessSummary.Instances[0].CPU).To(Equal("0.0%")) 132 Expect(webProcessSummary.Instances[0].Details).To(Equal("Some Details 1")) 133 134 Expect(webProcessSummary.Instances[1].Memory).To(Equal("1.9M of 32M")) 135 Expect(webProcessSummary.Instances[1].Disk).To(Equal("1.9M of 3.8M")) 136 Expect(webProcessSummary.Instances[1].CPU).To(Equal("0.0%")) 137 Expect(webProcessSummary.Instances[1].Details).To(Equal("Some Details 2")) 138 139 Expect(webProcessSummary.Instances[2].Memory).To(Equal("2.9M of 32M")) 140 Expect(webProcessSummary.Instances[2].Disk).To(Equal("2.9M of 5.7M")) 141 Expect(webProcessSummary.Instances[2].CPU).To(Equal("0.0%")) 142 143 consoleProcessSummary := processTable.Processes[1] 144 Expect(consoleProcessSummary.Type).To(Equal("console")) 145 Expect(consoleProcessSummary.Sidecars).To(Equal("")) 146 Expect(consoleProcessSummary.InstanceCount).To(Equal("1/1")) 147 Expect(consoleProcessSummary.MemUsage).To(Equal("16M")) 148 149 Expect(consoleProcessSummary.Instances[0].Memory).To(Equal("976.6K of 32M")) 150 Expect(consoleProcessSummary.Instances[0].Disk).To(Equal("976.6K of 7.6M")) 151 Expect(consoleProcessSummary.Instances[0].CPU).To(Equal("0.0%")) 152 }) 153 }) 154 155 When("some processes have > 0 instances and others have 0 instances", func() { 156 BeforeEach(func() { 157 summary = v7action.DetailedApplicationSummary{ 158 ApplicationSummary: v7action.ApplicationSummary{ 159 Application: v7action.Application{ 160 GUID: "some-app-guid", 161 State: constant.ApplicationStarted, 162 }, 163 ProcessSummaries: v7action.ProcessSummaries{ 164 { 165 Process: v7action.Process{ 166 Type: constant.ProcessTypeWeb, 167 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 168 DiskInMB: types.NullUint64{Value: 1024, IsSet: true}, 169 }, 170 Sidecars: []v7action.Sidecar{}, 171 InstanceDetails: []v7action.ProcessInstance{ 172 v7action.ProcessInstance{ 173 Index: 0, 174 State: constant.ProcessInstanceRunning, 175 MemoryUsage: 1000000, 176 DiskUsage: 1000000, 177 MemoryQuota: 33554432, 178 DiskQuota: 2000000, 179 Uptime: time.Since(time.Unix(267321600, 0)), 180 }, 181 }, 182 }, 183 { 184 Process: v7action.Process{ 185 Type: "console", 186 MemoryInMB: types.NullUint64{Value: 16, IsSet: true}, 187 DiskInMB: types.NullUint64{Value: 512, IsSet: true}, 188 }, 189 Sidecars: []v7action.Sidecar{}, 190 }, 191 }, 192 }, 193 } 194 }) 195 196 It("lists instance stats for process types that have > 0 instances", func() { 197 Expect(testUI.Out).To(Say(`type:\s+web`)) 198 Expect(testUI.Out).To(Say(`sidecars: `)) 199 Expect(testUI.Out).To(Say(`state\s+since\s+cpu\s+memory\s+disk\s+details`)) 200 }) 201 202 It("does not show the instance stats table for process types with 0 instances", func() { 203 Expect(testUI.Out).To(Say(`type:\s+console`)) 204 Expect(testUI.Out).To(Say(`sidecars: `)) 205 Expect(testUI.Out).To(Say("There are no running instances of this process.")) 206 }) 207 }) 208 209 When("all the instances for a process are down (but scaled to > 0 instances)", func() { 210 BeforeEach(func() { 211 summary = v7action.DetailedApplicationSummary{ 212 ApplicationSummary: v7action.ApplicationSummary{ 213 ProcessSummaries: []v7action.ProcessSummary{ 214 { 215 Process: v7action.Process{ 216 Type: constant.ProcessTypeWeb, 217 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 218 }, 219 Sidecars: []v7action.Sidecar{}, 220 InstanceDetails: []v7action.ProcessInstance{{State: constant.ProcessInstanceDown}}, 221 }}, 222 }, 223 } 224 }) 225 226 It("displays the instances table", func() { 227 Expect(testUI.Out).To(Say(`type:\s+web`)) 228 Expect(testUI.Out).To(Say(`sidecars: `)) 229 Expect(testUI.Out).To(Say(`state\s+since\s+cpu\s+memory\s+disk\s+details`)) 230 }) 231 }) 232 233 Describe("start command", func() { 234 BeforeEach(func() { 235 summary = v7action.DetailedApplicationSummary{ 236 ApplicationSummary: v7action.ApplicationSummary{ 237 Application: v7action.Application{ 238 GUID: "some-app-guid", 239 State: constant.ApplicationStarted, 240 }, 241 ProcessSummaries: v7action.ProcessSummaries{ 242 { 243 Process: v7action.Process{ 244 Type: constant.ProcessTypeWeb, 245 Command: *types.NewFilteredString("some-command-1"), 246 }, 247 Sidecars: []v7action.Sidecar{}, 248 }, 249 { 250 Process: v7action.Process{ 251 Type: "console", 252 Command: *types.NewFilteredString("some-command-2"), 253 }, 254 Sidecars: []v7action.Sidecar{}, 255 }, 256 { 257 Process: v7action.Process{ 258 Type: "random", 259 }, 260 Sidecars: []v7action.Sidecar{}, 261 }, 262 }, 263 }, 264 } 265 }) 266 267 When("displayStartCommand is true", func() { 268 BeforeEach(func() { 269 displayStartCommand = true 270 }) 271 272 It("displays the non-empty start command for each process", func() { 273 Expect(testUI.Out).To(Say(`type:\s+web`)) 274 Expect(testUI.Out).To(Say(`sidecars: `)) 275 Expect(testUI.Out).To(Say(`start command:\s+some-command-1`)) 276 277 Expect(testUI.Out).To(Say(`type:\s+console`)) 278 Expect(testUI.Out).To(Say(`sidecars: `)) 279 Expect(testUI.Out).To(Say(`start command:\s+some-command-2`)) 280 281 Expect(testUI.Out).To(Say(`type:\s+random`)) 282 Expect(testUI.Out).To(Say(`sidecars: `)) 283 Expect(testUI.Out).ToNot(Say("start command:")) 284 }) 285 }) 286 287 When("displayStartCommand is false", func() { 288 BeforeEach(func() { 289 displayStartCommand = false 290 }) 291 292 It("hides the start command", func() { 293 Expect(testUI.Out).ToNot(Say("start command:")) 294 }) 295 }) 296 }) 297 }) 298 299 When("the app has no instances", func() { 300 BeforeEach(func() { 301 summary = v7action.DetailedApplicationSummary{ 302 ApplicationSummary: v7action.ApplicationSummary{ 303 Application: v7action.Application{ 304 GUID: "some-app-guid", 305 State: constant.ApplicationStarted, 306 }, 307 ProcessSummaries: v7action.ProcessSummaries{ 308 { 309 Process: v7action.Process{ 310 Type: constant.ProcessTypeWeb, 311 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 312 DiskInMB: types.NullUint64{Value: 1024, IsSet: true}, 313 }, 314 Sidecars: []v7action.Sidecar{}, 315 }, 316 { 317 Process: v7action.Process{ 318 Type: "console", 319 MemoryInMB: types.NullUint64{Value: 16, IsSet: true}, 320 DiskInMB: types.NullUint64{Value: 512, IsSet: true}, 321 }, 322 Sidecars: []v7action.Sidecar{}, 323 }, 324 }, 325 }, 326 } 327 }) 328 329 It("lists information for each of the processes", func() { 330 Expect(testUI.Out).To(Say(`type:\s+web`)) 331 Expect(testUI.Out).To(Say(`sidecars: `)) 332 Expect(testUI.Out).To(Say(`instances:\s+0/0`)) 333 Expect(testUI.Out).To(Say(`memory usage:\s+32M`)) 334 Expect(testUI.Out).To(Say("There are no running instances of this process.")) 335 336 Expect(testUI.Out).To(Say(`type:\s+console`)) 337 Expect(testUI.Out).To(Say(`sidecars: `)) 338 Expect(testUI.Out).To(Say(`instances:\s+0/0`)) 339 Expect(testUI.Out).To(Say(`memory usage:\s+16M`)) 340 Expect(testUI.Out).To(Say("There are no running instances of this process.")) 341 }) 342 343 It("does not display the instance table", func() { 344 Expect(testUI.Out).NotTo(Say(`state\s+since\s+cpu\s+memory\s+disk\s+details`)) 345 }) 346 }) 347 348 When("the app has sidecars", func() { 349 BeforeEach(func() { 350 summary = v7action.DetailedApplicationSummary{ 351 ApplicationSummary: v7action.ApplicationSummary{ 352 Application: v7action.Application{ 353 GUID: "some-app-guid", 354 State: constant.ApplicationStarted, 355 }, 356 ProcessSummaries: v7action.ProcessSummaries{ 357 { 358 Process: v7action.Process{ 359 Type: constant.ProcessTypeWeb, 360 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 361 DiskInMB: types.NullUint64{Value: 1024, IsSet: true}, 362 }, 363 Sidecars: []v7action.Sidecar{ 364 {Name: "authenticator"}, 365 {Name: "clock"}, 366 }, 367 }, 368 }, 369 }, 370 } 371 }) 372 373 It("lists information for each of the processes", func() { 374 Expect(testUI.Out).To(Say(`type:\s+web`)) 375 Expect(testUI.Out).To(Say(`sidecars:\s+authenticator, clock`)) 376 Expect(testUI.Out).To(Say(`instances:\s+0/0`)) 377 Expect(testUI.Out).To(Say(`memory usage:\s+32M`)) 378 Expect(testUI.Out).To(Say("There are no running instances of this process.")) 379 }) 380 381 It("does not display the instance table", func() { 382 Expect(testUI.Out).NotTo(Say(`state\s+since\s+cpu\s+memory\s+disk\s+details`)) 383 }) 384 }) 385 386 When("the app is stopped", func() { 387 BeforeEach(func() { 388 summary = v7action.DetailedApplicationSummary{ 389 ApplicationSummary: v7action.ApplicationSummary{ 390 Application: v7action.Application{ 391 GUID: "some-app-guid", 392 State: constant.ApplicationStopped, 393 }, 394 ProcessSummaries: v7action.ProcessSummaries{ 395 { 396 Process: v7action.Process{ 397 Type: constant.ProcessTypeWeb, 398 }, 399 Sidecars: []v7action.Sidecar{}, 400 }, 401 { 402 Process: v7action.Process{ 403 Type: "console", 404 }, 405 Sidecars: []v7action.Sidecar{}, 406 }, 407 }, 408 }, 409 } 410 }) 411 412 It("lists information for each of the processes", func() { 413 Expect(testUI.Out).To(Say(`type:\s+web`)) 414 Expect(testUI.Out).To(Say(`sidecars: `)) 415 Expect(testUI.Out).To(Say("There are no running instances of this process.")) 416 417 Expect(testUI.Out).To(Say(`type:\s+console`)) 418 Expect(testUI.Out).To(Say(`sidecars: `)) 419 Expect(testUI.Out).To(Say("There are no running instances of this process.")) 420 }) 421 422 It("does not display the instance table", func() { 423 Expect(testUI.Out).NotTo(Say(`state\s+since\s+cpu\s+memory\s+disk\s+details`)) 424 }) 425 }) 426 427 Describe("isolation segments", func() { 428 When("the isolation segment name is provided", func() { 429 var isolationSegmentName string 430 BeforeEach(func() { 431 isolationSegmentName = "potato beans" 432 summary.ProcessSummaries = v7action.ProcessSummaries{ 433 v7action.ProcessSummary{ 434 InstanceDetails: []v7action.ProcessInstance{ 435 {IsolationSegment: isolationSegmentName}, 436 }, 437 }, 438 } 439 }) 440 441 It("should output the isolation segment name", func() { 442 Expect(testUI.Out).To(Say(`isolation segment:\s+%s`, isolationSegmentName)) 443 }) 444 }) 445 446 When("the application summary has no isolation segment information", func() { 447 BeforeEach(func() { 448 summary = v7action.DetailedApplicationSummary{ 449 ApplicationSummary: v7action.ApplicationSummary{ 450 Application: v7action.Application{ 451 GUID: "some-app-guid", 452 State: constant.ApplicationStopped, 453 }, 454 }, 455 } 456 }) 457 458 It("should not output isolation segment header", func() { 459 Expect(testUI.Out).ToNot(Say("isolation segment:")) 460 }) 461 }) 462 }) 463 464 Describe("last upload time", func() { 465 When("the application has a last uploaded time", func() { 466 var createdTime string 467 468 BeforeEach(func() { 469 createdTime = "2006-01-02T15:04:05-07:00" 470 summary.CurrentDroplet.CreatedAt = createdTime 471 }) 472 473 It("displays the uploaded time", func() { 474 t, err := time.Parse(time.RFC3339, createdTime) 475 Expect(err).To(Not(HaveOccurred())) 476 477 time := t.Local().Format("Mon 02 Jan 15:04:05 MST 2006") 478 Expect(testUI.Out).To(Say(`last uploaded:\s+%s`, time)) 479 }) 480 }) 481 482 When("the application does not have a last uploaded time", func() { 483 BeforeEach(func() { 484 summary.CurrentDroplet.CreatedAt = "" 485 }) 486 487 It("leaves last uploaded blank", func() { 488 Expect(testUI.Out).To(Say(`(?m)last uploaded:\s*\n`)) 489 }) 490 }) 491 }) 492 493 When("the application has routes", func() { 494 BeforeEach(func() { 495 summary.Routes = []v7action.Route{ 496 {Host: "route1", URL: "route1.example.com"}, 497 {Host: "route2", URL: "route2.example.com"}, 498 } 499 }) 500 501 It("displays routes", func() { 502 Expect(testUI.Out).To(Say(`routes:\s+%s, %s`, "route1.example.com", "route2.example.com")) 503 }) 504 }) 505 506 When("the application has a stack", func() { 507 BeforeEach(func() { 508 summary.CurrentDroplet.Stack = "some-stack" 509 }) 510 511 It("displays stack", func() { 512 Expect(testUI.Out).To(Say(`stack:\s+some-stack`)) 513 }) 514 }) 515 516 When("the application is a docker app", func() { 517 BeforeEach(func() { 518 summary = v7action.DetailedApplicationSummary{ 519 ApplicationSummary: v7action.ApplicationSummary{ 520 Application: v7action.Application{ 521 GUID: "some-guid", 522 Name: "some-app", 523 State: constant.ApplicationStarted, 524 LifecycleType: constant.AppLifecycleTypeDocker, 525 }, 526 }, 527 CurrentDroplet: v7action.Droplet{ 528 Image: "docker/some-image", 529 }, 530 } 531 }) 532 533 It("displays the app information", func() { 534 Expect(testUI.Out).To(Say(`name:\s+some-app`)) 535 Expect(testUI.Out).To(Say(`requested state:\s+started`)) 536 Expect(testUI.Out).To(Say(`routes:\s+\n`)) 537 Expect(testUI.Out).To(Say(`stack:\s+\n`)) 538 Expect(testUI.Out).To(Say(`(?m)docker image:\s+docker/some-image$\n`)) 539 }) 540 }) 541 542 When("the application is a buildpack app", func() { 543 BeforeEach(func() { 544 summary = v7action.DetailedApplicationSummary{ 545 CurrentDroplet: v7action.Droplet{ 546 Stack: "cflinuxfs2", 547 Buildpacks: []v7action.DropletBuildpack{ 548 { 549 Name: "ruby_buildpack", 550 DetectOutput: "some-detect-output", 551 }, 552 { 553 Name: "some-buildpack", 554 DetectOutput: "", 555 }, 556 }, 557 }, 558 } 559 }) 560 561 It("displays stack and buildpacks", func() { 562 Expect(testUI.Out).To(Say(`stack:\s+cflinuxfs2`)) 563 Expect(testUI.Out).To(Say(`buildpacks:\s+some-detect-output, some-buildpack`)) 564 }) 565 }) 566 }) 567 })