github.com/cloudfoundry-attic/cli-with-i18n@v6.32.1-0.20171002233121-7401370d3b85+incompatible/command/v3/v3_app_command_test.go (about) 1 package v3_test 2 3 import ( 4 "errors" 5 "time" 6 7 "code.cloudfoundry.org/cli/actor/sharedaction" 8 "code.cloudfoundry.org/cli/actor/v2action" 9 "code.cloudfoundry.org/cli/actor/v3action" 10 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 11 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 12 "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" 13 "code.cloudfoundry.org/cli/command/commandfakes" 14 "code.cloudfoundry.org/cli/command/flag" 15 "code.cloudfoundry.org/cli/command/translatableerror" 16 "code.cloudfoundry.org/cli/command/v3" 17 "code.cloudfoundry.org/cli/command/v3/shared" 18 "code.cloudfoundry.org/cli/command/v3/shared/sharedfakes" 19 "code.cloudfoundry.org/cli/command/v3/v3fakes" 20 "code.cloudfoundry.org/cli/types" 21 "code.cloudfoundry.org/cli/util/configv3" 22 "code.cloudfoundry.org/cli/util/ui" 23 . "github.com/onsi/ginkgo" 24 . "github.com/onsi/gomega" 25 . "github.com/onsi/gomega/gbytes" 26 ) 27 28 var _ = Describe("v3-app Command", func() { 29 var ( 30 cmd v3.V3AppCommand 31 testUI *ui.UI 32 fakeConfig *commandfakes.FakeConfig 33 fakeSharedActor *commandfakes.FakeSharedActor 34 fakeActor *v3fakes.FakeV3AppActor 35 fakeV2Actor *sharedfakes.FakeV2AppRouteActor 36 binaryName string 37 executeErr error 38 app string 39 ) 40 41 BeforeEach(func() { 42 testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) 43 fakeConfig = new(commandfakes.FakeConfig) 44 fakeSharedActor = new(commandfakes.FakeSharedActor) 45 fakeActor = new(v3fakes.FakeV3AppActor) 46 fakeV2Actor = new(sharedfakes.FakeV2AppRouteActor) 47 48 binaryName = "faceman" 49 fakeConfig.BinaryNameReturns(binaryName) 50 app = "some-app" 51 52 appSummaryDisplayer := shared.AppSummaryDisplayer{ 53 UI: testUI, 54 Config: fakeConfig, 55 Actor: fakeActor, 56 V2AppRouteActor: fakeV2Actor, 57 AppName: app, 58 } 59 60 cmd = v3.V3AppCommand{ 61 RequiredArgs: flag.AppName{AppName: app}, 62 63 UI: testUI, 64 Config: fakeConfig, 65 SharedActor: fakeSharedActor, 66 Actor: fakeActor, 67 AppSummaryDisplayer: appSummaryDisplayer, 68 } 69 70 fakeConfig.TargetedOrganizationReturns(configv3.Organization{ 71 Name: "some-org", 72 GUID: "some-org-guid", 73 }) 74 fakeConfig.TargetedSpaceReturns(configv3.Space{ 75 Name: "some-space", 76 GUID: "some-space-guid", 77 }) 78 79 fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) 80 fakeActor.CloudControllerAPIVersionReturns(ccversion.MinVersionV3) 81 }) 82 83 JustBeforeEach(func() { 84 executeErr = cmd.Execute(nil) 85 }) 86 87 Context("when the API version is below the minimum", func() { 88 BeforeEach(func() { 89 fakeActor.CloudControllerAPIVersionReturns("0.0.0") 90 }) 91 92 It("returns a MinimumAPIVersionNotMetError", func() { 93 Expect(executeErr).To(MatchError(translatableerror.MinimumAPIVersionNotMetError{ 94 CurrentVersion: "0.0.0", 95 MinimumVersion: ccversion.MinVersionV3, 96 })) 97 }) 98 }) 99 100 Context("when checking target fails", func() { 101 BeforeEach(func() { 102 fakeSharedActor.CheckTargetReturns(sharedaction.NoOrganizationTargetedError{BinaryName: binaryName}) 103 }) 104 105 It("returns an error", func() { 106 Expect(executeErr).To(MatchError(translatableerror.NoOrganizationTargetedError{BinaryName: binaryName})) 107 108 Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) 109 _, checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) 110 Expect(checkTargetedOrg).To(BeTrue()) 111 Expect(checkTargetedSpace).To(BeTrue()) 112 }) 113 }) 114 115 Context("when the user is not logged in", func() { 116 var expectedErr error 117 118 BeforeEach(func() { 119 expectedErr = errors.New("some current user error") 120 fakeConfig.CurrentUserReturns(configv3.User{}, expectedErr) 121 }) 122 123 It("return an error", func() { 124 Expect(executeErr).To(Equal(expectedErr)) 125 }) 126 }) 127 128 Context("when getting the application summary returns an error", func() { 129 var expectedErr error 130 131 BeforeEach(func() { 132 expectedErr = v3action.ApplicationNotFoundError{Name: app} 133 fakeActor.GetApplicationSummaryByNameAndSpaceReturns(v3action.ApplicationSummary{}, v3action.Warnings{"warning-1", "warning-2"}, expectedErr) 134 }) 135 136 It("returns the error and prints warnings", func() { 137 Expect(executeErr).To(Equal(translatableerror.ApplicationNotFoundError{Name: app})) 138 139 Expect(testUI.Out).To(Say("Showing health and status for app some-app in org some-org / space some-space as steve\\.\\.\\.")) 140 141 Expect(testUI.Err).To(Say("warning-1")) 142 Expect(testUI.Err).To(Say("warning-2")) 143 }) 144 }) 145 146 Context("when the --guid flag is provided", func() { 147 BeforeEach(func() { 148 cmd.GUID = true 149 }) 150 151 Context("when no errors occur", func() { 152 BeforeEach(func() { 153 fakeActor.GetApplicationByNameAndSpaceReturns( 154 v3action.Application{GUID: "some-guid"}, 155 v3action.Warnings{"warning-1", "warning-2"}, 156 nil) 157 }) 158 159 It("displays the application guid and all warnings", func() { 160 Expect(executeErr).ToNot(HaveOccurred()) 161 162 Expect(testUI.Out).To(Say("some-guid")) 163 Expect(testUI.Err).To(Say("warning-1")) 164 Expect(testUI.Err).To(Say("warning-2")) 165 166 Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1)) 167 appName, spaceGUID := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0) 168 Expect(appName).To(Equal("some-app")) 169 Expect(spaceGUID).To(Equal("some-space-guid")) 170 }) 171 }) 172 173 Context("when an error is encountered getting the app", func() { 174 Context("when the error is translatable", func() { 175 BeforeEach(func() { 176 fakeActor.GetApplicationByNameAndSpaceReturns( 177 v3action.Application{}, 178 v3action.Warnings{"warning-1", "warning-2"}, 179 v3action.ApplicationNotFoundError{Name: "some-app"}) 180 }) 181 182 It("returns a translatable error and all warnings", func() { 183 Expect(executeErr).To(MatchError(translatableerror.ApplicationNotFoundError{Name: "some-app"})) 184 185 Expect(testUI.Err).To(Say("warning-1")) 186 Expect(testUI.Err).To(Say("warning-2")) 187 }) 188 }) 189 190 Context("when the error is not translatable", func() { 191 var expectedErr error 192 193 BeforeEach(func() { 194 expectedErr = errors.New("get app summary error") 195 fakeActor.GetApplicationByNameAndSpaceReturns( 196 v3action.Application{}, 197 v3action.Warnings{"warning-1", "warning-2"}, 198 expectedErr) 199 }) 200 201 It("returns the error and all warnings", func() { 202 Expect(executeErr).To(MatchError(expectedErr)) 203 204 Expect(testUI.Err).To(Say("warning-1")) 205 Expect(testUI.Err).To(Say("warning-2")) 206 }) 207 }) 208 }) 209 210 }) 211 212 Context("when the app is a docker app", func() { 213 BeforeEach(func() { 214 fakeActor.GetApplicationSummaryByNameAndSpaceReturns( 215 v3action.ApplicationSummary{ 216 Application: v3action.Application{ 217 GUID: "some-guid", 218 Name: "some-app", 219 State: "STARTED", 220 Lifecycle: v3action.AppLifecycle{Type: v3action.DockerAppLifecycleType}, 221 }, 222 CurrentDroplet: v3action.Droplet{ 223 Image: "docker/some-image", 224 }, 225 }, 226 v3action.Warnings{"warning-1", "warning-2"}, 227 nil) 228 }) 229 230 It("displays app information without routes", func() { 231 Expect(executeErr).ToNot(HaveOccurred()) 232 233 Expect(testUI.Out).To(Say("(?m)Showing health and status for app some-app in org some-org / space some-space as steve\\.\\.\\.\n\n")) 234 Expect(testUI.Out).To(Say("name:\\s+some-app")) 235 Expect(testUI.Out).To(Say("requested state:\\s+started")) 236 Expect(testUI.Out).To(Say("processes:\\s+\\n")) 237 Expect(testUI.Out).To(Say("memory usage:\\s+\\n")) 238 Expect(testUI.Out).To(Say("routes:\\s+\\n")) 239 Expect(testUI.Out).To(Say("stack:\\s+\\n")) 240 Expect(testUI.Out).To(Say("(?m)docker image:\\s+docker/some-image$\\n")) 241 242 Expect(testUI.Err).To(Say("warning-1")) 243 Expect(testUI.Err).To(Say("warning-2")) 244 245 Expect(fakeActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1)) 246 appName, spaceGUID := fakeActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0) 247 Expect(appName).To(Equal("some-app")) 248 Expect(spaceGUID).To(Equal("some-space-guid")) 249 250 Expect(fakeV2Actor.GetApplicationRoutesCallCount()).To(Equal(0)) 251 }) 252 }) 253 254 Context("when app has no processes", func() { 255 BeforeEach(func() { 256 fakeActor.GetApplicationSummaryByNameAndSpaceReturns( 257 v3action.ApplicationSummary{ 258 Application: v3action.Application{ 259 GUID: "some-guid", 260 Name: "some-app", 261 State: "STARTED", 262 }, 263 }, 264 v3action.Warnings{"warning-1", "warning-2"}, 265 nil) 266 }) 267 268 It("displays app information without routes", func() { 269 Expect(executeErr).ToNot(HaveOccurred()) 270 271 Expect(testUI.Out).To(Say("(?m)Showing health and status for app some-app in org some-org / space some-space as steve\\.\\.\\.\n\n")) 272 Expect(testUI.Out).To(Say("name:\\s+some-app")) 273 Expect(testUI.Out).To(Say("requested state:\\s+started")) 274 Expect(testUI.Out).To(Say("processes:\\s+\\n")) 275 Expect(testUI.Out).To(Say("memory usage:\\s+\\n")) 276 Expect(testUI.Out).To(Say("routes:\\s+\\n")) 277 Expect(testUI.Out).To(Say("stack:\\s+\\n")) 278 Expect(testUI.Out).To(Say("(?m)buildpacks:\\s+$\\n")) 279 280 Expect(testUI.Err).To(Say("warning-1")) 281 Expect(testUI.Err).To(Say("warning-2")) 282 283 Expect(fakeActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1)) 284 appName, spaceGUID := fakeActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0) 285 Expect(appName).To(Equal("some-app")) 286 Expect(spaceGUID).To(Equal("some-space-guid")) 287 288 Expect(fakeV2Actor.GetApplicationRoutesCallCount()).To(Equal(0)) 289 }) 290 }) 291 292 Context("when app has processes", func() { 293 Context("when getting routes returns an error", func() { 294 var expectedErr error 295 296 BeforeEach(func() { 297 expectedErr = ccerror.RequestError{} 298 summary := v3action.ApplicationSummary{ 299 Application: v3action.Application{ 300 Name: "some-app", 301 State: "STARTED", 302 }, 303 ProcessSummaries: []v3action.ProcessSummary{ 304 {Process: v3action.Process{Type: constant.ProcessTypeWeb}}, 305 }, 306 } 307 fakeActor.GetApplicationSummaryByNameAndSpaceReturns( 308 summary, 309 v3action.Warnings{"warning-1", "warning-2"}, 310 nil, 311 ) 312 313 fakeV2Actor.GetApplicationRoutesReturns([]v2action.Route{}, v2action.Warnings{"route-warning-1", "route-warning-2"}, expectedErr) 314 }) 315 316 It("returns the error and prints warnings", func() { 317 Expect(executeErr).To(Equal(translatableerror.APIRequestError{})) 318 319 Expect(testUI.Out).To(Say("Showing health and status for app some-app in org some-org / space some-space as steve\\.\\.\\.")) 320 321 Expect(testUI.Err).To(Say("warning-1")) 322 Expect(testUI.Err).To(Say("warning-2")) 323 Expect(testUI.Err).To(Say("route-warning-1")) 324 Expect(testUI.Err).To(Say("route-warning-2")) 325 }) 326 }) 327 328 Context("when getting routes does not return any errors", func() { 329 BeforeEach(func() { 330 fakeV2Actor.GetApplicationRoutesReturns([]v2action.Route{ 331 {Domain: v2action.Domain{Name: "some-other-domain"}}, { 332 Domain: v2action.Domain{Name: "some-domain"}}}, 333 v2action.Warnings{"route-warning-1", "route-warning-2"}, nil) 334 }) 335 336 Context("when there are no instances of any process in the app", func() { 337 BeforeEach(func() { 338 summary := v3action.ApplicationSummary{ 339 Application: v3action.Application{ 340 Name: "some-app", 341 State: "STARTED", 342 }, 343 CurrentDroplet: v3action.Droplet{ 344 Stack: "cflinuxfs2", 345 Buildpacks: []v3action.Buildpack{ 346 { 347 Name: "ruby_buildpack", 348 DetectOutput: "some-detect-output", 349 }, 350 { 351 Name: "some-buildpack", 352 DetectOutput: "", 353 }, 354 }, 355 }, 356 ProcessSummaries: []v3action.ProcessSummary{ 357 { 358 Process: v3action.Process{ 359 Type: "console", 360 MemoryInMB: types.NullUint64{Value: 128, IsSet: true}, 361 }, 362 }, 363 { 364 Process: v3action.Process{ 365 Type: "worker", 366 MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, 367 }, 368 }, 369 { 370 Process: v3action.Process{ 371 Type: constant.ProcessTypeWeb, 372 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 373 }, 374 }, 375 }, 376 } 377 fakeActor.GetApplicationSummaryByNameAndSpaceReturns(summary, nil, nil) 378 }) 379 380 It("says no instances are running", func() { 381 Expect(executeErr).ToNot(HaveOccurred()) 382 383 Expect(testUI.Out).To(Say("There are no running instances of this app.")) 384 }) 385 386 It("does not display the instance table", func() { 387 Expect(executeErr).ToNot(HaveOccurred()) 388 389 Expect(testUI.Out).NotTo(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 390 }) 391 }) 392 393 Context("when all the instances in all processes are down", func() { 394 BeforeEach(func() { 395 summary := v3action.ApplicationSummary{ 396 Application: v3action.Application{ 397 Name: "some-app", 398 State: "STARTED", 399 }, 400 CurrentDroplet: v3action.Droplet{ 401 Stack: "cflinuxfs2", 402 Buildpacks: []v3action.Buildpack{ 403 { 404 Name: "ruby_buildpack", 405 DetectOutput: "some-detect-output", 406 }, 407 { 408 Name: "some-buildpack", 409 DetectOutput: "", 410 }, 411 }, 412 }, 413 ProcessSummaries: []v3action.ProcessSummary{ 414 { 415 Process: v3action.Process{ 416 Type: "console", 417 MemoryInMB: types.NullUint64{Value: 128, IsSet: true}, 418 }, 419 InstanceDetails: []v3action.Instance{{State: "DOWN"}}, 420 }, 421 { 422 Process: v3action.Process{ 423 Type: "worker", 424 MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, 425 }, 426 InstanceDetails: []v3action.Instance{{State: "DOWN"}}, 427 }, 428 { 429 Process: v3action.Process{ 430 Type: constant.ProcessTypeWeb, 431 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 432 }, 433 InstanceDetails: []v3action.Instance{{State: "DOWN"}}, 434 }, 435 }, 436 } 437 fakeActor.GetApplicationSummaryByNameAndSpaceReturns(summary, nil, nil) 438 }) 439 440 It("says no instances are running", func() { 441 Expect(executeErr).ToNot(HaveOccurred()) 442 Expect(testUI.Out).To(Say("buildpacks:")) 443 Expect(testUI.Out).To(Say("\n\n")) 444 445 Expect(testUI.Out).To(Say("There are no running instances of this app.")) 446 }) 447 448 It("does not display the instance table", func() { 449 Expect(executeErr).ToNot(HaveOccurred()) 450 451 Expect(testUI.Out).NotTo(Say(`state\s+since\s+cpu\s+memory\s+disk`)) 452 }) 453 }) 454 455 Context("when there are running instances of the app", func() { 456 BeforeEach(func() { 457 summary := v3action.ApplicationSummary{ 458 Application: v3action.Application{ 459 Name: "some-app", 460 State: "STARTED", 461 }, 462 CurrentDroplet: v3action.Droplet{ 463 Stack: "cflinuxfs2", 464 Buildpacks: []v3action.Buildpack{ 465 { 466 Name: "ruby_buildpack", 467 DetectOutput: "some-detect-output", 468 }, 469 { 470 Name: "some-buildpack", 471 DetectOutput: "", 472 }, 473 }, 474 }, 475 ProcessSummaries: []v3action.ProcessSummary{ 476 { 477 Process: v3action.Process{ 478 Type: "console", 479 MemoryInMB: types.NullUint64{Value: 128, IsSet: true}, 480 }, 481 InstanceDetails: []v3action.Instance{}, 482 }, 483 { 484 Process: v3action.Process{ 485 Type: "worker", 486 MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, 487 }, 488 InstanceDetails: []v3action.Instance{ 489 v3action.Instance{ 490 Index: 0, 491 State: "DOWN", 492 MemoryUsage: 4000000, 493 DiskUsage: 4000000, 494 MemoryQuota: 67108864, 495 DiskQuota: 8000000, 496 Uptime: int(time.Now().Sub(time.Unix(1371859200, 0)).Seconds()), 497 }, 498 }, 499 }, 500 { 501 Process: v3action.Process{ 502 Type: constant.ProcessTypeWeb, 503 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 504 }, 505 InstanceDetails: []v3action.Instance{ 506 v3action.Instance{ 507 Index: 0, 508 State: "RUNNING", 509 MemoryUsage: 1000000, 510 DiskUsage: 1000000, 511 MemoryQuota: 33554432, 512 DiskQuota: 2000000, 513 Uptime: int(time.Now().Sub(time.Unix(267321600, 0)).Seconds()), 514 }, 515 v3action.Instance{ 516 Index: 1, 517 State: "RUNNING", 518 MemoryUsage: 2000000, 519 DiskUsage: 2000000, 520 MemoryQuota: 33554432, 521 DiskQuota: 4000000, 522 Uptime: int(time.Now().Sub(time.Unix(330480000, 0)).Seconds()), 523 }, 524 v3action.Instance{ 525 Index: 2, 526 State: "RUNNING", 527 MemoryUsage: 3000000, 528 DiskUsage: 3000000, 529 MemoryQuota: 33554432, 530 DiskQuota: 6000000, 531 Uptime: int(time.Now().Sub(time.Unix(1277164800, 0)).Seconds()), 532 }, 533 }, 534 }, 535 }, 536 } 537 fakeActor.GetApplicationSummaryByNameAndSpaceReturns(summary, v3action.Warnings{"warning-1", "warning-2"}, nil) 538 }) 539 540 It("prints the application summary and outputs warnings", func() { 541 Expect(executeErr).ToNot(HaveOccurred()) 542 543 Expect(testUI.Out).To(Say("(?m)Showing health and status for app some-app in org some-org / space some-space as steve\\.\\.\\.\n\n")) 544 Expect(testUI.Out).To(Say("name:\\s+some-app")) 545 Expect(testUI.Out).To(Say("requested state:\\s+started")) 546 Expect(testUI.Out).To(Say("processes:\\s+web:3/3, console:0/0, worker:0/1")) 547 Expect(testUI.Out).To(Say("memory usage:\\s+32M x 3, 64M x 1")) 548 Expect(testUI.Out).To(Say("routes:\\s+some-other-domain, some-domain")) 549 Expect(testUI.Out).To(Say("stack:\\s+cflinuxfs2")) 550 Expect(testUI.Out).To(Say("(?m)buildpacks:\\s+some-detect-output, some-buildpack\n\n")) 551 Expect(testUI.Out).To(Say("web:3/3")) 552 Expect(testUI.Out).To(Say("\\s+state\\s+since\\s+cpu\\s+memory\\s+disk")) 553 Expect(testUI.Out).To(Say("#0\\s+running\\s+1978-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M\\s+0.0%\\s+976.6K of 32M\\s+976.6K of 1.9M")) 554 Expect(testUI.Out).To(Say("#1\\s+running\\s+1980-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M\\s+0.0%\\s+1.9M of 32M\\s+1.9M of 3.8M")) 555 Expect(testUI.Out).To(Say("#2\\s+running\\s+2010-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2} [AP]M\\s+0.0%\\s+2.9M of 32M\\s+2.9M of 5.7M")) 556 557 Expect(testUI.Out).To(Say("console:0/0")) 558 559 Expect(testUI.Out).To(Say("worker:0/1")) 560 561 Expect(testUI.Err).To(Say("warning-1")) 562 Expect(testUI.Err).To(Say("warning-2")) 563 564 Expect(fakeActor.GetApplicationSummaryByNameAndSpaceCallCount()).To(Equal(1)) 565 appName, spaceGUID := fakeActor.GetApplicationSummaryByNameAndSpaceArgsForCall(0) 566 Expect(appName).To(Equal("some-app")) 567 Expect(spaceGUID).To(Equal("some-space-guid")) 568 }) 569 }) 570 }) 571 }) 572 })