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