github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/actor/v7action/build_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/ccv3"
    11  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    12  	"code.cloudfoundry.org/cli/resources"
    13  	"code.cloudfoundry.org/clock"
    14  	. "github.com/onsi/ginkgo"
    15  	. "github.com/onsi/gomega"
    16  )
    17  
    18  var _ = Describe("Build Actions", func() {
    19  	var (
    20  		actor                     *Actor
    21  		fakeCloudControllerClient *v7actionfakes.FakeCloudControllerClient
    22  		fakeConfig                *v7actionfakes.FakeConfig
    23  	)
    24  
    25  	BeforeEach(func() {
    26  		fakeCloudControllerClient = new(v7actionfakes.FakeCloudControllerClient)
    27  		fakeConfig = new(v7actionfakes.FakeConfig)
    28  		actor = NewActor(fakeCloudControllerClient, fakeConfig, nil, nil, nil, clock.NewClock())
    29  	})
    30  
    31  	Describe("StagePackage", func() {
    32  		var (
    33  			dropletStream  <-chan resources.Droplet
    34  			warningsStream <-chan Warnings
    35  			errorStream    <-chan error
    36  
    37  			appName     string
    38  			appGUID     string
    39  			buildGUID   string
    40  			dropletGUID string
    41  			spaceGUID   string
    42  			packageGUID string
    43  		)
    44  
    45  		BeforeEach(func() {
    46  			appName = "some-app"
    47  			appGUID = "app-guid"
    48  			spaceGUID = "space-guid"
    49  			packageGUID = "some-package-guid"
    50  		})
    51  
    52  		AfterEach(func() {
    53  			Eventually(errorStream).Should(BeClosed())
    54  			Eventually(warningsStream).Should(BeClosed())
    55  			Eventually(dropletStream).Should(BeClosed())
    56  		})
    57  
    58  		JustBeforeEach(func() {
    59  			dropletStream, warningsStream, errorStream = actor.StagePackage(packageGUID, appName, spaceGUID)
    60  		})
    61  
    62  		When("finding the app fails", func() {
    63  			var expectedErr error
    64  
    65  			BeforeEach(func() {
    66  				expectedErr = errors.New("I am a tomato")
    67  				fakeCloudControllerClient.GetApplicationsReturns(nil, ccv3.Warnings{"get-apps-warning"}, expectedErr)
    68  			})
    69  
    70  			It("returns the error and warnings", func() {
    71  				Eventually(warningsStream).Should(Receive(ConsistOf("get-apps-warning")))
    72  				Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
    73  			})
    74  		})
    75  
    76  		When("app is not found", func() {
    77  			BeforeEach(func() {
    78  				fakeCloudControllerClient.GetApplicationsReturns([]resources.Application{}, ccv3.Warnings{"get-apps-warning"}, nil)
    79  			})
    80  
    81  			It("returns the error and warnings", func() {
    82  				Eventually(warningsStream).Should(Receive(ConsistOf("get-apps-warning")))
    83  				Eventually(errorStream).Should(Receive(MatchError(actionerror.ApplicationNotFoundError{Name: appName})))
    84  			})
    85  		})
    86  
    87  		When("finding the package fails", func() {
    88  			var expectedErr error
    89  
    90  			BeforeEach(func() {
    91  				expectedErr = errors.New("I am a passion fruit")
    92  				fakeCloudControllerClient.GetApplicationsReturns([]resources.Application{{GUID: appGUID}}, ccv3.Warnings{"get-apps-warning"}, nil)
    93  				fakeCloudControllerClient.GetPackagesReturns([]resources.Package{}, ccv3.Warnings{"get-packages-warning"}, expectedErr)
    94  			})
    95  
    96  			It("returns the error and warnings", func() {
    97  				Eventually(warningsStream).Should(Receive(ConsistOf("get-apps-warning")))
    98  				Eventually(warningsStream).Should(Receive(ConsistOf("get-packages-warning")))
    99  				Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
   100  			})
   101  		})
   102  
   103  		When("the package does not belong to the app", func() {
   104  			BeforeEach(func() {
   105  				fakeCloudControllerClient.GetApplicationsReturns([]resources.Application{{GUID: appGUID}}, ccv3.Warnings{"get-apps-warning"}, nil)
   106  				fakeCloudControllerClient.GetPackagesReturns(
   107  					[]resources.Package{},
   108  					ccv3.Warnings{"get-packages-warning"},
   109  					nil,
   110  				)
   111  			})
   112  
   113  			It("returns a not found error and warnings", func() {
   114  				Eventually(warningsStream).Should(Receive(ConsistOf("get-apps-warning")))
   115  				Eventually(warningsStream).Should(Receive(ConsistOf("get-packages-warning")))
   116  				Eventually(errorStream).Should(Receive(MatchError(actionerror.PackageNotFoundInAppError{GUID: packageGUID, AppName: appName})))
   117  			})
   118  		})
   119  
   120  		When("the creation is successful", func() {
   121  			BeforeEach(func() {
   122  				fakeCloudControllerClient.GetApplicationsReturns([]resources.Application{{GUID: appGUID}}, ccv3.Warnings{"get-apps-warning"}, nil)
   123  				fakeCloudControllerClient.GetPackagesReturns(
   124  					[]resources.Package{{GUID: packageGUID}},
   125  					ccv3.Warnings{"get-packages-warning"},
   126  					nil,
   127  				)
   128  
   129  				buildGUID = "some-build-guid"
   130  				dropletGUID = "some-droplet-guid"
   131  				fakeCloudControllerClient.CreateBuildReturns(resources.Build{GUID: buildGUID, State: constant.BuildStaging}, ccv3.Warnings{"create-warnings-1", "create-warnings-2"}, nil)
   132  				fakeConfig.StagingTimeoutReturns(time.Minute)
   133  			})
   134  
   135  			When("the polling is successful", func() {
   136  				BeforeEach(func() {
   137  					fakeCloudControllerClient.GetBuildReturnsOnCall(0, resources.Build{GUID: buildGUID, State: constant.BuildStaging}, ccv3.Warnings{"get-warnings-1", "get-warnings-2"}, nil)
   138  					fakeCloudControllerClient.GetBuildReturnsOnCall(1, resources.Build{CreatedAt: "some-time", GUID: buildGUID, State: constant.BuildStaged, DropletGUID: "some-droplet-guid"}, ccv3.Warnings{"get-warnings-3", "get-warnings-4"}, nil)
   139  				})
   140  
   141  				//TODO: uncommend after #150569020
   142  				// FWhen("looking up the droplet fails", func() {
   143  				// 	BeforeEach(func() {
   144  				// 		fakeCloudControllerClient.GetDropletReturns(resources.Droplet{}, ccv3.Warnings{"droplet-warnings-1", "droplet-warnings-2"}, errors.New("some-droplet-error"))
   145  				// 	})
   146  
   147  				// 	It("returns the warnings and the droplet error", func() {
   148  				//    Eventually(warningsStream).Should(Receive(ConsistOf("get-apps-warning")))
   149  				//    Eventually(warningsStream).Should(Receive(ConsistOf("get-packages-warning")))
   150  				// 		Eventually(warningsStream).Should(Receive(ConsistOf("create-warnings-1", "create-warnings-2")))
   151  				// 		Eventually(warningsStream).Should(Receive(ConsistOf("get-warnings-1", "get-warnings-2")))
   152  				// 		Eventually(warningsStream).Should(Receive(ConsistOf("get-warnings-3", "get-warnings-4")))
   153  				// 		Eventually(warningsStream).Should(Receive(ConsistOf("droplet-warnings-1", "droplet-warnings-2")))
   154  
   155  				// 		Eventually(errorStream).Should(Receive(MatchError("some-droplet-error")))
   156  				// 	})
   157  				// })
   158  
   159  				// When("looking up the droplet succeeds", func() {
   160  				// 	BeforeEach(func() {
   161  				// 		fakeCloudControllerClient.GetDropletReturns(resources.Droplet{GUID: dropletGUID, State: ccv3.DropletStateStaged}, ccv3.Warnings{"droplet-warnings-1", "droplet-warnings-2"}, nil)
   162  				// 	})
   163  
   164  				It("polls until build is finished and returns the final droplet", func() {
   165  					Eventually(warningsStream).Should(Receive(ConsistOf("get-apps-warning")))
   166  					Eventually(warningsStream).Should(Receive(ConsistOf("get-packages-warning")))
   167  					Eventually(warningsStream).Should(Receive(ConsistOf("create-warnings-1", "create-warnings-2")))
   168  					Eventually(warningsStream).Should(Receive(ConsistOf("get-warnings-1", "get-warnings-2")))
   169  					Eventually(warningsStream).Should(Receive(ConsistOf("get-warnings-3", "get-warnings-4")))
   170  					// Eventually(warningsStream).Should(Receive(ConsistOf("droplet-warnings-1", "droplet-warnings-2")))
   171  
   172  					Eventually(dropletStream).Should(Receive(Equal(resources.Droplet{GUID: dropletGUID, State: constant.DropletStaged, CreatedAt: "some-time"})))
   173  					Consistently(errorStream).ShouldNot(Receive())
   174  
   175  					Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   176  					Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(Equal([]ccv3.Query{
   177  						{Key: ccv3.NameFilter, Values: []string{appName}},
   178  						{Key: ccv3.SpaceGUIDFilter, Values: []string{spaceGUID}},
   179  					}))
   180  
   181  					Expect(fakeCloudControllerClient.GetPackagesCallCount()).To(Equal(1))
   182  					Expect(fakeCloudControllerClient.GetPackagesArgsForCall(0)).To(Equal([]ccv3.Query{
   183  						{Key: ccv3.GUIDFilter, Values: []string{packageGUID}},
   184  						{Key: ccv3.AppGUIDFilter, Values: []string{appGUID}},
   185  						{Key: ccv3.PerPage, Values: []string{"1"}},
   186  						{Key: ccv3.Page, Values: []string{"1"}},
   187  					}))
   188  
   189  					Expect(fakeCloudControllerClient.CreateBuildCallCount()).To(Equal(1))
   190  					Expect(fakeCloudControllerClient.CreateBuildArgsForCall(0)).To(Equal(resources.Build{
   191  						PackageGUID: "some-package-guid",
   192  					}))
   193  
   194  					Expect(fakeCloudControllerClient.GetBuildCallCount()).To(Equal(2))
   195  					Expect(fakeCloudControllerClient.GetBuildArgsForCall(0)).To(Equal(buildGUID))
   196  					Expect(fakeCloudControllerClient.GetBuildArgsForCall(1)).To(Equal(buildGUID))
   197  
   198  					Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(1))
   199  				})
   200  				// })
   201  
   202  				When("polling returns a failed build", func() {
   203  					BeforeEach(func() {
   204  						fakeCloudControllerClient.GetBuildReturnsOnCall(
   205  							1,
   206  							resources.Build{
   207  								GUID:  buildGUID,
   208  								State: constant.BuildFailed,
   209  								Error: "some staging error",
   210  							},
   211  							ccv3.Warnings{"get-warnings-3", "get-warnings-4"}, nil)
   212  					})
   213  
   214  					It("returns an error and all warnings", func() {
   215  						Eventually(warningsStream).Should(Receive(ConsistOf("get-apps-warning")))
   216  						Eventually(warningsStream).Should(Receive(ConsistOf("get-packages-warning")))
   217  						Eventually(warningsStream).Should(Receive(ConsistOf("create-warnings-1", "create-warnings-2")))
   218  						Eventually(warningsStream).Should(Receive(ConsistOf("get-warnings-1", "get-warnings-2")))
   219  						Eventually(warningsStream).Should(Receive(ConsistOf("get-warnings-3", "get-warnings-4")))
   220  						stagingErr := errors.New("some staging error")
   221  						Eventually(errorStream).Should(Receive(&stagingErr))
   222  						Eventually(dropletStream).ShouldNot(Receive())
   223  
   224  						Expect(fakeCloudControllerClient.GetBuildCallCount()).To(Equal(2))
   225  						Expect(fakeCloudControllerClient.GetBuildArgsForCall(0)).To(Equal(buildGUID))
   226  						Expect(fakeCloudControllerClient.GetBuildArgsForCall(1)).To(Equal(buildGUID))
   227  
   228  						Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(1))
   229  					})
   230  				})
   231  			})
   232  
   233  			When("polling times out", func() {
   234  				var expectedErr error
   235  
   236  				BeforeEach(func() {
   237  					expectedErr = actionerror.StagingTimeoutError{AppName: "some-app", Timeout: 0}
   238  					fakeConfig.StagingTimeoutReturns(0)
   239  				})
   240  
   241  				It("returns the error and warnings", func() {
   242  					Eventually(warningsStream).Should(Receive(ConsistOf("create-warnings-1", "create-warnings-2")))
   243  					Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
   244  				})
   245  			})
   246  
   247  			When("the polling errors", func() {
   248  				var expectedErr error
   249  
   250  				BeforeEach(func() {
   251  					expectedErr = errors.New("I am a banana")
   252  					fakeCloudControllerClient.GetBuildReturnsOnCall(0, resources.Build{GUID: buildGUID, State: constant.BuildStaging}, ccv3.Warnings{"get-warnings-1", "get-warnings-2"}, nil)
   253  					fakeCloudControllerClient.GetBuildReturnsOnCall(1, resources.Build{}, ccv3.Warnings{"get-warnings-3", "get-warnings-4"}, expectedErr)
   254  				})
   255  
   256  				It("returns the error and warnings", func() {
   257  					Eventually(warningsStream).Should(Receive(ConsistOf("get-apps-warning")))
   258  					Eventually(warningsStream).Should(Receive(ConsistOf("get-packages-warning")))
   259  					Eventually(warningsStream).Should(Receive(ConsistOf("create-warnings-1", "create-warnings-2")))
   260  					Eventually(warningsStream).Should(Receive(ConsistOf("get-warnings-1", "get-warnings-2")))
   261  					Eventually(warningsStream).Should(Receive(ConsistOf("get-warnings-3", "get-warnings-4")))
   262  					Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
   263  				})
   264  			})
   265  		})
   266  
   267  		When("creation errors", func() {
   268  			var expectedErr error
   269  
   270  			BeforeEach(func() {
   271  				fakeCloudControllerClient.GetApplicationsReturns([]resources.Application{{GUID: appGUID}}, ccv3.Warnings{"get-apps-warning"}, nil)
   272  				fakeCloudControllerClient.GetPackagesReturns(
   273  					[]resources.Package{{GUID: packageGUID}},
   274  					ccv3.Warnings{"get-packages-warning"},
   275  					nil,
   276  				)
   277  
   278  				expectedErr = errors.New("I am a banana")
   279  				fakeCloudControllerClient.CreateBuildReturns(resources.Build{}, ccv3.Warnings{"create-warnings-1", "create-warnings-2"}, expectedErr)
   280  			})
   281  
   282  			It("returns the error and warnings", func() {
   283  				Eventually(warningsStream).Should(Receive(ConsistOf("get-apps-warning")))
   284  				Eventually(warningsStream).Should(Receive(ConsistOf("get-packages-warning")))
   285  				Eventually(warningsStream).Should(Receive(ConsistOf("create-warnings-1", "create-warnings-2")))
   286  				Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
   287  			})
   288  		})
   289  	})
   290  
   291  	Describe("StageApplicationPackage", func() {
   292  		var (
   293  			build      resources.Build
   294  			warnings   Warnings
   295  			executeErr error
   296  		)
   297  
   298  		JustBeforeEach(func() {
   299  			build, warnings, executeErr = actor.StageApplicationPackage("some-package-guid")
   300  		})
   301  
   302  		When("the creation is successful", func() {
   303  			BeforeEach(func() {
   304  				fakeCloudControllerClient.CreateBuildReturns(resources.Build{GUID: "some-build-guid"}, ccv3.Warnings{"create-warnings-1", "create-warnings-2"}, nil)
   305  			})
   306  
   307  			It("returns the build and warnings", func() {
   308  				Expect(executeErr).ToNot(HaveOccurred())
   309  				Expect(build).To(Equal(resources.Build{GUID: "some-build-guid"}))
   310  				Expect(warnings).To(ConsistOf("create-warnings-1", "create-warnings-2"))
   311  			})
   312  		})
   313  
   314  		When("the creation fails", func() {
   315  			BeforeEach(func() {
   316  				fakeCloudControllerClient.CreateBuildReturns(resources.Build{}, ccv3.Warnings{"create-warnings-1", "create-warnings-2"}, errors.New("blurp"))
   317  			})
   318  
   319  			It("returns the error and warnings", func() {
   320  				Expect(executeErr).To(MatchError("blurp"))
   321  				Expect(warnings).To(ConsistOf("create-warnings-1", "create-warnings-2"))
   322  			})
   323  		})
   324  	})
   325  
   326  	Describe("PollBuild", func() {
   327  		var (
   328  			droplet    resources.Droplet
   329  			warnings   Warnings
   330  			executeErr error
   331  		)
   332  
   333  		JustBeforeEach(func() {
   334  			droplet, warnings, executeErr = actor.PollBuild("some-build-guid", "some-app")
   335  		})
   336  
   337  		When("getting the build yields a 'Staged' build", func() {
   338  			BeforeEach(func() {
   339  				fakeCloudControllerClient.GetBuildReturnsOnCall(0, resources.Build{State: constant.BuildStaging}, ccv3.Warnings{"some-get-build-warnings"}, nil)
   340  				fakeCloudControllerClient.GetBuildReturnsOnCall(1, resources.Build{GUID: "some-build-guid", DropletGUID: "some-droplet-guid", State: constant.BuildStaged}, ccv3.Warnings{"some-get-build-warnings"}, nil)
   341  				fakeConfig.StagingTimeoutReturns(500 * time.Millisecond)
   342  			})
   343  
   344  			It("gets the droplet", func() {
   345  				Expect(fakeCloudControllerClient.GetBuildCallCount()).To(Equal(2))
   346  
   347  				Expect(fakeCloudControllerClient.GetDropletCallCount()).To(Equal(1))
   348  				Expect(fakeCloudControllerClient.GetDropletArgsForCall(0)).To(Equal("some-droplet-guid"))
   349  			})
   350  
   351  			When("getting the droplet is successful", func() {
   352  				BeforeEach(func() {
   353  					fakeCloudControllerClient.GetDropletReturns(resources.Droplet{GUID: "some-droplet-guid", CreatedAt: "some-droplet-time", State: constant.DropletStaged}, ccv3.Warnings{"some-get-droplet-warnings"}, nil)
   354  				})
   355  
   356  				It("returns the droplet and warnings", func() {
   357  					Expect(executeErr).ToNot(HaveOccurred())
   358  
   359  					Expect(warnings).To(ConsistOf("some-get-build-warnings", "some-get-build-warnings", "some-get-droplet-warnings"))
   360  					Expect(droplet).To(Equal(resources.Droplet{
   361  						GUID:      "some-droplet-guid",
   362  						CreatedAt: "some-droplet-time",
   363  						State:     constant.DropletStaged,
   364  					}))
   365  				})
   366  			})
   367  
   368  			When("getting the droplet fails", func() {
   369  				BeforeEach(func() {
   370  					fakeCloudControllerClient.GetDropletReturns(resources.Droplet{}, ccv3.Warnings{"some-get-droplet-warnings"}, errors.New("no rain"))
   371  				})
   372  
   373  				It("returns the error and warnings", func() {
   374  					Expect(executeErr).To(MatchError("no rain"))
   375  					Expect(warnings).To(ConsistOf("some-get-build-warnings", "some-get-build-warnings", "some-get-droplet-warnings"))
   376  				})
   377  			})
   378  		})
   379  
   380  		When("getting the build yields a 'Failed' build", func() {
   381  			BeforeEach(func() {
   382  				fakeCloudControllerClient.GetBuildReturnsOnCall(0, resources.Build{State: constant.BuildFailed, Error: "ded build"}, ccv3.Warnings{"some-get-build-warnings"}, nil)
   383  				fakeConfig.StagingTimeoutReturns(500 * time.Millisecond)
   384  			})
   385  
   386  			It("returns the error and warnings", func() {
   387  				Expect(executeErr).To(MatchError("ded build"))
   388  				Expect(warnings).To(ConsistOf("some-get-build-warnings"))
   389  			})
   390  		})
   391  
   392  		When("getting the build fails", func() {
   393  			BeforeEach(func() {
   394  				fakeCloudControllerClient.GetBuildReturnsOnCall(0, resources.Build{}, ccv3.Warnings{"some-get-build-warnings"}, errors.New("some-poll-build-error"))
   395  				fakeConfig.StagingTimeoutReturns(500 * time.Millisecond)
   396  			})
   397  
   398  			It("returns the error and warnings", func() {
   399  				Expect(executeErr).To(MatchError("some-poll-build-error"))
   400  				Expect(warnings).To(ConsistOf("some-get-build-warnings"))
   401  			})
   402  		})
   403  
   404  		When("polling the build times out", func() {
   405  			BeforeEach(func() {
   406  				fakeCloudControllerClient.GetBuildReturnsOnCall(0, resources.Build{}, ccv3.Warnings{"some-get-build-warnings"}, nil)
   407  				fakeConfig.StagingTimeoutReturns(500 * time.Millisecond)
   408  			})
   409  
   410  			It("returns the error and warnings", func() {
   411  				Expect(executeErr).To(MatchError(actionerror.StagingTimeoutError{AppName: "some-app", Timeout: 500 * time.Millisecond}))
   412  				Expect(warnings).To(ConsistOf("some-get-build-warnings"))
   413  			})
   414  		})
   415  	})
   416  })