github.com/cloudfoundry-community/cloudfoundry-cli@v6.44.1-0.20240130060226-cda5ed8e89a5+incompatible/actor/v7pushaction/create_bits_package_for_application_test.go (about)

     1  package v7pushaction_test
     2  
     3  import (
     4  	"code.cloudfoundry.org/cli/actor/actionerror"
     5  	"code.cloudfoundry.org/cli/actor/sharedaction"
     6  	"code.cloudfoundry.org/cli/actor/v7action"
     7  	. "code.cloudfoundry.org/cli/actor/v7pushaction"
     8  	"code.cloudfoundry.org/cli/actor/v7pushaction/v7pushactionfakes"
     9  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
    10  	"errors"
    11  	. "github.com/onsi/ginkgo"
    12  	. "github.com/onsi/gomega"
    13  )
    14  
    15  var _ = Describe("CreateBitsPackageForApplication", func() {
    16  	var (
    17  		actor           *Actor
    18  		fakeV7Actor     *v7pushactionfakes.FakeV7Actor
    19  		fakeSharedActor *v7pushactionfakes.FakeSharedActor
    20  
    21  		returnedPushPlan PushPlan
    22  		paramPlan        PushPlan
    23  		fakeProgressBar  *v7pushactionfakes.FakeProgressBar
    24  
    25  		warnings   Warnings
    26  		executeErr error
    27  
    28  		events []Event
    29  	)
    30  
    31  	BeforeEach(func() {
    32  		actor, _, fakeV7Actor, fakeSharedActor = getTestPushActor()
    33  
    34  		fakeProgressBar = new(v7pushactionfakes.FakeProgressBar)
    35  
    36  		fakeSharedActor.ReadArchiveReturns(new(v7pushactionfakes.FakeReadCloser), 0, nil)
    37  
    38  		paramPlan = PushPlan{
    39  			Application: v7action.Application{
    40  				GUID: "some-app-guid",
    41  			},
    42  			DockerImageCredentialsNeedsUpdate: false,
    43  		}
    44  	})
    45  
    46  	JustBeforeEach(func() {
    47  		events = EventFollower(func(eventStream chan<- Event) {
    48  			returnedPushPlan, warnings, executeErr = actor.CreateBitsPackageForApplication(paramPlan, eventStream, fakeProgressBar)
    49  		})
    50  	})
    51  
    52  	Describe("package upload", func() {
    53  		When("resource match errors ", func() {
    54  			BeforeEach(func() {
    55  				fakeV7Actor.ResourceMatchReturns(
    56  					nil,
    57  					v7action.Warnings{"some-resource-match-warning"},
    58  					errors.New("resource-match-error"))
    59  			})
    60  
    61  			It("raises the error", func() {
    62  				Expect(executeErr).To(MatchError("resource-match-error"))
    63  				Expect(events).To(ConsistOf(ResourceMatching))
    64  				Expect(warnings).To(ConsistOf("some-resource-match-warning"))
    65  			})
    66  		})
    67  
    68  		When("resource match is successful", func() {
    69  			var (
    70  				matches   []sharedaction.V3Resource
    71  				unmatches []sharedaction.V3Resource
    72  			)
    73  
    74  			When("there are unmatched resources", func() {
    75  				BeforeEach(func() {
    76  					matches = []sharedaction.V3Resource{
    77  						buildV3Resource("some-matching-filename"),
    78  					}
    79  
    80  					unmatches = []sharedaction.V3Resource{
    81  						buildV3Resource("some-unmatching-filename"),
    82  					}
    83  
    84  					paramPlan = PushPlan{
    85  						Application: v7action.Application{
    86  							Name: "some-app",
    87  							GUID: "some-app-guid",
    88  						},
    89  						BitsPath: "/some-bits-path",
    90  						AllResources: append(
    91  							matches,
    92  							unmatches...,
    93  						),
    94  					}
    95  
    96  					fakeV7Actor.ResourceMatchReturns(
    97  						matches,
    98  						v7action.Warnings{"some-good-good-resource-match-warnings"},
    99  						nil,
   100  					)
   101  				})
   102  
   103  				When("the bits path is an archive", func() {
   104  					BeforeEach(func() {
   105  						paramPlan.Archive = true
   106  					})
   107  
   108  					It("creates the archive with the unmatched resources", func() {
   109  						Expect(fakeSharedActor.ZipArchiveResourcesCallCount()).To(Equal(1))
   110  						bitsPath, resources := fakeSharedActor.ZipArchiveResourcesArgsForCall(0)
   111  						Expect(bitsPath).To(Equal("/some-bits-path"))
   112  						Expect(resources).To(HaveLen(1))
   113  						Expect(resources[0].ToV3Resource()).To(Equal(unmatches[0]))
   114  					})
   115  				})
   116  
   117  				When("The bits path is a directory", func() {
   118  					It("creates the archive", func() {
   119  						Expect(fakeSharedActor.ZipDirectoryResourcesCallCount()).To(Equal(1))
   120  						bitsPath, resources := fakeSharedActor.ZipDirectoryResourcesArgsForCall(0)
   121  						Expect(bitsPath).To(Equal("/some-bits-path"))
   122  						Expect(resources).To(HaveLen(1))
   123  						Expect(resources[0].ToV3Resource()).To(Equal(unmatches[0]))
   124  					})
   125  				})
   126  
   127  				When("the archive creation is successful", func() {
   128  					BeforeEach(func() {
   129  						fakeSharedActor.ZipDirectoryResourcesReturns("/some/archive/path", nil)
   130  						fakeV7Actor.UpdateApplicationReturns(
   131  							v7action.Application{
   132  								Name: "some-app",
   133  								GUID: paramPlan.Application.GUID,
   134  							},
   135  							v7action.Warnings{"some-app-update-warnings"},
   136  							nil)
   137  					})
   138  
   139  					It("creates the package", func() {
   140  						Expect(fakeV7Actor.CreateBitsPackageByApplicationCallCount()).To(Equal(1))
   141  						Expect(fakeV7Actor.CreateBitsPackageByApplicationArgsForCall(0)).To(Equal("some-app-guid"))
   142  					})
   143  
   144  					When("the package creation is successful", func() {
   145  						BeforeEach(func() {
   146  							fakeV7Actor.CreateBitsPackageByApplicationReturns(v7action.Package{GUID: "some-guid"}, v7action.Warnings{"some-create-package-warning"}, nil)
   147  						})
   148  
   149  						It("reads the archive", func() {
   150  							Expect(fakeSharedActor.ReadArchiveCallCount()).To(Equal(1))
   151  							Expect(fakeSharedActor.ReadArchiveArgsForCall(0)).To(Equal("/some/archive/path"))
   152  						})
   153  
   154  						When("reading the archive is successful", func() {
   155  							BeforeEach(func() {
   156  								fakeReadCloser := new(v7pushactionfakes.FakeReadCloser)
   157  								fakeSharedActor.ReadArchiveReturns(fakeReadCloser, 6, nil)
   158  							})
   159  
   160  							It("uploads the bits package", func() {
   161  								Expect(fakeV7Actor.UploadBitsPackageCallCount()).To(Equal(1))
   162  								pkg, resource, _, size := fakeV7Actor.UploadBitsPackageArgsForCall(0)
   163  
   164  								Expect(pkg).To(Equal(v7action.Package{GUID: "some-guid"}))
   165  								Expect(resource).To(Equal(matches))
   166  								Expect(size).To(BeNumerically("==", 6))
   167  							})
   168  
   169  							When("the upload is successful", func() {
   170  								BeforeEach(func() {
   171  									fakeV7Actor.UploadBitsPackageReturns(v7action.Package{GUID: "some-guid"}, v7action.Warnings{"some-upload-package-warning"}, nil)
   172  								})
   173  
   174  								It("returns an upload complete event and warnings", func() {
   175  									Expect(events).To(ConsistOf(ResourceMatching, CreatingPackage, CreatingArchive, ReadingArchive, UploadingApplicationWithArchive, UploadWithArchiveComplete))
   176  									Expect(warnings).To(ConsistOf("some-good-good-resource-match-warnings", "some-create-package-warning", "some-upload-package-warning"))
   177  								})
   178  
   179  								When("the upload errors", func() {
   180  									When("the upload error is a retryable error", func() {
   181  										var someErr error
   182  
   183  										BeforeEach(func() {
   184  											someErr = errors.New("I AM A BANANA")
   185  											fakeV7Actor.UploadBitsPackageReturns(v7action.Package{}, v7action.Warnings{"upload-warnings-1", "upload-warnings-2"}, ccerror.PipeSeekError{Err: someErr})
   186  										})
   187  
   188  										It("should send a RetryUpload event and retry uploading", func() {
   189  											Expect(events).To(ConsistOf(
   190  												ResourceMatching, CreatingPackage, CreatingArchive,
   191  												ReadingArchive, UploadingApplicationWithArchive, RetryUpload,
   192  												ReadingArchive, UploadingApplicationWithArchive, RetryUpload,
   193  												ReadingArchive, UploadingApplicationWithArchive, RetryUpload,
   194  											))
   195  
   196  											Expect(warnings).To(ConsistOf("some-good-good-resource-match-warnings", "some-create-package-warning", "upload-warnings-1", "upload-warnings-2", "upload-warnings-1", "upload-warnings-2", "upload-warnings-1", "upload-warnings-2"))
   197  
   198  											Expect(fakeV7Actor.UploadBitsPackageCallCount()).To(Equal(3))
   199  											Expect(executeErr).To(MatchError(actionerror.UploadFailedError{Err: someErr}))
   200  										})
   201  
   202  									})
   203  
   204  									When("the upload error is not a retryable error", func() {
   205  										BeforeEach(func() {
   206  											fakeV7Actor.UploadBitsPackageReturns(v7action.Package{}, v7action.Warnings{"upload-warnings-1", "upload-warnings-2"}, errors.New("dios mio"))
   207  										})
   208  
   209  										It("sends warnings and errors, then stops", func() {
   210  											Expect(events).To(ConsistOf(ResourceMatching, CreatingPackage, CreatingArchive, ReadingArchive, UploadingApplicationWithArchive))
   211  											Expect(warnings).To(ConsistOf("some-good-good-resource-match-warnings", "some-create-package-warning", "upload-warnings-1", "upload-warnings-2"))
   212  											Expect(executeErr).To(MatchError("dios mio"))
   213  										})
   214  									})
   215  								})
   216  							})
   217  
   218  							When("reading the archive fails", func() {
   219  								BeforeEach(func() {
   220  									fakeSharedActor.ReadArchiveReturns(nil, 0, errors.New("the bits"))
   221  								})
   222  
   223  								It("returns an error", func() {
   224  									Expect(events).To(ConsistOf(ResourceMatching, CreatingPackage, CreatingArchive, ReadingArchive))
   225  									Expect(executeErr).To(MatchError("the bits"))
   226  								})
   227  							})
   228  						})
   229  
   230  						When("the package creation errors", func() {
   231  							BeforeEach(func() {
   232  								fakeV7Actor.CreateBitsPackageByApplicationReturns(v7action.Package{}, v7action.Warnings{"package-creation-warning"}, errors.New("the package"))
   233  							})
   234  
   235  							It("it returns errors and warnings", func() {
   236  								Expect(events).To(ConsistOf(ResourceMatching, CreatingPackage))
   237  
   238  								Expect(warnings).To(ConsistOf("some-good-good-resource-match-warnings", "package-creation-warning"))
   239  								Expect(executeErr).To(MatchError("the package"))
   240  							})
   241  						})
   242  					})
   243  
   244  					When("the archive creation errors", func() {
   245  						BeforeEach(func() {
   246  							fakeSharedActor.ZipDirectoryResourcesReturns("", errors.New("oh no"))
   247  						})
   248  
   249  						It("returns an error and exits", func() {
   250  							Expect(events).To(ConsistOf(ResourceMatching, CreatingPackage, CreatingArchive))
   251  							Expect(executeErr).To(MatchError("oh no"))
   252  						})
   253  					})
   254  				})
   255  			})
   256  
   257  			When("All resources are matched", func() {
   258  				BeforeEach(func() {
   259  					matches = []sharedaction.V3Resource{
   260  						buildV3Resource("some-matching-filename"),
   261  					}
   262  
   263  					paramPlan = PushPlan{
   264  						Application: v7action.Application{
   265  							Name: "some-app",
   266  							GUID: "some-app-guid",
   267  						},
   268  						BitsPath:     "/some-bits-path",
   269  						AllResources: matches,
   270  					}
   271  
   272  					fakeV7Actor.ResourceMatchReturns(
   273  						matches,
   274  						v7action.Warnings{"some-good-good-resource-match-warnings"},
   275  						nil,
   276  					)
   277  				})
   278  
   279  				When("package upload succeeds", func() {
   280  					BeforeEach(func() {
   281  						fakeV7Actor.UploadBitsPackageReturns(v7action.Package{GUID: "some-guid"}, v7action.Warnings{"upload-warning"}, nil)
   282  					})
   283  
   284  					It("Uploads the package without a zip", func() {
   285  						Expect(fakeSharedActor.ZipArchiveResourcesCallCount()).To(BeZero())
   286  						Expect(fakeSharedActor.ZipDirectoryResourcesCallCount()).To(BeZero())
   287  						Expect(fakeSharedActor.ReadArchiveCallCount()).To(BeZero())
   288  
   289  						Expect(events).To(ConsistOf(ResourceMatching, CreatingPackage, UploadingApplication))
   290  						Expect(fakeV7Actor.UploadBitsPackageCallCount()).To(Equal(1))
   291  						_, actualMatchedResources, actualProgressReader, actualSize := fakeV7Actor.UploadBitsPackageArgsForCall(0)
   292  
   293  						Expect(actualMatchedResources).To(Equal(matches))
   294  						Expect(actualProgressReader).To(BeNil())
   295  						Expect(actualSize).To(BeZero())
   296  					})
   297  				})
   298  
   299  				When("package upload fails", func() {
   300  					BeforeEach(func() {
   301  						fakeV7Actor.UploadBitsPackageReturns(
   302  							v7action.Package{},
   303  							v7action.Warnings{"upload-warning"},
   304  							errors.New("upload-error"),
   305  						)
   306  					})
   307  
   308  					It("returns an error", func() {
   309  						Expect(fakeSharedActor.ZipArchiveResourcesCallCount()).To(BeZero())
   310  						Expect(fakeSharedActor.ZipDirectoryResourcesCallCount()).To(BeZero())
   311  						Expect(fakeSharedActor.ReadArchiveCallCount()).To(BeZero())
   312  
   313  						Expect(events).To(ConsistOf(ResourceMatching, CreatingPackage, UploadingApplication))
   314  						Expect(fakeV7Actor.UploadBitsPackageCallCount()).To(Equal(1))
   315  						_, actualMatchedResources, actualProgressReader, actualSize := fakeV7Actor.UploadBitsPackageArgsForCall(0)
   316  
   317  						Expect(actualMatchedResources).To(Equal(matches))
   318  						Expect(actualProgressReader).To(BeNil())
   319  						Expect(actualSize).To(BeZero())
   320  
   321  						Expect(warnings).To(ConsistOf("some-good-good-resource-match-warnings", "upload-warning"))
   322  						Expect(executeErr).To(MatchError("upload-error"))
   323  					})
   324  				})
   325  			})
   326  		})
   327  	})
   328  
   329  	Describe("polling package", func() {
   330  		var (
   331  			matches   []sharedaction.V3Resource
   332  			unmatches []sharedaction.V3Resource
   333  		)
   334  
   335  		BeforeEach(func() {
   336  			matches = []sharedaction.V3Resource{
   337  				buildV3Resource("some-matching-filename"),
   338  			}
   339  
   340  			unmatches = []sharedaction.V3Resource{
   341  				buildV3Resource("some-unmatching-filename"),
   342  			}
   343  
   344  			paramPlan = PushPlan{
   345  				Application: v7action.Application{
   346  					Name: "some-app",
   347  					GUID: "some-app-guid",
   348  				},
   349  				BitsPath: "/some-bits-path",
   350  				AllResources: append(
   351  					matches,
   352  					unmatches...,
   353  				),
   354  			}
   355  
   356  			fakeV7Actor.ResourceMatchReturns(
   357  				matches,
   358  				v7action.Warnings{"some-good-good-resource-match-warnings"},
   359  				nil,
   360  			)
   361  		})
   362  
   363  		When("the the polling is successful", func() {
   364  			BeforeEach(func() {
   365  				fakeV7Actor.PollPackageReturns(v7action.Package{GUID: "some-package-guid"}, v7action.Warnings{"some-poll-package-warning"}, nil)
   366  			})
   367  
   368  			It("returns warnings", func() {
   369  				Expect(events).To(ConsistOf(ResourceMatching, CreatingPackage, CreatingArchive, ReadingArchive, UploadingApplicationWithArchive, UploadWithArchiveComplete))
   370  				Expect(warnings).To(ConsistOf("some-good-good-resource-match-warnings", "some-poll-package-warning"))
   371  			})
   372  
   373  			It("sets the package guid on push plan", func() {
   374  				Expect(returnedPushPlan.PackageGUID).To(Equal("some-package-guid"))
   375  			})
   376  		})
   377  
   378  		When("the the polling returns an error", func() {
   379  			var someErr error
   380  
   381  			BeforeEach(func() {
   382  				someErr = errors.New("I AM A BANANA")
   383  				fakeV7Actor.PollPackageReturns(v7action.Package{}, v7action.Warnings{"some-poll-package-warning"}, someErr)
   384  			})
   385  
   386  			It("returns errors and warnings", func() {
   387  				Expect(events).To(ConsistOf(ResourceMatching, CreatingPackage, CreatingArchive, ReadingArchive, UploadingApplicationWithArchive, UploadWithArchiveComplete))
   388  				Expect(executeErr).To(MatchError(someErr))
   389  			})
   390  		})
   391  	})
   392  })