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 })