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

     1  package v3action_test
     2  
     3  import (
     4  	"errors"
     5  	"io/ioutil"
     6  	"os"
     7  
     8  	"code.cloudfoundry.org/cli/actor/actionerror"
     9  	"code.cloudfoundry.org/cli/actor/sharedaction"
    10  	. "code.cloudfoundry.org/cli/actor/v3action"
    11  	"code.cloudfoundry.org/cli/actor/v3action/v3actionfakes"
    12  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
    13  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    14  
    15  	. "github.com/onsi/ginkgo"
    16  	. "github.com/onsi/ginkgo/extensions/table"
    17  	. "github.com/onsi/gomega"
    18  )
    19  
    20  var _ = Describe("Package Actions", func() {
    21  	var (
    22  		actor                     *Actor
    23  		fakeCloudControllerClient *v3actionfakes.FakeCloudControllerClient
    24  		fakeSharedActor           *v3actionfakes.FakeSharedActor
    25  		fakeConfig                *v3actionfakes.FakeConfig
    26  	)
    27  
    28  	BeforeEach(func() {
    29  		fakeCloudControllerClient = new(v3actionfakes.FakeCloudControllerClient)
    30  		fakeConfig = new(v3actionfakes.FakeConfig)
    31  		fakeSharedActor = new(v3actionfakes.FakeSharedActor)
    32  		actor = NewActor(fakeCloudControllerClient, fakeConfig, fakeSharedActor, nil)
    33  	})
    34  
    35  	Describe("GetApplicationPackages", func() {
    36  		Context("when there are no client errors", func() {
    37  			BeforeEach(func() {
    38  				fakeCloudControllerClient.GetApplicationsReturns(
    39  					[]ccv3.Application{
    40  						{GUID: "some-app-guid"},
    41  					},
    42  					ccv3.Warnings{"get-applications-warning"},
    43  					nil,
    44  				)
    45  
    46  				fakeCloudControllerClient.GetPackagesReturns(
    47  					[]ccv3.Package{
    48  						{
    49  							GUID:      "some-package-guid-1",
    50  							State:     constant.PackageReady,
    51  							CreatedAt: "2017-08-14T21:16:42Z",
    52  						},
    53  						{
    54  							GUID:      "some-package-guid-2",
    55  							State:     constant.PackageFailed,
    56  							CreatedAt: "2017-08-16T00:18:24Z",
    57  						},
    58  					},
    59  					ccv3.Warnings{"get-application-packages-warning"},
    60  					nil,
    61  				)
    62  			})
    63  
    64  			It("gets the app's packages", func() {
    65  				packages, warnings, err := actor.GetApplicationPackages("some-app-name", "some-space-guid")
    66  
    67  				Expect(err).ToNot(HaveOccurred())
    68  				Expect(warnings).To(ConsistOf("get-applications-warning", "get-application-packages-warning"))
    69  				Expect(packages).To(Equal([]Package{
    70  					{
    71  						GUID:      "some-package-guid-1",
    72  						State:     constant.PackageReady,
    73  						CreatedAt: "2017-08-14T21:16:42Z",
    74  					},
    75  					{
    76  						GUID:      "some-package-guid-2",
    77  						State:     constant.PackageFailed,
    78  						CreatedAt: "2017-08-16T00:18:24Z",
    79  					},
    80  				}))
    81  
    82  				Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
    83  				Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
    84  					ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name"}},
    85  					ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
    86  				))
    87  
    88  				Expect(fakeCloudControllerClient.GetPackagesCallCount()).To(Equal(1))
    89  				Expect(fakeCloudControllerClient.GetPackagesArgsForCall(0)).To(ConsistOf(
    90  					ccv3.Query{Key: ccv3.AppGUIDFilter, Values: []string{"some-app-guid"}},
    91  				))
    92  			})
    93  		})
    94  
    95  		Context("when getting the application fails", func() {
    96  			var expectedErr error
    97  
    98  			BeforeEach(func() {
    99  				expectedErr = errors.New("some get application error")
   100  
   101  				fakeCloudControllerClient.GetApplicationsReturns(
   102  					[]ccv3.Application{},
   103  					ccv3.Warnings{"get-applications-warning"},
   104  					expectedErr,
   105  				)
   106  			})
   107  
   108  			It("returns the error", func() {
   109  				_, warnings, err := actor.GetApplicationPackages("some-app-name", "some-space-guid")
   110  
   111  				Expect(err).To(Equal(expectedErr))
   112  				Expect(warnings).To(ConsistOf("get-applications-warning"))
   113  			})
   114  		})
   115  
   116  		Context("when getting the application packages fails", func() {
   117  			var expectedErr error
   118  
   119  			BeforeEach(func() {
   120  				expectedErr = errors.New("some get application error")
   121  
   122  				fakeCloudControllerClient.GetApplicationsReturns(
   123  					[]ccv3.Application{
   124  						{GUID: "some-app-guid"},
   125  					},
   126  					ccv3.Warnings{"get-applications-warning"},
   127  					nil,
   128  				)
   129  
   130  				fakeCloudControllerClient.GetPackagesReturns(
   131  					[]ccv3.Package{},
   132  					ccv3.Warnings{"get-application-packages-warning"},
   133  					expectedErr,
   134  				)
   135  			})
   136  
   137  			It("returns the error", func() {
   138  				_, warnings, err := actor.GetApplicationPackages("some-app-name", "some-space-guid")
   139  
   140  				Expect(err).To(Equal(expectedErr))
   141  				Expect(warnings).To(ConsistOf("get-applications-warning", "get-application-packages-warning"))
   142  			})
   143  		})
   144  	})
   145  
   146  	Describe("CreateDockerPackageByApplicationNameAndSpace", func() {
   147  		var (
   148  			dockerPackage Package
   149  			warnings      Warnings
   150  			executeErr    error
   151  		)
   152  
   153  		JustBeforeEach(func() {
   154  			dockerPackage, warnings, executeErr = actor.CreateDockerPackageByApplicationNameAndSpace("some-app-name", "some-space-guid", DockerImageCredentials{Path: "some-docker-image", Password: "some-password", Username: "some-username"})
   155  		})
   156  
   157  		Context("when the application can't be retrieved", func() {
   158  			BeforeEach(func() {
   159  				fakeCloudControllerClient.GetApplicationsReturns(
   160  					[]ccv3.Application{},
   161  					ccv3.Warnings{"some-app-warning"},
   162  					errors.New("some-app-error"),
   163  				)
   164  			})
   165  
   166  			It("returns the error and all warnings", func() {
   167  				Expect(executeErr).To(MatchError("some-app-error"))
   168  				Expect(warnings).To(ConsistOf("some-app-warning"))
   169  			})
   170  		})
   171  
   172  		Context("when the application can be retrieved", func() {
   173  			BeforeEach(func() {
   174  				fakeCloudControllerClient.GetApplicationsReturns(
   175  					[]ccv3.Application{
   176  						{
   177  							Name: "some-app-name",
   178  							GUID: "some-app-guid",
   179  						},
   180  					},
   181  					ccv3.Warnings{"some-app-warning"},
   182  					nil,
   183  				)
   184  			})
   185  
   186  			Context("when creating the package fails", func() {
   187  				BeforeEach(func() {
   188  					fakeCloudControllerClient.CreatePackageReturns(
   189  						ccv3.Package{},
   190  						ccv3.Warnings{"some-create-package-warning"},
   191  						errors.New("some-create-package-error"),
   192  					)
   193  				})
   194  				It("fails to create the package", func() {
   195  					Expect(executeErr).To(MatchError("some-create-package-error"))
   196  					Expect(warnings).To(ConsistOf("some-app-warning", "some-create-package-warning"))
   197  				})
   198  			})
   199  
   200  			Context("when creating the package succeeds", func() {
   201  				BeforeEach(func() {
   202  					createdPackage := ccv3.Package{
   203  						DockerImage:    "some-docker-image",
   204  						DockerUsername: "some-username",
   205  						DockerPassword: "some-password",
   206  						GUID:           "some-pkg-guid",
   207  						State:          constant.PackageReady,
   208  						Relationships: ccv3.Relationships{
   209  							constant.RelationshipTypeApplication: ccv3.Relationship{
   210  								GUID: "some-app-guid",
   211  							},
   212  						},
   213  					}
   214  
   215  					fakeCloudControllerClient.CreatePackageReturns(
   216  						createdPackage,
   217  						ccv3.Warnings{"some-create-package-warning"},
   218  						nil,
   219  					)
   220  				})
   221  
   222  				It("calls CC to create the package and returns the package", func() {
   223  					Expect(executeErr).ToNot(HaveOccurred())
   224  					Expect(warnings).To(ConsistOf("some-app-warning", "some-create-package-warning"))
   225  
   226  					expectedPackage := ccv3.Package{
   227  						DockerImage:    "some-docker-image",
   228  						DockerUsername: "some-username",
   229  						DockerPassword: "some-password",
   230  						GUID:           "some-pkg-guid",
   231  						State:          constant.PackageReady,
   232  						Relationships: ccv3.Relationships{
   233  							constant.RelationshipTypeApplication: ccv3.Relationship{
   234  								GUID: "some-app-guid",
   235  							},
   236  						},
   237  					}
   238  					Expect(dockerPackage).To(Equal(Package(expectedPackage)))
   239  
   240  					Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   241  					Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   242  						ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name"}},
   243  						ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
   244  					))
   245  
   246  					Expect(fakeCloudControllerClient.CreatePackageCallCount()).To(Equal(1))
   247  					Expect(fakeCloudControllerClient.CreatePackageArgsForCall(0)).To(Equal(ccv3.Package{
   248  						Type:           constant.PackageTypeDocker,
   249  						DockerImage:    "some-docker-image",
   250  						DockerUsername: "some-username",
   251  						DockerPassword: "some-password",
   252  						Relationships: ccv3.Relationships{
   253  							constant.RelationshipTypeApplication: ccv3.Relationship{GUID: "some-app-guid"},
   254  						},
   255  					}))
   256  				})
   257  			})
   258  		})
   259  	})
   260  
   261  	Describe("CreateAndUploadBitsPackageByApplicationNameAndSpace", func() {
   262  		var (
   263  			bitsPath   string
   264  			pkg        Package
   265  			warnings   Warnings
   266  			executeErr error
   267  		)
   268  
   269  		BeforeEach(func() {
   270  			bitsPath = ""
   271  			pkg = Package{}
   272  			warnings = nil
   273  			executeErr = nil
   274  
   275  			// putting this here so the tests don't hang on polling
   276  			fakeCloudControllerClient.GetPackageReturns(
   277  				ccv3.Package{GUID: "some-pkg-guid", State: constant.PackageReady},
   278  				ccv3.Warnings{},
   279  				nil,
   280  			)
   281  		})
   282  
   283  		JustBeforeEach(func() {
   284  			pkg, warnings, executeErr = actor.CreateAndUploadBitsPackageByApplicationNameAndSpace("some-app-name", "some-space-guid", bitsPath)
   285  		})
   286  
   287  		Context("when retrieving the application errors", func() {
   288  			BeforeEach(func() {
   289  				fakeCloudControllerClient.GetApplicationsReturns(
   290  					[]ccv3.Application{},
   291  					ccv3.Warnings{"some-app-warning"},
   292  					errors.New("some-get-error"),
   293  				)
   294  			})
   295  
   296  			It("returns the warnings and the error", func() {
   297  				Expect(executeErr).To(MatchError("some-get-error"))
   298  				Expect(warnings).To(ConsistOf("some-app-warning"))
   299  			})
   300  		})
   301  
   302  		Context("when the application can be retrieved", func() {
   303  			BeforeEach(func() {
   304  				fakeCloudControllerClient.GetApplicationsReturns(
   305  					[]ccv3.Application{
   306  						{
   307  							Name: "some-app-name",
   308  							GUID: "some-app-guid",
   309  						},
   310  					},
   311  					ccv3.Warnings{"some-app-warning"},
   312  					nil,
   313  				)
   314  			})
   315  
   316  			Context("when bits path is a directory", func() {
   317  				BeforeEach(func() {
   318  					var err error
   319  					bitsPath, err = ioutil.TempDir("", "example")
   320  					Expect(err).ToNot(HaveOccurred())
   321  				})
   322  
   323  				AfterEach(func() {
   324  					if bitsPath != "" {
   325  						err := os.RemoveAll(bitsPath)
   326  						Expect(err).ToNot(HaveOccurred())
   327  					}
   328  				})
   329  
   330  				It("calls GatherDirectoryResources and ZipDirectoryResources", func() {
   331  					Expect(fakeSharedActor.GatherDirectoryResourcesCallCount()).To(Equal(1))
   332  					Expect(fakeSharedActor.ZipDirectoryResourcesCallCount()).To(Equal(1))
   333  				})
   334  
   335  				Context("when gathering resources fails", func() {
   336  					BeforeEach(func() {
   337  						fakeSharedActor.GatherDirectoryResourcesReturns(nil, errors.New("some-gather-error"))
   338  					})
   339  
   340  					It("returns the error", func() {
   341  						Expect(executeErr).To(MatchError("some-gather-error"))
   342  						Expect(warnings).To(ConsistOf("some-app-warning"))
   343  					})
   344  				})
   345  
   346  				Context("when gathering resources succeeds", func() {
   347  					BeforeEach(func() {
   348  						fakeSharedActor.GatherDirectoryResourcesReturns([]sharedaction.Resource{{Filename: "file-1"}, {Filename: "file-2"}}, nil)
   349  					})
   350  
   351  					Context("when zipping gathered resources fails", func() {
   352  						BeforeEach(func() {
   353  							fakeSharedActor.ZipDirectoryResourcesReturns("", errors.New("some-archive-error"))
   354  						})
   355  
   356  						It("returns the error", func() {
   357  							Expect(executeErr).To(MatchError("some-archive-error"))
   358  							Expect(warnings).To(ConsistOf("some-app-warning"))
   359  						})
   360  					})
   361  
   362  					Context("when zipping gathered resources succeeds", func() {
   363  						BeforeEach(func() {
   364  							fakeSharedActor.ZipDirectoryResourcesReturns("zipped-archive", nil)
   365  						})
   366  
   367  						Context("when creating the package fails", func() {
   368  							BeforeEach(func() {
   369  								fakeCloudControllerClient.CreatePackageReturns(
   370  									ccv3.Package{},
   371  									ccv3.Warnings{"create-package-warning"},
   372  									errors.New("some-create-error"),
   373  								)
   374  							})
   375  
   376  							It("returns the error", func() {
   377  								Expect(executeErr).To(MatchError("some-create-error"))
   378  								Expect(warnings).To(ConsistOf("some-app-warning", "create-package-warning"))
   379  							})
   380  						})
   381  
   382  						Context("when creating the package succeeds", func() {
   383  							var createdPackage ccv3.Package
   384  
   385  							BeforeEach(func() {
   386  								createdPackage = ccv3.Package{
   387  									GUID:  "some-pkg-guid",
   388  									State: constant.PackageAwaitingUpload,
   389  									Relationships: ccv3.Relationships{
   390  										constant.RelationshipTypeApplication: ccv3.Relationship{
   391  											GUID: "some-app-guid",
   392  										},
   393  									},
   394  								}
   395  
   396  								fakeCloudControllerClient.CreatePackageReturns(
   397  									createdPackage,
   398  									ccv3.Warnings{"some-package-warning"},
   399  									nil,
   400  								)
   401  							})
   402  
   403  							It("uploads the package with the path to the zip", func() {
   404  								Expect(fakeCloudControllerClient.UploadPackageCallCount()).To(Equal(1))
   405  								_, zippedArchive := fakeCloudControllerClient.UploadPackageArgsForCall(0)
   406  								Expect(zippedArchive).To(Equal("zipped-archive"))
   407  							})
   408  
   409  							Context("when uploading fails", func() {
   410  								BeforeEach(func() {
   411  									fakeCloudControllerClient.UploadPackageReturns(
   412  										ccv3.Package{},
   413  										ccv3.Warnings{"upload-package-warning"},
   414  										errors.New("some-error"),
   415  									)
   416  								})
   417  
   418  								It("returns the error", func() {
   419  									Expect(executeErr).To(MatchError("some-error"))
   420  									Expect(warnings).To(ConsistOf("some-app-warning", "some-package-warning", "upload-package-warning"))
   421  								})
   422  							})
   423  
   424  							Context("when uploading succeeds", func() {
   425  								BeforeEach(func() {
   426  									fakeCloudControllerClient.UploadPackageReturns(
   427  										ccv3.Package{},
   428  										ccv3.Warnings{"upload-package-warning"},
   429  										nil,
   430  									)
   431  								})
   432  
   433  								Context("when the polling errors", func() {
   434  									var expectedErr error
   435  
   436  									BeforeEach(func() {
   437  										expectedErr = errors.New("Fake error during polling")
   438  										fakeCloudControllerClient.GetPackageReturns(
   439  											ccv3.Package{},
   440  											ccv3.Warnings{"some-get-pkg-warning"},
   441  											expectedErr,
   442  										)
   443  									})
   444  
   445  									It("returns the error and warnings", func() {
   446  										Expect(executeErr).To(MatchError(expectedErr))
   447  										Expect(warnings).To(ConsistOf("some-app-warning", "some-package-warning", "upload-package-warning", "some-get-pkg-warning"))
   448  									})
   449  								})
   450  
   451  								Context("when the polling is successful", func() {
   452  									It("collects all warnings", func() {
   453  										Expect(executeErr).NotTo(HaveOccurred())
   454  										Expect(warnings).To(ConsistOf("some-app-warning", "some-package-warning", "upload-package-warning"))
   455  									})
   456  
   457  									It("successfully resolves the app name", func() {
   458  										Expect(executeErr).ToNot(HaveOccurred())
   459  
   460  										Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   461  										Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   462  											ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name"}},
   463  											ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
   464  										))
   465  									})
   466  
   467  									It("successfully creates the Package", func() {
   468  										Expect(executeErr).ToNot(HaveOccurred())
   469  
   470  										Expect(fakeCloudControllerClient.CreatePackageCallCount()).To(Equal(1))
   471  										inputPackage := fakeCloudControllerClient.CreatePackageArgsForCall(0)
   472  										Expect(inputPackage).To(Equal(ccv3.Package{
   473  											Type: constant.PackageTypeBits,
   474  											Relationships: ccv3.Relationships{
   475  												constant.RelationshipTypeApplication: ccv3.Relationship{GUID: "some-app-guid"},
   476  											},
   477  										}))
   478  									})
   479  
   480  									It("returns the package", func() {
   481  										Expect(executeErr).ToNot(HaveOccurred())
   482  
   483  										expectedPackage := ccv3.Package{
   484  											GUID:  "some-pkg-guid",
   485  											State: constant.PackageReady,
   486  										}
   487  										Expect(pkg).To(Equal(Package(expectedPackage)))
   488  
   489  										Expect(fakeCloudControllerClient.GetPackageCallCount()).To(Equal(1))
   490  										Expect(fakeCloudControllerClient.GetPackageArgsForCall(0)).To(Equal("some-pkg-guid"))
   491  									})
   492  
   493  									DescribeTable("polls until terminal state is reached",
   494  										func(finalState constant.PackageState, expectedErr error) {
   495  											fakeCloudControllerClient.GetPackageReturns(
   496  												ccv3.Package{GUID: "some-pkg-guid", State: constant.PackageAwaitingUpload},
   497  												ccv3.Warnings{"poll-package-warning"},
   498  												nil,
   499  											)
   500  											fakeCloudControllerClient.GetPackageReturnsOnCall(
   501  												2,
   502  												ccv3.Package{State: finalState},
   503  												ccv3.Warnings{"poll-package-warning"},
   504  												nil,
   505  											)
   506  
   507  											_, tableWarnings, err := actor.CreateAndUploadBitsPackageByApplicationNameAndSpace("some-app-name", "some-space-guid", bitsPath)
   508  
   509  											if expectedErr == nil {
   510  												Expect(err).ToNot(HaveOccurred())
   511  											} else {
   512  												Expect(err).To(MatchError(expectedErr))
   513  											}
   514  
   515  											Expect(tableWarnings).To(ConsistOf("some-app-warning", "some-package-warning", "upload-package-warning", "poll-package-warning", "poll-package-warning"))
   516  
   517  											// hacky, get packages is called an extry time cause the
   518  											// JustBeforeEach executes everything once as well
   519  											Expect(fakeCloudControllerClient.GetPackageCallCount()).To(Equal(3))
   520  											Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(3))
   521  										},
   522  
   523  										Entry("READY", constant.PackageReady, nil),
   524  										Entry("FAILED", constant.PackageFailed, actionerror.PackageProcessingFailedError{}),
   525  										Entry("EXPIRED", constant.PackageExpired, actionerror.PackageProcessingExpiredError{}),
   526  									)
   527  								})
   528  							})
   529  						})
   530  					})
   531  				})
   532  			})
   533  
   534  			Context("when bitsPath is blank", func() {
   535  				var oldCurrentDir, appDir string
   536  				BeforeEach(func() {
   537  					var err error
   538  					oldCurrentDir, err = os.Getwd()
   539  					Expect(err).NotTo(HaveOccurred())
   540  
   541  					appDir, err = ioutil.TempDir("", "example")
   542  					Expect(err).ToNot(HaveOccurred())
   543  
   544  					Expect(os.Chdir(appDir)).NotTo(HaveOccurred())
   545  					appDir, err = os.Getwd()
   546  					Expect(err).ToNot(HaveOccurred())
   547  				})
   548  
   549  				AfterEach(func() {
   550  					Expect(os.Chdir(oldCurrentDir)).NotTo(HaveOccurred())
   551  					err := os.RemoveAll(appDir)
   552  					Expect(err).ToNot(HaveOccurred())
   553  				})
   554  
   555  				It("uses the current working directory", func() {
   556  					Expect(executeErr).NotTo(HaveOccurred())
   557  
   558  					Expect(fakeSharedActor.GatherDirectoryResourcesCallCount()).To(Equal(1))
   559  					Expect(fakeSharedActor.GatherDirectoryResourcesArgsForCall(0)).To(Equal(appDir))
   560  
   561  					Expect(fakeSharedActor.ZipDirectoryResourcesCallCount()).To(Equal(1))
   562  					pathArg, _ := fakeSharedActor.ZipDirectoryResourcesArgsForCall(0)
   563  					Expect(pathArg).To(Equal(appDir))
   564  				})
   565  			})
   566  
   567  			Context("when bits path is an archive", func() {
   568  				BeforeEach(func() {
   569  					var err error
   570  					tempFile, err := ioutil.TempFile("", "bits-zip-test")
   571  					Expect(err).ToNot(HaveOccurred())
   572  					Expect(tempFile.Close()).To(Succeed())
   573  					tempFilePath := tempFile.Name()
   574  
   575  					bitsPathFile, err := ioutil.TempFile("", "example")
   576  					Expect(err).ToNot(HaveOccurred())
   577  					Expect(bitsPathFile.Close()).To(Succeed())
   578  					bitsPath = bitsPathFile.Name()
   579  
   580  					zipit(tempFilePath, bitsPath, "")
   581  					Expect(os.Remove(tempFilePath)).To(Succeed())
   582  				})
   583  
   584  				AfterEach(func() {
   585  					err := os.RemoveAll(bitsPath)
   586  					Expect(err).ToNot(HaveOccurred())
   587  				})
   588  
   589  				It("calls GatherArchiveResources and ZipArchiveResources", func() {
   590  					Expect(fakeSharedActor.GatherArchiveResourcesCallCount()).To(Equal(1))
   591  					Expect(fakeSharedActor.ZipArchiveResourcesCallCount()).To(Equal(1))
   592  				})
   593  
   594  				Context("when gathering archive resources fails", func() {
   595  					BeforeEach(func() {
   596  						fakeSharedActor.GatherArchiveResourcesReturns(nil, errors.New("some-archive-resource-error"))
   597  					})
   598  					It("should return an error", func() {
   599  						Expect(executeErr).To(MatchError("some-archive-resource-error"))
   600  						Expect(warnings).To(ConsistOf("some-app-warning"))
   601  					})
   602  
   603  				})
   604  
   605  				Context("when gathering resources succeeds", func() {
   606  					BeforeEach(func() {
   607  						fakeSharedActor.GatherArchiveResourcesReturns([]sharedaction.Resource{{Filename: "file-1"}, {Filename: "file-2"}}, nil)
   608  					})
   609  
   610  					Context("when zipping gathered resources fails", func() {
   611  						BeforeEach(func() {
   612  							fakeSharedActor.ZipArchiveResourcesReturns("", errors.New("some-archive-error"))
   613  						})
   614  
   615  						It("returns the error", func() {
   616  							Expect(executeErr).To(MatchError("some-archive-error"))
   617  							Expect(warnings).To(ConsistOf("some-app-warning"))
   618  						})
   619  					})
   620  
   621  					Context("when zipping gathered resources succeeds", func() {
   622  						BeforeEach(func() {
   623  							fakeSharedActor.ZipArchiveResourcesReturns("zipped-archive", nil)
   624  						})
   625  
   626  						It("uploads the package", func() {
   627  							Expect(executeErr).ToNot(HaveOccurred())
   628  							Expect(warnings).To(ConsistOf("some-app-warning"))
   629  
   630  							Expect(fakeCloudControllerClient.UploadPackageCallCount()).To(Equal(1))
   631  							_, archivePathArg := fakeCloudControllerClient.UploadPackageArgsForCall(0)
   632  							Expect(archivePathArg).To(Equal("zipped-archive"))
   633  						})
   634  					})
   635  				})
   636  			})
   637  
   638  			Context("when bits path is a symlink to a directory", func() {
   639  				var tempDir string
   640  
   641  				BeforeEach(func() {
   642  					var err error
   643  					tempDir, err = ioutil.TempDir("", "example")
   644  					Expect(err).ToNot(HaveOccurred())
   645  
   646  					tempFile, err := ioutil.TempFile("", "example-file-")
   647  					Expect(err).ToNot(HaveOccurred())
   648  					Expect(tempFile.Close()).To(Succeed())
   649  
   650  					bitsPath = tempFile.Name()
   651  					Expect(os.Remove(bitsPath)).To(Succeed())
   652  					Expect(os.Symlink(tempDir, bitsPath)).To(Succeed())
   653  				})
   654  
   655  				AfterEach(func() {
   656  					Expect(os.RemoveAll(tempDir)).To(Succeed())
   657  					Expect(os.Remove(bitsPath)).To(Succeed())
   658  				})
   659  
   660  				It("calls GatherDirectoryResources and returns without an error", func() {
   661  					Expect(fakeSharedActor.GatherDirectoryResourcesCallCount()).To(Equal(1))
   662  					Expect(fakeSharedActor.GatherDirectoryResourcesArgsForCall(0)).To(Equal(bitsPath))
   663  					Expect(executeErr).ToNot(HaveOccurred())
   664  				})
   665  			})
   666  
   667  			Context("when bits path is symlink to an archive", func() {
   668  				var archivePath string
   669  
   670  				BeforeEach(func() {
   671  					var err error
   672  					tempArchiveFile, err := ioutil.TempFile("", "bits-zip-test")
   673  					Expect(err).ToNot(HaveOccurred())
   674  					Expect(tempArchiveFile.Close()).To(Succeed())
   675  					tempArchiveFilePath := tempArchiveFile.Name()
   676  
   677  					archivePathFile, err := ioutil.TempFile("", "example")
   678  					Expect(err).ToNot(HaveOccurred())
   679  					Expect(archivePathFile.Close()).To(Succeed())
   680  					archivePath = archivePathFile.Name()
   681  
   682  					zipit(tempArchiveFilePath, archivePath, "")
   683  					Expect(os.Remove(tempArchiveFilePath)).To(Succeed())
   684  
   685  					tempFile, err := ioutil.TempFile("", "example-file-")
   686  					Expect(err).ToNot(HaveOccurred())
   687  					Expect(tempFile.Close()).To(Succeed())
   688  
   689  					bitsPath = tempFile.Name()
   690  					Expect(os.Remove(bitsPath)).To(Succeed())
   691  					Expect(os.Symlink(archivePath, bitsPath)).To(Succeed())
   692  				})
   693  
   694  				AfterEach(func() {
   695  					Expect(os.Remove(archivePath)).To(Succeed())
   696  					Expect(os.Remove(bitsPath)).To(Succeed())
   697  				})
   698  
   699  				It("calls GatherArchiveResources and returns without an error", func() {
   700  					Expect(fakeSharedActor.GatherArchiveResourcesCallCount()).To(Equal(1))
   701  					Expect(fakeSharedActor.GatherArchiveResourcesArgsForCall(0)).To(Equal(bitsPath))
   702  					Expect(executeErr).ToNot(HaveOccurred())
   703  				})
   704  			})
   705  		})
   706  	})
   707  })