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