github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/actor/v7pushaction/create_bits_package_for_application_test.go (about)

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