github.com/lukasheimann/cloudfoundrycli@v7.1.0+incompatible/actor/v7action/package_test.go (about)

     1  package v7action_test
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  	"io/ioutil"
     7  	"os"
     8  	"strings"
     9  
    10  	"code.cloudfoundry.org/cli/actor/actionerror"
    11  	"code.cloudfoundry.org/cli/actor/sharedaction"
    12  	. "code.cloudfoundry.org/cli/actor/v7action"
    13  	"code.cloudfoundry.org/cli/actor/v7action/v7actionfakes"
    14  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
    15  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    16  	"code.cloudfoundry.org/cli/resources"
    17  
    18  	. "github.com/onsi/ginkgo"
    19  	. "github.com/onsi/ginkgo/extensions/table"
    20  	. "github.com/onsi/gomega"
    21  	. "github.com/onsi/gomega/gstruct"
    22  )
    23  
    24  var _ = Describe("Package Actions", func() {
    25  	var (
    26  		actor                     *Actor
    27  		fakeCloudControllerClient *v7actionfakes.FakeCloudControllerClient
    28  		fakeSharedActor           *v7actionfakes.FakeSharedActor
    29  		fakeConfig                *v7actionfakes.FakeConfig
    30  	)
    31  
    32  	BeforeEach(func() {
    33  		fakeCloudControllerClient = new(v7actionfakes.FakeCloudControllerClient)
    34  		fakeConfig = new(v7actionfakes.FakeConfig)
    35  		fakeSharedActor = new(v7actionfakes.FakeSharedActor)
    36  		actor = NewActor(fakeCloudControllerClient, fakeConfig, fakeSharedActor, nil, nil, nil)
    37  	})
    38  
    39  	Describe("GetApplicationPackages", func() {
    40  		When("there are no client errors", func() {
    41  			BeforeEach(func() {
    42  				fakeCloudControllerClient.GetApplicationsReturns(
    43  					[]resources.Application{
    44  						{GUID: "some-app-guid"},
    45  					},
    46  					ccv3.Warnings{"get-applications-warning"},
    47  					nil,
    48  				)
    49  
    50  				fakeCloudControllerClient.GetPackagesReturns(
    51  					[]ccv3.Package{
    52  						{
    53  							GUID:      "some-package-guid-1",
    54  							State:     constant.PackageReady,
    55  							CreatedAt: "2017-08-14T21:16:42Z",
    56  						},
    57  						{
    58  							GUID:      "some-package-guid-2",
    59  							State:     constant.PackageFailed,
    60  							CreatedAt: "2017-08-16T00:18:24Z",
    61  						},
    62  					},
    63  					ccv3.Warnings{"get-application-packages-warning"},
    64  					nil,
    65  				)
    66  			})
    67  
    68  			It("gets the app's packages", func() {
    69  				packages, warnings, err := actor.GetApplicationPackages("some-app-name", "some-space-guid")
    70  
    71  				Expect(err).ToNot(HaveOccurred())
    72  				Expect(warnings).To(ConsistOf("get-applications-warning", "get-application-packages-warning"))
    73  				Expect(packages).To(Equal([]Package{
    74  					{
    75  						GUID:      "some-package-guid-1",
    76  						State:     constant.PackageReady,
    77  						CreatedAt: "2017-08-14T21:16:42Z",
    78  					},
    79  					{
    80  						GUID:      "some-package-guid-2",
    81  						State:     constant.PackageFailed,
    82  						CreatedAt: "2017-08-16T00:18:24Z",
    83  					},
    84  				}))
    85  
    86  				Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
    87  				Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
    88  					ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name"}},
    89  					ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
    90  				))
    91  
    92  				Expect(fakeCloudControllerClient.GetPackagesCallCount()).To(Equal(1))
    93  				Expect(fakeCloudControllerClient.GetPackagesArgsForCall(0)).To(ConsistOf(
    94  					ccv3.Query{Key: ccv3.AppGUIDFilter, Values: []string{"some-app-guid"}},
    95  					ccv3.Query{Key: ccv3.OrderBy, Values: []string{ccv3.CreatedAtDescendingOrder}},
    96  				))
    97  			})
    98  		})
    99  
   100  		When("getting the application fails", func() {
   101  			var expectedErr error
   102  
   103  			BeforeEach(func() {
   104  				expectedErr = errors.New("some get application error")
   105  
   106  				fakeCloudControllerClient.GetApplicationsReturns(
   107  					[]resources.Application{},
   108  					ccv3.Warnings{"get-applications-warning"},
   109  					expectedErr,
   110  				)
   111  			})
   112  
   113  			It("returns the error", func() {
   114  				_, warnings, err := actor.GetApplicationPackages("some-app-name", "some-space-guid")
   115  
   116  				Expect(err).To(Equal(expectedErr))
   117  				Expect(warnings).To(ConsistOf("get-applications-warning"))
   118  			})
   119  		})
   120  
   121  		When("getting the application packages fails", func() {
   122  			var expectedErr error
   123  
   124  			BeforeEach(func() {
   125  				expectedErr = errors.New("some get application error")
   126  
   127  				fakeCloudControllerClient.GetApplicationsReturns(
   128  					[]resources.Application{
   129  						{GUID: "some-app-guid"},
   130  					},
   131  					ccv3.Warnings{"get-applications-warning"},
   132  					nil,
   133  				)
   134  
   135  				fakeCloudControllerClient.GetPackagesReturns(
   136  					[]ccv3.Package{},
   137  					ccv3.Warnings{"get-application-packages-warning"},
   138  					expectedErr,
   139  				)
   140  			})
   141  
   142  			It("returns the error", func() {
   143  				_, warnings, err := actor.GetApplicationPackages("some-app-name", "some-space-guid")
   144  
   145  				Expect(err).To(Equal(expectedErr))
   146  				Expect(warnings).To(ConsistOf("get-applications-warning", "get-application-packages-warning"))
   147  			})
   148  		})
   149  	})
   150  
   151  	Describe("GetNewestReadyPackageForApplication", func() {
   152  		var (
   153  			app        resources.Application
   154  			executeErr error
   155  
   156  			warnings Warnings
   157  		)
   158  
   159  		BeforeEach(func() {
   160  			app = resources.Application{
   161  				GUID: "some-app-guid",
   162  				Name: "some-app",
   163  			}
   164  		})
   165  
   166  		When("the GetNewestReadyPackageForApplication call succeeds", func() {
   167  			When("the cloud controller finds a package", func() {
   168  				BeforeEach(func() {
   169  					fakeCloudControllerClient.GetPackagesReturns(
   170  						[]ccv3.Package{
   171  							{
   172  								GUID:      "some-package-guid-1",
   173  								State:     constant.PackageReady,
   174  								CreatedAt: "2017-08-14T21:16:42Z",
   175  							},
   176  							{
   177  								GUID:      "some-package-guid-2",
   178  								State:     constant.PackageReady,
   179  								CreatedAt: "2017-08-16T00:18:24Z",
   180  							},
   181  						},
   182  						ccv3.Warnings{"get-application-packages-warning"},
   183  						nil,
   184  					)
   185  				})
   186  				It("gets the most recent package for the given app guid that has a ready state", func() {
   187  					expectedPackage, warnings, err := actor.GetNewestReadyPackageForApplication(app)
   188  
   189  					Expect(fakeCloudControllerClient.GetPackagesCallCount()).To(Equal(1))
   190  					Expect(fakeCloudControllerClient.GetPackagesArgsForCall(0)).To(ConsistOf(
   191  						ccv3.Query{Key: ccv3.AppGUIDFilter, Values: []string{"some-app-guid"}},
   192  						ccv3.Query{Key: ccv3.StatesFilter, Values: []string{"READY"}},
   193  						ccv3.Query{Key: ccv3.OrderBy, Values: []string{ccv3.CreatedAtDescendingOrder}},
   194  					))
   195  
   196  					Expect(err).ToNot(HaveOccurred())
   197  					Expect(warnings).To(ConsistOf("get-application-packages-warning"))
   198  					Expect(expectedPackage).To(Equal(Package{
   199  						GUID:      "some-package-guid-1",
   200  						State:     constant.PackageReady,
   201  						CreatedAt: "2017-08-14T21:16:42Z",
   202  					},
   203  					))
   204  				})
   205  			})
   206  
   207  			When("the cloud controller does not find any packages", func() {
   208  				BeforeEach(func() {
   209  					fakeCloudControllerClient.GetPackagesReturns(
   210  						[]ccv3.Package{},
   211  						ccv3.Warnings{"get-application-packages-warning"},
   212  						nil,
   213  					)
   214  				})
   215  
   216  				JustBeforeEach(func() {
   217  					_, warnings, executeErr = actor.GetNewestReadyPackageForApplication(app)
   218  				})
   219  
   220  				It("returns an error and warnings", func() {
   221  					Expect(executeErr).To(MatchError(actionerror.NoEligiblePackagesError{AppName: "some-app"}))
   222  					Expect(warnings).To(ConsistOf("get-application-packages-warning"))
   223  				})
   224  			})
   225  
   226  		})
   227  		When("getting the application packages fails", func() {
   228  			var expectedErr error
   229  
   230  			BeforeEach(func() {
   231  				expectedErr = errors.New("get-packages-error")
   232  
   233  				fakeCloudControllerClient.GetPackagesReturns(
   234  					[]ccv3.Package{},
   235  					ccv3.Warnings{"get-packages-warning"},
   236  					expectedErr,
   237  				)
   238  			})
   239  
   240  			It("returns the error", func() {
   241  				_, warnings, err := actor.GetNewestReadyPackageForApplication(app)
   242  
   243  				Expect(err).To(Equal(expectedErr))
   244  				Expect(warnings).To(ConsistOf("get-packages-warning"))
   245  			})
   246  		})
   247  	})
   248  
   249  	Describe("CreateDockerPackageByApplicationNameAndSpace", func() {
   250  		var (
   251  			dockerPackage Package
   252  			warnings      Warnings
   253  			executeErr    error
   254  		)
   255  
   256  		JustBeforeEach(func() {
   257  			dockerPackage, warnings, executeErr = actor.CreateDockerPackageByApplicationNameAndSpace("some-app-name", "some-space-guid", DockerImageCredentials{Path: "some-docker-image", Password: "some-password", Username: "some-username"})
   258  		})
   259  
   260  		When("the application can't be retrieved", func() {
   261  			BeforeEach(func() {
   262  				fakeCloudControllerClient.GetApplicationsReturns(
   263  					[]resources.Application{},
   264  					ccv3.Warnings{"some-app-warning"},
   265  					errors.New("some-app-error"),
   266  				)
   267  			})
   268  
   269  			It("returns the error and all warnings", func() {
   270  				Expect(executeErr).To(MatchError("some-app-error"))
   271  				Expect(warnings).To(ConsistOf("some-app-warning"))
   272  			})
   273  		})
   274  
   275  		When("the application can be retrieved", func() {
   276  			BeforeEach(func() {
   277  				fakeCloudControllerClient.GetApplicationsReturns(
   278  					[]resources.Application{
   279  						{
   280  							Name: "some-app-name",
   281  							GUID: "some-app-guid",
   282  						},
   283  					},
   284  					ccv3.Warnings{"some-app-warning"},
   285  					nil,
   286  				)
   287  			})
   288  
   289  			When("creating the package fails", func() {
   290  				BeforeEach(func() {
   291  					fakeCloudControllerClient.CreatePackageReturns(
   292  						ccv3.Package{},
   293  						ccv3.Warnings{"some-create-package-warning"},
   294  						errors.New("some-create-package-error"),
   295  					)
   296  				})
   297  				It("fails to create the package", func() {
   298  					Expect(executeErr).To(MatchError("some-create-package-error"))
   299  					Expect(warnings).To(ConsistOf("some-app-warning", "some-create-package-warning"))
   300  				})
   301  			})
   302  
   303  			When("creating the package succeeds", func() {
   304  				BeforeEach(func() {
   305  					createdPackage := ccv3.Package{
   306  						DockerImage:    "some-docker-image",
   307  						DockerUsername: "some-username",
   308  						DockerPassword: "some-password",
   309  						GUID:           "some-pkg-guid",
   310  						State:          constant.PackageReady,
   311  						Relationships: resources.Relationships{
   312  							constant.RelationshipTypeApplication: resources.Relationship{
   313  								GUID: "some-app-guid",
   314  							},
   315  						},
   316  					}
   317  
   318  					fakeCloudControllerClient.CreatePackageReturns(
   319  						createdPackage,
   320  						ccv3.Warnings{"some-create-package-warning"},
   321  						nil,
   322  					)
   323  				})
   324  
   325  				It("calls CC to create the package and returns the package", func() {
   326  					Expect(executeErr).ToNot(HaveOccurred())
   327  					Expect(warnings).To(ConsistOf("some-app-warning", "some-create-package-warning"))
   328  
   329  					expectedPackage := ccv3.Package{
   330  						DockerImage:    "some-docker-image",
   331  						DockerUsername: "some-username",
   332  						DockerPassword: "some-password",
   333  						GUID:           "some-pkg-guid",
   334  						State:          constant.PackageReady,
   335  						Relationships: resources.Relationships{
   336  							constant.RelationshipTypeApplication: resources.Relationship{
   337  								GUID: "some-app-guid",
   338  							},
   339  						},
   340  					}
   341  					Expect(dockerPackage).To(Equal(Package(expectedPackage)))
   342  
   343  					Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   344  					Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   345  						ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name"}},
   346  						ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
   347  					))
   348  
   349  					Expect(fakeCloudControllerClient.CreatePackageCallCount()).To(Equal(1))
   350  					Expect(fakeCloudControllerClient.CreatePackageArgsForCall(0)).To(Equal(ccv3.Package{
   351  						Type:           constant.PackageTypeDocker,
   352  						DockerImage:    "some-docker-image",
   353  						DockerUsername: "some-username",
   354  						DockerPassword: "some-password",
   355  						Relationships: resources.Relationships{
   356  							constant.RelationshipTypeApplication: resources.Relationship{GUID: "some-app-guid"},
   357  						},
   358  					}))
   359  				})
   360  			})
   361  		})
   362  	})
   363  
   364  	Describe("CreateAndUploadBitsPackageByApplicationNameAndSpace", func() {
   365  		var (
   366  			bitsPath   string
   367  			pkg        Package
   368  			warnings   Warnings
   369  			executeErr error
   370  		)
   371  
   372  		BeforeEach(func() {
   373  			bitsPath = ""
   374  			pkg = Package{}
   375  			warnings = nil
   376  			executeErr = nil
   377  
   378  			// putting this here so the tests don't hang on polling
   379  			fakeCloudControllerClient.GetPackageReturns(
   380  				ccv3.Package{GUID: "some-pkg-guid", State: constant.PackageReady},
   381  				ccv3.Warnings{},
   382  				nil,
   383  			)
   384  		})
   385  
   386  		JustBeforeEach(func() {
   387  			pkg, warnings, executeErr = actor.CreateAndUploadBitsPackageByApplicationNameAndSpace("some-app-name", "some-space-guid", bitsPath)
   388  		})
   389  
   390  		When("retrieving the application errors", func() {
   391  			BeforeEach(func() {
   392  				fakeCloudControllerClient.GetApplicationsReturns(
   393  					[]resources.Application{},
   394  					ccv3.Warnings{"some-app-warning"},
   395  					errors.New("some-get-error"),
   396  				)
   397  			})
   398  
   399  			It("returns the warnings and the error", func() {
   400  				Expect(executeErr).To(MatchError("some-get-error"))
   401  				Expect(warnings).To(ConsistOf("some-app-warning"))
   402  			})
   403  		})
   404  
   405  		When("the application can be retrieved", func() {
   406  			BeforeEach(func() {
   407  				fakeCloudControllerClient.GetApplicationsReturns(
   408  					[]resources.Application{
   409  						{
   410  							Name: "some-app-name",
   411  							GUID: "some-app-guid",
   412  						},
   413  					},
   414  					ccv3.Warnings{"some-app-warning"},
   415  					nil,
   416  				)
   417  			})
   418  
   419  			When("bits path is a directory", func() {
   420  				BeforeEach(func() {
   421  					var err error
   422  					bitsPath, err = ioutil.TempDir("", "example")
   423  					Expect(err).ToNot(HaveOccurred())
   424  				})
   425  
   426  				AfterEach(func() {
   427  					if bitsPath != "" {
   428  						err := os.RemoveAll(bitsPath)
   429  						Expect(err).ToNot(HaveOccurred())
   430  					}
   431  				})
   432  
   433  				It("calls GatherDirectoryResources and ZipDirectoryResources", func() {
   434  					Expect(fakeSharedActor.GatherDirectoryResourcesCallCount()).To(Equal(1))
   435  					Expect(fakeSharedActor.ZipDirectoryResourcesCallCount()).To(Equal(1))
   436  				})
   437  
   438  				When("gathering resources fails", func() {
   439  					BeforeEach(func() {
   440  						fakeSharedActor.GatherDirectoryResourcesReturns(nil, errors.New("some-gather-error"))
   441  					})
   442  
   443  					It("returns the error", func() {
   444  						Expect(executeErr).To(MatchError("some-gather-error"))
   445  						Expect(warnings).To(ConsistOf("some-app-warning"))
   446  					})
   447  				})
   448  
   449  				When("gathering resources succeeds", func() {
   450  					BeforeEach(func() {
   451  						fakeSharedActor.GatherDirectoryResourcesReturns([]sharedaction.Resource{{Filename: "file-1"}, {Filename: "file-2"}}, nil)
   452  					})
   453  
   454  					When("zipping gathered resources fails", func() {
   455  						BeforeEach(func() {
   456  							fakeSharedActor.ZipDirectoryResourcesReturns("", errors.New("some-archive-error"))
   457  						})
   458  
   459  						It("returns the error", func() {
   460  							Expect(executeErr).To(MatchError("some-archive-error"))
   461  							Expect(warnings).To(ConsistOf("some-app-warning"))
   462  						})
   463  					})
   464  
   465  					When("zipping gathered resources succeeds", func() {
   466  						BeforeEach(func() {
   467  							fakeSharedActor.ZipDirectoryResourcesReturns("zipped-archive", nil)
   468  						})
   469  
   470  						When("creating the package fails", func() {
   471  							BeforeEach(func() {
   472  								fakeCloudControllerClient.CreatePackageReturns(
   473  									ccv3.Package{},
   474  									ccv3.Warnings{"create-package-warning"},
   475  									errors.New("some-create-error"),
   476  								)
   477  							})
   478  
   479  							It("returns the error", func() {
   480  								Expect(executeErr).To(MatchError("some-create-error"))
   481  								Expect(warnings).To(ConsistOf("some-app-warning", "create-package-warning"))
   482  							})
   483  						})
   484  
   485  						When("creating the package succeeds", func() {
   486  							var createdPackage ccv3.Package
   487  
   488  							BeforeEach(func() {
   489  								createdPackage = ccv3.Package{
   490  									GUID:  "some-pkg-guid",
   491  									State: constant.PackageAwaitingUpload,
   492  									Relationships: resources.Relationships{
   493  										constant.RelationshipTypeApplication: resources.Relationship{
   494  											GUID: "some-app-guid",
   495  										},
   496  									},
   497  								}
   498  
   499  								fakeCloudControllerClient.CreatePackageReturns(
   500  									createdPackage,
   501  									ccv3.Warnings{"some-package-warning"},
   502  									nil,
   503  								)
   504  							})
   505  
   506  							It("uploads the package with the path to the zip", func() {
   507  								Expect(fakeCloudControllerClient.UploadPackageCallCount()).To(Equal(1))
   508  								_, zippedArchive := fakeCloudControllerClient.UploadPackageArgsForCall(0)
   509  								Expect(zippedArchive).To(Equal("zipped-archive"))
   510  							})
   511  
   512  							When("uploading fails", func() {
   513  								BeforeEach(func() {
   514  									fakeCloudControllerClient.UploadPackageReturns(
   515  										ccv3.Package{},
   516  										ccv3.Warnings{"upload-package-warning"},
   517  										errors.New("some-error"),
   518  									)
   519  								})
   520  
   521  								It("returns the error", func() {
   522  									Expect(executeErr).To(MatchError("some-error"))
   523  									Expect(warnings).To(ConsistOf("some-app-warning", "some-package-warning", "upload-package-warning"))
   524  								})
   525  							})
   526  
   527  							When("uploading succeeds", func() {
   528  								BeforeEach(func() {
   529  									fakeCloudControllerClient.UploadPackageReturns(
   530  										ccv3.Package{},
   531  										ccv3.Warnings{"upload-package-warning"},
   532  										nil,
   533  									)
   534  								})
   535  
   536  								When("the polling errors", func() {
   537  									var expectedErr error
   538  
   539  									BeforeEach(func() {
   540  										expectedErr = errors.New("Fake error during polling")
   541  										fakeCloudControllerClient.GetPackageReturns(
   542  											ccv3.Package{},
   543  											ccv3.Warnings{"some-get-pkg-warning"},
   544  											expectedErr,
   545  										)
   546  									})
   547  
   548  									It("returns the error and warnings", func() {
   549  										Expect(executeErr).To(MatchError(expectedErr))
   550  										Expect(warnings).To(ConsistOf("some-app-warning", "some-package-warning", "upload-package-warning", "some-get-pkg-warning"))
   551  									})
   552  								})
   553  
   554  								When("the polling is successful", func() {
   555  									It("collects all warnings", func() {
   556  										Expect(executeErr).NotTo(HaveOccurred())
   557  										Expect(warnings).To(ConsistOf("some-app-warning", "some-package-warning", "upload-package-warning"))
   558  									})
   559  
   560  									It("successfully resolves the app name", func() {
   561  										Expect(executeErr).ToNot(HaveOccurred())
   562  
   563  										Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   564  										Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   565  											ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app-name"}},
   566  											ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
   567  										))
   568  									})
   569  
   570  									It("successfully creates the Package", func() {
   571  										Expect(executeErr).ToNot(HaveOccurred())
   572  
   573  										Expect(fakeCloudControllerClient.CreatePackageCallCount()).To(Equal(1))
   574  										inputPackage := fakeCloudControllerClient.CreatePackageArgsForCall(0)
   575  										Expect(inputPackage).To(Equal(ccv3.Package{
   576  											Type: constant.PackageTypeBits,
   577  											Relationships: resources.Relationships{
   578  												constant.RelationshipTypeApplication: resources.Relationship{GUID: "some-app-guid"},
   579  											},
   580  										}))
   581  									})
   582  
   583  									It("returns the package", func() {
   584  										Expect(executeErr).ToNot(HaveOccurred())
   585  
   586  										expectedPackage := ccv3.Package{
   587  											GUID:  "some-pkg-guid",
   588  											State: constant.PackageReady,
   589  										}
   590  										Expect(pkg).To(Equal(Package(expectedPackage)))
   591  
   592  										Expect(fakeCloudControllerClient.GetPackageCallCount()).To(Equal(1))
   593  										Expect(fakeCloudControllerClient.GetPackageArgsForCall(0)).To(Equal("some-pkg-guid"))
   594  									})
   595  
   596  									DescribeTable("polls until terminal state is reached",
   597  										func(finalState constant.PackageState, expectedErr error) {
   598  											fakeCloudControllerClient.GetPackageReturns(
   599  												ccv3.Package{GUID: "some-pkg-guid", State: constant.PackageAwaitingUpload},
   600  												ccv3.Warnings{"poll-package-warning"},
   601  												nil,
   602  											)
   603  											fakeCloudControllerClient.GetPackageReturnsOnCall(
   604  												2,
   605  												ccv3.Package{State: finalState},
   606  												ccv3.Warnings{"poll-package-warning"},
   607  												nil,
   608  											)
   609  
   610  											_, tableWarnings, err := actor.CreateAndUploadBitsPackageByApplicationNameAndSpace("some-app-name", "some-space-guid", bitsPath)
   611  
   612  											if expectedErr == nil {
   613  												Expect(err).ToNot(HaveOccurred())
   614  											} else {
   615  												Expect(err).To(MatchError(expectedErr))
   616  											}
   617  
   618  											Expect(tableWarnings).To(ConsistOf("some-app-warning", "some-package-warning", "upload-package-warning", "poll-package-warning", "poll-package-warning"))
   619  
   620  											// hacky, get packages is called an extry time cause the
   621  											// JustBeforeEach executes everything once as well
   622  											Expect(fakeCloudControllerClient.GetPackageCallCount()).To(Equal(3))
   623  											Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(3))
   624  										},
   625  
   626  										Entry("READY", constant.PackageReady, nil),
   627  										Entry("FAILED", constant.PackageFailed, actionerror.PackageProcessingFailedError{}),
   628  										Entry("EXPIRED", constant.PackageExpired, actionerror.PackageProcessingExpiredError{}),
   629  									)
   630  								})
   631  							})
   632  						})
   633  					})
   634  				})
   635  			})
   636  
   637  			When("bitsPath is blank", func() {
   638  				var oldCurrentDir, appDir string
   639  				BeforeEach(func() {
   640  					var err error
   641  					oldCurrentDir, err = os.Getwd()
   642  					Expect(err).NotTo(HaveOccurred())
   643  
   644  					appDir, err = ioutil.TempDir("", "example")
   645  					Expect(err).ToNot(HaveOccurred())
   646  
   647  					Expect(os.Chdir(appDir)).NotTo(HaveOccurred())
   648  					appDir, err = os.Getwd()
   649  					Expect(err).ToNot(HaveOccurred())
   650  				})
   651  
   652  				AfterEach(func() {
   653  					Expect(os.Chdir(oldCurrentDir)).NotTo(HaveOccurred())
   654  					err := os.RemoveAll(appDir)
   655  					Expect(err).ToNot(HaveOccurred())
   656  				})
   657  
   658  				It("uses the current working directory", func() {
   659  					Expect(executeErr).NotTo(HaveOccurred())
   660  
   661  					Expect(fakeSharedActor.GatherDirectoryResourcesCallCount()).To(Equal(1))
   662  					Expect(fakeSharedActor.GatherDirectoryResourcesArgsForCall(0)).To(Equal(appDir))
   663  
   664  					Expect(fakeSharedActor.ZipDirectoryResourcesCallCount()).To(Equal(1))
   665  					pathArg, _ := fakeSharedActor.ZipDirectoryResourcesArgsForCall(0)
   666  					Expect(pathArg).To(Equal(appDir))
   667  				})
   668  			})
   669  
   670  			When("bits path is an archive", func() {
   671  				BeforeEach(func() {
   672  					var err error
   673  					tempFile, err := ioutil.TempFile("", "bits-zip-test")
   674  					Expect(err).ToNot(HaveOccurred())
   675  					Expect(tempFile.Close()).To(Succeed())
   676  					tempFilePath := tempFile.Name()
   677  
   678  					bitsPathFile, err := ioutil.TempFile("", "example")
   679  					Expect(err).ToNot(HaveOccurred())
   680  					Expect(bitsPathFile.Close()).To(Succeed())
   681  					bitsPath = bitsPathFile.Name()
   682  
   683  					err = zipit(tempFilePath, bitsPath, "")
   684  					Expect(err).NotTo(HaveOccurred())
   685  					Expect(os.Remove(tempFilePath)).To(Succeed())
   686  				})
   687  
   688  				AfterEach(func() {
   689  					err := os.RemoveAll(bitsPath)
   690  					Expect(err).ToNot(HaveOccurred())
   691  				})
   692  
   693  				It("calls GatherArchiveResources and ZipArchiveResources", func() {
   694  					Expect(fakeSharedActor.GatherArchiveResourcesCallCount()).To(Equal(1))
   695  					Expect(fakeSharedActor.ZipArchiveResourcesCallCount()).To(Equal(1))
   696  				})
   697  
   698  				When("gathering archive resources fails", func() {
   699  					BeforeEach(func() {
   700  						fakeSharedActor.GatherArchiveResourcesReturns(nil, errors.New("some-archive-resource-error"))
   701  					})
   702  					It("should return an error", func() {
   703  						Expect(executeErr).To(MatchError("some-archive-resource-error"))
   704  						Expect(warnings).To(ConsistOf("some-app-warning"))
   705  					})
   706  
   707  				})
   708  
   709  				When("gathering resources succeeds", func() {
   710  					BeforeEach(func() {
   711  						fakeSharedActor.GatherArchiveResourcesReturns([]sharedaction.Resource{{Filename: "file-1"}, {Filename: "file-2"}}, nil)
   712  					})
   713  
   714  					When("zipping gathered resources fails", func() {
   715  						BeforeEach(func() {
   716  							fakeSharedActor.ZipArchiveResourcesReturns("", errors.New("some-archive-error"))
   717  						})
   718  
   719  						It("returns the error", func() {
   720  							Expect(executeErr).To(MatchError("some-archive-error"))
   721  							Expect(warnings).To(ConsistOf("some-app-warning"))
   722  						})
   723  					})
   724  
   725  					When("zipping gathered resources succeeds", func() {
   726  						BeforeEach(func() {
   727  							fakeSharedActor.ZipArchiveResourcesReturns("zipped-archive", nil)
   728  						})
   729  
   730  						It("uploads the package", func() {
   731  							Expect(executeErr).ToNot(HaveOccurred())
   732  							Expect(warnings).To(ConsistOf("some-app-warning"))
   733  
   734  							Expect(fakeCloudControllerClient.UploadPackageCallCount()).To(Equal(1))
   735  							_, archivePathArg := fakeCloudControllerClient.UploadPackageArgsForCall(0)
   736  							Expect(archivePathArg).To(Equal("zipped-archive"))
   737  						})
   738  					})
   739  				})
   740  			})
   741  
   742  			When("bits path is a symlink to a directory", func() {
   743  				var tempDir string
   744  
   745  				BeforeEach(func() {
   746  					var err error
   747  					tempDir, err = ioutil.TempDir("", "example")
   748  					Expect(err).ToNot(HaveOccurred())
   749  
   750  					tempFile, err := ioutil.TempFile("", "example-file-")
   751  					Expect(err).ToNot(HaveOccurred())
   752  					Expect(tempFile.Close()).To(Succeed())
   753  
   754  					bitsPath = tempFile.Name()
   755  					Expect(os.Remove(bitsPath)).To(Succeed())
   756  					Expect(os.Symlink(tempDir, bitsPath)).To(Succeed())
   757  				})
   758  
   759  				AfterEach(func() {
   760  					Expect(os.RemoveAll(tempDir)).To(Succeed())
   761  					Expect(os.Remove(bitsPath)).To(Succeed())
   762  				})
   763  
   764  				It("calls GatherDirectoryResources and returns without an error", func() {
   765  					Expect(fakeSharedActor.GatherDirectoryResourcesCallCount()).To(Equal(1))
   766  					Expect(fakeSharedActor.GatherDirectoryResourcesArgsForCall(0)).To(Equal(bitsPath))
   767  					Expect(executeErr).ToNot(HaveOccurred())
   768  				})
   769  			})
   770  
   771  			When("bits path is symlink to an archive", func() {
   772  				var archivePath string
   773  
   774  				BeforeEach(func() {
   775  					var err error
   776  					tempArchiveFile, err := ioutil.TempFile("", "bits-zip-test")
   777  					Expect(err).ToNot(HaveOccurred())
   778  					Expect(tempArchiveFile.Close()).To(Succeed())
   779  					tempArchiveFilePath := tempArchiveFile.Name()
   780  
   781  					archivePathFile, err := ioutil.TempFile("", "example")
   782  					Expect(err).ToNot(HaveOccurred())
   783  					Expect(archivePathFile.Close()).To(Succeed())
   784  					archivePath = archivePathFile.Name()
   785  
   786  					err = zipit(tempArchiveFilePath, archivePath, "")
   787  					Expect(err).NotTo(HaveOccurred())
   788  					Expect(os.Remove(tempArchiveFilePath)).To(Succeed())
   789  
   790  					tempFile, err := ioutil.TempFile("", "example-file-")
   791  					Expect(err).ToNot(HaveOccurred())
   792  					Expect(tempFile.Close()).To(Succeed())
   793  
   794  					bitsPath = tempFile.Name()
   795  					Expect(os.Remove(bitsPath)).To(Succeed())
   796  					Expect(os.Symlink(archivePath, bitsPath)).To(Succeed())
   797  				})
   798  
   799  				AfterEach(func() {
   800  					Expect(os.Remove(archivePath)).To(Succeed())
   801  					Expect(os.Remove(bitsPath)).To(Succeed())
   802  				})
   803  
   804  				It("calls GatherArchiveResources and returns without an error", func() {
   805  					Expect(fakeSharedActor.GatherArchiveResourcesCallCount()).To(Equal(1))
   806  					Expect(fakeSharedActor.GatherArchiveResourcesArgsForCall(0)).To(Equal(bitsPath))
   807  					Expect(executeErr).ToNot(HaveOccurred())
   808  				})
   809  			})
   810  		})
   811  	})
   812  
   813  	Describe("CreateBitsPackageByApplication", func() {
   814  		var (
   815  			appGUID string
   816  
   817  			pkg        Package
   818  			executeErr error
   819  			warnings   Warnings
   820  		)
   821  
   822  		JustBeforeEach(func() {
   823  			pkg, warnings, executeErr = actor.CreateBitsPackageByApplication(appGUID)
   824  		})
   825  
   826  		When("creating the package fails", func() {
   827  			BeforeEach(func() {
   828  				fakeCloudControllerClient.CreatePackageReturns(
   829  					ccv3.Package{},
   830  					ccv3.Warnings{"create-package-warning"},
   831  					errors.New("some-create-error"),
   832  				)
   833  			})
   834  
   835  			It("returns the error", func() {
   836  				Expect(executeErr).To(MatchError("some-create-error"))
   837  				Expect(warnings).To(ConsistOf("create-package-warning"))
   838  			})
   839  		})
   840  
   841  		When("creating the package succeeds", func() {
   842  			var createdPackage ccv3.Package
   843  
   844  			BeforeEach(func() {
   845  				createdPackage = ccv3.Package{GUID: "some-pkg-guid"}
   846  				fakeCloudControllerClient.CreatePackageReturns(
   847  					createdPackage,
   848  					ccv3.Warnings{"create-package-warning"},
   849  					nil,
   850  				)
   851  			})
   852  
   853  			It("returns all warnings and the package", func() {
   854  				Expect(executeErr).ToNot(HaveOccurred())
   855  
   856  				Expect(fakeCloudControllerClient.CreatePackageCallCount()).To(Equal(1))
   857  				Expect(fakeCloudControllerClient.CreatePackageArgsForCall(0)).To(Equal(ccv3.Package{
   858  					Type: constant.PackageTypeBits,
   859  					Relationships: resources.Relationships{
   860  						constant.RelationshipTypeApplication: resources.Relationship{GUID: appGUID},
   861  					},
   862  				}))
   863  
   864  				Expect(warnings).To(ConsistOf("create-package-warning"))
   865  				Expect(pkg).To(MatchFields(IgnoreExtras, Fields{
   866  					"GUID": Equal("some-pkg-guid"),
   867  				}))
   868  			})
   869  		})
   870  	})
   871  
   872  	Describe("UploadBitsPackage", func() {
   873  		var (
   874  			pkg              Package
   875  			matchedResources []sharedaction.V3Resource
   876  			reader           io.Reader
   877  			readerLength     int64
   878  
   879  			appPkg     Package
   880  			warnings   Warnings
   881  			executeErr error
   882  		)
   883  
   884  		BeforeEach(func() {
   885  			pkg = Package{GUID: "some-package-guid"}
   886  
   887  			matchedResources = []sharedaction.V3Resource{{FilePath: "some-resource"}, {FilePath: "another-resource"}}
   888  			someString := "who reads these days"
   889  			reader = strings.NewReader(someString)
   890  			readerLength = int64(len([]byte(someString)))
   891  		})
   892  
   893  		JustBeforeEach(func() {
   894  			appPkg, warnings, executeErr = actor.UploadBitsPackage(pkg, matchedResources, reader, readerLength)
   895  		})
   896  
   897  		When("the upload is successful", func() {
   898  			BeforeEach(func() {
   899  				fakeCloudControllerClient.UploadBitsPackageReturns(ccv3.Package{GUID: "some-package-guid"}, ccv3.Warnings{"upload-warning-1", "upload-warning-2"}, nil)
   900  			})
   901  
   902  			It("returns all warnings", func() {
   903  				Expect(executeErr).ToNot(HaveOccurred())
   904  				Expect(warnings).To(ConsistOf("upload-warning-1", "upload-warning-2"))
   905  				Expect(appPkg).To(Equal(Package{GUID: "some-package-guid"}))
   906  
   907  				Expect(fakeCloudControllerClient.UploadBitsPackageCallCount()).To(Equal(1))
   908  				passedPackage, passedExistingResources, passedReader, passedReaderLength := fakeCloudControllerClient.UploadBitsPackageArgsForCall(0)
   909  				Expect(passedPackage).To(Equal(ccv3.Package(appPkg)))
   910  				Expect(passedExistingResources).To(ConsistOf(ccv3.Resource{FilePath: "some-resource"}, ccv3.Resource{FilePath: "another-resource"}))
   911  				Expect(passedReader).To(Equal(reader))
   912  				Expect(passedReaderLength).To(Equal(readerLength))
   913  			})
   914  		})
   915  
   916  		When("the upload returns an error", func() {
   917  			var err error
   918  
   919  			BeforeEach(func() {
   920  				err = errors.New("some-error")
   921  				fakeCloudControllerClient.UploadBitsPackageReturns(ccv3.Package{}, ccv3.Warnings{"upload-warning-1", "upload-warning-2"}, err)
   922  			})
   923  
   924  			It("returns the error", func() {
   925  				Expect(executeErr).To(MatchError(err))
   926  				Expect(warnings).To(ConsistOf("upload-warning-1", "upload-warning-2"))
   927  			})
   928  		})
   929  	})
   930  
   931  	Describe("PollPackage", func() {
   932  		Context("Polling Behavior", func() {
   933  			var (
   934  				pkg Package
   935  
   936  				appPkg     Package
   937  				warnings   Warnings
   938  				executeErr error
   939  			)
   940  
   941  			BeforeEach(func() {
   942  				pkg = Package{
   943  					GUID: "some-pkg-guid",
   944  				}
   945  
   946  				warnings = nil
   947  				executeErr = nil
   948  
   949  				// putting this here so the tests don't hang on polling
   950  				fakeCloudControllerClient.GetPackageReturns(
   951  					ccv3.Package{
   952  						GUID:  "some-pkg-guid",
   953  						State: constant.PackageReady,
   954  					},
   955  					ccv3.Warnings{},
   956  					nil,
   957  				)
   958  			})
   959  
   960  			JustBeforeEach(func() {
   961  				appPkg, warnings, executeErr = actor.PollPackage(pkg)
   962  			})
   963  
   964  			When("the polling errors", func() {
   965  				var expectedErr error
   966  
   967  				BeforeEach(func() {
   968  					expectedErr = errors.New("Fake error during polling")
   969  					fakeCloudControllerClient.GetPackageReturns(
   970  						ccv3.Package{},
   971  						ccv3.Warnings{"some-get-pkg-warning"},
   972  						expectedErr,
   973  					)
   974  				})
   975  
   976  				It("returns the error and warnings", func() {
   977  					Expect(executeErr).To(MatchError(expectedErr))
   978  					Expect(warnings).To(ConsistOf("some-get-pkg-warning"))
   979  				})
   980  			})
   981  
   982  			When("the polling is successful", func() {
   983  				It("returns the package", func() {
   984  					Expect(executeErr).ToNot(HaveOccurred())
   985  
   986  					expectedPackage := ccv3.Package{
   987  						GUID:  "some-pkg-guid",
   988  						State: constant.PackageReady,
   989  					}
   990  
   991  					Expect(appPkg).To(Equal(Package(expectedPackage)))
   992  					Expect(fakeCloudControllerClient.GetPackageCallCount()).To(Equal(1))
   993  					Expect(fakeCloudControllerClient.GetPackageArgsForCall(0)).To(Equal("some-pkg-guid"))
   994  				})
   995  			})
   996  		})
   997  
   998  		DescribeTable("Polling states",
   999  			func(finalState constant.PackageState, expectedErr error) {
  1000  				fakeCloudControllerClient.GetPackageReturns(
  1001  					ccv3.Package{GUID: "some-pkg-guid", State: constant.PackageAwaitingUpload},
  1002  					ccv3.Warnings{"poll-package-warning"},
  1003  					nil,
  1004  				)
  1005  
  1006  				fakeCloudControllerClient.GetPackageReturnsOnCall(
  1007  					1,
  1008  					ccv3.Package{State: finalState},
  1009  					ccv3.Warnings{"poll-package-warning"},
  1010  					nil,
  1011  				)
  1012  
  1013  				_, tableWarnings, err := actor.PollPackage(Package{
  1014  					GUID: "some-pkg-guid",
  1015  				})
  1016  
  1017  				if expectedErr == nil {
  1018  					Expect(err).ToNot(HaveOccurred())
  1019  				} else {
  1020  					Expect(err).To(MatchError(expectedErr))
  1021  				}
  1022  
  1023  				Expect(tableWarnings).To(ConsistOf("poll-package-warning", "poll-package-warning"))
  1024  
  1025  				Expect(fakeCloudControllerClient.GetPackageCallCount()).To(Equal(2))
  1026  				Expect(fakeConfig.PollingIntervalCallCount()).To(Equal(2))
  1027  			},
  1028  
  1029  			Entry("READY", constant.PackageReady, nil),
  1030  			Entry("FAILED", constant.PackageFailed, actionerror.PackageProcessingFailedError{}),
  1031  			Entry("EXPIRED", constant.PackageExpired, actionerror.PackageProcessingExpiredError{}),
  1032  		)
  1033  	})
  1034  
  1035  	Describe("CopyPackage", func() {
  1036  		var (
  1037  			sourceApp  resources.Application
  1038  			targetApp  resources.Application
  1039  			pkg        Package
  1040  			warnings   Warnings
  1041  			executeErr error
  1042  		)
  1043  
  1044  		BeforeEach(func() {
  1045  			targetApp = resources.Application{
  1046  				GUID: "target-app-guid",
  1047  				Name: "target-app",
  1048  			}
  1049  
  1050  			fakeCloudControllerClient.GetPackagesReturns(
  1051  				[]ccv3.Package{{GUID: "source-package-guid"}},
  1052  				ccv3.Warnings{"get-source-package-warning"},
  1053  				nil,
  1054  			)
  1055  
  1056  			fakeCloudControllerClient.CopyPackageReturns(
  1057  				ccv3.Package{GUID: "target-package-guid"},
  1058  				ccv3.Warnings{"copy-package-warning"},
  1059  				nil,
  1060  			)
  1061  
  1062  			fakeCloudControllerClient.GetPackageReturnsOnCall(0,
  1063  				ccv3.Package{State: constant.PackageCopying, GUID: "target-package-guid"},
  1064  				ccv3.Warnings{"get-package-warning-copying"},
  1065  				nil,
  1066  			)
  1067  			fakeCloudControllerClient.GetPackageReturnsOnCall(1,
  1068  				ccv3.Package{State: constant.PackageReady, GUID: "target-package-guid"},
  1069  				ccv3.Warnings{"get-package-warning-ready"},
  1070  				nil,
  1071  			)
  1072  		})
  1073  
  1074  		JustBeforeEach(func() {
  1075  			pkg, warnings, executeErr = actor.CopyPackage(sourceApp, targetApp)
  1076  		})
  1077  
  1078  		When("getting the source package fails", func() {
  1079  			var err error
  1080  
  1081  			BeforeEach(func() {
  1082  				err = errors.New("get-package-error")
  1083  				fakeCloudControllerClient.GetPackagesReturns(
  1084  					[]ccv3.Package{},
  1085  					ccv3.Warnings{"get-source-package-warning"},
  1086  					err,
  1087  				)
  1088  			})
  1089  
  1090  			It("returns the error", func() {
  1091  				Expect(executeErr).To(MatchError(err))
  1092  				Expect(warnings).To(ConsistOf("get-source-package-warning"))
  1093  
  1094  				queries := fakeCloudControllerClient.GetPackagesArgsForCall(0)
  1095  				Expect(queries).To(Equal([]ccv3.Query{
  1096  					ccv3.Query{
  1097  						Key:    ccv3.AppGUIDFilter,
  1098  						Values: []string{sourceApp.GUID},
  1099  					},
  1100  					ccv3.Query{
  1101  						Key:    ccv3.StatesFilter,
  1102  						Values: []string{string(constant.PackageReady)},
  1103  					},
  1104  					ccv3.Query{
  1105  						Key:    ccv3.OrderBy,
  1106  						Values: []string{ccv3.CreatedAtDescendingOrder},
  1107  					},
  1108  				}))
  1109  			})
  1110  		})
  1111  
  1112  		When("copying the package fails", func() {
  1113  			var err error
  1114  
  1115  			BeforeEach(func() {
  1116  				err = errors.New("copy-package-error")
  1117  				fakeCloudControllerClient.CopyPackageReturns(
  1118  					ccv3.Package{GUID: "target-package-guid"},
  1119  					ccv3.Warnings{"copy-package-warning"},
  1120  					err,
  1121  				)
  1122  			})
  1123  
  1124  			It("returns the error", func() {
  1125  				Expect(executeErr).To(MatchError(err))
  1126  				Expect(warnings).To(ConsistOf("get-source-package-warning", "copy-package-warning"))
  1127  
  1128  				sourcePkgGUID, appGUID := fakeCloudControllerClient.CopyPackageArgsForCall(0)
  1129  				Expect(sourcePkgGUID).To(Equal("source-package-guid"))
  1130  				Expect(appGUID).To(Equal(targetApp.GUID))
  1131  			})
  1132  		})
  1133  
  1134  		It("polls to make sure the package has finished copying", func() {
  1135  			Expect(executeErr).To(Not(HaveOccurred()))
  1136  			Expect(fakeCloudControllerClient.GetPackageCallCount()).To(Equal(2))
  1137  		})
  1138  
  1139  		When("the package fails to copy while polling the package", func() {
  1140  			BeforeEach(func() {
  1141  				fakeCloudControllerClient.GetPackageReturnsOnCall(0,
  1142  					ccv3.Package{State: constant.PackageFailed},
  1143  					ccv3.Warnings{"get-package-warning-copying"},
  1144  					nil,
  1145  				)
  1146  
  1147  			})
  1148  			It("fails", func() {
  1149  				Expect(fakeCloudControllerClient.GetPackageCallCount()).To(Equal(1))
  1150  				Expect(executeErr).To(MatchError(actionerror.PackageProcessingFailedError{}))
  1151  			})
  1152  		})
  1153  
  1154  		It("returns all warnings", func() {
  1155  			Expect(executeErr).ToNot(HaveOccurred())
  1156  			Expect(warnings).To(ConsistOf("get-source-package-warning", "copy-package-warning", "get-package-warning-copying", "get-package-warning-ready"))
  1157  			Expect(pkg).To(Equal(Package{State: constant.PackageReady, GUID: "target-package-guid"}))
  1158  		})
  1159  	})
  1160  })