github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/actor/v7action/application_summary_test.go (about)

     1  package v7action_test
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"code.cloudfoundry.org/cli/actor/v7action"
     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/resources"
    14  	"code.cloudfoundry.org/cli/types"
    15  	"code.cloudfoundry.org/clock"
    16  
    17  	"code.cloudfoundry.org/cli/actor/actionerror"
    18  	. "github.com/onsi/ginkgo"
    19  	. "github.com/onsi/ginkgo/extensions/table"
    20  	. "github.com/onsi/gomega"
    21  )
    22  
    23  var _ = Describe("Application Summary Actions", func() {
    24  	var (
    25  		actor                     *Actor
    26  		fakeCloudControllerClient *v7actionfakes.FakeCloudControllerClient
    27  	)
    28  
    29  	BeforeEach(func() {
    30  		fakeCloudControllerClient = new(v7actionfakes.FakeCloudControllerClient)
    31  		actor = NewActor(fakeCloudControllerClient, nil, nil, nil, nil, clock.NewClock())
    32  	})
    33  
    34  	Describe("ApplicationSummary", func() {
    35  		DescribeTable("GetIsolationSegmentName",
    36  			func(summary ApplicationSummary, isoName string, exists bool) {
    37  				name, ok := summary.GetIsolationSegmentName()
    38  				Expect(ok).To(Equal(exists))
    39  				Expect(name).To(Equal(isoName))
    40  			},
    41  
    42  			Entry("when the there are application instances and the isolationSegmentName is set",
    43  				ApplicationSummary{
    44  					ProcessSummaries: ProcessSummaries{
    45  						ProcessSummary{
    46  							InstanceDetails: []ProcessInstance{
    47  								{IsolationSegment: "some-name"},
    48  							},
    49  						},
    50  					},
    51  				},
    52  				"some-name",
    53  				true,
    54  			),
    55  
    56  			Entry("when the there are application instances and the isolationSegmentName is blank",
    57  				ApplicationSummary{
    58  					ProcessSummaries: ProcessSummaries{
    59  						ProcessSummary{InstanceDetails: []ProcessInstance{{}}},
    60  					},
    61  				},
    62  				"",
    63  				false,
    64  			),
    65  
    66  			Entry("when the there are no application instances", ApplicationSummary{ProcessSummaries: ProcessSummaries{{}}}, "", false),
    67  			Entry("when the there are no processes", ApplicationSummary{}, "", false),
    68  		)
    69  	})
    70  
    71  	Describe("GetAppSummariesForSpace", func() {
    72  		var (
    73  			spaceGUID     string
    74  			labelSelector string
    75  
    76  			summaries  []ApplicationSummary
    77  			warnings   Warnings
    78  			executeErr error
    79  		)
    80  
    81  		BeforeEach(func() {
    82  			spaceGUID = "some-space-guid"
    83  			labelSelector = "some-key=some-value"
    84  		})
    85  
    86  		JustBeforeEach(func() {
    87  			summaries, warnings, executeErr = actor.GetAppSummariesForSpace(spaceGUID, labelSelector)
    88  		})
    89  
    90  		When("getting the application is successful", func() {
    91  			BeforeEach(func() {
    92  				fakeCloudControllerClient.GetApplicationsReturns(
    93  					[]resources.Application{
    94  						{
    95  							Name:  "some-app-name",
    96  							GUID:  "some-app-guid",
    97  							State: constant.ApplicationStarted,
    98  						},
    99  					},
   100  					ccv3.Warnings{"get-apps-warning"},
   101  					nil,
   102  				)
   103  
   104  				listedProcesses := []resources.Process{
   105  					{
   106  						GUID:       "some-process-guid",
   107  						Type:       "some-type",
   108  						Command:    *types.NewFilteredString("[Redacted Value]"),
   109  						MemoryInMB: types.NullUint64{Value: 32, IsSet: true},
   110  						AppGUID:    "some-app-guid",
   111  					},
   112  					{
   113  						GUID:       "some-process-web-guid",
   114  						Type:       "web",
   115  						Command:    *types.NewFilteredString("[Redacted Value]"),
   116  						MemoryInMB: types.NullUint64{Value: 64, IsSet: true},
   117  						AppGUID:    "some-app-guid",
   118  					},
   119  				}
   120  
   121  				fakeCloudControllerClient.GetProcessesReturns(
   122  					listedProcesses,
   123  					ccv3.Warnings{"get-app-processes-warning"},
   124  					nil,
   125  				)
   126  
   127  				explicitlyCalledProcess := listedProcesses[0]
   128  				explicitlyCalledProcess.Command = *types.NewFilteredString("some-start-command")
   129  				fakeCloudControllerClient.GetProcessReturnsOnCall(
   130  					0,
   131  					explicitlyCalledProcess,
   132  					ccv3.Warnings{"get-process-by-type-warning"},
   133  					nil,
   134  				)
   135  
   136  				fakeCloudControllerClient.GetProcessReturnsOnCall(
   137  					1,
   138  					listedProcesses[1],
   139  					ccv3.Warnings{"get-process-by-type-warning"},
   140  					nil,
   141  				)
   142  
   143  				fakeCloudControllerClient.GetProcessInstancesReturns(
   144  					[]ccv3.ProcessInstance{
   145  						{
   146  							State:       constant.ProcessInstanceRunning,
   147  							CPU:         0.01,
   148  							MemoryUsage: 1000000,
   149  							DiskUsage:   2000000,
   150  							MemoryQuota: 3000000,
   151  							DiskQuota:   4000000,
   152  							Index:       0,
   153  						},
   154  					},
   155  					ccv3.Warnings{"get-process-instances-warning"},
   156  					nil,
   157  				)
   158  
   159  				fakeCloudControllerClient.GetRoutesReturns(
   160  					[]resources.Route{
   161  						{
   162  							GUID: "some-route-guid",
   163  							Destinations: []resources.RouteDestination{
   164  								{
   165  									App: resources.RouteDestinationApp{
   166  										GUID: "some-app-guid",
   167  									},
   168  								},
   169  							},
   170  						},
   171  						{
   172  							GUID: "some-other-route-guid",
   173  							Destinations: []resources.RouteDestination{
   174  								{
   175  									App: resources.RouteDestinationApp{
   176  										GUID: "some-app-guid",
   177  									},
   178  								},
   179  							},
   180  						},
   181  					},
   182  					ccv3.Warnings{"get-routes-warning"},
   183  					nil,
   184  				)
   185  			})
   186  
   187  			It("returns the summary and warnings with droplet information", func() {
   188  				Expect(executeErr).ToNot(HaveOccurred())
   189  
   190  				Expect(summaries).To(Equal([]ApplicationSummary{
   191  					{
   192  						Application: resources.Application{
   193  							Name:  "some-app-name",
   194  							GUID:  "some-app-guid",
   195  							State: constant.ApplicationStarted,
   196  						},
   197  						ProcessSummaries: []ProcessSummary{
   198  							{
   199  								Process: resources.Process{
   200  									GUID:       "some-process-web-guid",
   201  									Type:       "web",
   202  									Command:    *types.NewFilteredString("[Redacted Value]"),
   203  									MemoryInMB: types.NullUint64{Value: 64, IsSet: true},
   204  									AppGUID:    "some-app-guid",
   205  								},
   206  								InstanceDetails: []ProcessInstance{
   207  									{
   208  										State:       constant.ProcessInstanceRunning,
   209  										CPU:         0.01,
   210  										MemoryUsage: 1000000,
   211  										DiskUsage:   2000000,
   212  										MemoryQuota: 3000000,
   213  										DiskQuota:   4000000,
   214  										Index:       0,
   215  									},
   216  								},
   217  							},
   218  							{
   219  								Process: resources.Process{
   220  									GUID:       "some-process-guid",
   221  									MemoryInMB: types.NullUint64{Value: 32, IsSet: true},
   222  									Type:       "some-type",
   223  									Command:    *types.NewFilteredString("[Redacted Value]"),
   224  									AppGUID:    "some-app-guid",
   225  								},
   226  								InstanceDetails: []ProcessInstance{
   227  									{
   228  										State:       constant.ProcessInstanceRunning,
   229  										CPU:         0.01,
   230  										MemoryUsage: 1000000,
   231  										DiskUsage:   2000000,
   232  										MemoryQuota: 3000000,
   233  										DiskQuota:   4000000,
   234  										Index:       0,
   235  									},
   236  								},
   237  							},
   238  						},
   239  						Routes: []resources.Route{
   240  							{
   241  								GUID: "some-route-guid",
   242  								Destinations: []resources.RouteDestination{
   243  									{
   244  										App: resources.RouteDestinationApp{
   245  											GUID: "some-app-guid",
   246  										},
   247  									},
   248  								},
   249  							},
   250  							{
   251  								GUID: "some-other-route-guid",
   252  								Destinations: []resources.RouteDestination{
   253  									{
   254  										App: resources.RouteDestinationApp{
   255  											GUID: "some-app-guid",
   256  										},
   257  									},
   258  								},
   259  							},
   260  						},
   261  					},
   262  				}))
   263  
   264  				Expect(warnings).To(ConsistOf(
   265  					"get-apps-warning",
   266  					"get-app-processes-warning",
   267  					"get-process-instances-warning",
   268  					"get-process-instances-warning",
   269  					"get-routes-warning",
   270  				))
   271  
   272  				Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   273  				Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   274  					ccv3.Query{Key: ccv3.OrderBy, Values: []string{"name"}},
   275  					ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
   276  					ccv3.Query{Key: ccv3.LabelSelectorFilter, Values: []string{"some-key=some-value"}},
   277  				))
   278  
   279  				Expect(fakeCloudControllerClient.GetProcessesCallCount()).To(Equal(1))
   280  				Expect(fakeCloudControllerClient.GetProcessesArgsForCall(0)).To(ConsistOf(
   281  					ccv3.Query{Key: ccv3.AppGUIDFilter, Values: []string{"some-app-guid"}},
   282  				))
   283  
   284  				Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(2))
   285  				Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("some-process-guid"))
   286  			})
   287  
   288  			When("there is no label selector", func() {
   289  				BeforeEach(func() {
   290  					labelSelector = ""
   291  				})
   292  				It("doesn't pass a label selection filter", func() {
   293  					Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   294  					Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   295  						ccv3.Query{Key: ccv3.OrderBy, Values: []string{"name"}},
   296  						ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
   297  					))
   298  				})
   299  			})
   300  			When("there is long list of app guids", func() {
   301  				BeforeEach(func() {
   302  					lotsOfApps := []resources.Application{}
   303  					for i := 0; i < 600; i++ {
   304  						lotsOfApps = append(lotsOfApps, resources.Application{
   305  							Name:  "some-app-name",
   306  							GUID:  fmt.Sprintf("some-app-guid-%d", i),
   307  							State: constant.ApplicationStarted,
   308  						})
   309  					}
   310  					fakeCloudControllerClient.GetApplicationsReturns(
   311  						lotsOfApps,
   312  						ccv3.Warnings{"get-apps-warning"},
   313  						nil,
   314  					)
   315  				})
   316  
   317  				It("batches the calls to the API for processes", func() {
   318  					Expect(fakeCloudControllerClient.GetProcessesCallCount()).To(Equal(3))
   319  
   320  					getProcessesArgs := fakeCloudControllerClient.GetProcessesArgsForCall(0)
   321  					Expect(len(getProcessesArgs[0].Values)).To(Equal(200))
   322  					getProcessesArgs = fakeCloudControllerClient.GetProcessesArgsForCall(1)
   323  					Expect(len(getProcessesArgs[0].Values)).To(Equal(200))
   324  					getProcessesArgs = fakeCloudControllerClient.GetProcessesArgsForCall(2)
   325  					Expect(len(getProcessesArgs[0].Values)).To(Equal(200))
   326  
   327  					Expect(len(summaries)).To(Equal(600))
   328  				})
   329  				It("batches the calls to the API for routes", func() {
   330  					Expect(fakeCloudControllerClient.GetRoutesCallCount()).To(Equal(3))
   331  
   332  					getArgs := fakeCloudControllerClient.GetRoutesArgsForCall(0)
   333  					Expect(len(getArgs[0].Values)).To(Equal(200))
   334  					getArgs = fakeCloudControllerClient.GetRoutesArgsForCall(1)
   335  					Expect(len(getArgs[0].Values)).To(Equal(200))
   336  					getArgs = fakeCloudControllerClient.GetRoutesArgsForCall(2)
   337  					Expect(len(getArgs[0].Values)).To(Equal(200))
   338  
   339  					Expect(len(summaries)).To(Equal(600))
   340  				})
   341  			})
   342  		})
   343  
   344  		When("getting the application fails", func() {
   345  			BeforeEach(func() {
   346  				fakeCloudControllerClient.GetApplicationsReturns(
   347  					[]resources.Application{
   348  						{
   349  							Name:  "some-app-name",
   350  							GUID:  "some-app-guid",
   351  							State: constant.ApplicationStarted,
   352  						},
   353  					},
   354  					ccv3.Warnings{"get-apps-warning"},
   355  					errors.New("failed to get app"),
   356  				)
   357  			})
   358  
   359  			It("returns the error and warnings", func() {
   360  				Expect(executeErr).To(MatchError("failed to get app"))
   361  				Expect(warnings).To(ConsistOf("get-apps-warning"))
   362  			})
   363  		})
   364  	})
   365  
   366  	Describe("GetDetailedAppSummary", func() {
   367  		var (
   368  			appName              string
   369  			spaceGUID            string
   370  			withObfuscatedValues bool
   371  
   372  			summary    DetailedApplicationSummary
   373  			warnings   Warnings
   374  			executeErr error
   375  		)
   376  
   377  		BeforeEach(func() {
   378  			appName = "some-app-name"
   379  			spaceGUID = "some-space-guid"
   380  			withObfuscatedValues = true
   381  		})
   382  
   383  		JustBeforeEach(func() {
   384  			summary, warnings, executeErr = actor.GetDetailedAppSummary(appName, spaceGUID, withObfuscatedValues)
   385  		})
   386  
   387  		When("getting the application is successful", func() {
   388  			BeforeEach(func() {
   389  				fakeCloudControllerClient.GetApplicationsReturns(
   390  					[]resources.Application{
   391  						{
   392  							Name:  "some-app-name",
   393  							GUID:  "some-app-guid",
   394  							State: constant.ApplicationStarted,
   395  						},
   396  					},
   397  					ccv3.Warnings{"get-apps-warning"},
   398  					nil,
   399  				)
   400  			})
   401  
   402  			When("getting the process information is successful", func() {
   403  				BeforeEach(func() {
   404  					listedProcesses := []resources.Process{
   405  						{
   406  							GUID:       "some-process-guid",
   407  							Type:       "some-type",
   408  							Command:    *types.NewFilteredString("[Redacted Value]"),
   409  							MemoryInMB: types.NullUint64{Value: 32, IsSet: true},
   410  						},
   411  						{
   412  							GUID:       "some-process-web-guid",
   413  							Type:       "web",
   414  							Command:    *types.NewFilteredString("[Redacted Value]"),
   415  							MemoryInMB: types.NullUint64{Value: 64, IsSet: true},
   416  						},
   417  					}
   418  					fakeCloudControllerClient.GetApplicationProcessesReturns(
   419  						listedProcesses,
   420  						ccv3.Warnings{"get-app-processes-warning"},
   421  						nil,
   422  					)
   423  
   424  					explicitlyCalledProcess := listedProcesses[0]
   425  					explicitlyCalledProcess.Command = *types.NewFilteredString("some-start-command")
   426  					fakeCloudControllerClient.GetProcessReturnsOnCall(
   427  						0,
   428  						explicitlyCalledProcess,
   429  						ccv3.Warnings{"get-process-by-type-warning"},
   430  						nil,
   431  					)
   432  
   433  					fakeCloudControllerClient.GetProcessReturnsOnCall(
   434  						1,
   435  						listedProcesses[1],
   436  						ccv3.Warnings{"get-process-by-type-warning"},
   437  						nil,
   438  					)
   439  
   440  					fakeCloudControllerClient.GetProcessSidecarsReturns(
   441  						[]resources.Sidecar{
   442  							{
   443  								GUID:    "sidecar-guid",
   444  								Name:    "sidecar_name",
   445  								Command: *types.NewFilteredString("my-sidecar-command"),
   446  							},
   447  						},
   448  						ccv3.Warnings{"get-process-sidecars-warning"},
   449  						nil,
   450  					)
   451  
   452  					fakeCloudControllerClient.GetProcessInstancesReturns(
   453  						[]ccv3.ProcessInstance{
   454  							{
   455  								State:       constant.ProcessInstanceRunning,
   456  								CPU:         0.01,
   457  								MemoryUsage: 1000000,
   458  								DiskUsage:   2000000,
   459  								MemoryQuota: 3000000,
   460  								DiskQuota:   4000000,
   461  								Index:       0,
   462  							},
   463  						},
   464  						ccv3.Warnings{"get-process-instances-warning"},
   465  						nil,
   466  					)
   467  				})
   468  
   469  				When("getting current droplet succeeds", func() {
   470  					BeforeEach(func() {
   471  						fakeCloudControllerClient.GetApplicationDropletCurrentReturns(
   472  							resources.Droplet{
   473  								Stack: "some-stack",
   474  								Buildpacks: []resources.DropletBuildpack{
   475  									{
   476  										Name: "some-buildpack",
   477  									},
   478  								},
   479  								Image: "docker/some-image",
   480  							},
   481  							ccv3.Warnings{"get-app-droplet-warning"},
   482  							nil,
   483  						)
   484  					})
   485  
   486  					When("getting application routes succeeds", func() {
   487  						BeforeEach(func() {
   488  							fakeCloudControllerClient.GetApplicationRoutesReturns(
   489  								[]resources.Route{
   490  									{GUID: "some-route-guid"},
   491  									{GUID: "some-other-route-guid"},
   492  								},
   493  								ccv3.Warnings{"get-routes-warning"},
   494  								nil,
   495  							)
   496  						})
   497  
   498  						It("returns the summary and warnings with droplet information", func() {
   499  							Expect(executeErr).ToNot(HaveOccurred())
   500  							Expect(summary).To(Equal(DetailedApplicationSummary{
   501  								ApplicationSummary: v7action.ApplicationSummary{
   502  									Application: resources.Application{
   503  										Name:  "some-app-name",
   504  										GUID:  "some-app-guid",
   505  										State: constant.ApplicationStarted,
   506  									},
   507  									ProcessSummaries: []ProcessSummary{
   508  										{
   509  											Process: resources.Process{
   510  												GUID:       "some-process-web-guid",
   511  												Type:       "web",
   512  												Command:    *types.NewFilteredString("[Redacted Value]"),
   513  												MemoryInMB: types.NullUint64{Value: 64, IsSet: true},
   514  											},
   515  											Sidecars: []resources.Sidecar{
   516  												{
   517  													GUID:    "sidecar-guid",
   518  													Name:    "sidecar_name",
   519  													Command: *types.NewFilteredString("my-sidecar-command"),
   520  												},
   521  											},
   522  											InstanceDetails: []ProcessInstance{
   523  												{
   524  													State:       constant.ProcessInstanceRunning,
   525  													CPU:         0.01,
   526  													MemoryUsage: 1000000,
   527  													DiskUsage:   2000000,
   528  													MemoryQuota: 3000000,
   529  													DiskQuota:   4000000,
   530  													Index:       0,
   531  												},
   532  											},
   533  										},
   534  										{
   535  											Process: resources.Process{
   536  												GUID:       "some-process-guid",
   537  												MemoryInMB: types.NullUint64{Value: 32, IsSet: true},
   538  												Type:       "some-type",
   539  												Command:    *types.NewFilteredString("some-start-command"),
   540  											},
   541  											Sidecars: []resources.Sidecar{
   542  												{
   543  													GUID:    "sidecar-guid",
   544  													Name:    "sidecar_name",
   545  													Command: *types.NewFilteredString("my-sidecar-command"),
   546  												},
   547  											},
   548  											InstanceDetails: []ProcessInstance{
   549  												{
   550  													State:       constant.ProcessInstanceRunning,
   551  													CPU:         0.01,
   552  													MemoryUsage: 1000000,
   553  													DiskUsage:   2000000,
   554  													MemoryQuota: 3000000,
   555  													DiskQuota:   4000000,
   556  													Index:       0,
   557  												},
   558  											},
   559  										},
   560  									},
   561  									Routes: []resources.Route{
   562  										{GUID: "some-route-guid"},
   563  										{GUID: "some-other-route-guid"},
   564  									},
   565  								},
   566  								CurrentDroplet: resources.Droplet{
   567  									Stack: "some-stack",
   568  									Image: "docker/some-image",
   569  									Buildpacks: []resources.DropletBuildpack{
   570  										{
   571  											Name: "some-buildpack",
   572  										},
   573  									},
   574  								},
   575  							}))
   576  
   577  							Expect(warnings).To(ConsistOf(
   578  								"get-apps-warning",
   579  								"get-app-processes-warning",
   580  								"get-process-by-type-warning",
   581  								"get-process-by-type-warning",
   582  								"get-process-instances-warning",
   583  								"get-process-instances-warning",
   584  								"get-process-sidecars-warning",
   585  								"get-process-sidecars-warning",
   586  								"get-app-droplet-warning",
   587  								"get-routes-warning",
   588  							))
   589  
   590  							Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   591  							Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   592  								ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name"}},
   593  								ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
   594  							))
   595  
   596  							Expect(fakeCloudControllerClient.GetApplicationDropletCurrentCallCount()).To(Equal(1))
   597  							Expect(fakeCloudControllerClient.GetApplicationDropletCurrentArgsForCall(0)).To(Equal("some-app-guid"))
   598  
   599  							Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(1))
   600  							Expect(fakeCloudControllerClient.GetApplicationProcessesArgsForCall(0)).To(Equal("some-app-guid"))
   601  
   602  							Expect(fakeCloudControllerClient.GetProcessCallCount()).To(Equal(2))
   603  							processGUID := fakeCloudControllerClient.GetProcessArgsForCall(0)
   604  							Expect(processGUID).To(Equal("some-process-guid"))
   605  
   606  							Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(2))
   607  							Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("some-process-guid"))
   608  						})
   609  					})
   610  
   611  					When("getting application routes fails", func() {
   612  						BeforeEach(func() {
   613  							fakeCloudControllerClient.GetApplicationRoutesReturns(nil, ccv3.Warnings{"get-routes-warnings"}, errors.New("some-error"))
   614  						})
   615  
   616  						It("returns the warnings and error", func() {
   617  							Expect(executeErr).To(MatchError("some-error"))
   618  							Expect(warnings).To(ConsistOf(
   619  								"get-apps-warning",
   620  								"get-app-processes-warning",
   621  								"get-process-by-type-warning",
   622  								"get-process-by-type-warning",
   623  								"get-process-instances-warning",
   624  								"get-process-instances-warning",
   625  								"get-process-sidecars-warning",
   626  								"get-process-sidecars-warning",
   627  								"get-routes-warnings",
   628  							))
   629  						})
   630  					})
   631  				})
   632  
   633  				When("app does not have current droplet", func() {
   634  					BeforeEach(func() {
   635  						fakeCloudControllerClient.GetApplicationDropletCurrentReturns(
   636  							resources.Droplet{},
   637  							ccv3.Warnings{"get-app-droplet-warning"},
   638  							ccerror.DropletNotFoundError{},
   639  						)
   640  					})
   641  
   642  					It("returns the summary and warnings without droplet information", func() {
   643  						Expect(executeErr).ToNot(HaveOccurred())
   644  						Expect(summary).To(Equal(DetailedApplicationSummary{
   645  							ApplicationSummary: v7action.ApplicationSummary{
   646  								Application: resources.Application{
   647  									Name:  "some-app-name",
   648  									GUID:  "some-app-guid",
   649  									State: constant.ApplicationStarted,
   650  								},
   651  								ProcessSummaries: []ProcessSummary{
   652  									{
   653  										Process: resources.Process{
   654  											GUID:       "some-process-web-guid",
   655  											Type:       "web",
   656  											Command:    *types.NewFilteredString("[Redacted Value]"),
   657  											MemoryInMB: types.NullUint64{Value: 64, IsSet: true},
   658  										},
   659  										Sidecars: []resources.Sidecar{
   660  											{
   661  												GUID:    "sidecar-guid",
   662  												Name:    "sidecar_name",
   663  												Command: *types.NewFilteredString("my-sidecar-command"),
   664  											},
   665  										},
   666  										InstanceDetails: []ProcessInstance{
   667  											{
   668  												State:       constant.ProcessInstanceRunning,
   669  												CPU:         0.01,
   670  												MemoryUsage: 1000000,
   671  												DiskUsage:   2000000,
   672  												MemoryQuota: 3000000,
   673  												DiskQuota:   4000000,
   674  												Index:       0,
   675  											},
   676  										},
   677  									},
   678  									{
   679  										Process: resources.Process{
   680  											GUID:       "some-process-guid",
   681  											MemoryInMB: types.NullUint64{Value: 32, IsSet: true},
   682  											Type:       "some-type",
   683  											Command:    *types.NewFilteredString("some-start-command"),
   684  										},
   685  										Sidecars: []resources.Sidecar{
   686  											{
   687  												GUID:    "sidecar-guid",
   688  												Name:    "sidecar_name",
   689  												Command: *types.NewFilteredString("my-sidecar-command"),
   690  											},
   691  										},
   692  										InstanceDetails: []ProcessInstance{
   693  											{
   694  												State:       constant.ProcessInstanceRunning,
   695  												CPU:         0.01,
   696  												MemoryUsage: 1000000,
   697  												DiskUsage:   2000000,
   698  												MemoryQuota: 3000000,
   699  												DiskQuota:   4000000,
   700  												Index:       0,
   701  											},
   702  										},
   703  									},
   704  								},
   705  							},
   706  						}))
   707  
   708  						Expect(warnings).To(ConsistOf(
   709  							"get-apps-warning",
   710  							"get-app-processes-warning",
   711  							"get-process-by-type-warning",
   712  							"get-process-by-type-warning",
   713  							"get-process-instances-warning",
   714  							"get-process-instances-warning",
   715  							"get-process-sidecars-warning",
   716  							"get-process-sidecars-warning",
   717  							"get-app-droplet-warning",
   718  						))
   719  					})
   720  				})
   721  
   722  				When("getting the current droplet returns an error", func() {
   723  					var expectedErr error
   724  
   725  					BeforeEach(func() {
   726  						expectedErr = errors.New("some error")
   727  						fakeCloudControllerClient.GetApplicationDropletCurrentReturns(
   728  							resources.Droplet{},
   729  							ccv3.Warnings{"get-droplet-warning"},
   730  							expectedErr,
   731  						)
   732  					})
   733  
   734  					It("returns the error", func() {
   735  						Expect(executeErr).To(Equal(expectedErr))
   736  						Expect(warnings).To(ConsistOf(
   737  							"get-apps-warning",
   738  							"get-app-processes-warning",
   739  							"get-process-by-type-warning",
   740  							"get-process-by-type-warning",
   741  							"get-process-instances-warning",
   742  							"get-process-instances-warning",
   743  							"get-process-sidecars-warning",
   744  							"get-process-sidecars-warning",
   745  							"get-droplet-warning",
   746  						))
   747  					})
   748  				})
   749  			})
   750  
   751  			When("getting the app processes returns an error", func() {
   752  				var expectedErr error
   753  
   754  				BeforeEach(func() {
   755  					fakeCloudControllerClient.GetApplicationProcessesReturns(
   756  						[]resources.Process{
   757  							{
   758  								GUID: "some-process-guid",
   759  								Type: "some-type",
   760  							},
   761  						},
   762  						ccv3.Warnings{"get-app-processes-warning"},
   763  						nil,
   764  					)
   765  
   766  					fakeCloudControllerClient.GetProcessReturns(
   767  						resources.Process{},
   768  						ccv3.Warnings{"get-process-warning"},
   769  						nil,
   770  					)
   771  
   772  					expectedErr = errors.New("some error")
   773  					fakeCloudControllerClient.GetProcessInstancesReturns(
   774  						[]ccv3.ProcessInstance{},
   775  						ccv3.Warnings{"get-process-instances-warning"},
   776  						expectedErr,
   777  					)
   778  				})
   779  
   780  				It("returns the error and warnings", func() {
   781  					Expect(executeErr).To(Equal(expectedErr))
   782  					Expect(warnings).To(ConsistOf("get-apps-warning", "get-app-processes-warning", "get-process-warning", "get-process-instances-warning"))
   783  				})
   784  			})
   785  		})
   786  
   787  		When("no applications are returned", func() {
   788  			BeforeEach(func() {
   789  				fakeCloudControllerClient.GetApplicationsReturns(
   790  					[]resources.Application{},
   791  					ccv3.Warnings{"get-apps-warning"},
   792  					nil,
   793  				)
   794  			})
   795  
   796  			It("returns an error and warnings", func() {
   797  				Expect(executeErr).To(MatchError(actionerror.ApplicationNotFoundError{Name: appName}))
   798  				Expect(warnings).To(ConsistOf("get-apps-warning"))
   799  			})
   800  		})
   801  
   802  		When("getting the application fails", func() {
   803  			BeforeEach(func() {
   804  				fakeCloudControllerClient.GetApplicationsReturns(
   805  					[]resources.Application{
   806  						{
   807  							Name:  "some-app-name",
   808  							GUID:  "some-app-guid",
   809  							State: constant.ApplicationStarted,
   810  						},
   811  					},
   812  					ccv3.Warnings{"get-apps-warning"},
   813  					errors.New("failed to get app"),
   814  				)
   815  			})
   816  
   817  			It("returns the error and warnings", func() {
   818  				Expect(executeErr).To(MatchError("failed to get app"))
   819  				Expect(warnings).To(ConsistOf("get-apps-warning"))
   820  			})
   821  		})
   822  	})
   823  })