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