github.com/swisscom/cloudfoundry-cli@v7.1.0+incompatible/actor/v2action/application_test.go (about)

     1  package v2action_test
     2  
     3  import (
     4  	"errors"
     5  	"time"
     6  
     7  	"code.cloudfoundry.org/cli/actor/actionerror"
     8  	. "code.cloudfoundry.org/cli/actor/v2action"
     9  	"code.cloudfoundry.org/cli/actor/v2action/v2actionfakes"
    10  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
    11  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv2"
    12  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/constant"
    13  	"code.cloudfoundry.org/cli/types"
    14  	. "github.com/onsi/ginkgo"
    15  	. "github.com/onsi/gomega"
    16  )
    17  
    18  var _ = Describe("Application Actions", func() {
    19  	var (
    20  		actor                     *Actor
    21  		fakeCloudControllerClient *v2actionfakes.FakeCloudControllerClient
    22  		fakeConfig                *v2actionfakes.FakeConfig
    23  	)
    24  
    25  	BeforeEach(func() {
    26  		actor, fakeCloudControllerClient, _, fakeConfig = NewTestActor()
    27  		fakeConfig.DialTimeoutReturns(time.Millisecond)
    28  	})
    29  
    30  	Describe("Application", func() {
    31  		var app Application
    32  		BeforeEach(func() {
    33  			app = Application{}
    34  		})
    35  
    36  		Describe("CalculatedCommand", func() {
    37  			When("command is set", func() {
    38  				BeforeEach(func() {
    39  					app.Command = types.FilteredString{IsSet: true, Value: "foo"}
    40  					app.DetectedStartCommand = types.FilteredString{IsSet: true, Value: "bar"}
    41  				})
    42  
    43  				It("returns back the command", func() {
    44  					Expect(app.CalculatedCommand()).To(Equal("foo"))
    45  				})
    46  			})
    47  
    48  			Context("only detected start command is set", func() {
    49  				BeforeEach(func() {
    50  					app.DetectedStartCommand = types.FilteredString{IsSet: true, Value: "bar"}
    51  				})
    52  
    53  				It("returns back the detected start command", func() {
    54  					Expect(app.CalculatedCommand()).To(Equal("bar"))
    55  				})
    56  			})
    57  
    58  			Context("neither command nor detected start command are set", func() {
    59  				It("returns an empty string", func() {
    60  					Expect(app.CalculatedCommand()).To(BeEmpty())
    61  				})
    62  			})
    63  		})
    64  
    65  		Describe("CalculatedBuildpack", func() {
    66  			When("buildpack is set", func() {
    67  				BeforeEach(func() {
    68  					app.Buildpack = types.FilteredString{IsSet: true, Value: "foo"}
    69  					app.DetectedBuildpack = types.FilteredString{IsSet: true, Value: "bar"}
    70  				})
    71  
    72  				It("returns back the buildpack", func() {
    73  					Expect(app.CalculatedBuildpack()).To(Equal("foo"))
    74  				})
    75  			})
    76  
    77  			Context("only detected buildpack is set", func() {
    78  				BeforeEach(func() {
    79  					app.DetectedBuildpack = types.FilteredString{IsSet: true, Value: "bar"}
    80  				})
    81  
    82  				It("returns back the detected buildpack", func() {
    83  					Expect(app.CalculatedBuildpack()).To(Equal("bar"))
    84  				})
    85  			})
    86  
    87  			Context("neither buildpack nor detected buildpack are set", func() {
    88  				It("returns an empty string", func() {
    89  					Expect(app.CalculatedBuildpack()).To(BeEmpty())
    90  				})
    91  			})
    92  		})
    93  
    94  		Describe("CalculatedHealthCheckEndpoint", func() {
    95  			When("the health check type is http", func() {
    96  				BeforeEach(func() {
    97  					app.HealthCheckType = constant.ApplicationHealthCheckHTTP
    98  					app.HealthCheckHTTPEndpoint = "/some-endpoint"
    99  				})
   100  
   101  				It("returns the endpoint field", func() {
   102  					Expect(app.CalculatedHealthCheckEndpoint()).To(Equal(
   103  						"/some-endpoint"))
   104  				})
   105  			})
   106  
   107  			When("the health check type is not http", func() {
   108  				BeforeEach(func() {
   109  					app.HealthCheckType = constant.ApplicationHealthCheckProcess
   110  					app.HealthCheckHTTPEndpoint = "/some-endpoint"
   111  				})
   112  
   113  				It("returns the empty string", func() {
   114  					Expect(app.CalculatedHealthCheckEndpoint()).To(Equal(""))
   115  				})
   116  			})
   117  		})
   118  
   119  		Describe("StagingCompleted", func() {
   120  			When("staging the application completes", func() {
   121  				It("returns true", func() {
   122  					app.PackageState = constant.ApplicationPackageStaged
   123  					Expect(app.StagingCompleted()).To(BeTrue())
   124  				})
   125  			})
   126  
   127  			When("the application is *not* staged", func() {
   128  				It("returns false", func() {
   129  					app.PackageState = constant.ApplicationPackageFailed
   130  					Expect(app.StagingCompleted()).To(BeFalse())
   131  				})
   132  			})
   133  		})
   134  
   135  		Describe("StagingFailed", func() {
   136  			When("staging the application fails", func() {
   137  				It("returns true", func() {
   138  					app.PackageState = constant.ApplicationPackageFailed
   139  					Expect(app.StagingFailed()).To(BeTrue())
   140  				})
   141  			})
   142  
   143  			When("staging the application does *not* fail", func() {
   144  				It("returns false", func() {
   145  					app.PackageState = constant.ApplicationPackageStaged
   146  					Expect(app.StagingFailed()).To(BeFalse())
   147  				})
   148  			})
   149  		})
   150  
   151  		Describe("StagingFailedMessage", func() {
   152  			When("the application has a staging failed description", func() {
   153  				BeforeEach(func() {
   154  					app.StagingFailedDescription = "An app was not successfully detected by any available buildpack"
   155  					app.StagingFailedReason = "NoAppDetectedError"
   156  				})
   157  				It("returns that description", func() {
   158  					Expect(app.StagingFailedMessage()).To(Equal("An app was not successfully detected by any available buildpack"))
   159  				})
   160  			})
   161  
   162  			When("the application does not have a staging failed description", func() {
   163  				BeforeEach(func() {
   164  					app.StagingFailedDescription = ""
   165  					app.StagingFailedReason = "NoAppDetectedError"
   166  				})
   167  				It("returns the staging failed code", func() {
   168  					Expect(app.StagingFailedMessage()).To(Equal("NoAppDetectedError"))
   169  				})
   170  			})
   171  		})
   172  
   173  		Describe("StagingFailedNoAppDetected", func() {
   174  			When("staging the application fails due to a no app detected error", func() {
   175  				It("returns true", func() {
   176  					app.StagingFailedReason = "NoAppDetectedError"
   177  					Expect(app.StagingFailedNoAppDetected()).To(BeTrue())
   178  				})
   179  			})
   180  
   181  			When("staging the application fails due to any other reason", func() {
   182  				It("returns false", func() {
   183  					app.StagingFailedReason = "InsufficientResources"
   184  					Expect(app.StagingFailedNoAppDetected()).To(BeFalse())
   185  				})
   186  			})
   187  		})
   188  
   189  		Describe("Started", func() {
   190  			When("app is started", func() {
   191  				It("returns true", func() {
   192  					Expect(Application{State: constant.ApplicationStarted}.Started()).To(BeTrue())
   193  				})
   194  			})
   195  
   196  			When("app is stopped", func() {
   197  				It("returns false", func() {
   198  					Expect(Application{State: constant.ApplicationStopped}.Started()).To(BeFalse())
   199  				})
   200  			})
   201  		})
   202  
   203  		Describe("Stopped", func() {
   204  			When("app is started", func() {
   205  				It("returns true", func() {
   206  					Expect(Application{State: constant.ApplicationStopped}.Stopped()).To(BeTrue())
   207  				})
   208  			})
   209  
   210  			When("app is stopped", func() {
   211  				It("returns false", func() {
   212  					Expect(Application{State: constant.ApplicationStarted}.Stopped()).To(BeFalse())
   213  				})
   214  			})
   215  		})
   216  	})
   217  
   218  	Describe("CreateApplication", func() {
   219  		When("the create is successful", func() {
   220  			var expectedApp ccv2.Application
   221  			BeforeEach(func() {
   222  				expectedApp = ccv2.Application{
   223  					GUID:      "some-app-guid",
   224  					Name:      "some-app-name",
   225  					SpaceGUID: "some-space-guid",
   226  				}
   227  				fakeCloudControllerClient.CreateApplicationReturns(expectedApp, ccv2.Warnings{"some-app-warning-1"}, nil)
   228  			})
   229  
   230  			It("creates and returns the application", func() {
   231  				newApp := Application{
   232  					Name:      "some-app-name",
   233  					SpaceGUID: "some-space-guid",
   234  				}
   235  				app, warnings, err := actor.CreateApplication(newApp)
   236  				Expect(err).ToNot(HaveOccurred())
   237  				Expect(warnings).To(ConsistOf("some-app-warning-1"))
   238  				Expect(app).To(Equal(Application(expectedApp)))
   239  
   240  				Expect(fakeCloudControllerClient.CreateApplicationCallCount()).To(Equal(1))
   241  				Expect(fakeCloudControllerClient.CreateApplicationArgsForCall(0)).To(Equal(ccv2.Application(newApp)))
   242  			})
   243  		})
   244  
   245  		When("the client returns back an error", func() {
   246  			var expectedErr error
   247  			BeforeEach(func() {
   248  				expectedErr = errors.New("some create app error")
   249  				fakeCloudControllerClient.CreateApplicationReturns(ccv2.Application{}, ccv2.Warnings{"some-app-warning-1"}, expectedErr)
   250  			})
   251  
   252  			It("returns warnings and an error", func() {
   253  				newApp := Application{
   254  					Name:      "some-app-name",
   255  					SpaceGUID: "some-space-guid",
   256  				}
   257  				_, warnings, err := actor.CreateApplication(newApp)
   258  				Expect(warnings).To(ConsistOf("some-app-warning-1"))
   259  				Expect(err).To(MatchError(expectedErr))
   260  			})
   261  		})
   262  	})
   263  
   264  	Describe("GetApplication", func() {
   265  		When("the application exists", func() {
   266  			BeforeEach(func() {
   267  				fakeCloudControllerClient.GetApplicationReturns(
   268  					ccv2.Application{
   269  						GUID: "some-app-guid",
   270  						Name: "some-app",
   271  					},
   272  					ccv2.Warnings{"foo"},
   273  					nil,
   274  				)
   275  			})
   276  
   277  			It("returns the application and warnings", func() {
   278  				app, warnings, err := actor.GetApplication("some-app-guid")
   279  				Expect(err).ToNot(HaveOccurred())
   280  				Expect(app).To(Equal(Application{
   281  					GUID: "some-app-guid",
   282  					Name: "some-app",
   283  				}))
   284  				Expect(warnings).To(ConsistOf("foo"))
   285  
   286  				Expect(fakeCloudControllerClient.GetApplicationCallCount()).To(Equal(1))
   287  				Expect(fakeCloudControllerClient.GetApplicationArgsForCall(0)).To(Equal("some-app-guid"))
   288  			})
   289  		})
   290  
   291  		When("the application does not exist", func() {
   292  			BeforeEach(func() {
   293  				fakeCloudControllerClient.GetApplicationReturns(ccv2.Application{}, nil, ccerror.ResourceNotFoundError{})
   294  			})
   295  
   296  			It("returns an ApplicationNotFoundError", func() {
   297  				_, _, err := actor.GetApplication("some-app-guid")
   298  				Expect(err).To(MatchError(actionerror.ApplicationNotFoundError{GUID: "some-app-guid"}))
   299  			})
   300  		})
   301  	})
   302  
   303  	Describe("GetApplicationByNameAndSpace", func() {
   304  		When("the application exists", func() {
   305  			BeforeEach(func() {
   306  				fakeCloudControllerClient.GetApplicationsReturns(
   307  					[]ccv2.Application{
   308  						{
   309  							GUID: "some-app-guid",
   310  							Name: "some-app",
   311  						},
   312  					},
   313  					ccv2.Warnings{"foo"},
   314  					nil,
   315  				)
   316  			})
   317  
   318  			It("returns the application and warnings", func() {
   319  				app, warnings, err := actor.GetApplicationByNameAndSpace("some-app", "some-space-guid")
   320  				Expect(err).ToNot(HaveOccurred())
   321  				Expect(app).To(Equal(Application{
   322  					GUID: "some-app-guid",
   323  					Name: "some-app",
   324  				}))
   325  				Expect(warnings).To(ConsistOf("foo"))
   326  
   327  				Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   328  				Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf([]ccv2.Filter{
   329  					ccv2.Filter{
   330  						Type:     constant.NameFilter,
   331  						Operator: constant.EqualOperator,
   332  						Values:   []string{"some-app"},
   333  					},
   334  					ccv2.Filter{
   335  						Type:     constant.SpaceGUIDFilter,
   336  						Operator: constant.EqualOperator,
   337  						Values:   []string{"some-space-guid"},
   338  					},
   339  				}))
   340  			})
   341  		})
   342  
   343  		When("the application does not exists", func() {
   344  			BeforeEach(func() {
   345  				fakeCloudControllerClient.GetApplicationsReturns([]ccv2.Application{}, nil, nil)
   346  			})
   347  
   348  			It("returns an ApplicationNotFoundError", func() {
   349  				_, _, err := actor.GetApplicationByNameAndSpace("some-app", "some-space-guid")
   350  				Expect(err).To(MatchError(actionerror.ApplicationNotFoundError{Name: "some-app"}))
   351  			})
   352  		})
   353  
   354  		When("the cloud controller client returns an error", func() {
   355  			var expectedError error
   356  
   357  			BeforeEach(func() {
   358  				expectedError = errors.New("I am a CloudControllerClient Error")
   359  				fakeCloudControllerClient.GetApplicationsReturns([]ccv2.Application{}, nil, expectedError)
   360  			})
   361  
   362  			It("returns the error", func() {
   363  				_, _, err := actor.GetApplicationByNameAndSpace("some-app", "some-space-guid")
   364  				Expect(err).To(MatchError(expectedError))
   365  			})
   366  		})
   367  	})
   368  
   369  	Describe("GetApplicationsBySpace", func() {
   370  		When("the there are applications in the space", func() {
   371  			BeforeEach(func() {
   372  				fakeCloudControllerClient.GetApplicationsReturns(
   373  					[]ccv2.Application{
   374  						{
   375  							GUID: "some-app-guid-1",
   376  							Name: "some-app-1",
   377  						},
   378  						{
   379  							GUID: "some-app-guid-2",
   380  							Name: "some-app-2",
   381  						},
   382  					},
   383  					ccv2.Warnings{"warning-1", "warning-2"},
   384  					nil,
   385  				)
   386  			})
   387  
   388  			It("returns the application and warnings", func() {
   389  				apps, warnings, err := actor.GetApplicationsBySpace("some-space-guid")
   390  				Expect(err).ToNot(HaveOccurred())
   391  				Expect(apps).To(ConsistOf(
   392  					Application{
   393  						GUID: "some-app-guid-1",
   394  						Name: "some-app-1",
   395  					},
   396  					Application{
   397  						GUID: "some-app-guid-2",
   398  						Name: "some-app-2",
   399  					},
   400  				))
   401  				Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   402  
   403  				Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   404  				Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf([]ccv2.Filter{
   405  					ccv2.Filter{
   406  						Type:     constant.SpaceGUIDFilter,
   407  						Operator: constant.EqualOperator,
   408  						Values:   []string{"some-space-guid"},
   409  					},
   410  				}))
   411  			})
   412  		})
   413  
   414  		When("the cloud controller client returns an error", func() {
   415  			var expectedError error
   416  
   417  			BeforeEach(func() {
   418  				expectedError = errors.New("some cc error")
   419  				fakeCloudControllerClient.GetApplicationsReturns(
   420  					[]ccv2.Application{},
   421  					ccv2.Warnings{"warning-1", "warning-2"},
   422  					expectedError)
   423  			})
   424  
   425  			It("returns the error and warnings", func() {
   426  				_, warnings, err := actor.GetApplicationsBySpace("some-space-guid")
   427  				Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   428  				Expect(err).To(MatchError(expectedError))
   429  			})
   430  		})
   431  	})
   432  
   433  	Describe("GetRouteApplications", func() {
   434  		When("the CC client returns no errors", func() {
   435  			BeforeEach(func() {
   436  				fakeCloudControllerClient.GetRouteApplicationsReturns(
   437  					[]ccv2.Application{
   438  						{
   439  							GUID: "application-guid",
   440  							Name: "application-name",
   441  						},
   442  					}, ccv2.Warnings{"route-applications-warning"}, nil)
   443  			})
   444  			It("returns the applications bound to the route and warnings", func() {
   445  				applications, warnings, err := actor.GetRouteApplications("route-guid")
   446  				Expect(fakeCloudControllerClient.GetRouteApplicationsCallCount()).To(Equal(1))
   447  				Expect(fakeCloudControllerClient.GetRouteApplicationsArgsForCall(0)).To(Equal("route-guid"))
   448  
   449  				Expect(err).ToNot(HaveOccurred())
   450  				Expect(warnings).To(ConsistOf("route-applications-warning"))
   451  				Expect(applications).To(ConsistOf(
   452  					Application{
   453  						GUID: "application-guid",
   454  						Name: "application-name",
   455  					},
   456  				))
   457  			})
   458  		})
   459  
   460  		When("the CC client returns an error", func() {
   461  			BeforeEach(func() {
   462  				fakeCloudControllerClient.GetRouteApplicationsReturns(
   463  					[]ccv2.Application{}, ccv2.Warnings{"route-applications-warning"}, errors.New("get-route-applications-error"))
   464  			})
   465  
   466  			It("returns the error and warnings", func() {
   467  				apps, warnings, err := actor.GetRouteApplications("route-guid")
   468  				Expect(fakeCloudControllerClient.GetRouteApplicationsCallCount()).To(Equal(1))
   469  				Expect(fakeCloudControllerClient.GetRouteApplicationsArgsForCall(0)).To(Equal("route-guid"))
   470  
   471  				Expect(err).To(MatchError("get-route-applications-error"))
   472  				Expect(warnings).To(ConsistOf("route-applications-warning"))
   473  				Expect(apps).To(BeNil())
   474  			})
   475  		})
   476  	})
   477  
   478  	Describe("SetApplicationHealthCheckTypeByNameAndSpace", func() {
   479  		When("setting an http endpoint with a health check that is not http", func() {
   480  			It("returns an http health check invalid error", func() {
   481  				_, _, err := actor.SetApplicationHealthCheckTypeByNameAndSpace(
   482  					"some-app", "some-space-guid", "some-health-check-type", "/foo")
   483  				Expect(err).To(MatchError(actionerror.HTTPHealthCheckInvalidError{}))
   484  			})
   485  		})
   486  
   487  		When("the app exists", func() {
   488  			When("the desired health check type is different", func() {
   489  				BeforeEach(func() {
   490  					fakeCloudControllerClient.GetApplicationsReturns(
   491  						[]ccv2.Application{
   492  							{GUID: "some-app-guid"},
   493  						},
   494  						ccv2.Warnings{"get application warning"},
   495  						nil,
   496  					)
   497  					fakeCloudControllerClient.UpdateApplicationReturns(
   498  						ccv2.Application{
   499  							GUID:            "some-app-guid",
   500  							HealthCheckType: constant.ApplicationHealthCheckProcess,
   501  						},
   502  						ccv2.Warnings{"update warnings"},
   503  						nil,
   504  					)
   505  				})
   506  
   507  				It("sets the desired health check type and returns the warnings", func() {
   508  					returnedApp, warnings, err := actor.SetApplicationHealthCheckTypeByNameAndSpace(
   509  						"some-app", "some-space-guid", "process", "/")
   510  					Expect(err).ToNot(HaveOccurred())
   511  					Expect(warnings).To(ConsistOf("get application warning", "update warnings"))
   512  
   513  					Expect(returnedApp).To(Equal(Application{
   514  						GUID:            "some-app-guid",
   515  						HealthCheckType: constant.ApplicationHealthCheckProcess,
   516  					}))
   517  
   518  					Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(1))
   519  					app := fakeCloudControllerClient.UpdateApplicationArgsForCall(0)
   520  					Expect(app).To(Equal(ccv2.Application{
   521  						GUID:            "some-app-guid",
   522  						HealthCheckType: constant.ApplicationHealthCheckProcess,
   523  					}))
   524  				})
   525  			})
   526  
   527  			When("the desired health check type is 'http'", func() {
   528  				When("the desired http endpoint is already set", func() {
   529  					BeforeEach(func() {
   530  						fakeCloudControllerClient.GetApplicationsReturns(
   531  							[]ccv2.Application{
   532  								{GUID: "some-app-guid", HealthCheckType: constant.ApplicationHealthCheckHTTP, HealthCheckHTTPEndpoint: "/"},
   533  							},
   534  							ccv2.Warnings{"get application warning"},
   535  							nil,
   536  						)
   537  					})
   538  
   539  					It("does not send the update", func() {
   540  						_, warnings, err := actor.SetApplicationHealthCheckTypeByNameAndSpace(
   541  							"some-app", "some-space-guid", "http", "/")
   542  						Expect(err).ToNot(HaveOccurred())
   543  						Expect(warnings).To(ConsistOf("get application warning"))
   544  
   545  						Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(0))
   546  					})
   547  				})
   548  
   549  				When("the desired http endpoint is not set", func() {
   550  					BeforeEach(func() {
   551  						fakeCloudControllerClient.GetApplicationsReturns(
   552  							[]ccv2.Application{
   553  								{GUID: "some-app-guid", HealthCheckType: constant.ApplicationHealthCheckHTTP, HealthCheckHTTPEndpoint: "/"},
   554  							},
   555  							ccv2.Warnings{"get application warning"},
   556  							nil,
   557  						)
   558  						fakeCloudControllerClient.UpdateApplicationReturns(
   559  							ccv2.Application{},
   560  							ccv2.Warnings{"update warnings"},
   561  							nil,
   562  						)
   563  					})
   564  
   565  					It("sets the desired health check type and returns the warnings", func() {
   566  						_, warnings, err := actor.SetApplicationHealthCheckTypeByNameAndSpace(
   567  							"some-app", "some-space-guid", "http", "/v2/anything")
   568  						Expect(err).ToNot(HaveOccurred())
   569  
   570  						Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(1))
   571  						app := fakeCloudControllerClient.UpdateApplicationArgsForCall(0)
   572  						Expect(app).To(Equal(ccv2.Application{
   573  							GUID:                    "some-app-guid",
   574  							HealthCheckType:         constant.ApplicationHealthCheckHTTP,
   575  							HealthCheckHTTPEndpoint: "/v2/anything",
   576  						}))
   577  
   578  						Expect(warnings).To(ConsistOf("get application warning", "update warnings"))
   579  					})
   580  				})
   581  			})
   582  
   583  			When("the application health check type is already set to the desired type", func() {
   584  				BeforeEach(func() {
   585  					fakeCloudControllerClient.GetApplicationsReturns(
   586  						[]ccv2.Application{
   587  							{
   588  								GUID:            "some-app-guid",
   589  								HealthCheckType: constant.ApplicationHealthCheckProcess,
   590  							},
   591  						},
   592  						ccv2.Warnings{"get application warning"},
   593  						nil,
   594  					)
   595  				})
   596  
   597  				It("does not update the health check type", func() {
   598  					returnedApp, warnings, err := actor.SetApplicationHealthCheckTypeByNameAndSpace(
   599  						"some-app", "some-space-guid", "process", "/")
   600  					Expect(err).ToNot(HaveOccurred())
   601  					Expect(warnings).To(ConsistOf("get application warning"))
   602  					Expect(returnedApp).To(Equal(Application{
   603  						GUID:            "some-app-guid",
   604  						HealthCheckType: constant.ApplicationHealthCheckProcess,
   605  					}))
   606  
   607  					Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(0))
   608  				})
   609  			})
   610  		})
   611  
   612  		When("getting the application returns an error", func() {
   613  			BeforeEach(func() {
   614  				fakeCloudControllerClient.GetApplicationsReturns(
   615  					[]ccv2.Application{}, ccv2.Warnings{"get application warning"}, errors.New("get application error"))
   616  			})
   617  
   618  			It("returns the error and warnings", func() {
   619  				_, warnings, err := actor.SetApplicationHealthCheckTypeByNameAndSpace(
   620  					"some-app", "some-space-guid", "process", "/")
   621  
   622  				Expect(warnings).To(ConsistOf("get application warning"))
   623  				Expect(err).To(MatchError("get application error"))
   624  			})
   625  		})
   626  
   627  		When("updating the application returns an error", func() {
   628  			var expectedErr error
   629  
   630  			BeforeEach(func() {
   631  				expectedErr = errors.New("foo bar")
   632  				fakeCloudControllerClient.GetApplicationsReturns(
   633  					[]ccv2.Application{
   634  						{GUID: "some-app-guid"},
   635  					},
   636  					ccv2.Warnings{"get application warning"},
   637  					nil,
   638  				)
   639  				fakeCloudControllerClient.UpdateApplicationReturns(
   640  					ccv2.Application{},
   641  					ccv2.Warnings{"update warnings"},
   642  					expectedErr,
   643  				)
   644  			})
   645  
   646  			It("returns the error and warnings", func() {
   647  				_, warnings, err := actor.SetApplicationHealthCheckTypeByNameAndSpace(
   648  					"some-app", "some-space-guid", "process", "/")
   649  				Expect(err).To(MatchError(expectedErr))
   650  				Expect(warnings).To(ConsistOf("get application warning", "update warnings"))
   651  			})
   652  		})
   653  	})
   654  
   655  	Describe("StartApplication/RestartApplication", func() {
   656  		var (
   657  			app Application
   658  
   659  			appState <-chan ApplicationStateChange
   660  			warnings <-chan string
   661  			errs     <-chan error
   662  		)
   663  
   664  		BeforeEach(func() {
   665  			fakeConfig.StagingTimeoutReturns(time.Minute)
   666  			fakeConfig.StartupTimeoutReturns(time.Minute)
   667  
   668  			app = Application{
   669  				GUID:      "some-app-guid",
   670  				Name:      "some-app",
   671  				Instances: types.NullInt{Value: 2, IsSet: true},
   672  			}
   673  			appCount := 0
   674  			fakeCloudControllerClient.GetApplicationStub = func(appGUID string) (ccv2.Application, ccv2.Warnings, error) {
   675  				if appCount == 0 {
   676  					appCount++
   677  					return ccv2.Application{
   678  						GUID:         "some-app-guid",
   679  						Instances:    types.NullInt{Value: 2, IsSet: true},
   680  						Name:         "some-app",
   681  						PackageState: constant.ApplicationPackagePending,
   682  					}, ccv2.Warnings{"app-warnings-1"}, nil
   683  				}
   684  
   685  				return ccv2.Application{
   686  					GUID:         "some-app-guid",
   687  					Name:         "some-app",
   688  					Instances:    types.NullInt{Value: 2, IsSet: true},
   689  					PackageState: constant.ApplicationPackageStaged,
   690  				}, ccv2.Warnings{"app-warnings-2"}, nil
   691  			}
   692  
   693  			instanceCount := 0
   694  			fakeCloudControllerClient.GetApplicationApplicationInstancesStub = func(guid string) (map[int]ccv2.ApplicationInstance, ccv2.Warnings, error) {
   695  				if instanceCount == 0 {
   696  					instanceCount++
   697  					return map[int]ccv2.ApplicationInstance{
   698  						0: {State: constant.ApplicationInstanceStarting},
   699  						1: {State: constant.ApplicationInstanceStarting},
   700  					}, ccv2.Warnings{"app-instance-warnings-1"}, nil
   701  				}
   702  
   703  				return map[int]ccv2.ApplicationInstance{
   704  					0: {State: constant.ApplicationInstanceStarting},
   705  					1: {State: constant.ApplicationInstanceRunning},
   706  				}, ccv2.Warnings{"app-instance-warnings-2"}, nil
   707  			}
   708  		})
   709  
   710  		AfterEach(func() {
   711  			Eventually(appState).Should(BeClosed())
   712  			Eventually(warnings).Should(BeClosed())
   713  			Eventually(errs).Should(BeClosed())
   714  		})
   715  
   716  		var ItHandlesStagingIssues = func() {
   717  			Context("staging issues", func() {
   718  				When("polling fails", func() {
   719  					var expectedErr error
   720  					BeforeEach(func() {
   721  						expectedErr = errors.New("I am a banana!!!!")
   722  						fakeCloudControllerClient.GetApplicationStub = func(appGUID string) (ccv2.Application, ccv2.Warnings, error) {
   723  							return ccv2.Application{}, ccv2.Warnings{"app-warnings-1"}, expectedErr
   724  						}
   725  					})
   726  
   727  					It("sends the error and stops polling", func() {
   728  						Eventually(appState).Should(Receive(Equal(ApplicationStateStaging)))
   729  						Eventually(warnings).Should(Receive(Equal("state-warning")))
   730  						Eventually(warnings).Should(Receive(Equal("app-warnings-1")))
   731  						Eventually(errs).Should(Receive(MatchError(expectedErr)))
   732  
   733  						Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(0))
   734  						Expect(fakeCloudControllerClient.GetApplicationCallCount()).To(Equal(1))
   735  						Expect(fakeCloudControllerClient.GetApplicationApplicationInstancesCallCount()).To(Equal(0))
   736  					})
   737  				})
   738  
   739  				When("the application fails to stage", func() {
   740  					Context("due to a NoAppDetectedError", func() {
   741  						BeforeEach(func() {
   742  							fakeCloudControllerClient.GetApplicationStub = func(appGUID string) (ccv2.Application, ccv2.Warnings, error) {
   743  								return ccv2.Application{
   744  									GUID:                "some-app-guid",
   745  									Name:                "some-app",
   746  									Instances:           types.NullInt{Value: 2, IsSet: true},
   747  									PackageState:        constant.ApplicationPackageFailed,
   748  									StagingFailedReason: "NoAppDetectedError",
   749  								}, ccv2.Warnings{"app-warnings-1"}, nil
   750  							}
   751  						})
   752  
   753  						It("sends a StagingFailedNoAppDetectedError and stops polling", func() {
   754  							Eventually(appState).Should(Receive(Equal(ApplicationStateStaging)))
   755  							Eventually(warnings).Should(Receive(Equal("state-warning")))
   756  							Eventually(warnings).Should(Receive(Equal("app-warnings-1")))
   757  							Eventually(errs).Should(Receive(MatchError(actionerror.StagingFailedNoAppDetectedError{Reason: "NoAppDetectedError"})))
   758  
   759  							Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(0))
   760  							Expect(fakeConfig.StagingTimeoutCallCount()).To(Equal(1))
   761  							Expect(fakeCloudControllerClient.GetApplicationCallCount()).To(Equal(1))
   762  							Expect(fakeCloudControllerClient.GetApplicationApplicationInstancesCallCount()).To(Equal(0))
   763  						})
   764  					})
   765  
   766  					Context("due to any other error", func() {
   767  						BeforeEach(func() {
   768  							fakeCloudControllerClient.GetApplicationStub = func(appGUID string) (ccv2.Application, ccv2.Warnings, error) {
   769  								return ccv2.Application{
   770  									GUID:                "some-app-guid",
   771  									Name:                "some-app",
   772  									Instances:           types.NullInt{Value: 2, IsSet: true},
   773  									PackageState:        constant.ApplicationPackageFailed,
   774  									StagingFailedReason: "OhNoes",
   775  								}, ccv2.Warnings{"app-warnings-1"}, nil
   776  							}
   777  						})
   778  
   779  						It("sends a StagingFailedError and stops polling", func() {
   780  							Eventually(appState).Should(Receive(Equal(ApplicationStateStaging)))
   781  							Eventually(warnings).Should(Receive(Equal("state-warning")))
   782  							Eventually(warnings).Should(Receive(Equal("app-warnings-1")))
   783  							Eventually(errs).Should(Receive(MatchError(actionerror.StagingFailedError{Reason: "OhNoes"})))
   784  
   785  							Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(0))
   786  							Expect(fakeConfig.StagingTimeoutCallCount()).To(Equal(1))
   787  							Expect(fakeCloudControllerClient.GetApplicationCallCount()).To(Equal(1))
   788  							Expect(fakeCloudControllerClient.GetApplicationApplicationInstancesCallCount()).To(Equal(0))
   789  						})
   790  					})
   791  				})
   792  
   793  				When("the application takes too long to stage", func() {
   794  					BeforeEach(func() {
   795  						fakeConfig.StagingTimeoutReturns(0)
   796  						fakeCloudControllerClient.GetApplicationApplicationInstancesStub = nil
   797  					})
   798  
   799  					It("sends a timeout error and stops polling", func() {
   800  						Eventually(appState).Should(Receive(Equal(ApplicationStateStaging)))
   801  						Eventually(warnings).Should(Receive(Equal("state-warning")))
   802  						Eventually(errs).Should(Receive(MatchError(actionerror.StagingTimeoutError{AppName: "some-app", Timeout: 0})))
   803  
   804  						Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(0))
   805  						Expect(fakeConfig.StagingTimeoutCallCount()).To(Equal(2))
   806  						Expect(fakeCloudControllerClient.GetApplicationCallCount()).To(Equal(0))
   807  						Expect(fakeCloudControllerClient.GetApplicationApplicationInstancesCallCount()).To(Equal(0))
   808  					})
   809  				})
   810  			})
   811  		}
   812  
   813  		var ItHandlesStartingIssues = func() {
   814  			Context("starting issues", func() {
   815  				When("polling fails", func() {
   816  					var expectedErr error
   817  					BeforeEach(func() {
   818  						expectedErr = errors.New("I am a banana!!!!")
   819  						fakeCloudControllerClient.GetApplicationApplicationInstancesStub = func(guid string) (map[int]ccv2.ApplicationInstance, ccv2.Warnings, error) {
   820  							return nil, ccv2.Warnings{"app-instance-warnings-1"}, expectedErr
   821  						}
   822  					})
   823  
   824  					It("sends the error and stops polling", func() {
   825  						Eventually(appState).Should(Receive(Equal(ApplicationStateStaging)))
   826  						Eventually(warnings).Should(Receive(Equal("state-warning")))
   827  						Eventually(warnings).Should(Receive(Equal("app-warnings-1")))
   828  						Eventually(warnings).Should(Receive(Equal("app-warnings-2")))
   829  						Eventually(appState).Should(Receive(Equal(ApplicationStateStarting)))
   830  						Eventually(warnings).Should(Receive(Equal("app-instance-warnings-1")))
   831  						Eventually(errs).Should(Receive(MatchError(expectedErr)))
   832  
   833  						Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(1))
   834  						Expect(fakeCloudControllerClient.GetApplicationApplicationInstancesCallCount()).To(Equal(1))
   835  					})
   836  				})
   837  
   838  				When("the application takes too long to start", func() {
   839  					BeforeEach(func() {
   840  						fakeConfig.StartupTimeoutReturns(0)
   841  					})
   842  
   843  					It("sends a timeout error and stops polling", func() {
   844  						Eventually(appState).Should(Receive(Equal(ApplicationStateStaging)))
   845  						Eventually(warnings).Should(Receive(Equal("state-warning")))
   846  						Eventually(warnings).Should(Receive(Equal("app-warnings-1")))
   847  						Eventually(warnings).Should(Receive(Equal("app-warnings-2")))
   848  						Eventually(appState).Should(Receive(Equal(ApplicationStateStarting)))
   849  						Eventually(errs).Should(Receive(MatchError(actionerror.StartupTimeoutError{Name: "some-app"})))
   850  
   851  						Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(1))
   852  						Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1))
   853  						Expect(fakeCloudControllerClient.GetApplicationApplicationInstancesCallCount()).To(Equal(0))
   854  					})
   855  				})
   856  
   857  				When("the application crashes", func() {
   858  					BeforeEach(func() {
   859  						fakeCloudControllerClient.GetApplicationApplicationInstancesStub = func(guid string) (map[int]ccv2.ApplicationInstance, ccv2.Warnings, error) {
   860  							return map[int]ccv2.ApplicationInstance{
   861  								0: {State: constant.ApplicationInstanceCrashed},
   862  							}, ccv2.Warnings{"app-instance-warnings-1"}, nil
   863  						}
   864  					})
   865  
   866  					It("returns an ApplicationInstanceCrashedError and stops polling", func() {
   867  						Eventually(appState).Should(Receive(Equal(ApplicationStateStaging)))
   868  						Eventually(warnings).Should(Receive(Equal("state-warning")))
   869  						Eventually(warnings).Should(Receive(Equal("app-warnings-1")))
   870  						Eventually(warnings).Should(Receive(Equal("app-warnings-2")))
   871  						Eventually(appState).Should(Receive(Equal(ApplicationStateStarting)))
   872  						Eventually(warnings).Should(Receive(Equal("app-instance-warnings-1")))
   873  						Eventually(errs).Should(Receive(MatchError(actionerror.ApplicationInstanceCrashedError{Name: "some-app"})))
   874  
   875  						Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(1))
   876  						Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1))
   877  						Expect(fakeCloudControllerClient.GetApplicationApplicationInstancesCallCount()).To(Equal(1))
   878  					})
   879  				})
   880  
   881  				When("the application flaps", func() {
   882  					BeforeEach(func() {
   883  						fakeCloudControllerClient.GetApplicationApplicationInstancesStub = func(guid string) (map[int]ccv2.ApplicationInstance, ccv2.Warnings, error) {
   884  							return map[int]ccv2.ApplicationInstance{
   885  								0: {State: constant.ApplicationInstanceFlapping},
   886  							}, ccv2.Warnings{"app-instance-warnings-1"}, nil
   887  						}
   888  					})
   889  
   890  					It("returns an ApplicationInstanceFlappingError and stops polling", func() {
   891  						Eventually(appState).Should(Receive(Equal(ApplicationStateStaging)))
   892  						Eventually(warnings).Should(Receive(Equal("state-warning")))
   893  						Eventually(warnings).Should(Receive(Equal("app-warnings-1")))
   894  						Eventually(warnings).Should(Receive(Equal("app-warnings-2")))
   895  						Eventually(appState).Should(Receive(Equal(ApplicationStateStarting)))
   896  						Eventually(warnings).Should(Receive(Equal("app-instance-warnings-1")))
   897  						Eventually(errs).Should(Receive(MatchError(actionerror.ApplicationInstanceFlappingError{Name: "some-app"})))
   898  
   899  						Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(1))
   900  						Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1))
   901  						Expect(fakeCloudControllerClient.GetApplicationApplicationInstancesCallCount()).To(Equal(1))
   902  					})
   903  				})
   904  			})
   905  		}
   906  
   907  		var ItStartsApplication = func() {
   908  			When("the app is not running", func() {
   909  				It("starts and polls for an app instance", func() {
   910  					Eventually(appState).Should(Receive(Equal(ApplicationStateStaging)))
   911  					Eventually(warnings).Should(Receive(Equal("state-warning")))
   912  					Eventually(warnings).Should(Receive(Equal("app-warnings-1")))
   913  					Eventually(warnings).Should(Receive(Equal("app-warnings-2")))
   914  					Eventually(appState).Should(Receive(Equal(ApplicationStateStarting)))
   915  					Eventually(warnings).Should(Receive(Equal("app-instance-warnings-1")))
   916  					Eventually(warnings).Should(Receive(Equal("app-instance-warnings-2")))
   917  
   918  					Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(2))
   919  
   920  					Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(1))
   921  					passedApp := fakeCloudControllerClient.UpdateApplicationArgsForCall(0)
   922  					Expect(passedApp).To(Equal(ccv2.Application{
   923  						GUID:  "some-app-guid",
   924  						State: constant.ApplicationStarted,
   925  					}))
   926  
   927  					Expect(fakeCloudControllerClient.GetApplicationCallCount()).To(Equal(2))
   928  					Expect(fakeCloudControllerClient.GetApplicationApplicationInstancesCallCount()).To(Equal(2))
   929  				})
   930  			})
   931  
   932  			When("the app has zero instances", func() {
   933  				BeforeEach(func() {
   934  					fakeCloudControllerClient.UpdateApplicationReturns(ccv2.Application{GUID: "some-app-guid",
   935  						Instances: types.NullInt{Value: 0, IsSet: true},
   936  						Name:      "some-app",
   937  					}, ccv2.Warnings{"state-warning"}, nil)
   938  				})
   939  
   940  				It("starts and only polls for staging to finish", func() {
   941  					Eventually(appState).Should(Receive(Equal(ApplicationStateStaging)))
   942  					Eventually(warnings).Should(Receive(Equal("state-warning")))
   943  					Eventually(warnings).Should(Receive(Equal("app-warnings-1")))
   944  					Eventually(warnings).Should(Receive(Equal("app-warnings-2")))
   945  					Consistently(appState).ShouldNot(Receive(Equal(ApplicationStateStarting)))
   946  
   947  					Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(1))
   948  
   949  					Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(1))
   950  					passedApp := fakeCloudControllerClient.UpdateApplicationArgsForCall(0)
   951  					Expect(passedApp).To(Equal(ccv2.Application{
   952  						GUID:  "some-app-guid",
   953  						State: constant.ApplicationStarted,
   954  					}))
   955  
   956  					Expect(fakeCloudControllerClient.GetApplicationCallCount()).To(Equal(2))
   957  					Expect(fakeCloudControllerClient.GetApplicationApplicationInstancesCallCount()).To(Equal(0))
   958  				})
   959  			})
   960  
   961  			When("updating the application fails", func() {
   962  				var expectedErr error
   963  				BeforeEach(func() {
   964  					expectedErr = errors.New("I am a banana!!!!")
   965  					fakeCloudControllerClient.UpdateApplicationReturns(ccv2.Application{}, ccv2.Warnings{"state-warning"}, expectedErr)
   966  				})
   967  
   968  				It("sends the update error and never polls", func() {
   969  					Eventually(appState).Should(Receive(Equal(ApplicationStateStaging)))
   970  					Eventually(warnings).Should(Receive(Equal("state-warning")))
   971  					Eventually(errs).Should(Receive(MatchError(expectedErr)))
   972  
   973  					Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(0))
   974  					Expect(fakeCloudControllerClient.GetApplicationCallCount()).To(Equal(0))
   975  					Expect(fakeCloudControllerClient.GetApplicationApplicationInstancesCallCount()).To(Equal(0))
   976  				})
   977  			})
   978  
   979  			ItHandlesStagingIssues()
   980  
   981  			ItHandlesStartingIssues()
   982  		}
   983  
   984  		Describe("StartApplication", func() {
   985  			BeforeEach(func() {
   986  				fakeCloudControllerClient.UpdateApplicationReturns(ccv2.Application{GUID: "some-app-guid",
   987  					Instances: types.NullInt{Value: 2, IsSet: true},
   988  					Name:      "some-app",
   989  				}, ccv2.Warnings{"state-warning"}, nil)
   990  			})
   991  
   992  			JustBeforeEach(func() {
   993  				appState, warnings, errs = actor.StartApplication(app)
   994  			})
   995  
   996  			When("the app is already staged", func() {
   997  				BeforeEach(func() {
   998  					app.PackageState = constant.ApplicationPackageStaged
   999  				})
  1000  
  1001  				It("does not send ApplicationStateStaging", func() {
  1002  					Consistently(appState).ShouldNot(Receive(Equal(ApplicationStateStaging)))
  1003  					Eventually(warnings).Should(Receive(Equal("state-warning")))
  1004  					Eventually(warnings).Should(Receive(Equal("app-warnings-1")))
  1005  					Eventually(warnings).Should(Receive(Equal("app-warnings-2")))
  1006  					Eventually(appState).Should(Receive(Equal(ApplicationStateStarting)))
  1007  					Eventually(warnings).Should(Receive(Equal("app-instance-warnings-1")))
  1008  					Eventually(warnings).Should(Receive(Equal("app-instance-warnings-2")))
  1009  
  1010  					Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(1))
  1011  					passedApp := fakeCloudControllerClient.UpdateApplicationArgsForCall(0)
  1012  					Expect(passedApp).To(Equal(ccv2.Application{
  1013  						GUID:  "some-app-guid",
  1014  						State: constant.ApplicationStarted,
  1015  					}))
  1016  				})
  1017  			})
  1018  
  1019  			ItStartsApplication()
  1020  		})
  1021  
  1022  		Describe("RestartApplication", func() {
  1023  			BeforeEach(func() {
  1024  				fakeCloudControllerClient.UpdateApplicationReturns(ccv2.Application{GUID: "some-app-guid",
  1025  					Instances: types.NullInt{Value: 2, IsSet: true},
  1026  					Name:      "some-app",
  1027  				}, ccv2.Warnings{"state-warning"}, nil)
  1028  			})
  1029  
  1030  			JustBeforeEach(func() {
  1031  				appState, warnings, errs = actor.RestartApplication(app)
  1032  			})
  1033  
  1034  			When("application is running", func() {
  1035  				BeforeEach(func() {
  1036  					app.State = constant.ApplicationStarted
  1037  				})
  1038  
  1039  				It("stops, starts and polls for an app instance", func() {
  1040  					Eventually(appState).Should(Receive(Equal(ApplicationStateStopping)))
  1041  					Eventually(warnings).Should(Receive(Equal("state-warning")))
  1042  					Eventually(appState).Should(Receive(Equal(ApplicationStateStaging)))
  1043  					Eventually(warnings).Should(Receive(Equal("state-warning")))
  1044  					Eventually(warnings).Should(Receive(Equal("app-warnings-1")))
  1045  					Eventually(warnings).Should(Receive(Equal("app-warnings-2")))
  1046  					Eventually(appState).Should(Receive(Equal(ApplicationStateStarting)))
  1047  					Eventually(warnings).Should(Receive(Equal("app-instance-warnings-1")))
  1048  					Eventually(warnings).Should(Receive(Equal("app-instance-warnings-2")))
  1049  
  1050  					Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(2))
  1051  
  1052  					Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(2))
  1053  					passedApp := fakeCloudControllerClient.UpdateApplicationArgsForCall(0)
  1054  					Expect(passedApp).To(Equal(ccv2.Application{
  1055  						GUID:  "some-app-guid",
  1056  						State: constant.ApplicationStopped,
  1057  					}))
  1058  
  1059  					passedApp = fakeCloudControllerClient.UpdateApplicationArgsForCall(1)
  1060  					Expect(passedApp).To(Equal(ccv2.Application{
  1061  						GUID:  "some-app-guid",
  1062  						State: constant.ApplicationStarted,
  1063  					}))
  1064  
  1065  					Expect(fakeCloudControllerClient.GetApplicationCallCount()).To(Equal(2))
  1066  					Expect(fakeCloudControllerClient.GetApplicationApplicationInstancesCallCount()).To(Equal(2))
  1067  				})
  1068  
  1069  				When("updating the application to stop fails", func() {
  1070  					var expectedErr error
  1071  					BeforeEach(func() {
  1072  						expectedErr = errors.New("I am a banana!!!!")
  1073  						updateApplicationCalled := false
  1074  						fakeCloudControllerClient.UpdateApplicationStub = func(app ccv2.Application) (ccv2.Application, ccv2.Warnings, error) {
  1075  							if !updateApplicationCalled {
  1076  								return ccv2.Application{}, ccv2.Warnings{"state-warning"}, expectedErr
  1077  							}
  1078  
  1079  							updateApplicationCalled = true
  1080  							return ccv2.Application{GUID: "some-app-guid",
  1081  								Instances: types.NullInt{Value: 2, IsSet: true},
  1082  								Name:      "some-app",
  1083  							}, ccv2.Warnings{"state-warning"}, nil
  1084  						}
  1085  					})
  1086  
  1087  					It("sends the update error and never polls", func() {
  1088  						Eventually(appState).Should(Receive(Equal(ApplicationStateStopping)))
  1089  						Eventually(warnings).Should(Receive(Equal("state-warning")))
  1090  						Eventually(errs).Should(Receive(MatchError(expectedErr)))
  1091  						Eventually(appState).ShouldNot(Receive(Equal(ApplicationStateStaging)))
  1092  
  1093  						Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(0))
  1094  						Expect(fakeCloudControllerClient.GetApplicationCallCount()).To(Equal(0))
  1095  						Expect(fakeCloudControllerClient.GetApplicationApplicationInstancesCallCount()).To(Equal(0))
  1096  					})
  1097  				})
  1098  			})
  1099  
  1100  			When("the app is not running", func() {
  1101  				BeforeEach(func() {
  1102  					app.State = constant.ApplicationStopped
  1103  				})
  1104  
  1105  				It("does not stop an app instance", func() {
  1106  					Eventually(appState).Should(Receive(Equal(ApplicationStateStaging)))
  1107  					Eventually(warnings).Should(Receive(Equal("state-warning")))
  1108  					Eventually(warnings).Should(Receive(Equal("app-warnings-1")))
  1109  					Eventually(warnings).Should(Receive(Equal("app-warnings-2")))
  1110  					Eventually(appState).Should(Receive(Equal(ApplicationStateStarting)))
  1111  					Eventually(warnings).Should(Receive(Equal("app-instance-warnings-1")))
  1112  					Eventually(warnings).Should(Receive(Equal("app-instance-warnings-2")))
  1113  
  1114  					Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(1))
  1115  					passedApp := fakeCloudControllerClient.UpdateApplicationArgsForCall(0)
  1116  					Expect(passedApp).To(Equal(ccv2.Application{
  1117  						GUID:  "some-app-guid",
  1118  						State: constant.ApplicationStarted,
  1119  					}))
  1120  				})
  1121  			})
  1122  
  1123  			When("the app is already staged", func() {
  1124  				BeforeEach(func() {
  1125  					app.PackageState = constant.ApplicationPackageStaged
  1126  				})
  1127  
  1128  				It("does not send ApplicationStateStaging", func() {
  1129  					Consistently(appState).ShouldNot(Receive(Equal(ApplicationStateStaging)))
  1130  					Eventually(warnings).Should(Receive(Equal("state-warning")))
  1131  					Eventually(warnings).Should(Receive(Equal("app-warnings-1")))
  1132  					Eventually(warnings).Should(Receive(Equal("app-warnings-2")))
  1133  					Eventually(appState).Should(Receive(Equal(ApplicationStateStarting)))
  1134  					Eventually(warnings).Should(Receive(Equal("app-instance-warnings-1")))
  1135  					Eventually(warnings).Should(Receive(Equal("app-instance-warnings-2")))
  1136  
  1137  					Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(1))
  1138  					passedApp := fakeCloudControllerClient.UpdateApplicationArgsForCall(0)
  1139  					Expect(passedApp).To(Equal(ccv2.Application{
  1140  						GUID:  "some-app-guid",
  1141  						State: constant.ApplicationStarted,
  1142  					}))
  1143  				})
  1144  			})
  1145  
  1146  			ItStartsApplication()
  1147  		})
  1148  
  1149  		Describe("RestageApplication", func() {
  1150  			JustBeforeEach(func() {
  1151  				appState, warnings, errs = actor.RestageApplication(app)
  1152  			})
  1153  
  1154  			When("restaging succeeds", func() {
  1155  				BeforeEach(func() {
  1156  					fakeCloudControllerClient.RestageApplicationReturns(ccv2.Application{GUID: "some-app-guid",
  1157  						Instances: types.NullInt{Value: 2, IsSet: true},
  1158  						Name:      "some-app",
  1159  					}, ccv2.Warnings{"state-warning"}, nil)
  1160  				})
  1161  
  1162  				It("restages and polls for app instances", func() {
  1163  					Eventually(appState).Should(Receive(Equal(ApplicationStateStaging)))
  1164  					Eventually(warnings).Should(Receive(Equal("state-warning")))
  1165  					Eventually(warnings).Should(Receive(Equal("app-warnings-1")))
  1166  					Eventually(warnings).Should(Receive(Equal("app-warnings-2")))
  1167  					Eventually(appState).Should(Receive(Equal(ApplicationStateStarting)))
  1168  					Eventually(warnings).Should(Receive(Equal("app-instance-warnings-1")))
  1169  					Eventually(warnings).Should(Receive(Equal("app-instance-warnings-2")))
  1170  
  1171  					Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(2))
  1172  
  1173  					Expect(fakeCloudControllerClient.RestageApplicationCallCount()).To(Equal(1))
  1174  					app := fakeCloudControllerClient.RestageApplicationArgsForCall(0)
  1175  					Expect(app).To(Equal(ccv2.Application{
  1176  						GUID: "some-app-guid",
  1177  					}))
  1178  
  1179  					Expect(fakeCloudControllerClient.GetApplicationCallCount()).To(Equal(2))
  1180  					Expect(fakeCloudControllerClient.GetApplicationApplicationInstancesCallCount()).To(Equal(2))
  1181  				})
  1182  
  1183  				ItHandlesStagingIssues()
  1184  
  1185  				ItHandlesStartingIssues()
  1186  			})
  1187  
  1188  			When("restaging errors", func() {
  1189  				BeforeEach(func() {
  1190  					fakeCloudControllerClient.RestageApplicationReturns(ccv2.Application{GUID: "some-app-guid",
  1191  						Instances: types.NullInt{Value: 2, IsSet: true},
  1192  						Name:      "some-app",
  1193  					}, ccv2.Warnings{"state-warning"}, errors.New("some-error"))
  1194  				})
  1195  
  1196  				It("sends the restage error and never polls", func() {
  1197  					Eventually(appState).Should(Receive(Equal(ApplicationStateStaging)))
  1198  					Eventually(warnings).Should(Receive(Equal("state-warning")))
  1199  					Eventually(errs).Should(Receive(MatchError("some-error")))
  1200  
  1201  					Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(0))
  1202  					Expect(fakeCloudControllerClient.GetApplicationCallCount()).To(Equal(0))
  1203  					Expect(fakeCloudControllerClient.GetApplicationApplicationInstancesCallCount()).To(Equal(0))
  1204  				})
  1205  			})
  1206  		})
  1207  	})
  1208  
  1209  	Describe("UpdateApplication", func() {
  1210  		When("the update is successful", func() {
  1211  			var expectedApp ccv2.Application
  1212  			BeforeEach(func() {
  1213  				expectedApp = ccv2.Application{
  1214  					GUID:      "some-app-guid",
  1215  					Name:      "some-app-name",
  1216  					SpaceGUID: "some-space-guid",
  1217  				}
  1218  				fakeCloudControllerClient.UpdateApplicationReturns(expectedApp, ccv2.Warnings{"some-app-warning-1"}, nil)
  1219  			})
  1220  
  1221  			It("updates and returns the application", func() {
  1222  				newApp := Application{
  1223  					Name:      "some-app-name",
  1224  					SpaceGUID: "some-space-guid",
  1225  				}
  1226  				app, warnings, err := actor.UpdateApplication(newApp)
  1227  				Expect(err).ToNot(HaveOccurred())
  1228  				Expect(warnings).To(ConsistOf("some-app-warning-1"))
  1229  				Expect(app).To(Equal(Application(expectedApp)))
  1230  
  1231  				Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(1))
  1232  				Expect(fakeCloudControllerClient.UpdateApplicationArgsForCall(0)).To(Equal(ccv2.Application(newApp)))
  1233  			})
  1234  		})
  1235  
  1236  		When("the client returns back an error", func() {
  1237  			var expectedErr error
  1238  			BeforeEach(func() {
  1239  				expectedErr = errors.New("some update app error")
  1240  				fakeCloudControllerClient.UpdateApplicationReturns(ccv2.Application{}, ccv2.Warnings{"some-app-warning-1"}, expectedErr)
  1241  			})
  1242  
  1243  			It("returns warnings and an error", func() {
  1244  				newApp := Application{
  1245  					Name:      "some-app-name",
  1246  					SpaceGUID: "some-space-guid",
  1247  				}
  1248  				_, warnings, err := actor.UpdateApplication(newApp)
  1249  				Expect(warnings).To(ConsistOf("some-app-warning-1"))
  1250  				Expect(err).To(MatchError(expectedErr))
  1251  			})
  1252  		})
  1253  	})
  1254  })