github.com/nimakaviani/cli@v6.37.1-0.20180619223813-e734901a73fa+incompatible/actor/v3action/application_test.go (about)

     1  package v3action_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/v3action"
    11  	"code.cloudfoundry.org/cli/actor/v3action/v3actionfakes"
    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  
    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 *v3actionfakes.FakeCloudControllerClient
    24  		fakeConfig                *v3actionfakes.FakeConfig
    25  	)
    26  
    27  	BeforeEach(func() {
    28  		fakeCloudControllerClient = new(v3actionfakes.FakeCloudControllerClient)
    29  		fakeConfig = new(v3actionfakes.FakeConfig)
    30  		actor = NewActor(fakeCloudControllerClient, fakeConfig, nil, nil)
    31  	})
    32  
    33  	Describe("DeleteApplicationByNameAndSpace", func() {
    34  		var (
    35  			warnings   Warnings
    36  			executeErr error
    37  		)
    38  
    39  		JustBeforeEach(func() {
    40  			warnings, executeErr = actor.DeleteApplicationByNameAndSpace("some-app", "some-space-guid")
    41  		})
    42  
    43  		Context("when looking up the app guid fails", func() {
    44  			BeforeEach(func() {
    45  				fakeCloudControllerClient.GetApplicationsReturns([]ccv3.Application{}, ccv3.Warnings{"some-get-app-warning"}, errors.New("some-get-app-error"))
    46  			})
    47  
    48  			It("returns the warnings and error", func() {
    49  				Expect(warnings).To(ConsistOf("some-get-app-warning"))
    50  				Expect(executeErr).To(MatchError("some-get-app-error"))
    51  			})
    52  		})
    53  
    54  		Context("when looking up the app guid succeeds", func() {
    55  			BeforeEach(func() {
    56  				fakeCloudControllerClient.GetApplicationsReturns([]ccv3.Application{ccv3.Application{Name: "some-app", GUID: "abc123"}}, ccv3.Warnings{"some-get-app-warning"}, nil)
    57  			})
    58  
    59  			Context("when sending the delete fails", func() {
    60  				BeforeEach(func() {
    61  					fakeCloudControllerClient.DeleteApplicationReturns("", ccv3.Warnings{"some-delete-app-warning"}, errors.New("some-delete-app-error"))
    62  				})
    63  
    64  				It("returns the warnings and error", func() {
    65  					Expect(warnings).To(ConsistOf("some-get-app-warning", "some-delete-app-warning"))
    66  					Expect(executeErr).To(MatchError("some-delete-app-error"))
    67  				})
    68  			})
    69  
    70  			Context("when sending the delete succeeds", func() {
    71  				BeforeEach(func() {
    72  					fakeCloudControllerClient.DeleteApplicationReturns("/some-job-url", ccv3.Warnings{"some-delete-app-warning"}, nil)
    73  				})
    74  
    75  				Context("when polling fails", func() {
    76  					BeforeEach(func() {
    77  						fakeCloudControllerClient.PollJobReturns(ccv3.Warnings{"some-poll-warning"}, errors.New("some-poll-error"))
    78  					})
    79  
    80  					It("returns the warnings and poll error", func() {
    81  						Expect(warnings).To(ConsistOf("some-get-app-warning", "some-delete-app-warning", "some-poll-warning"))
    82  						Expect(executeErr).To(MatchError("some-poll-error"))
    83  					})
    84  				})
    85  
    86  				Context("when polling succeeds", func() {
    87  					BeforeEach(func() {
    88  						fakeCloudControllerClient.PollJobReturns(ccv3.Warnings{"some-poll-warning"}, nil)
    89  					})
    90  
    91  					It("returns all the warnings and no error", func() {
    92  						Expect(warnings).To(ConsistOf("some-get-app-warning", "some-delete-app-warning", "some-poll-warning"))
    93  						Expect(executeErr).ToNot(HaveOccurred())
    94  					})
    95  				})
    96  			})
    97  		})
    98  	})
    99  
   100  	Describe("GetApplicationByNameAndSpace", func() {
   101  		Context("when the app exists", func() {
   102  			BeforeEach(func() {
   103  				fakeCloudControllerClient.GetApplicationsReturns(
   104  					[]ccv3.Application{
   105  						{
   106  							Name: "some-app-name",
   107  							GUID: "some-app-guid",
   108  						},
   109  					},
   110  					ccv3.Warnings{"some-warning"},
   111  					nil,
   112  				)
   113  			})
   114  
   115  			It("returns the application and warnings", func() {
   116  				app, warnings, err := actor.GetApplicationByNameAndSpace("some-app-name", "some-space-guid")
   117  				Expect(err).ToNot(HaveOccurred())
   118  				Expect(app).To(Equal(Application{
   119  					Name: "some-app-name",
   120  					GUID: "some-app-guid",
   121  				}))
   122  				Expect(warnings).To(Equal(Warnings{"some-warning"}))
   123  
   124  				Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   125  				Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   126  					ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name"}},
   127  					ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
   128  				))
   129  			})
   130  		})
   131  
   132  		Context("when the cloud controller client returns an error", func() {
   133  			var expectedError error
   134  
   135  			BeforeEach(func() {
   136  				expectedError = errors.New("I am a CloudControllerClient Error")
   137  				fakeCloudControllerClient.GetApplicationsReturns(
   138  					[]ccv3.Application{},
   139  					ccv3.Warnings{"some-warning"},
   140  					expectedError)
   141  			})
   142  
   143  			It("returns the warnings and the error", func() {
   144  				_, warnings, err := actor.GetApplicationByNameAndSpace("some-app-name", "some-space-guid")
   145  				Expect(warnings).To(ConsistOf("some-warning"))
   146  				Expect(err).To(MatchError(expectedError))
   147  			})
   148  		})
   149  
   150  		Context("when the app does not exist", func() {
   151  			BeforeEach(func() {
   152  				fakeCloudControllerClient.GetApplicationsReturns(
   153  					[]ccv3.Application{},
   154  					ccv3.Warnings{"some-warning"},
   155  					nil,
   156  				)
   157  			})
   158  
   159  			It("returns an ApplicationNotFoundError and the warnings", func() {
   160  				_, warnings, err := actor.GetApplicationByNameAndSpace("some-app-name", "some-space-guid")
   161  				Expect(warnings).To(ConsistOf("some-warning"))
   162  				Expect(err).To(MatchError(actionerror.ApplicationNotFoundError{Name: "some-app-name"}))
   163  			})
   164  		})
   165  	})
   166  
   167  	Describe("GetApplicationsBySpace", func() {
   168  		Context("when the there are applications in the space", func() {
   169  			BeforeEach(func() {
   170  				fakeCloudControllerClient.GetApplicationsReturns(
   171  					[]ccv3.Application{
   172  						{
   173  							GUID: "some-app-guid-1",
   174  							Name: "some-app-1",
   175  						},
   176  						{
   177  							GUID: "some-app-guid-2",
   178  							Name: "some-app-2",
   179  						},
   180  					},
   181  					ccv3.Warnings{"warning-1", "warning-2"},
   182  					nil,
   183  				)
   184  			})
   185  
   186  			It("returns the application and warnings", func() {
   187  				apps, warnings, err := actor.GetApplicationsBySpace("some-space-guid")
   188  				Expect(err).ToNot(HaveOccurred())
   189  				Expect(apps).To(ConsistOf(
   190  					Application{
   191  						GUID: "some-app-guid-1",
   192  						Name: "some-app-1",
   193  					},
   194  					Application{
   195  						GUID: "some-app-guid-2",
   196  						Name: "some-app-2",
   197  					},
   198  				))
   199  				Expect(warnings).To(ConsistOf("warning-1", "warning-2"))
   200  
   201  				Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   202  				Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   203  					ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
   204  				))
   205  			})
   206  		})
   207  
   208  		Context("when the cloud controller client returns an error", func() {
   209  			var expectedError error
   210  
   211  			BeforeEach(func() {
   212  				expectedError = errors.New("I am a CloudControllerClient Error")
   213  				fakeCloudControllerClient.GetApplicationsReturns(
   214  					[]ccv3.Application{},
   215  					ccv3.Warnings{"some-warning"},
   216  					expectedError)
   217  			})
   218  
   219  			It("returns the error and warnings", func() {
   220  				_, warnings, err := actor.GetApplicationsBySpace("some-space-guid")
   221  				Expect(warnings).To(ConsistOf("some-warning"))
   222  				Expect(err).To(MatchError(expectedError))
   223  			})
   224  		})
   225  	})
   226  
   227  	Describe("CreateApplicationInSpace", func() {
   228  		var (
   229  			application Application
   230  			warnings    Warnings
   231  			err         error
   232  		)
   233  
   234  		JustBeforeEach(func() {
   235  			application, warnings, err = actor.CreateApplicationInSpace(Application{
   236  				Name:                "some-app-name",
   237  				LifecycleType:       constant.AppLifecycleTypeBuildpack,
   238  				LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   239  			}, "some-space-guid")
   240  		})
   241  
   242  		Context("when the app successfully gets created", func() {
   243  			BeforeEach(func() {
   244  				fakeCloudControllerClient.CreateApplicationReturns(
   245  					ccv3.Application{
   246  						Name:                "some-app-name",
   247  						GUID:                "some-app-guid",
   248  						LifecycleType:       constant.AppLifecycleTypeBuildpack,
   249  						LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   250  					},
   251  					ccv3.Warnings{"some-warning"},
   252  					nil,
   253  				)
   254  			})
   255  
   256  			It("creates and returns the application and warnings", func() {
   257  				Expect(err).ToNot(HaveOccurred())
   258  				Expect(application).To(Equal(Application{
   259  					Name:                "some-app-name",
   260  					GUID:                "some-app-guid",
   261  					LifecycleType:       constant.AppLifecycleTypeBuildpack,
   262  					LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   263  				}))
   264  				Expect(warnings).To(ConsistOf("some-warning"))
   265  
   266  				Expect(fakeCloudControllerClient.CreateApplicationCallCount()).To(Equal(1))
   267  				Expect(fakeCloudControllerClient.CreateApplicationArgsForCall(0)).To(Equal(ccv3.Application{
   268  					Name: "some-app-name",
   269  					Relationships: ccv3.Relationships{
   270  						constant.RelationshipTypeSpace: ccv3.Relationship{GUID: "some-space-guid"},
   271  					},
   272  					LifecycleType:       constant.AppLifecycleTypeBuildpack,
   273  					LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   274  				}))
   275  			})
   276  		})
   277  
   278  		Context("when the cc client returns an error", func() {
   279  			var expectedError error
   280  
   281  			BeforeEach(func() {
   282  				expectedError = errors.New("I am a CloudControllerClient Error")
   283  				fakeCloudControllerClient.CreateApplicationReturns(
   284  					ccv3.Application{},
   285  					ccv3.Warnings{"some-warning"},
   286  					expectedError,
   287  				)
   288  			})
   289  
   290  			It("raises the error and warnings", func() {
   291  				Expect(err).To(MatchError(expectedError))
   292  				Expect(warnings).To(ConsistOf("some-warning"))
   293  			})
   294  		})
   295  
   296  		Context("when the cc client returns an NameNotUniqueInSpaceError", func() {
   297  			BeforeEach(func() {
   298  				fakeCloudControllerClient.CreateApplicationReturns(
   299  					ccv3.Application{},
   300  					ccv3.Warnings{"some-warning"},
   301  					ccerror.NameNotUniqueInSpaceError{},
   302  				)
   303  			})
   304  
   305  			It("returns the ApplicationAlreadyExistsError and warnings", func() {
   306  				Expect(err).To(MatchError(actionerror.ApplicationAlreadyExistsError{Name: "some-app-name"}))
   307  				Expect(warnings).To(ConsistOf("some-warning"))
   308  			})
   309  		})
   310  	})
   311  
   312  	Describe("UpdateApplication", func() {
   313  		var (
   314  			application Application
   315  			warnings    Warnings
   316  			err         error
   317  		)
   318  
   319  		JustBeforeEach(func() {
   320  			application, warnings, err = actor.UpdateApplication(Application{
   321  				GUID:                "some-app-guid",
   322  				LifecycleType:       constant.AppLifecycleTypeBuildpack,
   323  				LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   324  			})
   325  		})
   326  
   327  		Context("when the app successfully gets updated", func() {
   328  			BeforeEach(func() {
   329  				fakeCloudControllerClient.UpdateApplicationReturns(
   330  					ccv3.Application{
   331  						GUID:                "some-app-guid",
   332  						LifecycleType:       constant.AppLifecycleTypeBuildpack,
   333  						LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   334  					},
   335  					ccv3.Warnings{"some-warning"},
   336  					nil,
   337  				)
   338  			})
   339  
   340  			It("creates and returns the application and warnings", func() {
   341  				Expect(err).ToNot(HaveOccurred())
   342  				Expect(application).To(Equal(Application{
   343  					GUID:                "some-app-guid",
   344  					LifecycleType:       constant.AppLifecycleTypeBuildpack,
   345  					LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   346  				}))
   347  				Expect(warnings).To(ConsistOf("some-warning"))
   348  
   349  				Expect(fakeCloudControllerClient.UpdateApplicationCallCount()).To(Equal(1))
   350  				Expect(fakeCloudControllerClient.UpdateApplicationArgsForCall(0)).To(Equal(ccv3.Application{
   351  					GUID:                "some-app-guid",
   352  					LifecycleType:       constant.AppLifecycleTypeBuildpack,
   353  					LifecycleBuildpacks: []string{"buildpack-1", "buildpack-2"},
   354  				}))
   355  			})
   356  		})
   357  
   358  		Context("when the cc client returns an error", func() {
   359  			var expectedError error
   360  
   361  			BeforeEach(func() {
   362  				expectedError = errors.New("I am a CloudControllerClient Error")
   363  				fakeCloudControllerClient.UpdateApplicationReturns(
   364  					ccv3.Application{},
   365  					ccv3.Warnings{"some-warning"},
   366  					expectedError,
   367  				)
   368  			})
   369  
   370  			It("raises the error and warnings", func() {
   371  				Expect(err).To(MatchError(expectedError))
   372  				Expect(warnings).To(ConsistOf("some-warning"))
   373  			})
   374  		})
   375  	})
   376  
   377  	Describe("PollStart", func() {
   378  		var warningsChannel chan Warnings
   379  		var allWarnings Warnings
   380  		var funcDone chan interface{}
   381  
   382  		BeforeEach(func() {
   383  			warningsChannel = make(chan Warnings)
   384  			funcDone = make(chan interface{})
   385  			allWarnings = Warnings{}
   386  			go func() {
   387  				for {
   388  					select {
   389  					case warnings := <-warningsChannel:
   390  						allWarnings = append(allWarnings, warnings...)
   391  					case <-funcDone:
   392  						return
   393  					}
   394  				}
   395  			}()
   396  		})
   397  
   398  		Context("when getting the application processes fails", func() {
   399  			BeforeEach(func() {
   400  				fakeCloudControllerClient.GetApplicationProcessesReturns(nil, ccv3.Warnings{"get-app-warning-1", "get-app-warning-2"}, errors.New("some-error"))
   401  			})
   402  
   403  			It("returns the error and all warnings", func() {
   404  				err := actor.PollStart("some-guid", warningsChannel)
   405  				funcDone <- nil
   406  				Expect(allWarnings).To(ConsistOf("get-app-warning-1", "get-app-warning-2"))
   407  				Expect(err).To(MatchError(errors.New("some-error")))
   408  			})
   409  		})
   410  
   411  		Context("when getting the application processes succeeds", func() {
   412  			var processes []ccv3.Process
   413  
   414  			BeforeEach(func() {
   415  				fakeConfig.StartupTimeoutReturns(time.Second)
   416  				fakeConfig.PollingIntervalReturns(0)
   417  			})
   418  
   419  			JustBeforeEach(func() {
   420  				fakeCloudControllerClient.GetApplicationProcessesReturns(
   421  					processes,
   422  					ccv3.Warnings{"get-app-warning-1"}, nil)
   423  			})
   424  
   425  			Context("when there is a single process", func() {
   426  				BeforeEach(func() {
   427  					processes = []ccv3.Process{{GUID: "abc123"}}
   428  				})
   429  
   430  				Context("when the polling times out", func() {
   431  					BeforeEach(func() {
   432  						fakeConfig.StartupTimeoutReturns(time.Millisecond)
   433  						fakeConfig.PollingIntervalReturns(time.Millisecond * 2)
   434  						fakeCloudControllerClient.GetProcessInstancesReturns(
   435  							[]ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}},
   436  							ccv3.Warnings{"get-process-warning-1", "get-process-warning-2"},
   437  							nil,
   438  						)
   439  					})
   440  
   441  					It("returns the timeout error", func() {
   442  						err := actor.PollStart("some-guid", warningsChannel)
   443  						funcDone <- nil
   444  
   445  						Expect(allWarnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2"))
   446  						Expect(err).To(MatchError(actionerror.StartupTimeoutError{}))
   447  					})
   448  
   449  					It("gets polling and timeout values from the config", func() {
   450  						actor.PollStart("some-guid", warningsChannel)
   451  						funcDone <- nil
   452  
   453  						Expect(fakeConfig.StartupTimeoutCallCount()).To(Equal(1))
   454  						Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(1))
   455  					})
   456  				})
   457  
   458  				Context("when getting the process instances errors", func() {
   459  					BeforeEach(func() {
   460  						fakeCloudControllerClient.GetProcessInstancesReturns(
   461  							nil,
   462  							ccv3.Warnings{"get-process-warning-1", "get-process-warning-2"},
   463  							errors.New("some-error"),
   464  						)
   465  					})
   466  
   467  					It("returns the error", func() {
   468  						err := actor.PollStart("some-guid", warningsChannel)
   469  						funcDone <- nil
   470  
   471  						Expect(allWarnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2"))
   472  						Expect(err).To(MatchError("some-error"))
   473  					})
   474  				})
   475  
   476  				Context("when getting the process instances succeeds", func() {
   477  					var (
   478  						initialInstanceStates    []ccv3.ProcessInstance
   479  						eventualInstanceStates   []ccv3.ProcessInstance
   480  						pollStartErr             error
   481  						processInstanceCallCount int
   482  					)
   483  
   484  					BeforeEach(func() {
   485  						processInstanceCallCount = 0
   486  					})
   487  
   488  					JustBeforeEach(func() {
   489  						fakeCloudControllerClient.GetProcessInstancesStub = func(processGuid string) ([]ccv3.ProcessInstance, ccv3.Warnings, error) {
   490  							defer func() { processInstanceCallCount++ }()
   491  							if processInstanceCallCount == 0 {
   492  								return initialInstanceStates,
   493  									ccv3.Warnings{"get-process-warning-1", "get-process-warning-2"},
   494  									nil
   495  							} else {
   496  								return eventualInstanceStates,
   497  									ccv3.Warnings{fmt.Sprintf("get-process-warning-%d", processInstanceCallCount+2)},
   498  									nil
   499  							}
   500  						}
   501  
   502  						pollStartErr = actor.PollStart("some-guid", warningsChannel)
   503  						funcDone <- nil
   504  					})
   505  
   506  					Context("when there are no process instances", func() {
   507  						BeforeEach(func() {
   508  							initialInstanceStates = []ccv3.ProcessInstance{}
   509  							eventualInstanceStates = []ccv3.ProcessInstance{}
   510  						})
   511  
   512  						It("should not return an error", func() {
   513  							Expect(pollStartErr).NotTo(HaveOccurred())
   514  						})
   515  
   516  						It("should only call GetProcessInstances once before exiting", func() {
   517  							Expect(processInstanceCallCount).To(Equal(1))
   518  						})
   519  
   520  						It("should return correct warnings", func() {
   521  							Expect(allWarnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2"))
   522  						})
   523  					})
   524  
   525  					Context("when all instances become running by the second call", func() {
   526  						BeforeEach(func() {
   527  							initialInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}}
   528  							eventualInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceRunning}, {State: constant.ProcessInstanceRunning}}
   529  						})
   530  
   531  						It("should not return an error", func() {
   532  							Expect(pollStartErr).NotTo(HaveOccurred())
   533  						})
   534  
   535  						It("should call GetProcessInstances twice", func() {
   536  							Expect(processInstanceCallCount).To(Equal(2))
   537  						})
   538  
   539  						It("should return correct warnings", func() {
   540  							Expect(allWarnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2", "get-process-warning-3"))
   541  						})
   542  					})
   543  
   544  					Context("when at least one instance has become running by the second call", func() {
   545  						BeforeEach(func() {
   546  							initialInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}}
   547  							eventualInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceRunning}}
   548  						})
   549  
   550  						It("should not return an error", func() {
   551  							Expect(pollStartErr).NotTo(HaveOccurred())
   552  						})
   553  
   554  						It("should call GetProcessInstances twice", func() {
   555  							Expect(processInstanceCallCount).To(Equal(2))
   556  						})
   557  
   558  						It("should return correct warnings", func() {
   559  							Expect(len(allWarnings)).To(Equal(4))
   560  							Expect(allWarnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2", "get-process-warning-3"))
   561  						})
   562  					})
   563  
   564  					Context("when all of the instances have crashed by the second call", func() {
   565  						BeforeEach(func() {
   566  							initialInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}, {State: constant.ProcessInstanceStarting}}
   567  							eventualInstanceStates = []ccv3.ProcessInstance{{State: constant.ProcessInstanceCrashed}, {State: constant.ProcessInstanceCrashed}, {State: constant.ProcessInstanceCrashed}}
   568  						})
   569  
   570  						It("should not return an error", func() {
   571  							Expect(pollStartErr).NotTo(HaveOccurred())
   572  						})
   573  
   574  						It("should call GetProcessInstances twice", func() {
   575  							Expect(processInstanceCallCount).To(Equal(2))
   576  						})
   577  
   578  						It("should return correct warnings", func() {
   579  							Expect(len(allWarnings)).To(Equal(4))
   580  							Expect(allWarnings).To(ConsistOf("get-app-warning-1", "get-process-warning-1", "get-process-warning-2", "get-process-warning-3"))
   581  						})
   582  					})
   583  				})
   584  			})
   585  
   586  			Context("where there are multiple processes", func() {
   587  				var (
   588  					pollStartErr             error
   589  					processInstanceCallCount int
   590  				)
   591  
   592  				BeforeEach(func() {
   593  					processInstanceCallCount = 0
   594  					fakeConfig.StartupTimeoutReturns(time.Millisecond)
   595  					fakeConfig.PollingIntervalReturns(time.Millisecond * 2)
   596  				})
   597  
   598  				JustBeforeEach(func() {
   599  					fakeCloudControllerClient.GetProcessInstancesStub = func(processGuid string) ([]ccv3.ProcessInstance, ccv3.Warnings, error) {
   600  						defer func() { processInstanceCallCount++ }()
   601  						if strings.HasPrefix(processGuid, "good") {
   602  							return []ccv3.ProcessInstance{ccv3.ProcessInstance{State: constant.ProcessInstanceRunning}}, nil, nil
   603  						} else {
   604  							return []ccv3.ProcessInstance{ccv3.ProcessInstance{State: constant.ProcessInstanceStarting}}, nil, nil
   605  						}
   606  					}
   607  
   608  					pollStartErr = actor.PollStart("some-guid", warningsChannel)
   609  					funcDone <- nil
   610  				})
   611  
   612  				Context("when none of the processes are ready", func() {
   613  					BeforeEach(func() {
   614  						processes = []ccv3.Process{{GUID: "bad-1"}, {GUID: "bad-2"}}
   615  					})
   616  
   617  					It("returns the timeout error", func() {
   618  						Expect(pollStartErr).To(MatchError(actionerror.StartupTimeoutError{}))
   619  					})
   620  
   621  				})
   622  
   623  				Context("when some of the processes are ready", func() {
   624  					BeforeEach(func() {
   625  						processes = []ccv3.Process{{GUID: "bad-1"}, {GUID: "good-1"}}
   626  					})
   627  
   628  					It("returns the timeout error", func() {
   629  						Expect(pollStartErr).To(MatchError(actionerror.StartupTimeoutError{}))
   630  					})
   631  				})
   632  
   633  				Context("when all of the processes are ready", func() {
   634  					BeforeEach(func() {
   635  						processes = []ccv3.Process{{GUID: "good-1"}, {GUID: "good-2"}}
   636  					})
   637  
   638  					It("returns nil", func() {
   639  						Expect(pollStartErr).ToNot(HaveOccurred())
   640  					})
   641  				})
   642  			})
   643  		})
   644  	})
   645  
   646  	Describe("StopApplication", func() {
   647  		var (
   648  			warnings   Warnings
   649  			executeErr error
   650  		)
   651  
   652  		JustBeforeEach(func() {
   653  			warnings, executeErr = actor.StopApplication("some-app-guid")
   654  		})
   655  
   656  		Context("when there are no client errors", func() {
   657  			BeforeEach(func() {
   658  				fakeCloudControllerClient.UpdateApplicationStopReturns(
   659  					ccv3.Application{GUID: "some-app-guid"},
   660  					ccv3.Warnings{"stop-application-warning"},
   661  					nil,
   662  				)
   663  			})
   664  
   665  			It("stops the application", func() {
   666  				Expect(executeErr).ToNot(HaveOccurred())
   667  				Expect(warnings).To(ConsistOf("stop-application-warning"))
   668  
   669  				Expect(fakeCloudControllerClient.UpdateApplicationStopCallCount()).To(Equal(1))
   670  				Expect(fakeCloudControllerClient.UpdateApplicationStopArgsForCall(0)).To(Equal("some-app-guid"))
   671  			})
   672  		})
   673  
   674  		Context("when stopping the application fails", func() {
   675  			var expectedErr error
   676  			BeforeEach(func() {
   677  				expectedErr = errors.New("some set stop-application error")
   678  				fakeCloudControllerClient.UpdateApplicationStopReturns(
   679  					ccv3.Application{},
   680  					ccv3.Warnings{"stop-application-warning"},
   681  					expectedErr,
   682  				)
   683  			})
   684  
   685  			It("returns the error", func() {
   686  				Expect(executeErr).To(Equal(expectedErr))
   687  				Expect(warnings).To(ConsistOf("stop-application-warning"))
   688  			})
   689  		})
   690  	})
   691  
   692  	Describe("StartApplication", func() {
   693  		Context("when there are no client errors", func() {
   694  			BeforeEach(func() {
   695  				fakeCloudControllerClient.UpdateApplicationStartReturns(
   696  					ccv3.Application{GUID: "some-app-guid"},
   697  					ccv3.Warnings{"start-application-warning"},
   698  					nil,
   699  				)
   700  			})
   701  
   702  			It("starts the application", func() {
   703  				app, warnings, err := actor.StartApplication("some-app-guid")
   704  
   705  				Expect(err).ToNot(HaveOccurred())
   706  				Expect(warnings).To(ConsistOf("start-application-warning"))
   707  				Expect(app).To(Equal(Application{GUID: "some-app-guid"}))
   708  
   709  				Expect(fakeCloudControllerClient.UpdateApplicationStartCallCount()).To(Equal(1))
   710  				Expect(fakeCloudControllerClient.UpdateApplicationStartArgsForCall(0)).To(Equal("some-app-guid"))
   711  			})
   712  		})
   713  
   714  		Context("when starting the application fails", func() {
   715  			var expectedErr error
   716  			BeforeEach(func() {
   717  				expectedErr = errors.New("some set start-application error")
   718  				fakeCloudControllerClient.UpdateApplicationStartReturns(
   719  					ccv3.Application{},
   720  					ccv3.Warnings{"start-application-warning"},
   721  					expectedErr,
   722  				)
   723  			})
   724  
   725  			It("returns the error", func() {
   726  				_, warnings, err := actor.StartApplication("some-app-guid")
   727  
   728  				Expect(err).To(Equal(expectedErr))
   729  				Expect(warnings).To(ConsistOf("start-application-warning"))
   730  			})
   731  		})
   732  	})
   733  })