github.com/randomtask1155/cli@v6.41.1-0.20181227003417-a98eed78cbde+incompatible/actor/v7action/application_test.go (about)

     1  package v7action_test
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  	"time"
     8  
     9  	"code.cloudfoundry.org/cli/actor/actionerror"
    10  	. "code.cloudfoundry.org/cli/actor/v7action"
    11  	"code.cloudfoundry.org/cli/actor/v7action/v7actionfakes"
    12  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
    13  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
    14  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    15  
    16  	. "github.com/onsi/ginkgo"
    17  	. "github.com/onsi/gomega"
    18  )
    19  
    20  var _ = Describe("Application Actions", func() {
    21  	var (
    22  		actor                     *Actor
    23  		fakeCloudControllerClient *v7actionfakes.FakeCloudControllerClient
    24  		fakeConfig                *v7actionfakes.FakeConfig
    25  	)
    26  
    27  	BeforeEach(func() {
    28  		fakeCloudControllerClient = new(v7actionfakes.FakeCloudControllerClient)
    29  		fakeConfig = new(v7actionfakes.FakeConfig)
    30  		actor = NewActor(fakeCloudControllerClient, fakeConfig, nil, nil)
    31  	})
    32  
    33  	Describe("DeleteApplicationByNameAndSpace", func() {
    34  		var (
    35  			warnings   Warnings
    36  			executeErr error
    37  		)
    38  
    39  		JustBeforeEach(func() {
    40  			warnings, executeErr = actor.DeleteApplicationByNameAndSpace("some-app", "some-space-guid")
    41  		})
    42  
    43  		When("looking up the app guid fails", func() {
    44  			BeforeEach(func() {
    45  				fakeCloudControllerClient.GetApplicationsReturns([]ccv3.Application{}, ccv3.Warnings{"some-get-app-warning"}, errors.New("some-get-app-error"))
    46  			})
    47  
    48  			It("returns the warnings and error", func() {
    49  				Expect(warnings).To(ConsistOf("some-get-app-warning"))
    50  				Expect(executeErr).To(MatchError("some-get-app-error"))
    51  			})
    52  		})
    53  
    54  		When("looking up the app guid succeeds", func() {
    55  			BeforeEach(func() {
    56  				fakeCloudControllerClient.GetApplicationsReturns([]ccv3.Application{{Name: "some-app", GUID: "abc123"}}, ccv3.Warnings{"some-get-app-warning"}, nil)
    57  			})
    58  
    59  			When("sending the delete fails", func() {
    60  				BeforeEach(func() {
    61  					fakeCloudControllerClient.DeleteApplicationReturns("", ccv3.Warnings{"some-delete-app-warning"}, errors.New("some-delete-app-error"))
    62  				})
    63  
    64  				It("returns the warnings and error", func() {
    65  					Expect(warnings).To(ConsistOf("some-get-app-warning", "some-delete-app-warning"))
    66  					Expect(executeErr).To(MatchError("some-delete-app-error"))
    67  				})
    68  			})
    69  
    70  			When("sending the delete succeeds", func() {
    71  				BeforeEach(func() {
    72  					fakeCloudControllerClient.DeleteApplicationReturns("/some-job-url", ccv3.Warnings{"some-delete-app-warning"}, nil)
    73  				})
    74  
    75  				When("polling fails", func() {
    76  					BeforeEach(func() {
    77  						fakeCloudControllerClient.PollJobReturns(ccv3.Warnings{"some-poll-warning"}, errors.New("some-poll-error"))
    78  					})
    79  
    80  					It("returns the warnings and poll error", func() {
    81  						Expect(warnings).To(ConsistOf("some-get-app-warning", "some-delete-app-warning", "some-poll-warning"))
    82  						Expect(executeErr).To(MatchError("some-poll-error"))
    83  					})
    84  				})
    85  
    86  				When("polling succeeds", func() {
    87  					BeforeEach(func() {
    88  						fakeCloudControllerClient.PollJobReturns(ccv3.Warnings{"some-poll-warning"}, nil)
    89  					})
    90  
    91  					It("returns all the warnings and no error", func() {
    92  						Expect(warnings).To(ConsistOf("some-get-app-warning", "some-delete-app-warning", "some-poll-warning"))
    93  						Expect(executeErr).ToNot(HaveOccurred())
    94  					})
    95  				})
    96  			})
    97  		})
    98  	})
    99  
   100  	Describe("GetApplicationByNameAndSpace", func() {
   101  		When("the app exists", func() {
   102  			BeforeEach(func() {
   103  				fakeCloudControllerClient.GetApplicationsReturns(
   104  					[]ccv3.Application{
   105  						{
   106  							Name: "some-app-name",
   107  							GUID: "some-app-guid",
   108  						},
   109  					},
   110  					ccv3.Warnings{"some-warning"},
   111  					nil,
   112  				)
   113  			})
   114  
   115  			It("returns the application and warnings", func() {
   116  				app, warnings, err := actor.GetApplicationByNameAndSpace("some-app-name", "some-space-guid")
   117  				Expect(err).ToNot(HaveOccurred())
   118  				Expect(app).To(Equal(Application{
   119  					Name: "some-app-name",
   120  					GUID: "some-app-guid",
   121  				}))
   122  				Expect(warnings).To(ConsistOf("some-warning"))
   123  
   124  				Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   125  				Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   126  					ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name"}},
   127  					ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
   128  				))
   129  			})
   130  		})
   131  
   132  		When("the cloud controller client returns an error", func() {
   133  			var expectedError error
   134  
   135  			BeforeEach(func() {
   136  				expectedError = errors.New("I am a CloudControllerClient Error")
   137  				fakeCloudControllerClient.GetApplicationsReturns(
   138  					[]ccv3.Application{},
   139  					ccv3.Warnings{"some-warning"},
   140  					expectedError)
   141  			})
   142  
   143  			It("returns the warnings and the error", func() {
   144  				_, warnings, err := actor.GetApplicationByNameAndSpace("some-app-name", "some-space-guid")
   145  				Expect(warnings).To(ConsistOf("some-warning"))
   146  				Expect(err).To(MatchError(expectedError))
   147  			})
   148  		})
   149  
   150  		When("the app does not exist", func() {
   151  			BeforeEach(func() {
   152  				fakeCloudControllerClient.GetApplicationsReturns(
   153  					[]ccv3.Application{},
   154  					ccv3.Warnings{"some-warning"},
   155  					nil,
   156  				)
   157  			})
   158  
   159  			It("returns an ApplicationNotFoundError and the warnings", func() {
   160  				_, warnings, err := actor.GetApplicationByNameAndSpace("some-app-name", "some-space-guid")
   161  				Expect(warnings).To(ConsistOf("some-warning"))
   162  				Expect(err).To(MatchError(actionerror.ApplicationNotFoundError{Name: "some-app-name"}))
   163  			})
   164  		})
   165  	})
   166  
   167  	Describe("GetApplicationsBySpace", func() {
   168  		When("the there are applications in the space", func() {
   169  			BeforeEach(func() {
   170  				fakeCloudControllerClient.GetApplicationsReturns(
   171  					[]ccv3.Application{
   172  						{
   173  							GUID: "some-app-guid-1",
   174  							Name: "some-app-1",
   175  						},
   176  						{
   177  							GUID: "some-app-guid-2",
   178  							Name: "some-app-2",
   179  						},
   180  					},
   181  					ccv3.Warnings{"warning-1", "warning-2"},
   182  					nil,
   183  				)
   184  			})
   185  
   186  			It("returns the application and warnings", func() {
   187  				apps, warnings, err := actor.GetApplicationsBySpace("some-space-guid")
   188  				Expect(err).ToNot(HaveOccurred())
   189  				Expect(apps).To(ConsistOf(
   190  					Application{
   191  						GUID: "some-app-guid-1",
   192  						Name: "some-app-1",
   193  					},
   194  					Application{
   195  						GUID: "some-app-guid-2",
   196  						Name: "some-app-2",
   197  					},
   198  				))
   199  				Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   200  
   201  				Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   202  				Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   203  					ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
   204  				))
   205  			})
   206  		})
   207  
   208  		When("the cloud controller client returns an error", func() {
   209  			var expectedError error
   210  
   211  			BeforeEach(func() {
   212  				expectedError = errors.New("I am a CloudControllerClient Error")
   213  				fakeCloudControllerClient.GetApplicationsReturns(
   214  					[]ccv3.Application{},
   215  					ccv3.Warnings{"some-warning"},
   216  					expectedError)
   217  			})
   218  
   219  			It("returns the error and warnings", func() {
   220  				_, warnings, err := actor.GetApplicationsBySpace("some-space-guid")
   221  				Expect(warnings).To(ConsistOf("some-warning"))
   222  				Expect(err).To(MatchError(expectedError))
   223  			})
   224  		})
   225  	})
   226  
   227  	Describe("CreateApplicationInSpace", func() {
   228  		var (
   229  			application Application
   230  			warnings    Warnings
   231  			err         error
   232  		)
   233  
   234  		JustBeforeEach(func() {
   235  			application, warnings, err = actor.CreateApplicationInSpace(Application{
   236  				Name:                "some-app-name",
   237  				LifecycleType:       constant.AppLifecycleTypeBuildpack,
   238  				LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   239  			}, "some-space-guid")
   240  		})
   241  
   242  		When("the app successfully gets created", func() {
   243  			BeforeEach(func() {
   244  				fakeCloudControllerClient.CreateApplicationReturns(
   245  					ccv3.Application{
   246  						Name:                "some-app-name",
   247  						GUID:                "some-app-guid",
   248  						LifecycleType:       constant.AppLifecycleTypeBuildpack,
   249  						LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   250  					},
   251  					ccv3.Warnings{"some-warning"},
   252  					nil,
   253  				)
   254  			})
   255  
   256  			It("creates and returns the application and warnings", func() {
   257  				Expect(err).ToNot(HaveOccurred())
   258  				Expect(application).To(Equal(Application{
   259  					Name:                "some-app-name",
   260  					GUID:                "some-app-guid",
   261  					LifecycleType:       constant.AppLifecycleTypeBuildpack,
   262  					LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   263  				}))
   264  				Expect(warnings).To(ConsistOf("some-warning"))
   265  
   266  				Expect(fakeCloudControllerClient.CreateApplicationCallCount()).To(Equal(1))
   267  				Expect(fakeCloudControllerClient.CreateApplicationArgsForCall(0)).To(Equal(ccv3.Application{
   268  					Name: "some-app-name",
   269  					Relationships: ccv3.Relationships{
   270  						constant.RelationshipTypeSpace: ccv3.Relationship{GUID: "some-space-guid"},
   271  					},
   272  					LifecycleType:       constant.AppLifecycleTypeBuildpack,
   273  					LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   274  				}))
   275  			})
   276  		})
   277  
   278  		When("the cc client returns an error", func() {
   279  			var expectedError error
   280  
   281  			BeforeEach(func() {
   282  				expectedError = errors.New("I am a CloudControllerClient Error")
   283  				fakeCloudControllerClient.CreateApplicationReturns(
   284  					ccv3.Application{},
   285  					ccv3.Warnings{"some-warning"},
   286  					expectedError,
   287  				)
   288  			})
   289  
   290  			It("raises the error and warnings", func() {
   291  				Expect(err).To(MatchError(expectedError))
   292  				Expect(warnings).To(ConsistOf("some-warning"))
   293  			})
   294  		})
   295  
   296  		When("the cc client returns an NameNotUniqueInSpaceError", func() {
   297  			BeforeEach(func() {
   298  				fakeCloudControllerClient.CreateApplicationReturns(
   299  					ccv3.Application{},
   300  					ccv3.Warnings{"some-warning"},
   301  					ccerror.NameNotUniqueInSpaceError{},
   302  				)
   303  			})
   304  
   305  			It("returns the ApplicationAlreadyExistsError and warnings", func() {
   306  				Expect(err).To(MatchError(actionerror.ApplicationAlreadyExistsError{Name: "some-app-name"}))
   307  				Expect(warnings).To(ConsistOf("some-warning"))
   308  			})
   309  		})
   310  	})
   311  
   312  	Describe("UpdateApplication", func() {
   313  		var (
   314  			submitApp, resultApp Application
   315  			warnings             Warnings
   316  			err                  error
   317  		)
   318  
   319  		JustBeforeEach(func() {
   320  			submitApp = Application{
   321  				GUID:                "some-app-guid",
   322  				StackName:           "some-stack-name",
   323  				LifecycleType:       constant.AppLifecycleTypeBuildpack,
   324  				LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   325  			}
   326  			resultApp, warnings, err = actor.UpdateApplication(submitApp)
   327  		})
   328  
   329  		When("the app successfully gets updated", func() {
   330  			var apiResponseApp ccv3.Application
   331  
   332  			BeforeEach(func() {
   333  				apiResponseApp = ccv3.Application{
   334  					GUID:                "response-app-guid",
   335  					StackName:           "response-stack-name",
   336  					LifecycleType:       constant.AppLifecycleTypeBuildpack,
   337  					LifecycleBuildpacks: []string{"response-buildpack-1", "response-buildpack-2"},
   338  				}
   339  				fakeCloudControllerClient.UpdateApplicationReturns(
   340  					apiResponseApp,
   341  					ccv3.Warnings{"some-warning"},
   342  					nil,
   343  				)
   344  			})
   345  
   346  			It("creates and returns the application and warnings", func() {
   347  				Expect(err).ToNot(HaveOccurred())
   348  				Expect(resultApp).To(Equal(Application{
   349  					GUID:                apiResponseApp.GUID,
   350  					StackName:           apiResponseApp.StackName,
   351  					LifecycleType:       apiResponseApp.LifecycleType,
   352  					LifecycleBuildpacks: apiResponseApp.LifecycleBuildpacks,
   353  				}))
   354  				Expect(warnings).To(ConsistOf("some-warning"))
   355  
   356  				Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(1))
   357  				Expect(fakeCloudControllerClient.UpdateApplicationArgsForCall(0)).To(Equal(ccv3.Application{
   358  					GUID:                submitApp.GUID,
   359  					StackName:           submitApp.StackName,
   360  					LifecycleType:       submitApp.LifecycleType,
   361  					LifecycleBuildpacks: submitApp.LifecycleBuildpacks,
   362  				}))
   363  			})
   364  		})
   365  
   366  		When("the cc client returns an error", func() {
   367  			var expectedError error
   368  
   369  			BeforeEach(func() {
   370  				expectedError = errors.New("I am a CloudControllerClient Error")
   371  				fakeCloudControllerClient.UpdateApplicationReturns(
   372  					ccv3.Application{},
   373  					ccv3.Warnings{"some-warning"},
   374  					expectedError,
   375  				)
   376  			})
   377  
   378  			It("raises the error and warnings", func() {
   379  				Expect(err).To(MatchError(expectedError))
   380  				Expect(warnings).To(ConsistOf("some-warning"))
   381  			})
   382  		})
   383  	})
   384  
   385  	Describe("PollStart", func() {
   386  		var (
   387  			appGUID string
   388  
   389  			warnings   Warnings
   390  			executeErr error
   391  		)
   392  
   393  		BeforeEach(func() {
   394  			appGUID = "some-guid"
   395  		})
   396  
   397  		JustBeforeEach(func() {
   398  			warnings, executeErr = actor.PollStart(appGUID)
   399  		})
   400  
   401  		When("getting the application processes fails", func() {
   402  			BeforeEach(func() {
   403  				fakeCloudControllerClient.GetApplicationProcessesReturns(nil, ccv3.Warnings{"get-app-warning-1", "get-app-warning-2"}, errors.New("some-error"))
   404  			})
   405  
   406  			It("returns the error and all warnings", func() {
   407  				Expect(executeErr).To(MatchError(errors.New("some-error")))
   408  				Expect(warnings).To(ConsistOf("get-app-warning-1", "get-app-warning-2"))
   409  			})
   410  		})
   411  
   412  		When("getting the application processes succeeds", func() {
   413  			var processes []ccv3.Process
   414  
   415  			BeforeEach(func() {
   416  				fakeConfig.StartupTimeoutReturns(time.Second)
   417  				fakeConfig.PollingIntervalReturns(0)
   418  			})
   419  
   420  			When("there is a single process", func() {
   421  				BeforeEach(func() {
   422  					processes = []ccv3.Process{{GUID: "abc123"}}
   423  					fakeCloudControllerClient.GetApplicationProcessesReturns(
   424  						processes,
   425  						ccv3.Warnings{"get-app-warning-1"}, nil)
   426  				})
   427  
   428  				When("the polling times out", func() {
   429  					BeforeEach(func() {
   430  						fakeConfig.StartupTimeoutReturns(time.Millisecond)
   431  						fakeConfig.PollingIntervalReturns(time.Millisecond * 2)
   432  						fakeCloudControllerClient.GetProcessInstancesReturns(
   433  							[]ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}},
   434  							ccv3.Warnings{"get-process-warning-1", "get-process-warning-2"},
   435  							nil,
   436  						)
   437  					})
   438  
   439  					It("returns the timeout error", func() {
   440  						Expect(executeErr).To(MatchError(actionerror.StartupTimeoutError{}))
   441  						Expect(warnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2"))
   442  					})
   443  
   444  					It("gets polling and timeout values from the config", func() {
   445  						Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1))
   446  						Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(1))
   447  					})
   448  				})
   449  
   450  				When("getting the process instances errors", func() {
   451  					BeforeEach(func() {
   452  						fakeCloudControllerClient.GetProcessInstancesReturns(
   453  							nil,
   454  							ccv3.Warnings{"get-process-warning-1", "get-process-warning-2"},
   455  							errors.New("some-error"),
   456  						)
   457  					})
   458  
   459  					It("returns the error", func() {
   460  						Expect(executeErr).To(MatchError("some-error"))
   461  						Expect(warnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2"))
   462  					})
   463  				})
   464  
   465  				When("getting the process instances succeeds", func() {
   466  					var (
   467  						initialInstanceStates    []ccv3.ProcessInstance
   468  						eventualInstanceStates   []ccv3.ProcessInstance
   469  						processInstanceCallCount int
   470  					)
   471  
   472  					BeforeEach(func() {
   473  						processInstanceCallCount = 0
   474  
   475  						fakeCloudControllerClient.GetProcessInstancesStub = func(processGuid string) ([]ccv3.ProcessInstance, ccv3.Warnings, error) {
   476  							defer func() { processInstanceCallCount++ }()
   477  							if processInstanceCallCount == 0 {
   478  								return initialInstanceStates,
   479  									ccv3.Warnings{"get-process-warning-1", "get-process-warning-2"},
   480  									nil
   481  							} else {
   482  								return eventualInstanceStates,
   483  									ccv3.Warnings{fmt.Sprintf("get-process-warning-%d", processInstanceCallCount+2)},
   484  									nil
   485  							}
   486  						}
   487  					})
   488  
   489  					When("there are no process instances", func() {
   490  						BeforeEach(func() {
   491  							initialInstanceStates = []ccv3.ProcessInstance{}
   492  							eventualInstanceStates = []ccv3.ProcessInstance{}
   493  						})
   494  
   495  						It("should not return an error", func() {
   496  							Expect(executeErr).NotTo(HaveOccurred())
   497  						})
   498  
   499  						It("should only call GetProcessInstances once before exiting", func() {
   500  							Expect(processInstanceCallCount).To(Equal(1))
   501  						})
   502  
   503  						It("should return correct warnings", func() {
   504  							Expect(warnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2"))
   505  						})
   506  					})
   507  
   508  					When("all instances become running by the second call", func() {
   509  						BeforeEach(func() {
   510  							initialInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}}
   511  							eventualInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceRunning}, {State: constant.ProcessInstanceRunning}}
   512  						})
   513  
   514  						It("should not return an error", func() {
   515  							Expect(executeErr).NotTo(HaveOccurred())
   516  						})
   517  
   518  						It("should call GetProcessInstances twice", func() {
   519  							Expect(processInstanceCallCount).To(Equal(2))
   520  						})
   521  
   522  						It("should return correct warnings", func() {
   523  							Expect(warnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2", "get-process-warning-3"))
   524  						})
   525  					})
   526  
   527  					When("at least one instance has become running by the second call", func() {
   528  						BeforeEach(func() {
   529  							initialInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}}
   530  							eventualInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceRunning}}
   531  						})
   532  
   533  						It("should not return an error", func() {
   534  							Expect(executeErr).NotTo(HaveOccurred())
   535  						})
   536  
   537  						It("should call GetProcessInstances twice", func() {
   538  							Expect(processInstanceCallCount).To(Equal(2))
   539  						})
   540  
   541  						It("should return correct warnings", func() {
   542  							Expect(warnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2", "get-process-warning-3"))
   543  						})
   544  					})
   545  
   546  					When("all of the instances have crashed by the second call", func() {
   547  						BeforeEach(func() {
   548  							initialInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}}
   549  							eventualInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceCrashed}, {State: constant.ProcessInstanceCrashed}, {State: constant.ProcessInstanceCrashed}}
   550  						})
   551  
   552  						It("should not return an error", func() {
   553  							Expect(executeErr).To(MatchError(actionerror.AllInstancesCrashedError{}))
   554  						})
   555  
   556  						It("should call GetProcessInstances twice", func() {
   557  							Expect(processInstanceCallCount).To(Equal(2))
   558  						})
   559  
   560  						It("should return correct warnings", func() {
   561  							Expect(warnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2", "get-process-warning-3"))
   562  						})
   563  					})
   564  				})
   565  			})
   566  
   567  			Context("where there are multiple processes", func() {
   568  				var (
   569  					processInstanceCallCount int
   570  				)
   571  
   572  				BeforeEach(func() {
   573  					processInstanceCallCount = 0
   574  					fakeConfig.StartupTimeoutReturns(time.Millisecond)
   575  					fakeConfig.PollingIntervalReturns(time.Millisecond * 2)
   576  
   577  					fakeCloudControllerClient.GetProcessInstancesStub = func(processGuid string) ([]ccv3.ProcessInstance, ccv3.Warnings, error) {
   578  						defer func() { processInstanceCallCount++ }()
   579  						if strings.HasPrefix(processGuid, "good") {
   580  							return []ccv3.ProcessInstance{{State: constant.ProcessInstanceRunning}}, nil, nil
   581  						} else {
   582  							return []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}}, nil, nil
   583  						}
   584  					}
   585  				})
   586  
   587  				When("none of the processes are ready", func() {
   588  					BeforeEach(func() {
   589  						processes = []ccv3.Process{{GUID: "bad-1"}, {GUID: "bad-2"}}
   590  						fakeCloudControllerClient.GetApplicationProcessesReturns(
   591  							processes,
   592  							ccv3.Warnings{"get-app-warning-1"}, nil)
   593  					})
   594  
   595  					It("returns the timeout error", func() {
   596  						Expect(executeErr).To(MatchError(actionerror.StartupTimeoutError{}))
   597  					})
   598  				})
   599  
   600  				When("some of the processes are ready", func() {
   601  					BeforeEach(func() {
   602  						processes = []ccv3.Process{{GUID: "bad-1"}, {GUID: "good-1"}}
   603  						fakeCloudControllerClient.GetApplicationProcessesReturns(
   604  							processes,
   605  							ccv3.Warnings{"get-app-warning-1"}, nil)
   606  					})
   607  
   608  					It("returns the timeout error", func() {
   609  						Expect(executeErr).To(MatchError(actionerror.StartupTimeoutError{}))
   610  					})
   611  				})
   612  
   613  				When("all of the processes are ready", func() {
   614  					BeforeEach(func() {
   615  						processes = []ccv3.Process{{GUID: "good-1"}, {GUID: "good-2"}}
   616  						fakeCloudControllerClient.GetApplicationProcessesReturns(
   617  							processes,
   618  							ccv3.Warnings{"get-app-warning-1"}, nil)
   619  					})
   620  
   621  					It("returns nil", func() {
   622  						Expect(executeErr).ToNot(HaveOccurred())
   623  					})
   624  				})
   625  			})
   626  		})
   627  	})
   628  
   629  	Describe("SetApplicationProcessHealthCheckTypeByNameAndSpace", func() {
   630  		var (
   631  			healthCheckType     constant.HealthCheckType
   632  			healthCheckEndpoint string
   633  
   634  			warnings Warnings
   635  			err      error
   636  			app      Application
   637  		)
   638  
   639  		BeforeEach(func() {
   640  			healthCheckType = constant.HTTP
   641  			healthCheckEndpoint = "some-http-endpoint"
   642  		})
   643  
   644  		JustBeforeEach(func() {
   645  			app, warnings, err = actor.SetApplicationProcessHealthCheckTypeByNameAndSpace(
   646  				"some-app-name",
   647  				"some-space-guid",
   648  				healthCheckType,
   649  				healthCheckEndpoint,
   650  				"some-process-type",
   651  				42,
   652  			)
   653  		})
   654  
   655  		When("getting application returns an error", func() {
   656  			var expectedErr error
   657  
   658  			BeforeEach(func() {
   659  				expectedErr = errors.New("some-error")
   660  				fakeCloudControllerClient.GetApplicationsReturns(
   661  					[]ccv3.Application{},
   662  					ccv3.Warnings{"some-warning"},
   663  					expectedErr,
   664  				)
   665  			})
   666  
   667  			It("returns the error and warnings", func() {
   668  				Expect(err).To(Equal(expectedErr))
   669  				Expect(warnings).To(ConsistOf("some-warning"))
   670  			})
   671  		})
   672  
   673  		When("application exists", func() {
   674  			var ccv3App ccv3.Application
   675  
   676  			BeforeEach(func() {
   677  				ccv3App = ccv3.Application{
   678  					GUID: "some-app-guid",
   679  				}
   680  
   681  				fakeCloudControllerClient.GetApplicationsReturns(
   682  					[]ccv3.Application{ccv3App},
   683  					ccv3.Warnings{"some-warning"},
   684  					nil,
   685  				)
   686  			})
   687  
   688  			When("setting the health check returns an error", func() {
   689  				var expectedErr error
   690  
   691  				BeforeEach(func() {
   692  					expectedErr = errors.New("some-error")
   693  					fakeCloudControllerClient.GetApplicationProcessByTypeReturns(
   694  						ccv3.Process{},
   695  						ccv3.Warnings{"some-process-warning"},
   696  						expectedErr,
   697  					)
   698  				})
   699  
   700  				It("returns the error and warnings", func() {
   701  					Expect(err).To(Equal(expectedErr))
   702  					Expect(warnings).To(ConsistOf("some-warning", "some-process-warning"))
   703  				})
   704  			})
   705  
   706  			When("application process exists", func() {
   707  				BeforeEach(func() {
   708  					fakeCloudControllerClient.GetApplicationProcessByTypeReturns(
   709  						ccv3.Process{
   710  							GUID: "some-process-guid",
   711  						},
   712  						ccv3.Warnings{"some-process-warning"},
   713  						nil,
   714  					)
   715  
   716  					fakeCloudControllerClient.UpdateProcessReturns(
   717  						ccv3.Process{GUID: "some-process-guid"},
   718  						ccv3.Warnings{"some-health-check-warning"},
   719  						nil,
   720  					)
   721  				})
   722  
   723  				It("returns the application", func() {
   724  					Expect(err).NotTo(HaveOccurred())
   725  					Expect(warnings).To(ConsistOf("some-warning", "some-process-warning", "some-health-check-warning"))
   726  
   727  					Expect(app).To(Equal(Application{
   728  						GUID: ccv3App.GUID,
   729  					}))
   730  
   731  					Expect(fakeCloudControllerClient.GetApplicationProcessByTypeCallCount()).To(Equal(1))
   732  					appGUID, processType := fakeCloudControllerClient.GetApplicationProcessByTypeArgsForCall(0)
   733  					Expect(appGUID).To(Equal("some-app-guid"))
   734  					Expect(processType).To(Equal("some-process-type"))
   735  
   736  					Expect(fakeCloudControllerClient.UpdateProcessCallCount()).To(Equal(1))
   737  					process := fakeCloudControllerClient.UpdateProcessArgsForCall(0)
   738  					Expect(process.GUID).To(Equal("some-process-guid"))
   739  					Expect(process.HealthCheckType).To(Equal(constant.HTTP))
   740  					Expect(process.HealthCheckEndpoint).To(Equal("some-http-endpoint"))
   741  					Expect(process.HealthCheckInvocationTimeout).To(Equal(42))
   742  				})
   743  			})
   744  		})
   745  	})
   746  
   747  	Describe("StopApplication", func() {
   748  		var (
   749  			warnings   Warnings
   750  			executeErr error
   751  		)
   752  
   753  		JustBeforeEach(func() {
   754  			warnings, executeErr = actor.StopApplication("some-app-guid")
   755  		})
   756  
   757  		When("there are no client errors", func() {
   758  			BeforeEach(func() {
   759  				fakeCloudControllerClient.UpdateApplicationStopReturns(
   760  					ccv3.Application{GUID: "some-app-guid"},
   761  					ccv3.Warnings{"stop-application-warning"},
   762  					nil,
   763  				)
   764  			})
   765  
   766  			It("stops the application", func() {
   767  				Expect(executeErr).ToNot(HaveOccurred())
   768  				Expect(warnings).To(ConsistOf("stop-application-warning"))
   769  
   770  				Expect(fakeCloudControllerClient.UpdateApplicationStopCallCount()).To(Equal(1))
   771  				Expect(fakeCloudControllerClient.UpdateApplicationStopArgsForCall(0)).To(Equal("some-app-guid"))
   772  			})
   773  		})
   774  
   775  		When("stopping the application fails", func() {
   776  			var expectedErr error
   777  			BeforeEach(func() {
   778  				expectedErr = errors.New("some set stop-application error")
   779  				fakeCloudControllerClient.UpdateApplicationStopReturns(
   780  					ccv3.Application{},
   781  					ccv3.Warnings{"stop-application-warning"},
   782  					expectedErr,
   783  				)
   784  			})
   785  
   786  			It("returns the error", func() {
   787  				Expect(executeErr).To(Equal(expectedErr))
   788  				Expect(warnings).To(ConsistOf("stop-application-warning"))
   789  			})
   790  		})
   791  	})
   792  
   793  	Describe("StartApplication", func() {
   794  		When("there are no client errors", func() {
   795  			BeforeEach(func() {
   796  				fakeCloudControllerClient.UpdateApplicationStartReturns(
   797  					ccv3.Application{GUID: "some-app-guid"},
   798  					ccv3.Warnings{"start-application-warning"},
   799  					nil,
   800  				)
   801  			})
   802  
   803  			It("starts the application", func() {
   804  				app, warnings, err := actor.StartApplication("some-app-guid")
   805  
   806  				Expect(err).ToNot(HaveOccurred())
   807  				Expect(warnings).To(ConsistOf("start-application-warning"))
   808  				Expect(app).To(Equal(Application{GUID: "some-app-guid"}))
   809  
   810  				Expect(fakeCloudControllerClient.UpdateApplicationStartCallCount()).To(Equal(1))
   811  				Expect(fakeCloudControllerClient.UpdateApplicationStartArgsForCall(0)).To(Equal("some-app-guid"))
   812  			})
   813  		})
   814  
   815  		When("starting the application fails", func() {
   816  			var expectedErr error
   817  			BeforeEach(func() {
   818  				expectedErr = errors.New("some set start-application error")
   819  				fakeCloudControllerClient.UpdateApplicationStartReturns(
   820  					ccv3.Application{},
   821  					ccv3.Warnings{"start-application-warning"},
   822  					expectedErr,
   823  				)
   824  			})
   825  
   826  			It("returns the error", func() {
   827  				_, warnings, err := actor.StartApplication("some-app-guid")
   828  
   829  				Expect(err).To(Equal(expectedErr))
   830  				Expect(warnings).To(ConsistOf("start-application-warning"))
   831  			})
   832  		})
   833  	})
   834  
   835  	Describe("RestartApplication", func() {
   836  		var (
   837  			warnings   Warnings
   838  			executeErr error
   839  		)
   840  
   841  		BeforeEach(func() {
   842  			fakeConfig.StartupTimeoutReturns(time.Second)
   843  			fakeConfig.PollingIntervalReturns(0)
   844  		})
   845  
   846  		JustBeforeEach(func() {
   847  			warnings, executeErr = actor.RestartApplication("some-app-guid")
   848  		})
   849  
   850  		When("restarting the application is successful", func() {
   851  			BeforeEach(func() {
   852  				fakeCloudControllerClient.UpdateApplicationRestartReturns(
   853  					ccv3.Application{GUID: "some-app-guid"},
   854  					ccv3.Warnings{"restart-application-warning"},
   855  					nil,
   856  				)
   857  			})
   858  
   859  			When("polling the application start is successful", func() {
   860  				BeforeEach(func() {
   861  					processes := []ccv3.Process{{GUID: "some-process-guid"}}
   862  					fakeCloudControllerClient.GetApplicationProcessesReturns(processes, ccv3.Warnings{"get-process-warnings"}, nil)
   863  					fakeCloudControllerClient.GetProcessInstancesReturns(nil, ccv3.Warnings{"some-process-instance-warnings"}, nil)
   864  				})
   865  
   866  				It("returns all the warnings", func() {
   867  					Expect(executeErr).ToNot(HaveOccurred())
   868  					Expect(warnings).To(ConsistOf("restart-application-warning", "get-process-warnings", "some-process-instance-warnings"))
   869  				})
   870  
   871  				It("calls restart", func() {
   872  					Expect(fakeCloudControllerClient.UpdateApplicationRestartCallCount()).To(Equal(1))
   873  					Expect(fakeCloudControllerClient.UpdateApplicationRestartArgsForCall(0)).To(Equal("some-app-guid"))
   874  				})
   875  
   876  				It("polls for the application's process to start", func() {
   877  					Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(1))
   878  					Expect(fakeCloudControllerClient.GetApplicationProcessesArgsForCall(0)).To(Equal("some-app-guid"))
   879  
   880  					Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(1))
   881  					Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("some-process-guid"))
   882  				})
   883  			})
   884  
   885  			When("polling the application start errors", func() {
   886  				var expectedErr error
   887  				BeforeEach(func() {
   888  					expectedErr = errors.New("some polling error")
   889  					fakeCloudControllerClient.GetApplicationProcessesReturns(nil, ccv3.Warnings{"get-process-warnings"}, expectedErr)
   890  				})
   891  
   892  				It("returns the warnings and error", func() {
   893  					Expect(executeErr).To(Equal(expectedErr))
   894  					Expect(warnings).To(ConsistOf("restart-application-warning", "get-process-warnings"))
   895  				})
   896  			})
   897  		})
   898  
   899  		When("restarting the application fails", func() {
   900  			var expectedErr error
   901  			BeforeEach(func() {
   902  				expectedErr = errors.New("some set restart-application error")
   903  				fakeCloudControllerClient.UpdateApplicationRestartReturns(
   904  					ccv3.Application{},
   905  					ccv3.Warnings{"restart-application-warning"},
   906  					expectedErr,
   907  				)
   908  			})
   909  
   910  			It("returns the warnings and error", func() {
   911  				Expect(executeErr).To(Equal(expectedErr))
   912  				Expect(warnings).To(ConsistOf("restart-application-warning"))
   913  			})
   914  		})
   915  	})
   916  })