github.com/arunkumar7540/cli@v6.45.0+incompatible/actor/v7action/application_test.go (about)

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