github.com/franc20/ayesa_sap@v7.0.0-beta.28.0.20200124003224-302d4d52fa6c+incompatible/actor/v7action/application_test.go (about)

     1  package v7action_test
     2  
     3  import (
     4  	"errors"
     5  	"time"
     6  
     7  	"code.cloudfoundry.org/cli/actor/actionerror"
     8  	. "code.cloudfoundry.org/cli/actor/v7action"
     9  	"code.cloudfoundry.org/cli/actor/v7action/v7actionfakes"
    10  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
    11  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
    12  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    13  	"code.cloudfoundry.org/cli/types"
    14  	"code.cloudfoundry.org/clock/fakeclock"
    15  
    16  	. "github.com/onsi/ginkgo"
    17  	. "github.com/onsi/gomega"
    18  )
    19  
    20  var _ = Describe("Application Actions", func() {
    21  	var (
    22  		actor                     *Actor
    23  		fakeCloudControllerClient *v7actionfakes.FakeCloudControllerClient
    24  		fakeConfig                *v7actionfakes.FakeConfig
    25  		fakeClock                 *fakeclock.FakeClock
    26  	)
    27  
    28  	BeforeEach(func() {
    29  		fakeCloudControllerClient = new(v7actionfakes.FakeCloudControllerClient)
    30  		fakeConfig = new(v7actionfakes.FakeConfig)
    31  		fakeClock = fakeclock.NewFakeClock(time.Now())
    32  		actor = NewActor(fakeCloudControllerClient, fakeConfig, nil, nil, fakeClock)
    33  	})
    34  
    35  	Describe("DeleteApplicationByNameAndSpace", func() {
    36  		var (
    37  			warnings           Warnings
    38  			executeErr         error
    39  			deleteMappedRoutes bool
    40  			appName            string
    41  		)
    42  
    43  		JustBeforeEach(func() {
    44  			appName = "some-app"
    45  			warnings, executeErr = actor.DeleteApplicationByNameAndSpace(appName, "some-space-guid", deleteMappedRoutes)
    46  		})
    47  
    48  		When("looking up the app guid fails", func() {
    49  			BeforeEach(func() {
    50  				fakeCloudControllerClient.GetApplicationsReturns([]ccv3.Application{}, ccv3.Warnings{"some-get-app-warning"}, errors.New("some-get-app-error"))
    51  			})
    52  
    53  			It("returns the warnings and error", func() {
    54  				Expect(warnings).To(ConsistOf("some-get-app-warning"))
    55  				Expect(executeErr).To(MatchError("some-get-app-error"))
    56  			})
    57  		})
    58  
    59  		When("looking up the app guid succeeds", func() {
    60  			BeforeEach(func() {
    61  				fakeCloudControllerClient.GetApplicationsReturns([]ccv3.Application{{Name: "some-app", GUID: "abc123"}}, ccv3.Warnings{"some-get-app-warning"}, nil)
    62  			})
    63  
    64  			When("sending the delete fails", func() {
    65  				BeforeEach(func() {
    66  					fakeCloudControllerClient.DeleteApplicationReturns("", ccv3.Warnings{"some-delete-app-warning"}, errors.New("some-delete-app-error"))
    67  				})
    68  
    69  				It("returns the warnings and error", func() {
    70  					Expect(warnings).To(ConsistOf("some-get-app-warning", "some-delete-app-warning"))
    71  					Expect(executeErr).To(MatchError("some-delete-app-error"))
    72  				})
    73  			})
    74  
    75  			When("sending the delete succeeds", func() {
    76  				BeforeEach(func() {
    77  					fakeCloudControllerClient.DeleteApplicationReturns("/some-job-url", ccv3.Warnings{"some-delete-app-warning"}, nil)
    78  				})
    79  
    80  				When("polling fails", func() {
    81  					BeforeEach(func() {
    82  						fakeCloudControllerClient.PollJobReturns(ccv3.Warnings{"some-poll-warning"}, errors.New("some-poll-error"))
    83  					})
    84  
    85  					It("returns the warnings and poll error", func() {
    86  						Expect(warnings).To(ConsistOf("some-get-app-warning", "some-delete-app-warning", "some-poll-warning"))
    87  						Expect(executeErr).To(MatchError("some-poll-error"))
    88  					})
    89  				})
    90  
    91  				When("polling succeeds", func() {
    92  					BeforeEach(func() {
    93  						fakeCloudControllerClient.PollJobReturns(ccv3.Warnings{"some-poll-warning"}, nil)
    94  					})
    95  
    96  					It("returns all the warnings and no error", func() {
    97  						Expect(warnings).To(ConsistOf("some-get-app-warning", "some-delete-app-warning", "some-poll-warning"))
    98  						Expect(executeErr).ToNot(HaveOccurred())
    99  					})
   100  				})
   101  			})
   102  		})
   103  
   104  		When("attempting to delete mapped routes", func() {
   105  			BeforeEach(func() {
   106  				deleteMappedRoutes = true
   107  				fakeCloudControllerClient.GetApplicationsReturns([]ccv3.Application{{Name: "some-app", GUID: "abc123"}}, nil, nil)
   108  			})
   109  
   110  			When("getting the routes fails", func() {
   111  				BeforeEach(func() {
   112  					fakeCloudControllerClient.GetApplicationRoutesReturns(nil, ccv3.Warnings{"get-routes-warning"}, errors.New("get-routes-error"))
   113  				})
   114  
   115  				It("returns the warnings and an error", func() {
   116  					Expect(warnings).To(ConsistOf("get-routes-warning"))
   117  					Expect(executeErr).To(MatchError("get-routes-error"))
   118  				})
   119  			})
   120  
   121  			When("getting the routes succeeds", func() {
   122  				When("there are no routes", func() {
   123  					BeforeEach(func() {
   124  						fakeCloudControllerClient.GetApplicationRoutesReturns([]ccv3.Route{}, nil, nil)
   125  					})
   126  
   127  					It("does not delete any routes", func() {
   128  						Expect(fakeCloudControllerClient.DeleteRouteCallCount()).To(Equal(0))
   129  					})
   130  				})
   131  
   132  				When("there are routes", func() {
   133  					BeforeEach(func() {
   134  						fakeCloudControllerClient.GetApplicationRoutesReturns([]ccv3.Route{{GUID: "route-1-guid"}, {GUID: "route-2-guid", URL: "route-2.example.com"}}, nil, nil)
   135  					})
   136  
   137  					It("deletes the routes", func() {
   138  						Expect(fakeCloudControllerClient.GetApplicationRoutesCallCount()).To(Equal(1))
   139  						Expect(fakeCloudControllerClient.GetApplicationRoutesArgsForCall(0)).To(Equal("abc123"))
   140  						Expect(fakeCloudControllerClient.DeleteRouteCallCount()).To(Equal(2))
   141  						guids := []string{fakeCloudControllerClient.DeleteRouteArgsForCall(0), fakeCloudControllerClient.DeleteRouteArgsForCall(1)}
   142  						Expect(guids).To(ConsistOf("route-1-guid", "route-2-guid"))
   143  					})
   144  
   145  					When("the route has already been deleted", func() {
   146  						BeforeEach(func() {
   147  							fakeCloudControllerClient.DeleteRouteReturnsOnCall(0,
   148  								"",
   149  								ccv3.Warnings{"delete-route-1-warning"},
   150  								ccerror.ResourceNotFoundError{},
   151  							)
   152  							fakeCloudControllerClient.DeleteRouteReturnsOnCall(1,
   153  								"poll-job-url",
   154  								ccv3.Warnings{"delete-route-2-warning"},
   155  								nil,
   156  							)
   157  							fakeCloudControllerClient.PollJobReturnsOnCall(1, ccv3.Warnings{"poll-job-warning"}, nil)
   158  						})
   159  
   160  						It("does **not** fail", func() {
   161  							Expect(executeErr).ToNot(HaveOccurred())
   162  							Expect(warnings).To(ConsistOf("delete-route-1-warning", "delete-route-2-warning", "poll-job-warning"))
   163  							Expect(fakeCloudControllerClient.DeleteRouteCallCount()).To(Equal(2))
   164  							Expect(fakeCloudControllerClient.PollJobCallCount()).To(Equal(2))
   165  							Expect(fakeCloudControllerClient.PollJobArgsForCall(1)).To(BeEquivalentTo("poll-job-url"))
   166  						})
   167  					})
   168  
   169  					When("app to delete has a route bound to another app", func() {
   170  						BeforeEach(func() {
   171  							fakeCloudControllerClient.GetApplicationRoutesReturns(
   172  								[]ccv3.Route{
   173  									{GUID: "route-1-guid"},
   174  									{GUID: "route-2-guid",
   175  										URL: "route-2.example.com",
   176  										Destinations: []ccv3.RouteDestination{
   177  											{App: ccv3.RouteDestinationApp{GUID: "abc123"}},
   178  											{App: ccv3.RouteDestinationApp{GUID: "different-app-guid"}},
   179  										},
   180  									},
   181  								},
   182  								nil,
   183  								nil,
   184  							)
   185  						})
   186  
   187  						It("refuses the entire operation", func() {
   188  							Expect(executeErr).To(MatchError(actionerror.RouteBoundToMultipleAppsError{AppName: "some-app", RouteURL: "route-2.example.com"}))
   189  							Expect(warnings).To(BeEmpty())
   190  							Expect(fakeCloudControllerClient.DeleteApplicationCallCount()).To(Equal(0))
   191  							Expect(fakeCloudControllerClient.DeleteRouteCallCount()).To(Equal(0))
   192  						})
   193  					})
   194  
   195  					When("deleting the route fails", func() {
   196  						BeforeEach(func() {
   197  							fakeCloudControllerClient.DeleteRouteReturnsOnCall(0,
   198  								"poll-job-url",
   199  								ccv3.Warnings{"delete-route-1-warning"},
   200  								nil,
   201  							)
   202  							fakeCloudControllerClient.DeleteRouteReturnsOnCall(1,
   203  								"",
   204  								ccv3.Warnings{"delete-route-2-warning"},
   205  								errors.New("delete-route-2-error"),
   206  							)
   207  							fakeCloudControllerClient.PollJobReturnsOnCall(1, ccv3.Warnings{"poll-job-warning"}, nil)
   208  						})
   209  
   210  						It("returns the error", func() {
   211  							Expect(executeErr).To(MatchError("delete-route-2-error"))
   212  							Expect(warnings).To(ConsistOf("delete-route-1-warning", "delete-route-2-warning", "poll-job-warning"))
   213  						})
   214  					})
   215  
   216  					When("the polling job fails", func() {
   217  						BeforeEach(func() {
   218  							fakeCloudControllerClient.PollJobReturns(ccv3.Warnings{"poll-job-warning"}, errors.New("poll-job-error"))
   219  						})
   220  
   221  						It("returns the error", func() {
   222  							Expect(executeErr).To(MatchError("poll-job-error"))
   223  						})
   224  					})
   225  
   226  				})
   227  			})
   228  		})
   229  	})
   230  
   231  	Describe("GetApplicationsByGUIDs", func() {
   232  		When("all of the requested apps exist", func() {
   233  			BeforeEach(func() {
   234  				fakeCloudControllerClient.GetApplicationsReturns(
   235  					[]ccv3.Application{
   236  						{
   237  							Name: "some-app-name",
   238  							GUID: "some-app-guid",
   239  						},
   240  						{
   241  							Name: "other-app-name",
   242  							GUID: "other-app-guid",
   243  						},
   244  					},
   245  					ccv3.Warnings{"some-warning"},
   246  					nil,
   247  				)
   248  			})
   249  
   250  			It("returns the applications and warnings", func() {
   251  				apps, warnings, err := actor.GetApplicationsByGUIDs([]string{"some-app-guid", "other-app-guid"})
   252  				Expect(err).ToNot(HaveOccurred())
   253  				Expect(apps).To(ConsistOf(
   254  					Application{
   255  						Name: "some-app-name",
   256  						GUID: "some-app-guid",
   257  					},
   258  					Application{
   259  						Name: "other-app-name",
   260  						GUID: "other-app-guid",
   261  					},
   262  				))
   263  				Expect(warnings).To(ConsistOf("some-warning"))
   264  
   265  				Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   266  				Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   267  					ccv3.Query{Key: ccv3.GUIDFilter, Values: []string{"some-app-guid", "other-app-guid"}},
   268  				))
   269  			})
   270  		})
   271  
   272  		When("at least one of the requested apps does not exist", func() {
   273  			BeforeEach(func() {
   274  				fakeCloudControllerClient.GetApplicationsReturns(
   275  					[]ccv3.Application{
   276  						{
   277  							Name: "some-app-name",
   278  							GUID: "some-app-guid",
   279  						},
   280  					},
   281  					ccv3.Warnings{"some-warning"},
   282  					nil,
   283  				)
   284  			})
   285  
   286  			It("returns an ApplicationNotFoundError and the warnings", func() {
   287  				_, warnings, err := actor.GetApplicationsByGUIDs([]string{"some-app-guid", "non-existent-app-guid"})
   288  				Expect(warnings).To(ConsistOf("some-warning"))
   289  				Expect(err).To(MatchError(actionerror.ApplicationsNotFoundError{}))
   290  			})
   291  		})
   292  
   293  		When("a single app has two routes", func() {
   294  			BeforeEach(func() {
   295  				fakeCloudControllerClient.GetApplicationsReturns(
   296  					[]ccv3.Application{
   297  						{
   298  							Name: "some-app-name",
   299  							GUID: "some-app-guid",
   300  						},
   301  					},
   302  					ccv3.Warnings{"some-warning"},
   303  					nil,
   304  				)
   305  			})
   306  
   307  			It("returns an ApplicationNotFoundError and the warnings", func() {
   308  				_, warnings, err := actor.GetApplicationsByGUIDs([]string{"some-app-guid", "some-app-guid"})
   309  				Expect(err).ToNot(HaveOccurred())
   310  				Expect(warnings).To(ConsistOf("some-warning"))
   311  			})
   312  		})
   313  
   314  		When("the cloud controller client returns an error", func() {
   315  			var expectedError error
   316  
   317  			BeforeEach(func() {
   318  				expectedError = errors.New("I am a CloudControllerClient Error")
   319  				fakeCloudControllerClient.GetApplicationsReturns(
   320  					[]ccv3.Application{},
   321  					ccv3.Warnings{"some-warning"},
   322  					expectedError)
   323  			})
   324  
   325  			It("returns the warnings and the error", func() {
   326  				_, warnings, err := actor.GetApplicationsByGUIDs([]string{"some-app-guid"})
   327  				Expect(warnings).To(ConsistOf("some-warning"))
   328  				Expect(err).To(MatchError(expectedError))
   329  			})
   330  		})
   331  	})
   332  
   333  	Describe("GetApplicationsByNameAndSpace", func() {
   334  		When("all of the requested apps exist", func() {
   335  			BeforeEach(func() {
   336  				fakeCloudControllerClient.GetApplicationsReturns(
   337  					[]ccv3.Application{
   338  						{
   339  							Name: "some-app-name",
   340  							GUID: "some-app-guid",
   341  						},
   342  						{
   343  							Name: "other-app-name",
   344  							GUID: "other-app-guid",
   345  						},
   346  					},
   347  					ccv3.Warnings{"some-warning"},
   348  					nil,
   349  				)
   350  			})
   351  
   352  			It("returns the applications and warnings", func() {
   353  				apps, warnings, err := actor.GetApplicationsByNamesAndSpace([]string{"some-app-name", "other-app-name"}, "some-space-guid")
   354  				Expect(err).ToNot(HaveOccurred())
   355  				Expect(apps).To(ConsistOf(
   356  					Application{
   357  						Name: "some-app-name",
   358  						GUID: "some-app-guid",
   359  					},
   360  					Application{
   361  						Name: "other-app-name",
   362  						GUID: "other-app-guid",
   363  					},
   364  				))
   365  				Expect(warnings).To(ConsistOf("some-warning"))
   366  
   367  				Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   368  				Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   369  					ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name", "other-app-name"}},
   370  					ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
   371  				))
   372  			})
   373  		})
   374  
   375  		When("at least one of the requested apps does not exist", func() {
   376  			BeforeEach(func() {
   377  				fakeCloudControllerClient.GetApplicationsReturns(
   378  					[]ccv3.Application{
   379  						{
   380  							Name: "some-app-name",
   381  						},
   382  					},
   383  					ccv3.Warnings{"some-warning"},
   384  					nil,
   385  				)
   386  			})
   387  
   388  			It("returns an ApplicationNotFoundError and the warnings", func() {
   389  				_, warnings, err := actor.GetApplicationsByNamesAndSpace([]string{"some-app-name", "other-app-name"}, "some-space-guid")
   390  				Expect(warnings).To(ConsistOf("some-warning"))
   391  				Expect(err).To(MatchError(actionerror.ApplicationsNotFoundError{}))
   392  			})
   393  		})
   394  
   395  		When("a given app has two routes", func() {
   396  			BeforeEach(func() {
   397  				fakeCloudControllerClient.GetApplicationsReturns(
   398  					[]ccv3.Application{
   399  						{
   400  							Name: "some-app-name",
   401  						},
   402  					},
   403  					ccv3.Warnings{"some-warning"},
   404  					nil,
   405  				)
   406  			})
   407  
   408  			It("returns an ApplicationNotFoundError and the warnings", func() {
   409  				_, warnings, err := actor.GetApplicationsByNamesAndSpace([]string{"some-app-name", "some-app-name"}, "some-space-guid")
   410  				Expect(err).ToNot(HaveOccurred())
   411  				Expect(warnings).To(ConsistOf("some-warning"))
   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("I am a CloudControllerClient Error")
   420  				fakeCloudControllerClient.GetApplicationsReturns(
   421  					[]ccv3.Application{},
   422  					ccv3.Warnings{"some-warning"},
   423  					expectedError)
   424  			})
   425  
   426  			It("returns the warnings and the error", func() {
   427  				_, warnings, err := actor.GetApplicationsByNamesAndSpace([]string{"some-app-name"}, "some-space-guid")
   428  				Expect(warnings).To(ConsistOf("some-warning"))
   429  				Expect(err).To(MatchError(expectedError))
   430  			})
   431  		})
   432  	})
   433  
   434  	Describe("GetApplicationByNameAndSpace", func() {
   435  		When("the app exists", func() {
   436  			BeforeEach(func() {
   437  				fakeCloudControllerClient.GetApplicationsReturns(
   438  					[]ccv3.Application{
   439  						{
   440  							Name: "some-app-name",
   441  							GUID: "some-app-guid",
   442  							Metadata: &ccv3.Metadata{
   443  								Labels: map[string]types.NullString{
   444  									"some-key": types.NewNullString("some-value"),
   445  								},
   446  							},
   447  						},
   448  					},
   449  					ccv3.Warnings{"some-warning"},
   450  					nil,
   451  				)
   452  			})
   453  
   454  			It("returns the application and warnings", func() {
   455  				app, warnings, err := actor.GetApplicationByNameAndSpace("some-app-name", "some-space-guid")
   456  				Expect(err).ToNot(HaveOccurred())
   457  				Expect(app).To(Equal(Application{
   458  					Name: "some-app-name",
   459  					GUID: "some-app-guid",
   460  					Metadata: &Metadata{
   461  						Labels: map[string]types.NullString{"some-key": types.NewNullString("some-value")},
   462  					},
   463  				}))
   464  				Expect(warnings).To(ConsistOf("some-warning"))
   465  
   466  				Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   467  				Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   468  					ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name"}},
   469  					ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
   470  				))
   471  			})
   472  		})
   473  
   474  		When("the cloud controller client returns an error", func() {
   475  			var expectedError error
   476  
   477  			BeforeEach(func() {
   478  				expectedError = errors.New("I am a CloudControllerClient Error")
   479  				fakeCloudControllerClient.GetApplicationsReturns(
   480  					[]ccv3.Application{},
   481  					ccv3.Warnings{"some-warning"},
   482  					expectedError)
   483  			})
   484  
   485  			It("returns the warnings and the error", func() {
   486  				_, warnings, err := actor.GetApplicationByNameAndSpace("some-app-name", "some-space-guid")
   487  				Expect(warnings).To(ConsistOf("some-warning"))
   488  				Expect(err).To(MatchError(expectedError))
   489  			})
   490  		})
   491  
   492  		When("the app does not exist", func() {
   493  			BeforeEach(func() {
   494  				fakeCloudControllerClient.GetApplicationsReturns(
   495  					[]ccv3.Application{},
   496  					ccv3.Warnings{"some-warning"},
   497  					nil,
   498  				)
   499  			})
   500  
   501  			It("returns an ApplicationNotFoundError and the warnings", func() {
   502  				_, warnings, err := actor.GetApplicationByNameAndSpace("some-app-name", "some-space-guid")
   503  				Expect(warnings).To(ConsistOf("some-warning"))
   504  				Expect(err).To(MatchError(actionerror.ApplicationNotFoundError{Name: "some-app-name"}))
   505  			})
   506  		})
   507  	})
   508  
   509  	Describe("GetApplicationsBySpace", func() {
   510  		When("the there are applications in the space", func() {
   511  			BeforeEach(func() {
   512  				fakeCloudControllerClient.GetApplicationsReturns(
   513  					[]ccv3.Application{
   514  						{
   515  							GUID: "some-app-guid-1",
   516  							Name: "some-app-1",
   517  						},
   518  						{
   519  							GUID: "some-app-guid-2",
   520  							Name: "some-app-2",
   521  						},
   522  					},
   523  					ccv3.Warnings{"warning-1", "warning-2"},
   524  					nil,
   525  				)
   526  			})
   527  
   528  			It("returns the application and warnings", func() {
   529  				apps, warnings, err := actor.GetApplicationsBySpace("some-space-guid")
   530  				Expect(err).ToNot(HaveOccurred())
   531  				Expect(apps).To(ConsistOf(
   532  					Application{
   533  						GUID: "some-app-guid-1",
   534  						Name: "some-app-1",
   535  					},
   536  					Application{
   537  						GUID: "some-app-guid-2",
   538  						Name: "some-app-2",
   539  					},
   540  				))
   541  				Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   542  
   543  				Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   544  				Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   545  					ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
   546  				))
   547  			})
   548  		})
   549  
   550  		When("the cloud controller client returns an error", func() {
   551  			var expectedError error
   552  
   553  			BeforeEach(func() {
   554  				expectedError = errors.New("I am a CloudControllerClient Error")
   555  				fakeCloudControllerClient.GetApplicationsReturns(
   556  					[]ccv3.Application{},
   557  					ccv3.Warnings{"some-warning"},
   558  					expectedError)
   559  			})
   560  
   561  			It("returns the error and warnings", func() {
   562  				_, warnings, err := actor.GetApplicationsBySpace("some-space-guid")
   563  				Expect(warnings).To(ConsistOf("some-warning"))
   564  				Expect(err).To(MatchError(expectedError))
   565  			})
   566  		})
   567  	})
   568  
   569  	Describe("CreateApplicationInSpace", func() {
   570  		var (
   571  			application Application
   572  			warnings    Warnings
   573  			err         error
   574  		)
   575  
   576  		JustBeforeEach(func() {
   577  			application, warnings, err = actor.CreateApplicationInSpace(Application{
   578  				Name:                "some-app-name",
   579  				LifecycleType:       constant.AppLifecycleTypeBuildpack,
   580  				LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   581  			}, "some-space-guid")
   582  		})
   583  
   584  		When("the app successfully gets created", func() {
   585  			BeforeEach(func() {
   586  				fakeCloudControllerClient.CreateApplicationReturns(
   587  					ccv3.Application{
   588  						Name:                "some-app-name",
   589  						GUID:                "some-app-guid",
   590  						LifecycleType:       constant.AppLifecycleTypeBuildpack,
   591  						LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   592  					},
   593  					ccv3.Warnings{"some-warning"},
   594  					nil,
   595  				)
   596  			})
   597  
   598  			It("creates and returns the application and warnings", func() {
   599  				Expect(err).ToNot(HaveOccurred())
   600  				Expect(application).To(Equal(Application{
   601  					Name:                "some-app-name",
   602  					GUID:                "some-app-guid",
   603  					LifecycleType:       constant.AppLifecycleTypeBuildpack,
   604  					LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   605  				}))
   606  				Expect(warnings).To(ConsistOf("some-warning"))
   607  
   608  				Expect(fakeCloudControllerClient.CreateApplicationCallCount()).To(Equal(1))
   609  				Expect(fakeCloudControllerClient.CreateApplicationArgsForCall(0)).To(Equal(ccv3.Application{
   610  					Name: "some-app-name",
   611  					Relationships: ccv3.Relationships{
   612  						constant.RelationshipTypeSpace: ccv3.Relationship{GUID: "some-space-guid"},
   613  					},
   614  					LifecycleType:       constant.AppLifecycleTypeBuildpack,
   615  					LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   616  				}))
   617  			})
   618  		})
   619  
   620  		When("the cc client returns an error", func() {
   621  			var expectedError error
   622  
   623  			BeforeEach(func() {
   624  				expectedError = errors.New("I am a CloudControllerClient Error")
   625  				fakeCloudControllerClient.CreateApplicationReturns(
   626  					ccv3.Application{},
   627  					ccv3.Warnings{"some-warning"},
   628  					expectedError,
   629  				)
   630  			})
   631  
   632  			It("raises the error and warnings", func() {
   633  				Expect(err).To(MatchError(expectedError))
   634  				Expect(warnings).To(ConsistOf("some-warning"))
   635  			})
   636  		})
   637  
   638  		When("the cc client returns an NameNotUniqueInSpaceError", func() {
   639  			BeforeEach(func() {
   640  				fakeCloudControllerClient.CreateApplicationReturns(
   641  					ccv3.Application{},
   642  					ccv3.Warnings{"some-warning"},
   643  					ccerror.NameNotUniqueInSpaceError{},
   644  				)
   645  			})
   646  
   647  			It("returns the NameNotUniqueInSpaceError and warnings", func() {
   648  				Expect(err).To(MatchError(ccerror.NameNotUniqueInSpaceError{}))
   649  				Expect(warnings).To(ConsistOf("some-warning"))
   650  			})
   651  		})
   652  	})
   653  
   654  	Describe("UpdateApplication", func() {
   655  		var (
   656  			submitApp, resultApp Application
   657  			warnings             Warnings
   658  			err                  error
   659  		)
   660  
   661  		JustBeforeEach(func() {
   662  			submitApp = Application{
   663  				GUID:                "some-app-guid",
   664  				StackName:           "some-stack-name",
   665  				Name:                "some-app-name",
   666  				LifecycleType:       constant.AppLifecycleTypeBuildpack,
   667  				LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   668  				Metadata: &Metadata{Labels: map[string]types.NullString{
   669  					"some-label":  types.NewNullString("some-value"),
   670  					"other-label": types.NewNullString("other-value"),
   671  				}},
   672  			}
   673  
   674  			resultApp, warnings, err = actor.UpdateApplication(submitApp)
   675  		})
   676  
   677  		When("the app successfully gets updated", func() {
   678  			var apiResponseApp ccv3.Application
   679  
   680  			BeforeEach(func() {
   681  				apiResponseApp = ccv3.Application{
   682  					GUID:                "response-app-guid",
   683  					StackName:           "response-stack-name",
   684  					Name:                "response-app-name",
   685  					LifecycleType:       constant.AppLifecycleTypeBuildpack,
   686  					LifecycleBuildpacks: []string{"response-buildpack-1", "response-buildpack-2"},
   687  				}
   688  				fakeCloudControllerClient.UpdateApplicationReturns(
   689  					apiResponseApp,
   690  					ccv3.Warnings{"some-warning"},
   691  					nil,
   692  				)
   693  			})
   694  
   695  			It("creates and returns the application and warnings", func() {
   696  				Expect(err).ToNot(HaveOccurred())
   697  				Expect(resultApp).To(Equal(Application{
   698  					Name:                apiResponseApp.Name,
   699  					GUID:                apiResponseApp.GUID,
   700  					StackName:           apiResponseApp.StackName,
   701  					LifecycleType:       apiResponseApp.LifecycleType,
   702  					LifecycleBuildpacks: apiResponseApp.LifecycleBuildpacks,
   703  				}))
   704  				Expect(warnings).To(ConsistOf("some-warning"))
   705  
   706  				Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(1))
   707  				Expect(fakeCloudControllerClient.UpdateApplicationArgsForCall(0)).To(Equal(ccv3.Application{
   708  					GUID:                submitApp.GUID,
   709  					StackName:           submitApp.StackName,
   710  					LifecycleType:       submitApp.LifecycleType,
   711  					LifecycleBuildpacks: submitApp.LifecycleBuildpacks,
   712  					Name:                submitApp.Name,
   713  					Metadata:            (*ccv3.Metadata)(submitApp.Metadata),
   714  				}))
   715  			})
   716  		})
   717  
   718  		When("the cc client returns an error", func() {
   719  			var expectedError error
   720  
   721  			BeforeEach(func() {
   722  				expectedError = errors.New("I am a CloudControllerClient Error")
   723  				fakeCloudControllerClient.UpdateApplicationReturns(
   724  					ccv3.Application{},
   725  					ccv3.Warnings{"some-warning"},
   726  					expectedError,
   727  				)
   728  			})
   729  
   730  			It("raises the error and warnings", func() {
   731  				Expect(err).To(MatchError(expectedError))
   732  				Expect(warnings).To(ConsistOf("some-warning"))
   733  			})
   734  		})
   735  	})
   736  
   737  	Describe("PollStart", func() {
   738  		var (
   739  			appGUID string
   740  			noWait  bool
   741  
   742  			done chan bool
   743  
   744  			warnings   Warnings
   745  			executeErr error
   746  		)
   747  
   748  		BeforeEach(func() {
   749  			done = make(chan bool)
   750  			fakeConfig.StartupTimeoutReturns(2 * time.Second)
   751  			fakeConfig.PollingIntervalReturns(1 * time.Second)
   752  			appGUID = "some-guid"
   753  			noWait = false
   754  		})
   755  
   756  		JustBeforeEach(func() {
   757  			go func() {
   758  				defer close(done)
   759  				warnings, executeErr = actor.PollStart(appGUID, noWait)
   760  				done <- true
   761  			}()
   762  		})
   763  
   764  		It("gets the apps processes", func() {
   765  			// advanced clock so function exits
   766  			fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2)
   767  
   768  			// wait for function to finish
   769  			Eventually(done).Should(Receive(BeTrue()))
   770  
   771  			Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(1))
   772  			Expect(fakeCloudControllerClient.GetApplicationProcessesArgsForCall(0)).To(Equal("some-guid"))
   773  
   774  		})
   775  
   776  		When("getting the application processes fails", func() {
   777  			BeforeEach(func() {
   778  				fakeCloudControllerClient.GetApplicationProcessesReturns(nil, ccv3.Warnings{"get-app-warning-1", "get-app-warning-2"}, errors.New("some-error"))
   779  			})
   780  
   781  			It("returns the error and all warnings", func() {
   782  				// wait for function to finish
   783  				Eventually(done).Should(Receive(BeTrue()))
   784  
   785  				Expect(executeErr).To(MatchError(errors.New("some-error")))
   786  				Expect(warnings).To(ConsistOf("get-app-warning-1", "get-app-warning-2"))
   787  			})
   788  		})
   789  
   790  		When("getting the application process succeeds", func() {
   791  			BeforeEach(func() {
   792  				fakeCloudControllerClient.GetApplicationProcessesReturns(
   793  					[]ccv3.Process{
   794  						{GUID: "process1", Type: "web"},
   795  					},
   796  					ccv3.Warnings{"get-app-warning-1"},
   797  					nil,
   798  				)
   799  
   800  			})
   801  
   802  			It("gets the startup timeout", func() {
   803  				// advanced clock so function exits
   804  				fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2)
   805  
   806  				// wait for function to finish
   807  				Eventually(done).Should(Receive(BeTrue()))
   808  
   809  				Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1))
   810  			})
   811  
   812  			When("the no-wait flag is provided", func() {
   813  				BeforeEach(func() {
   814  					noWait = true
   815  					fakeCloudControllerClient.GetApplicationProcessesReturns(
   816  						[]ccv3.Process{
   817  							{GUID: "process1", Type: "web"},
   818  							{GUID: "process2", Type: "worker"},
   819  						},
   820  						ccv3.Warnings{"get-app-warning-1"},
   821  						nil,
   822  					)
   823  				})
   824  
   825  				It("filters out the non web processes", func() {
   826  					// send something on the timer channel
   827  					fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2)
   828  
   829  					// Wait for function to finish
   830  					Eventually(done).Should(Receive(BeTrue()))
   831  
   832  					// assert on the cc call made within poll processes to make sure there is only the web process
   833  					Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(1))
   834  					Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("process1"))
   835  
   836  				})
   837  			})
   838  
   839  			When("polling processes returns an error", func() {
   840  				BeforeEach(func() {
   841  					fakeCloudControllerClient.GetProcessInstancesReturns(nil, ccv3.Warnings{"poll-process-warning"}, errors.New("poll-process-error"))
   842  				})
   843  
   844  				It("returns the error and warnings", func() {
   845  					// send something on the timer channel
   846  					fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2)
   847  
   848  					// Wait for function to finish
   849  					Eventually(done).Should(Receive(BeTrue()))
   850  
   851  					Expect(executeErr).Should(MatchError("poll-process-error"))
   852  					Expect(warnings).Should(ConsistOf("poll-process-warning", "get-app-warning-1"))
   853  				})
   854  			})
   855  
   856  			When("polling start times out", func() {
   857  				BeforeEach(func() {
   858  					fakeCloudControllerClient.GetProcessInstancesReturns(
   859  						[]ccv3.ProcessInstance{
   860  							{State: constant.ProcessInstanceStarting},
   861  						},
   862  						ccv3.Warnings{"poll-process-warning"},
   863  						nil,
   864  					)
   865  
   866  					fakeConfig.StartupTimeoutReturns(2 * time.Millisecond)
   867  				})
   868  
   869  				It("returns a timeout error and any warnings", func() {
   870  					// send something on the timer channel for first tick
   871  					fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2)
   872  
   873  					fakeClock.Increment(1 * time.Millisecond)
   874  
   875  					// Wait for function to finish
   876  					Eventually(done).Should(Receive(BeTrue()))
   877  
   878  					Expect(executeErr).To(MatchError(actionerror.StartupTimeoutError{}))
   879  					Expect(warnings).To(ConsistOf("poll-process-warning", "get-app-warning-1"))
   880  				})
   881  			})
   882  
   883  			When("polling process eventually returns we should stop polling", func() {
   884  				BeforeEach(func() {
   885  					fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(0,
   886  						[]ccv3.ProcessInstance{
   887  							{State: constant.ProcessInstanceStarting},
   888  						},
   889  						ccv3.Warnings{"poll-process-warning1"},
   890  						nil,
   891  					)
   892  
   893  					fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(1,
   894  						[]ccv3.ProcessInstance{
   895  							{State: constant.ProcessInstanceRunning},
   896  						},
   897  						ccv3.Warnings{"poll-process-warning2"},
   898  						nil,
   899  					)
   900  				})
   901  
   902  				It("returns success and any warnings", func() {
   903  					// send something on the timer channel
   904  					fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2)
   905  
   906  					Eventually(fakeConfig.PollingIntervalCallCount).Should(Equal(1))
   907  
   908  					fakeClock.Increment(1 * time.Second)
   909  
   910  					// Wait for function to finish
   911  					Eventually(done).Should(Receive(BeTrue()))
   912  					Expect(executeErr).NotTo(HaveOccurred())
   913  					Expect(warnings).To(ConsistOf("poll-process-warning1", "get-app-warning-1", "poll-process-warning2"))
   914  				})
   915  
   916  			})
   917  		})
   918  	})
   919  
   920  	Describe("PollStartForRolling", func() {
   921  		var (
   922  			appGUID        string
   923  			deploymentGUID string
   924  			noWait         bool
   925  
   926  			done chan bool
   927  
   928  			warnings   Warnings
   929  			executeErr error
   930  		)
   931  
   932  		BeforeEach(func() {
   933  			appGUID = "some-rolling-app-guid"
   934  			deploymentGUID = "some-deployment-guid"
   935  			noWait = false
   936  
   937  			done = make(chan bool)
   938  
   939  			fakeConfig.StartupTimeoutReturns(5 * time.Second)
   940  			fakeConfig.PollingIntervalReturns(1 * time.Second)
   941  		})
   942  
   943  		JustBeforeEach(func() {
   944  			go func() {
   945  				warnings, executeErr = actor.PollStartForRolling(appGUID, deploymentGUID, noWait)
   946  				done <- true
   947  			}()
   948  		})
   949  
   950  		When("There is a non-timeout failure in the loop", func() {
   951  			// this may need to be expanded to also include when the deployment is superseded or cancelled
   952  			When("getting the deployment fails", func() {
   953  				When("it is because the deployment was cancelled", func() {
   954  					BeforeEach(func() {
   955  						fakeCloudControllerClient.GetDeploymentReturns(
   956  							ccv3.Deployment{
   957  								StatusValue:  constant.DeploymentStatusValueFinalized,
   958  								StatusReason: constant.DeploymentStatusReasonCanceled,
   959  							},
   960  							ccv3.Warnings{"get-deployment-warning"},
   961  							nil,
   962  						)
   963  					})
   964  
   965  					It("returns warnings and the error", func() {
   966  						// initial tick
   967  						fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2)
   968  
   969  						// wait for func to finish
   970  						Eventually(done).Should(Receive(BeTrue()))
   971  
   972  						Expect(executeErr).To(MatchError("Deployment has been canceled"))
   973  						Expect(warnings).To(ConsistOf("get-deployment-warning"))
   974  
   975  						Expect(fakeCloudControllerClient.GetDeploymentCallCount()).To(Equal(1))
   976  						Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID))
   977  
   978  						Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(0))
   979  						Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(0))
   980  
   981  						Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1))
   982  					})
   983  
   984  				})
   985  
   986  				When("it is because the deployment was superseded", func() {
   987  					BeforeEach(func() {
   988  						fakeCloudControllerClient.GetDeploymentReturns(
   989  							ccv3.Deployment{
   990  								StatusValue:  constant.DeploymentStatusValueFinalized,
   991  								StatusReason: constant.DeploymentStatusReasonSuperseded,
   992  							},
   993  							ccv3.Warnings{"get-deployment-warning"},
   994  							nil,
   995  						)
   996  					})
   997  
   998  					It("returns warnings and the error", func() {
   999  						// initial tick
  1000  						fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2)
  1001  
  1002  						// wait for func to finish
  1003  						Eventually(done).Should(Receive(BeTrue()))
  1004  
  1005  						Expect(executeErr).To(MatchError("Deployment has been superseded"))
  1006  						Expect(warnings).To(ConsistOf("get-deployment-warning"))
  1007  
  1008  						Expect(fakeCloudControllerClient.GetDeploymentCallCount()).To(Equal(1))
  1009  						Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID))
  1010  
  1011  						Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(0))
  1012  						Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(0))
  1013  
  1014  						Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1))
  1015  					})
  1016  
  1017  				})
  1018  
  1019  				When("it is because of an API error", func() {
  1020  					BeforeEach(func() {
  1021  						fakeCloudControllerClient.GetDeploymentReturns(
  1022  							ccv3.Deployment{},
  1023  							ccv3.Warnings{"get-deployment-warning"},
  1024  							errors.New("get-deployment-error"),
  1025  						)
  1026  					})
  1027  
  1028  					It("returns warnings and the error", func() {
  1029  						// initial tick
  1030  						fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2)
  1031  
  1032  						// wait for func to finish
  1033  						Eventually(done).Should(Receive(BeTrue()))
  1034  
  1035  						Expect(executeErr).To(MatchError("get-deployment-error"))
  1036  						Expect(warnings).To(ConsistOf("get-deployment-warning"))
  1037  
  1038  						Expect(fakeCloudControllerClient.GetDeploymentCallCount()).To(Equal(1))
  1039  						Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID))
  1040  
  1041  						Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(0))
  1042  						Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(0))
  1043  
  1044  						Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1))
  1045  					})
  1046  
  1047  				})
  1048  			})
  1049  
  1050  			When("getting the deployment succeeds", func() {
  1051  				BeforeEach(func() {
  1052  					// get processes requires the deployment to be deployed so we need this to indirectly test the error case
  1053  					fakeCloudControllerClient.GetDeploymentReturns(
  1054  						ccv3.Deployment{StatusValue: constant.DeploymentStatusValueFinalized, StatusReason: constant.DeploymentStatusReasonDeployed},
  1055  						ccv3.Warnings{"get-deployment-warning"},
  1056  						nil,
  1057  					)
  1058  
  1059  				})
  1060  
  1061  				When("getting the processes fails", func() {
  1062  					BeforeEach(func() {
  1063  						fakeCloudControllerClient.GetApplicationProcessesReturns(
  1064  							[]ccv3.Process{},
  1065  							ccv3.Warnings{"get-processes-warning"},
  1066  							errors.New("get-processes-error"),
  1067  						)
  1068  					})
  1069  
  1070  					It("returns warnings and the error", func() {
  1071  						// initial tick
  1072  						fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2)
  1073  
  1074  						// wait for func to finish
  1075  						Eventually(done).Should(Receive(BeTrue()))
  1076  
  1077  						Expect(executeErr).To(MatchError("get-processes-error"))
  1078  						Expect(warnings).To(ConsistOf("get-deployment-warning", "get-processes-warning"))
  1079  
  1080  						Expect(fakeCloudControllerClient.GetDeploymentCallCount()).To(Equal(1))
  1081  						Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID))
  1082  
  1083  						Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(1))
  1084  						Expect(fakeCloudControllerClient.GetApplicationProcessesArgsForCall(0)).To(Equal(appGUID))
  1085  
  1086  						Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(0))
  1087  
  1088  					})
  1089  				})
  1090  
  1091  				When("getting the processes succeeds", func() {
  1092  					BeforeEach(func() {
  1093  						fakeCloudControllerClient.GetApplicationProcessesReturns(
  1094  							[]ccv3.Process{{GUID: "process-guid"}},
  1095  							ccv3.Warnings{"get-processes-warning"},
  1096  							nil,
  1097  						)
  1098  					})
  1099  
  1100  					When("polling the processes fails", func() {
  1101  						BeforeEach(func() {
  1102  							fakeCloudControllerClient.GetProcessInstancesReturns(
  1103  								[]ccv3.ProcessInstance{},
  1104  								ccv3.Warnings{"poll-processes-warning"},
  1105  								errors.New("poll-processes-error"),
  1106  							)
  1107  						})
  1108  
  1109  						It("returns all warnings and errors", func() {
  1110  							// initial tick
  1111  							fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2)
  1112  
  1113  							// wait for func to finish
  1114  							Eventually(done).Should(Receive(BeTrue()))
  1115  
  1116  							Expect(executeErr).To(MatchError("poll-processes-error"))
  1117  							Expect(warnings).To(ConsistOf("get-deployment-warning", "get-processes-warning", "poll-processes-warning"))
  1118  
  1119  							Expect(fakeCloudControllerClient.GetDeploymentCallCount()).To(Equal(1))
  1120  							Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID))
  1121  
  1122  							Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(1))
  1123  							Expect(fakeCloudControllerClient.GetApplicationProcessesArgsForCall(0)).To(Equal(appGUID))
  1124  
  1125  							Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(1))
  1126  							Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("process-guid"))
  1127  						})
  1128  
  1129  					})
  1130  				})
  1131  
  1132  			})
  1133  
  1134  		})
  1135  
  1136  		// intentionally ignore the no-wait flag here for simplicity. One of these two things must cause timeout regardless of no-wait state
  1137  		When("there is a timeout error", func() {
  1138  			BeforeEach(func() {
  1139  				// 1 millisecond for initial tick then 1 to trigger timeout
  1140  				fakeConfig.StartupTimeoutReturns(2 * time.Millisecond)
  1141  			})
  1142  
  1143  			When("the deployment never deploys", func() {
  1144  				BeforeEach(func() {
  1145  					fakeCloudControllerClient.GetDeploymentReturns(
  1146  						ccv3.Deployment{StatusValue: constant.DeploymentStatusValueActive},
  1147  						ccv3.Warnings{"get-deployment-warning"},
  1148  						nil,
  1149  					)
  1150  				})
  1151  
  1152  				It("returns a timeout error and any warnings", func() {
  1153  					// initial tick
  1154  					fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2)
  1155  
  1156  					Eventually(fakeCloudControllerClient.GetDeploymentCallCount).Should(Equal(1))
  1157  
  1158  					// timeout tick
  1159  					fakeClock.Increment(1 * time.Millisecond)
  1160  
  1161  					// wait for func to finish
  1162  					Eventually(done).Should(Receive(BeTrue()))
  1163  
  1164  					Expect(executeErr).To(MatchError(actionerror.StartupTimeoutError{}))
  1165  					Expect(warnings).To(ConsistOf("get-deployment-warning"))
  1166  				})
  1167  			})
  1168  
  1169  			When("the processes dont become healthy", func() {
  1170  				BeforeEach(func() {
  1171  					fakeCloudControllerClient.GetDeploymentReturns(
  1172  						ccv3.Deployment{StatusValue: constant.DeploymentStatusValueFinalized, StatusReason: constant.DeploymentStatusReasonDeployed},
  1173  						ccv3.Warnings{"get-deployment-warning"},
  1174  						nil,
  1175  					)
  1176  
  1177  					fakeCloudControllerClient.GetApplicationProcessesReturns(
  1178  						[]ccv3.Process{{GUID: "process-guid"}},
  1179  						ccv3.Warnings{"get-processes-warning"},
  1180  						nil,
  1181  					)
  1182  
  1183  					fakeCloudControllerClient.GetProcessInstancesReturns(
  1184  						[]ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}},
  1185  						ccv3.Warnings{"poll-processes-warning"},
  1186  						nil,
  1187  					)
  1188  				})
  1189  
  1190  				It("returns a timeout error and any warnings", func() {
  1191  					// initial tick
  1192  					fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2)
  1193  
  1194  					Eventually(fakeCloudControllerClient.GetDeploymentCallCount).Should(Equal(1))
  1195  					Eventually(fakeCloudControllerClient.GetApplicationProcessesCallCount).Should(Equal(1))
  1196  					Eventually(fakeCloudControllerClient.GetProcessInstancesCallCount).Should(Equal(1))
  1197  
  1198  					// timeout tick
  1199  					fakeClock.Increment(1 * time.Millisecond)
  1200  
  1201  					// wait for func to finish
  1202  					Eventually(done).Should(Receive(BeTrue()))
  1203  
  1204  					Expect(executeErr).To(MatchError(actionerror.StartupTimeoutError{}))
  1205  					Expect(warnings).To(ConsistOf("get-deployment-warning", "get-processes-warning", "poll-processes-warning"))
  1206  				})
  1207  
  1208  			})
  1209  		})
  1210  
  1211  		When("things eventually become healthy", func() {
  1212  			When("the no wait flag is given", func() {
  1213  				BeforeEach(func() {
  1214  					// in total three loops 1: deployment still deploying 2: deployment deployed processes starting 3: processes started
  1215  					noWait = true
  1216  
  1217  					// Always return deploying as a way to check we respect no wait
  1218  					fakeCloudControllerClient.GetDeploymentReturns(
  1219  						ccv3.Deployment{
  1220  							StatusValue:  constant.DeploymentStatusValueActive,
  1221  							NewProcesses: []ccv3.Process{{GUID: "new-deployment-process"}},
  1222  						},
  1223  						ccv3.Warnings{"get-deployment-warning"},
  1224  						nil,
  1225  					)
  1226  
  1227  					// We only poll the processes. Two loops for fun
  1228  					fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(0,
  1229  						[]ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}},
  1230  						ccv3.Warnings{"poll-processes-warning-1"},
  1231  						nil,
  1232  					)
  1233  
  1234  					fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(1,
  1235  						[]ccv3.ProcessInstance{{State: constant.ProcessInstanceRunning}},
  1236  						ccv3.Warnings{"poll-processes-warning-2"},
  1237  						nil,
  1238  					)
  1239  				})
  1240  
  1241  				It("polls the start of the application correctly and returns warnings and no error", func() {
  1242  					// Initial tick
  1243  					fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2)
  1244  
  1245  					// assert one of our watcher is the timeout
  1246  					Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1))
  1247  
  1248  					// the first time through we always get the deployment regardless of no-wait
  1249  					Eventually(fakeCloudControllerClient.GetDeploymentCallCount).Should(Equal(1))
  1250  					Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID))
  1251  					Eventually(fakeCloudControllerClient.GetProcessInstancesCallCount).Should(Equal(1))
  1252  					Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("new-deployment-process"))
  1253  					Eventually(fakeConfig.PollingIntervalCallCount).Should(Equal(1))
  1254  
  1255  					fakeClock.Increment(1 * time.Second)
  1256  
  1257  					Eventually(fakeCloudControllerClient.GetDeploymentCallCount).Should(Equal(2))
  1258  					Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID))
  1259  					Eventually(fakeCloudControllerClient.GetProcessInstancesCallCount).Should(Equal(2))
  1260  					Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("new-deployment-process"))
  1261  
  1262  					Eventually(done).Should(Receive(BeTrue()))
  1263  
  1264  					Expect(executeErr).NotTo(HaveOccurred())
  1265  					Expect(warnings).To(ConsistOf(
  1266  						"get-deployment-warning",
  1267  						"poll-processes-warning-1",
  1268  						"get-deployment-warning",
  1269  						"poll-processes-warning-2",
  1270  					))
  1271  
  1272  					Expect(fakeCloudControllerClient.GetDeploymentCallCount()).To(Equal(2))
  1273  					Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(0))
  1274  					Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(2))
  1275  					Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(1))
  1276  
  1277  				})
  1278  
  1279  			})
  1280  
  1281  			When("the no wait flag is not given", func() {
  1282  				BeforeEach(func() {
  1283  					// in total three loops 1: deployment still deploying 2: deployment deployed processes starting 3: processes started
  1284  					fakeCloudControllerClient.GetDeploymentReturnsOnCall(0,
  1285  						ccv3.Deployment{StatusValue: constant.DeploymentStatusValueActive},
  1286  						ccv3.Warnings{"get-deployment-warning-1"},
  1287  						nil,
  1288  					)
  1289  
  1290  					// Poll the deployment twice to make sure we are polling (one in the above before each)
  1291  					fakeCloudControllerClient.GetDeploymentReturnsOnCall(1,
  1292  						ccv3.Deployment{StatusValue: constant.DeploymentStatusValueFinalized, StatusReason: constant.DeploymentStatusReasonDeployed},
  1293  						ccv3.Warnings{"get-deployment-warning-2"},
  1294  						nil,
  1295  					)
  1296  
  1297  					// then we get the processes. This should only be called once
  1298  					fakeCloudControllerClient.GetApplicationProcessesReturns(
  1299  						[]ccv3.Process{{GUID: "process-guid"}},
  1300  						ccv3.Warnings{"get-processes-warning"},
  1301  						nil,
  1302  					)
  1303  
  1304  					// then we poll the processes. Two loops for fun
  1305  					fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(0,
  1306  						[]ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}},
  1307  						ccv3.Warnings{"poll-processes-warning-1"},
  1308  						nil,
  1309  					)
  1310  
  1311  					fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(1,
  1312  						[]ccv3.ProcessInstance{{State: constant.ProcessInstanceRunning}},
  1313  						ccv3.Warnings{"poll-processes-warning-2"},
  1314  						nil,
  1315  					)
  1316  				})
  1317  
  1318  				It("polls the start of the application correctly and returns warnings and no error", func() {
  1319  					// Initial tick
  1320  					fakeClock.WaitForNWatchersAndIncrement(1*time.Millisecond, 2)
  1321  
  1322  					// assert one of our watchers is for the timeout
  1323  					Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1))
  1324  
  1325  					Eventually(fakeCloudControllerClient.GetDeploymentCallCount).Should(Equal(1))
  1326  					Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(0)).To(Equal(deploymentGUID))
  1327  					Eventually(fakeConfig.PollingIntervalCallCount).Should(Equal(1))
  1328  
  1329  					// start the second loop where the deployment is deployed so we poll processes
  1330  					fakeClock.Increment(1 * time.Second)
  1331  
  1332  					Eventually(fakeCloudControllerClient.GetDeploymentCallCount).Should(Equal(2))
  1333  					Expect(fakeCloudControllerClient.GetDeploymentArgsForCall(1)).To(Equal(deploymentGUID))
  1334  					Eventually(fakeCloudControllerClient.GetApplicationProcessesCallCount).Should(Equal(1))
  1335  					Expect(fakeCloudControllerClient.GetApplicationProcessesArgsForCall(0)).To(Equal(appGUID))
  1336  					Eventually(fakeCloudControllerClient.GetProcessInstancesCallCount).Should(Equal(1))
  1337  					Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("process-guid"))
  1338  					Eventually(fakeConfig.PollingIntervalCallCount).Should(Equal(2))
  1339  
  1340  					fakeClock.Increment(1 * time.Second)
  1341  
  1342  					// we should stop polling because it is deployed
  1343  					Eventually(fakeCloudControllerClient.GetProcessInstancesCallCount).Should(Equal(2))
  1344  					Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("process-guid"))
  1345  
  1346  					Eventually(done).Should(Receive(BeTrue()))
  1347  
  1348  					Expect(executeErr).NotTo(HaveOccurred())
  1349  					Expect(warnings).To(ConsistOf(
  1350  						"get-deployment-warning-1",
  1351  						"get-deployment-warning-2",
  1352  						"get-processes-warning",
  1353  						"poll-processes-warning-1",
  1354  						"poll-processes-warning-2",
  1355  					))
  1356  
  1357  					Expect(fakeCloudControllerClient.GetDeploymentCallCount()).To(Equal(2))
  1358  					Expect(fakeCloudControllerClient.GetApplicationProcessesCallCount()).To(Equal(1))
  1359  					Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(2))
  1360  					Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(2))
  1361  
  1362  				})
  1363  
  1364  			})
  1365  
  1366  		})
  1367  	})
  1368  
  1369  	Describe("SetApplicationProcessHealthCheckTypeByNameAndSpace", func() {
  1370  		var (
  1371  			healthCheckType     constant.HealthCheckType
  1372  			healthCheckEndpoint string
  1373  
  1374  			warnings Warnings
  1375  			err      error
  1376  			app      Application
  1377  		)
  1378  
  1379  		BeforeEach(func() {
  1380  			healthCheckType = constant.HTTP
  1381  			healthCheckEndpoint = "some-http-endpoint"
  1382  		})
  1383  
  1384  		JustBeforeEach(func() {
  1385  			app, warnings, err = actor.SetApplicationProcessHealthCheckTypeByNameAndSpace(
  1386  				"some-app-name",
  1387  				"some-space-guid",
  1388  				healthCheckType,
  1389  				healthCheckEndpoint,
  1390  				"some-process-type",
  1391  				42,
  1392  			)
  1393  		})
  1394  
  1395  		When("getting application returns an error", func() {
  1396  			var expectedErr error
  1397  
  1398  			BeforeEach(func() {
  1399  				expectedErr = errors.New("some-error")
  1400  				fakeCloudControllerClient.GetApplicationsReturns(
  1401  					[]ccv3.Application{},
  1402  					ccv3.Warnings{"some-warning"},
  1403  					expectedErr,
  1404  				)
  1405  			})
  1406  
  1407  			It("returns the error and warnings", func() {
  1408  				Expect(err).To(Equal(expectedErr))
  1409  				Expect(warnings).To(ConsistOf("some-warning"))
  1410  			})
  1411  		})
  1412  
  1413  		When("application exists", func() {
  1414  			var ccv3App ccv3.Application
  1415  
  1416  			BeforeEach(func() {
  1417  				ccv3App = ccv3.Application{
  1418  					GUID: "some-app-guid",
  1419  				}
  1420  
  1421  				fakeCloudControllerClient.GetApplicationsReturns(
  1422  					[]ccv3.Application{ccv3App},
  1423  					ccv3.Warnings{"some-warning"},
  1424  					nil,
  1425  				)
  1426  			})
  1427  
  1428  			When("setting the health check returns an error", func() {
  1429  				var expectedErr error
  1430  
  1431  				BeforeEach(func() {
  1432  					expectedErr = errors.New("some-error")
  1433  					fakeCloudControllerClient.GetApplicationProcessByTypeReturns(
  1434  						ccv3.Process{},
  1435  						ccv3.Warnings{"some-process-warning"},
  1436  						expectedErr,
  1437  					)
  1438  				})
  1439  
  1440  				It("returns the error and warnings", func() {
  1441  					Expect(err).To(Equal(expectedErr))
  1442  					Expect(warnings).To(ConsistOf("some-warning", "some-process-warning"))
  1443  				})
  1444  			})
  1445  
  1446  			When("application process exists", func() {
  1447  				BeforeEach(func() {
  1448  					fakeCloudControllerClient.GetApplicationProcessByTypeReturns(
  1449  						ccv3.Process{GUID: "some-process-guid"},
  1450  						ccv3.Warnings{"some-process-warning"},
  1451  						nil,
  1452  					)
  1453  
  1454  					fakeCloudControllerClient.UpdateProcessReturns(
  1455  						ccv3.Process{GUID: "some-process-guid"},
  1456  						ccv3.Warnings{"some-health-check-warning"},
  1457  						nil,
  1458  					)
  1459  				})
  1460  
  1461  				It("returns the application", func() {
  1462  					Expect(err).NotTo(HaveOccurred())
  1463  					Expect(warnings).To(ConsistOf("some-warning", "some-process-warning", "some-health-check-warning"))
  1464  
  1465  					Expect(app).To(Equal(Application{
  1466  						GUID: ccv3App.GUID,
  1467  					}))
  1468  
  1469  					Expect(fakeCloudControllerClient.GetApplicationProcessByTypeCallCount()).To(Equal(1))
  1470  					appGUID, processType := fakeCloudControllerClient.GetApplicationProcessByTypeArgsForCall(0)
  1471  					Expect(appGUID).To(Equal("some-app-guid"))
  1472  					Expect(processType).To(Equal("some-process-type"))
  1473  
  1474  					Expect(fakeCloudControllerClient.UpdateProcessCallCount()).To(Equal(1))
  1475  					process := fakeCloudControllerClient.UpdateProcessArgsForCall(0)
  1476  					Expect(process.GUID).To(Equal("some-process-guid"))
  1477  					Expect(process.HealthCheckType).To(Equal(constant.HTTP))
  1478  					Expect(process.HealthCheckEndpoint).To(Equal("some-http-endpoint"))
  1479  					Expect(process.HealthCheckInvocationTimeout).To(BeEquivalentTo(42))
  1480  				})
  1481  			})
  1482  		})
  1483  	})
  1484  
  1485  	Describe("StopApplication", func() {
  1486  		var (
  1487  			warnings   Warnings
  1488  			executeErr error
  1489  		)
  1490  
  1491  		JustBeforeEach(func() {
  1492  			warnings, executeErr = actor.StopApplication("some-app-guid")
  1493  		})
  1494  
  1495  		When("there are no client errors", func() {
  1496  			BeforeEach(func() {
  1497  				fakeCloudControllerClient.UpdateApplicationStopReturns(
  1498  					ccv3.Application{GUID: "some-app-guid"},
  1499  					ccv3.Warnings{"stop-application-warning"},
  1500  					nil,
  1501  				)
  1502  			})
  1503  
  1504  			It("stops the application", func() {
  1505  				Expect(executeErr).ToNot(HaveOccurred())
  1506  				Expect(warnings).To(ConsistOf("stop-application-warning"))
  1507  
  1508  				Expect(fakeCloudControllerClient.UpdateApplicationStopCallCount()).To(Equal(1))
  1509  				Expect(fakeCloudControllerClient.UpdateApplicationStopArgsForCall(0)).To(Equal("some-app-guid"))
  1510  			})
  1511  		})
  1512  
  1513  		When("stopping the application fails", func() {
  1514  			var expectedErr error
  1515  			BeforeEach(func() {
  1516  				expectedErr = errors.New("some set stop-application error")
  1517  				fakeCloudControllerClient.UpdateApplicationStopReturns(
  1518  					ccv3.Application{},
  1519  					ccv3.Warnings{"stop-application-warning"},
  1520  					expectedErr,
  1521  				)
  1522  			})
  1523  
  1524  			It("returns the error", func() {
  1525  				Expect(executeErr).To(Equal(expectedErr))
  1526  				Expect(warnings).To(ConsistOf("stop-application-warning"))
  1527  			})
  1528  		})
  1529  	})
  1530  
  1531  	Describe("StartApplication", func() {
  1532  		var (
  1533  			warnings   Warnings
  1534  			executeErr error
  1535  		)
  1536  
  1537  		BeforeEach(func() {
  1538  			fakeConfig.StartupTimeoutReturns(time.Second)
  1539  			fakeConfig.PollingIntervalReturns(0)
  1540  		})
  1541  
  1542  		JustBeforeEach(func() {
  1543  			warnings, executeErr = actor.StartApplication("some-app-guid")
  1544  		})
  1545  
  1546  		When("there are no client errors", func() {
  1547  			BeforeEach(func() {
  1548  				fakeCloudControllerClient.UpdateApplicationStartReturns(
  1549  					ccv3.Application{GUID: "some-app-guid"},
  1550  					ccv3.Warnings{"start-application-warning"},
  1551  					nil,
  1552  				)
  1553  			})
  1554  
  1555  			It("starts the application", func() {
  1556  				Expect(executeErr).ToNot(HaveOccurred())
  1557  				Expect(warnings).To(ConsistOf("start-application-warning"))
  1558  
  1559  				Expect(fakeCloudControllerClient.UpdateApplicationStartCallCount()).To(Equal(1))
  1560  				Expect(fakeCloudControllerClient.UpdateApplicationStartArgsForCall(0)).To(Equal("some-app-guid"))
  1561  			})
  1562  		})
  1563  
  1564  		When("starting the application fails", func() {
  1565  			var expectedErr error
  1566  
  1567  			BeforeEach(func() {
  1568  				expectedErr = errors.New("some set start-application error")
  1569  				fakeCloudControllerClient.UpdateApplicationStartReturns(
  1570  					ccv3.Application{},
  1571  					ccv3.Warnings{"start-application-warning"},
  1572  					expectedErr,
  1573  				)
  1574  			})
  1575  
  1576  			It("returns the error", func() {
  1577  				warnings, err := actor.StartApplication("some-app-guid")
  1578  
  1579  				Expect(err).To(Equal(expectedErr))
  1580  				Expect(warnings).To(ConsistOf("start-application-warning"))
  1581  			})
  1582  		})
  1583  	})
  1584  
  1585  	Describe("RestartApplication", func() {
  1586  		var (
  1587  			warnings   Warnings
  1588  			executeErr error
  1589  			noWait     bool
  1590  		)
  1591  
  1592  		BeforeEach(func() {
  1593  			fakeConfig.StartupTimeoutReturns(time.Second)
  1594  			fakeConfig.PollingIntervalReturns(0)
  1595  			noWait = false
  1596  		})
  1597  
  1598  		JustBeforeEach(func() {
  1599  			warnings, executeErr = actor.RestartApplication("some-app-guid", noWait)
  1600  		})
  1601  
  1602  		When("restarting the application is successful", func() {
  1603  			BeforeEach(func() {
  1604  				fakeCloudControllerClient.UpdateApplicationRestartReturns(
  1605  					ccv3.Application{GUID: "some-app-guid"},
  1606  					ccv3.Warnings{"restart-application-warning"},
  1607  					nil,
  1608  				)
  1609  			})
  1610  
  1611  			It("does not error", func() {
  1612  				Expect(executeErr).ToNot(HaveOccurred())
  1613  				Expect(warnings).To(ConsistOf("restart-application-warning"))
  1614  			})
  1615  		})
  1616  
  1617  		When("restarting the application fails", func() {
  1618  			var expectedErr error
  1619  
  1620  			BeforeEach(func() {
  1621  				expectedErr = errors.New("some set restart-application error")
  1622  				fakeCloudControllerClient.UpdateApplicationRestartReturns(
  1623  					ccv3.Application{},
  1624  					ccv3.Warnings{"restart-application-warning"},
  1625  					expectedErr,
  1626  				)
  1627  			})
  1628  
  1629  			It("returns the warnings and error", func() {
  1630  				Expect(executeErr).To(Equal(expectedErr))
  1631  				Expect(warnings).To(ConsistOf("restart-application-warning"))
  1632  			})
  1633  		})
  1634  	})
  1635  
  1636  	Describe("PollProcesses", func() {
  1637  		var (
  1638  			processes []ccv3.Process
  1639  
  1640  			keepPolling bool
  1641  			warnings    Warnings
  1642  			executeErr  error
  1643  		)
  1644  
  1645  		BeforeEach(func() {
  1646  			processes = []ccv3.Process{
  1647  				{GUID: "process-1"},
  1648  				{GUID: "process-2"},
  1649  			}
  1650  		})
  1651  
  1652  		JustBeforeEach(func() {
  1653  			keepPolling, warnings, executeErr = actor.PollProcesses(processes)
  1654  		})
  1655  
  1656  		It("gets process instances for each process", func() {
  1657  			Expect(executeErr).NotTo(HaveOccurred())
  1658  			Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(2))
  1659  			Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("process-1"))
  1660  			Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(1)).To(Equal("process-2"))
  1661  		})
  1662  
  1663  		When("getting the process instances fails", func() {
  1664  			BeforeEach(func() {
  1665  				fakeCloudControllerClient.GetProcessInstancesReturns(nil, ccv3.Warnings{"get-instances-warning"}, errors.New("get-instances-error"))
  1666  			})
  1667  
  1668  			It("returns an error and warnings and terminates the loop", func() {
  1669  				Expect(executeErr).To(MatchError("get-instances-error"))
  1670  				Expect(warnings).To(ConsistOf("get-instances-warning"))
  1671  				Expect(keepPolling).To(BeTrue())
  1672  
  1673  				Expect(fakeCloudControllerClient.GetProcessInstancesCallCount()).To(Equal(1))
  1674  				Expect(fakeCloudControllerClient.GetProcessInstancesArgsForCall(0)).To(Equal("process-1"))
  1675  			})
  1676  		})
  1677  
  1678  		When("getting the process instances is always successful", func() {
  1679  			When("a process has all instances crashed", func() {
  1680  				BeforeEach(func() {
  1681  					fakeCloudControllerClient.GetProcessInstancesReturns(
  1682  						[]ccv3.ProcessInstance{
  1683  							{State: constant.ProcessInstanceCrashed},
  1684  						},
  1685  						ccv3.Warnings{"get-process1-instances-warning"},
  1686  						nil,
  1687  					)
  1688  				})
  1689  
  1690  				It("returns an all instances crashed error", func() {
  1691  					Expect(executeErr).To(MatchError(actionerror.AllInstancesCrashedError{}))
  1692  					Expect(warnings).To(ConsistOf("get-process1-instances-warning"))
  1693  					Expect(keepPolling).To(BeTrue())
  1694  				})
  1695  			})
  1696  
  1697  			When("there are still instances in the starting state for a process", func() {
  1698  				BeforeEach(func() {
  1699  					fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(0,
  1700  						[]ccv3.ProcessInstance{
  1701  							{State: constant.ProcessInstanceRunning},
  1702  						},
  1703  						ccv3.Warnings{"get-process1-instances-warning"},
  1704  						nil,
  1705  					)
  1706  
  1707  					fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(1,
  1708  						[]ccv3.ProcessInstance{
  1709  							{State: constant.ProcessInstanceStarting},
  1710  						},
  1711  						ccv3.Warnings{"get-process2-instances-warning"},
  1712  						nil,
  1713  					)
  1714  				})
  1715  
  1716  				It("returns success and that we should keep polling", func() {
  1717  					Expect(executeErr).NotTo(HaveOccurred())
  1718  					Expect(warnings).To(ConsistOf("get-process1-instances-warning", "get-process2-instances-warning"))
  1719  					Expect(keepPolling).To(BeFalse())
  1720  				})
  1721  			})
  1722  
  1723  			When("all the instances of all processes are stable", func() {
  1724  				BeforeEach(func() {
  1725  					fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(0,
  1726  						[]ccv3.ProcessInstance{
  1727  							{State: constant.ProcessInstanceRunning},
  1728  						},
  1729  						ccv3.Warnings{"get-process1-instances-warning"},
  1730  						nil,
  1731  					)
  1732  
  1733  					fakeCloudControllerClient.GetProcessInstancesReturnsOnCall(1,
  1734  						[]ccv3.ProcessInstance{
  1735  							{State: constant.ProcessInstanceRunning},
  1736  						},
  1737  						ccv3.Warnings{"get-process2-instances-warning"},
  1738  						nil,
  1739  					)
  1740  				})
  1741  
  1742  				It("returns success and that we should keep polling", func() {
  1743  					Expect(executeErr).NotTo(HaveOccurred())
  1744  					Expect(warnings).To(ConsistOf("get-process1-instances-warning", "get-process2-instances-warning"))
  1745  					Expect(keepPolling).To(BeTrue())
  1746  				})
  1747  
  1748  			})
  1749  		})
  1750  
  1751  	})
  1752  
  1753  	Describe("GetUnstagedNewestPackageGUID", func() {
  1754  		var (
  1755  			packageToStage string
  1756  			warnings       Warnings
  1757  			executeErr     error
  1758  		)
  1759  
  1760  		JustBeforeEach(func() {
  1761  			packageToStage, warnings, executeErr = actor.GetUnstagedNewestPackageGUID("some-app-guid")
  1762  		})
  1763  
  1764  		// Nothing to stage.
  1765  		When("There are no packages on the app", func() {
  1766  			When("getting the packages succeeds", func() {
  1767  				BeforeEach(func() {
  1768  					fakeCloudControllerClient.GetPackagesReturns([]ccv3.Package{}, ccv3.Warnings{"get-packages-warnings"}, nil)
  1769  				})
  1770  
  1771  				It("checks for packages", func() {
  1772  					Expect(fakeCloudControllerClient.GetPackagesCallCount()).To(Equal(1))
  1773  					Expect(fakeCloudControllerClient.GetPackagesArgsForCall(0)).To(ConsistOf(
  1774  						ccv3.Query{Key: ccv3.AppGUIDFilter, Values: []string{"some-app-guid"}},
  1775  						ccv3.Query{Key: ccv3.OrderBy, Values: []string{ccv3.CreatedAtDescendingOrder}},
  1776  						ccv3.Query{Key: ccv3.PerPage, Values: []string{"1"}},
  1777  					))
  1778  				})
  1779  
  1780  				It("returns empty string", func() {
  1781  					Expect(packageToStage).To(Equal(""))
  1782  					Expect(warnings).To(ConsistOf("get-packages-warnings"))
  1783  					Expect(executeErr).To(BeNil())
  1784  				})
  1785  			})
  1786  
  1787  			When("getting the packages fails", func() {
  1788  				BeforeEach(func() {
  1789  					fakeCloudControllerClient.GetPackagesReturns(
  1790  						nil,
  1791  						ccv3.Warnings{"get-packages-warnings"},
  1792  						errors.New("get-packages-error"),
  1793  					)
  1794  				})
  1795  
  1796  				It("returns the error", func() {
  1797  					Expect(warnings).To(ConsistOf("get-packages-warnings"))
  1798  					Expect(executeErr).To(MatchError("get-packages-error"))
  1799  				})
  1800  			})
  1801  		})
  1802  
  1803  		When("there are packages", func() {
  1804  			BeforeEach(func() {
  1805  				fakeCloudControllerClient.GetPackagesReturns(
  1806  					[]ccv3.Package{{GUID: "package-guid", CreatedAt: "2019-01-01T06:00:00Z"}},
  1807  					ccv3.Warnings{"get-packages-warning"},
  1808  					nil)
  1809  			})
  1810  
  1811  			It("checks for the packages latest droplet", func() {
  1812  				Expect(fakeCloudControllerClient.GetPackageDropletsCallCount()).To(Equal(1))
  1813  				packageGuid, queries := fakeCloudControllerClient.GetPackageDropletsArgsForCall(0)
  1814  				Expect(packageGuid).To(Equal("package-guid"))
  1815  				Expect(queries).To(ConsistOf(
  1816  					ccv3.Query{Key: ccv3.PerPage, Values: []string{"1"}},
  1817  					ccv3.Query{Key: ccv3.StatesFilter, Values: []string{"STAGED"}},
  1818  				))
  1819  			})
  1820  
  1821  			When("the newest package's has a STAGED droplet", func() {
  1822  				BeforeEach(func() {
  1823  					fakeCloudControllerClient.GetPackageDropletsReturns(
  1824  						[]ccv3.Droplet{{State: constant.DropletStaged}},
  1825  						ccv3.Warnings{"get-package-droplet-warning"},
  1826  						nil,
  1827  					)
  1828  				})
  1829  
  1830  				It("returns empty string", func() {
  1831  					Expect(packageToStage).To(Equal(""))
  1832  					Expect(warnings).To(ConsistOf("get-packages-warning", "get-package-droplet-warning"))
  1833  					Expect(executeErr).To(BeNil())
  1834  				})
  1835  			})
  1836  
  1837  			When("the package has no STAGED droplets", func() {
  1838  				BeforeEach(func() {
  1839  					fakeCloudControllerClient.GetPackageDropletsReturns(
  1840  						[]ccv3.Droplet{},
  1841  						ccv3.Warnings{"get-package-droplet-warning"},
  1842  						nil,
  1843  					)
  1844  				})
  1845  
  1846  				It("returns the guid of the newest package", func() {
  1847  					Expect(packageToStage).To(Equal("package-guid"))
  1848  					Expect(warnings).To(ConsistOf("get-packages-warning", "get-package-droplet-warning"))
  1849  					Expect(executeErr).To(BeNil())
  1850  				})
  1851  			})
  1852  		})
  1853  	})
  1854  
  1855  	Describe("RenameApplicationByNameAndSpaceGUID", func() {
  1856  		When("the app does not exist", func() {
  1857  			BeforeEach(func() {
  1858  				fakeCloudControllerClient.GetApplicationsReturns(
  1859  					[]ccv3.Application{},
  1860  					ccv3.Warnings{"some-warning"},
  1861  					nil,
  1862  				)
  1863  			})
  1864  
  1865  			It("returns an ApplicationNotFoundError and the warnings", func() {
  1866  				_, warnings, err := actor.RenameApplicationByNameAndSpaceGUID("old-app-name", "new-app-name", "space-guid")
  1867  				Expect(warnings).To(ConsistOf("some-warning"))
  1868  				Expect(err).To(MatchError(actionerror.ApplicationNotFoundError{Name: "old-app-name"}))
  1869  			})
  1870  		})
  1871  
  1872  		When("the cloud controller client returns an error on application find", func() {
  1873  			var expectedError error
  1874  
  1875  			BeforeEach(func() {
  1876  				expectedError = errors.New("I am a CloudControllerClient Error")
  1877  				fakeCloudControllerClient.GetApplicationsReturns(
  1878  					[]ccv3.Application{},
  1879  					ccv3.Warnings{"some-warning"},
  1880  					expectedError)
  1881  			})
  1882  
  1883  			It("returns the warnings and the error", func() {
  1884  				_, warnings, err := actor.RenameApplicationByNameAndSpaceGUID("old-app-name", "new-app-name", "space-guid")
  1885  				Expect(warnings).To(ConsistOf("some-warning"))
  1886  				Expect(err).To(MatchError(expectedError))
  1887  			})
  1888  		})
  1889  
  1890  		When("the cloud controller client returns an error on application update", func() {
  1891  			var expectedError error
  1892  
  1893  			BeforeEach(func() {
  1894  				expectedError = errors.New("I am a CloudControllerClient Error")
  1895  				fakeCloudControllerClient.GetApplicationsReturns(
  1896  					[]ccv3.Application{
  1897  						{
  1898  							Name: "old-app-name",
  1899  							GUID: "old-app-guid",
  1900  						},
  1901  					},
  1902  					ccv3.Warnings{"get-app-warning"},
  1903  					nil)
  1904  				fakeCloudControllerClient.UpdateApplicationReturns(
  1905  					ccv3.Application{},
  1906  					ccv3.Warnings{"update-app-warning"},
  1907  					expectedError)
  1908  			})
  1909  
  1910  			It("returns the warnings and the error", func() {
  1911  				_, warnings, err := actor.RenameApplicationByNameAndSpaceGUID("old-app-name", "new-app-name", "space-guid")
  1912  				Expect(warnings).To(ConsistOf("get-app-warning", "update-app-warning"))
  1913  				Expect(err).To(MatchError(expectedError))
  1914  			})
  1915  		})
  1916  
  1917  		When("the app exists", func() {
  1918  			BeforeEach(func() {
  1919  				fakeCloudControllerClient.GetApplicationsReturns(
  1920  					[]ccv3.Application{
  1921  						{
  1922  							Name: "old-app-name",
  1923  							GUID: "old-app-guid",
  1924  						},
  1925  					},
  1926  					ccv3.Warnings{"get-app-warning"},
  1927  					nil,
  1928  				)
  1929  
  1930  				fakeCloudControllerClient.UpdateApplicationReturns(
  1931  					ccv3.Application{
  1932  						Name: "new-app-name",
  1933  						GUID: "old-app-guid",
  1934  					},
  1935  					ccv3.Warnings{"update-app-warning"},
  1936  					nil,
  1937  				)
  1938  			})
  1939  
  1940  			It("changes the app name and returns the application and warnings", func() {
  1941  				app, warnings, err := actor.RenameApplicationByNameAndSpaceGUID("old-app-name", "new-app-name", "some-space-guid")
  1942  				Expect(err).ToNot(HaveOccurred())
  1943  				Expect(app).To(Equal(Application{
  1944  					Name: "new-app-name",
  1945  					GUID: "old-app-guid",
  1946  				}))
  1947  				Expect(warnings).To(ConsistOf("get-app-warning", "update-app-warning"))
  1948  
  1949  				Expect(fakeCloudControllerClient.UpdateApplicationArgsForCall(0)).To(Equal(
  1950  					ccv3.Application{
  1951  						Name: "new-app-name",
  1952  						GUID: "old-app-guid",
  1953  					}))
  1954  
  1955  			})
  1956  		})
  1957  
  1958  	})
  1959  })