github.com/cloudfoundry-community/cloudfoundry-cli@v6.44.1-0.20240130060226-cda5ed8e89a5+incompatible/actor/v7action/application_summary_test.go (about) 1 package v7action_test 2 3 import ( 4 "code.cloudfoundry.org/cli/resources" 5 "errors" 6 7 "code.cloudfoundry.org/cli/actor/v2action" 8 . "code.cloudfoundry.org/cli/actor/v7action" 9 "code.cloudfoundry.org/cli/actor/v7action/v7actionfakes" 10 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 11 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" 12 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 13 "code.cloudfoundry.org/cli/types" 14 15 . "github.com/onsi/ginkgo" 16 . "github.com/onsi/ginkgo/extensions/table" 17 . "github.com/onsi/gomega" 18 ) 19 20 var _ = Describe("Application Summary Actions", func() { 21 var ( 22 actor *Actor 23 fakeCloudControllerClient *v7actionfakes.FakeCloudControllerClient 24 ) 25 26 BeforeEach(func() { 27 fakeCloudControllerClient = new(v7actionfakes.FakeCloudControllerClient) 28 actor = NewActor(fakeCloudControllerClient, nil, nil, nil) 29 }) 30 31 Describe("ApplicationSummary", func() { 32 DescribeTable("GetIsolationSegmentName", 33 func(summary ApplicationSummary, isoName string, exists bool) { 34 name, ok := summary.GetIsolationSegmentName() 35 Expect(ok).To(Equal(exists)) 36 Expect(name).To(Equal(isoName)) 37 }, 38 39 Entry("when the there are application instances and the isolationSegmentName is set", 40 ApplicationSummary{ 41 ProcessSummaries: ProcessSummaries{ 42 ProcessSummary{ 43 InstanceDetails: []ProcessInstance{ 44 {IsolationSegment: "some-name"}, 45 }, 46 }, 47 }, 48 }, 49 "some-name", 50 true, 51 ), 52 53 Entry("when the there are application instances and the isolationSegmentName is blank", 54 ApplicationSummary{ 55 ProcessSummaries: ProcessSummaries{ 56 ProcessSummary{InstanceDetails: []ProcessInstance{{}}}, 57 }, 58 }, 59 "", 60 false, 61 ), 62 63 Entry("when the there are no application instances", ApplicationSummary{ProcessSummaries: ProcessSummaries{{}}}, "", false), 64 Entry("when the there are no processes", ApplicationSummary{}, "", false), 65 ) 66 }) 67 68 Describe("GetApplicationSummaryByNameAndSpace", func() { 69 var ( 70 appName string 71 spaceGUID string 72 withObfuscatedValues bool 73 fakeRouteActor *v7actionfakes.FakeRouteActor 74 75 summary ApplicationSummary 76 warnings Warnings 77 executeErr error 78 ) 79 80 BeforeEach(func() { 81 appName = "some-app-name" 82 spaceGUID = "some-space-guid" 83 withObfuscatedValues = true 84 fakeRouteActor = new(v7actionfakes.FakeRouteActor) 85 }) 86 87 Context("when a route actor is not provided", func() { 88 JustBeforeEach(func() { 89 summary, warnings, executeErr = actor.GetApplicationSummaryByNameAndSpace(appName, spaceGUID, withObfuscatedValues, nil) 90 }) 91 92 When("retrieving the application is successful", func() { 93 BeforeEach(func() { 94 fakeCloudControllerClient.GetApplicationsReturns( 95 []resources.Application{ 96 { 97 Name: "some-app-name", 98 GUID: "some-app-guid", 99 State: constant.ApplicationStarted, 100 }, 101 }, 102 ccv3.Warnings{"some-warning"}, 103 nil, 104 ) 105 }) 106 107 When("retrieving the process information is successful", func() { 108 BeforeEach(func() { 109 listedProcesses := []resources.Process{ 110 { 111 GUID: "some-process-guid", 112 Type: "some-type", 113 Command: *types.NewFilteredString("[Redacted Value]"), 114 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 115 }, 116 { 117 GUID: "some-process-web-guid", 118 Type: "web", 119 Command: *types.NewFilteredString("[Redacted Value]"), 120 MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, 121 }, 122 } 123 fakeCloudControllerClient.GetApplicationProcessesReturns( 124 listedProcesses, 125 ccv3.Warnings{"some-process-warning"}, 126 nil, 127 ) 128 129 explicitlyCalledProcess := listedProcesses[0] 130 explicitlyCalledProcess.Command = *types.NewFilteredString("some-start-command") 131 fakeCloudControllerClient.GetApplicationProcessByTypeReturnsOnCall( 132 0, 133 explicitlyCalledProcess, 134 ccv3.Warnings{"get-process-by-type-warning"}, 135 nil, 136 ) 137 138 fakeCloudControllerClient.GetApplicationProcessByTypeReturnsOnCall( 139 1, 140 listedProcesses[1], 141 ccv3.Warnings{"get-process-by-type-warning"}, 142 nil, 143 ) 144 145 fakeCloudControllerClient.GetProcessInstancesReturns( 146 []ccv3.ProcessInstance{ 147 { 148 State: constant.ProcessInstanceRunning, 149 CPU: 0.01, 150 MemoryUsage: 1000000, 151 DiskUsage: 2000000, 152 MemoryQuota: 3000000, 153 DiskQuota: 4000000, 154 Index: 0, 155 }, 156 }, 157 ccv3.Warnings{"some-process-stats-warning"}, 158 nil, 159 ) 160 }) 161 162 When("app has droplet", func() { 163 BeforeEach(func() { 164 fakeCloudControllerClient.GetApplicationDropletCurrentReturns( 165 resources.Droplet{ 166 Stack: "some-stack", 167 Buildpacks: []resources.DropletBuildpack{ 168 { 169 Name: "some-buildpack", 170 }, 171 }, 172 Image: "docker/some-image", 173 }, 174 ccv3.Warnings{"some-droplet-warning"}, 175 nil, 176 ) 177 }) 178 179 It("returns the summary and warnings with droplet information", func() { 180 Expect(executeErr).ToNot(HaveOccurred()) 181 Expect(summary).To(Equal(ApplicationSummary{ 182 Application: Application{ 183 Name: "some-app-name", 184 GUID: "some-app-guid", 185 State: constant.ApplicationStarted, 186 }, 187 CurrentDroplet: Droplet{ 188 Stack: "some-stack", 189 Image: "docker/some-image", 190 Buildpacks: []DropletBuildpack{ 191 { 192 Name: "some-buildpack", 193 }, 194 }, 195 }, 196 ProcessSummaries: []ProcessSummary{ 197 { 198 Process: Process{ 199 GUID: "some-process-web-guid", 200 Type: "web", 201 Command: *types.NewFilteredString("[Redacted Value]"), 202 MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, 203 }, 204 InstanceDetails: []ProcessInstance{ 205 { 206 State: constant.ProcessInstanceRunning, 207 CPU: 0.01, 208 MemoryUsage: 1000000, 209 DiskUsage: 2000000, 210 MemoryQuota: 3000000, 211 DiskQuota: 4000000, 212 Index: 0, 213 }, 214 }, 215 }, 216 { 217 Process: Process{ 218 GUID: "some-process-guid", 219 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 220 Type: "some-type", 221 Command: *types.NewFilteredString("some-start-command"), 222 }, 223 InstanceDetails: []ProcessInstance{ 224 { 225 State: constant.ProcessInstanceRunning, 226 CPU: 0.01, 227 MemoryUsage: 1000000, 228 DiskUsage: 2000000, 229 MemoryQuota: 3000000, 230 DiskQuota: 4000000, 231 Index: 0, 232 }, 233 }, 234 }, 235 }, 236 })) 237 Expect(warnings).To(ConsistOf("some-warning", "some-process-warning", "get-process-by-type-warning", "get-process-by-type-warning", "some-process-stats-warning", "some-process-stats-warning", "some-droplet-warning")) 238 239 Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1)) 240 Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf( 241 ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name"}}, 242 ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}}, 243 )) 244 245 Expect(fakeCloudControllerClient.GetApplicationDropletCurrentCallCount()).To(Equal(1)) 246 Expect(fakeCloudControllerClient.GetApplicationDropletCurrentArgsForCall(0)).To(Equal("some-app-guid")) 247 248 Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(1)) 249 Expect(fakeCloudControllerClient.GetApplicationProcessesArgsForCall(0)).To(Equal("some-app-guid")) 250 251 Expect(fakeCloudControllerClient.GetApplicationProcessByTypeCallCount()).To(Equal(2)) 252 appGUID, processType := fakeCloudControllerClient.GetApplicationProcessByTypeArgsForCall(0) 253 Expect(appGUID).To(Equal("some-app-guid")) 254 Expect(processType).To(Equal("some-type")) 255 256 Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(2)) 257 Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("some-process-guid")) 258 }) 259 260 When("getting the current droplet returns an error", func() { 261 var expectedErr error 262 263 BeforeEach(func() { 264 expectedErr = errors.New("some error") 265 fakeCloudControllerClient.GetApplicationDropletCurrentReturns( 266 resources.Droplet{}, 267 ccv3.Warnings{"some-droplet-warning"}, 268 expectedErr, 269 ) 270 }) 271 272 It("returns the error", func() { 273 Expect(executeErr).To(Equal(expectedErr)) 274 Expect(warnings).To(ConsistOf("some-warning", "some-process-warning", "get-process-by-type-warning", "get-process-by-type-warning", "some-process-stats-warning", "some-process-stats-warning", "some-droplet-warning")) 275 }) 276 }) 277 }) 278 279 When("app does not have current droplet", func() { 280 BeforeEach(func() { 281 fakeCloudControllerClient.GetApplicationDropletCurrentReturns( 282 resources.Droplet{}, 283 ccv3.Warnings{"some-droplet-warning"}, 284 ccerror.DropletNotFoundError{}, 285 ) 286 }) 287 288 It("returns the summary and warnings without droplet information", func() { 289 Expect(executeErr).ToNot(HaveOccurred()) 290 Expect(summary).To(Equal(ApplicationSummary{ 291 Application: Application{ 292 Name: "some-app-name", 293 GUID: "some-app-guid", 294 State: constant.ApplicationStarted, 295 }, 296 ProcessSummaries: []ProcessSummary{ 297 { 298 Process: Process{ 299 GUID: "some-process-web-guid", 300 Type: "web", 301 Command: *types.NewFilteredString("[Redacted Value]"), 302 MemoryInMB: types.NullUint64{Value: 64, IsSet: true}, 303 }, 304 InstanceDetails: []ProcessInstance{ 305 { 306 State: constant.ProcessInstanceRunning, 307 CPU: 0.01, 308 MemoryUsage: 1000000, 309 DiskUsage: 2000000, 310 MemoryQuota: 3000000, 311 DiskQuota: 4000000, 312 Index: 0, 313 }, 314 }, 315 }, 316 { 317 Process: Process{ 318 GUID: "some-process-guid", 319 MemoryInMB: types.NullUint64{Value: 32, IsSet: true}, 320 Type: "some-type", 321 Command: *types.NewFilteredString("some-start-command"), 322 }, 323 InstanceDetails: []ProcessInstance{ 324 { 325 State: constant.ProcessInstanceRunning, 326 CPU: 0.01, 327 MemoryUsage: 1000000, 328 DiskUsage: 2000000, 329 MemoryQuota: 3000000, 330 DiskQuota: 4000000, 331 Index: 0, 332 }, 333 }, 334 }, 335 }, 336 })) 337 Expect(warnings).To(ConsistOf("some-warning", "some-process-warning", "get-process-by-type-warning", "get-process-by-type-warning", "some-process-stats-warning", "some-process-stats-warning", "some-droplet-warning")) 338 }) 339 }) 340 341 }) 342 343 When("getting the app process instances returns an error", func() { 344 var expectedErr error 345 346 BeforeEach(func() { 347 fakeCloudControllerClient.GetApplicationProcessesReturns( 348 []resources.Process{ 349 { 350 GUID: "some-process-guid", 351 Type: "some-type", 352 }, 353 }, 354 ccv3.Warnings{"some-process-warning"}, 355 nil, 356 ) 357 358 fakeCloudControllerClient.GetApplicationProcessByTypeReturns( 359 resources.Process{}, 360 ccv3.Warnings{"get-process-by-type-warning"}, 361 nil, 362 ) 363 364 expectedErr = errors.New("some error") 365 fakeCloudControllerClient.GetProcessInstancesReturns( 366 []ccv3.ProcessInstance{}, 367 ccv3.Warnings{"some-process-stats-warning"}, 368 expectedErr, 369 ) 370 }) 371 372 It("returns the error", func() { 373 Expect(executeErr).To(Equal(expectedErr)) 374 Expect(warnings).To(ConsistOf("some-warning", "some-process-warning", "get-process-by-type-warning", "some-process-stats-warning")) 375 }) 376 }) 377 }) 378 379 When("getting the app processes returns an error", func() { 380 var expectedErr error 381 382 BeforeEach(func() { 383 fakeCloudControllerClient.GetApplicationsReturns( 384 []resources.Application{ 385 { 386 Name: "some-app-name", 387 GUID: "some-app-guid", 388 State: constant.ApplicationStarted, 389 }, 390 }, 391 ccv3.Warnings{"some-warning"}, 392 nil, 393 ) 394 395 expectedErr = errors.New("some error") 396 fakeCloudControllerClient.GetApplicationProcessesReturns( 397 []resources.Process{{Type: constant.ProcessTypeWeb}}, 398 ccv3.Warnings{"some-process-warning"}, 399 expectedErr, 400 ) 401 }) 402 403 It("returns the error", func() { 404 Expect(executeErr).To(Equal(expectedErr)) 405 Expect(warnings).To(ConsistOf("some-warning", "some-process-warning")) 406 }) 407 }) 408 }) 409 410 When("passed with a routeActor", func() { 411 BeforeEach(func() { 412 fakeCloudControllerClient.GetApplicationsReturns( 413 []resources.Application{ 414 { 415 Name: "some-app-name", 416 GUID: "some-app-guid", 417 State: constant.ApplicationStarted, 418 }, 419 }, 420 ccv3.Warnings{"some-warning"}, 421 nil, 422 ) 423 }) 424 425 JustBeforeEach(func() { 426 summary, warnings, executeErr = actor.GetApplicationSummaryByNameAndSpace(appName, spaceGUID, withObfuscatedValues, fakeRouteActor) 427 }) 428 429 When("getting the routes is successful", func() { 430 BeforeEach(func() { 431 routes := v2action.Routes{ 432 {GUID: "some-route-guid"}, 433 {GUID: "some-other-route-guid"}, 434 } 435 436 fakeRouteActor.GetApplicationRoutesReturns(routes, v2action.Warnings{"v2-routes-warnings"}, nil) 437 }) 438 439 It("retrieves and sets the application routes", func() { 440 Expect(warnings).To(ConsistOf("some-warning", "v2-routes-warnings")) 441 Expect(summary.Routes).To(ConsistOf( 442 v2action.Route{GUID: "some-route-guid"}, 443 v2action.Route{GUID: "some-other-route-guid"}, 444 )) 445 446 Expect(fakeRouteActor.GetApplicationRoutesCallCount()).To(Equal(1)) 447 Expect(fakeRouteActor.GetApplicationRoutesArgsForCall(0)).To(Equal("some-app-guid")) 448 }) 449 }) 450 451 When("getting the application routes errors", func() { 452 When("a generic error is returned", func() { 453 BeforeEach(func() { 454 fakeRouteActor.GetApplicationRoutesReturns(nil, v2action.Warnings{"v2-routes-warnings"}, errors.New("some-error")) 455 }) 456 457 It("returns warnings and the error", func() { 458 Expect(executeErr).To(MatchError("some-error")) 459 Expect(warnings).To(ConsistOf("some-warning", "v2-routes-warnings")) 460 }) 461 }) 462 463 When("a ResourceNotFoundError is returned", func() { 464 BeforeEach(func() { 465 fakeRouteActor.GetApplicationRoutesReturns(nil, v2action.Warnings{"v2-routes-warnings"}, ccerror.ResourceNotFoundError{}) 466 }) 467 468 It("adds warnings and continues", func() { 469 Expect(executeErr).ToNot(HaveOccurred()) 470 Expect(warnings).To(ConsistOf("some-warning", "v2-routes-warnings")) 471 }) 472 }) 473 }) 474 }) 475 }) 476 })