github.com/jghiloni/cli@v6.28.1-0.20170628223758-0ce05fe032a2+incompatible/actor/pushaction/apply_test.go (about)

     1  package pushaction_test
     2  
     3  import (
     4  	"errors"
     5  	"io/ioutil"
     6  
     7  	. "code.cloudfoundry.org/cli/actor/pushaction"
     8  	"code.cloudfoundry.org/cli/actor/pushaction/pushactionfakes"
     9  	"code.cloudfoundry.org/cli/actor/v2action"
    10  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
    11  
    12  	. "github.com/onsi/ginkgo"
    13  	. "github.com/onsi/gomega"
    14  )
    15  
    16  func streamsDrainedAndClosed(configStream <-chan ApplicationConfig, eventStream <-chan Event, warningsStream <-chan Warnings, errorStream <-chan error) bool {
    17  	var configStreamClosed, eventStreamClosed, warningsStreamClosed, errorStreamClosed bool
    18  	for {
    19  		select {
    20  		case _, ok := <-configStream:
    21  			if !ok {
    22  				configStreamClosed = true
    23  			}
    24  		case _, ok := <-eventStream:
    25  			if !ok {
    26  				eventStreamClosed = true
    27  			}
    28  		case _, ok := <-warningsStream:
    29  			if !ok {
    30  				warningsStreamClosed = true
    31  			}
    32  		case _, ok := <-errorStream:
    33  			if !ok {
    34  				errorStreamClosed = true
    35  			}
    36  		}
    37  		if configStreamClosed && eventStreamClosed && warningsStreamClosed && errorStreamClosed {
    38  			break
    39  		}
    40  	}
    41  	return true
    42  }
    43  
    44  var _ = Describe("Apply", func() {
    45  	var (
    46  		actor       *Actor
    47  		fakeV2Actor *pushactionfakes.FakeV2Actor
    48  
    49  		config          ApplicationConfig
    50  		fakeProgressBar *pushactionfakes.FakeProgressBar
    51  
    52  		eventStream    <-chan Event
    53  		warningsStream <-chan Warnings
    54  		errorStream    <-chan error
    55  		configStream   <-chan ApplicationConfig
    56  	)
    57  
    58  	BeforeEach(func() {
    59  		fakeV2Actor = new(pushactionfakes.FakeV2Actor)
    60  		actor = NewActor(fakeV2Actor)
    61  
    62  		config = ApplicationConfig{
    63  			DesiredApplication: v2action.Application{
    64  				Name:      "some-app-name",
    65  				SpaceGUID: "some-space-guid",
    66  			},
    67  			DesiredRoutes: []v2action.Route{{Host: "banana"}},
    68  			Path:          "some-path",
    69  		}
    70  		fakeProgressBar = new(pushactionfakes.FakeProgressBar)
    71  	})
    72  
    73  	JustBeforeEach(func() {
    74  		configStream, eventStream, warningsStream, errorStream = actor.Apply(config, fakeProgressBar)
    75  	})
    76  
    77  	AfterEach(func() {
    78  		Eventually(streamsDrainedAndClosed(configStream, eventStream, warningsStream, errorStream)).Should(BeTrue())
    79  	})
    80  
    81  	Context("when creating/updating the application is successful", func() {
    82  		var createdApp v2action.Application
    83  
    84  		BeforeEach(func() {
    85  			fakeV2Actor.CreateApplicationStub = func(application v2action.Application) (v2action.Application, v2action.Warnings, error) {
    86  				createdApp = application
    87  				createdApp.GUID = "some-app-guid"
    88  
    89  				return createdApp, v2action.Warnings{"create-application-warnings-1", "create-application-warnings-2"}, nil
    90  			}
    91  		})
    92  
    93  		JustBeforeEach(func() {
    94  			Eventually(eventStream).Should(Receive(Equal(SettingUpApplication)))
    95  			Eventually(warningsStream).Should(Receive(ConsistOf("create-application-warnings-1", "create-application-warnings-2")))
    96  			Eventually(eventStream).Should(Receive(Equal(CreatedApplication)))
    97  		})
    98  
    99  		Context("when the route creation is successful", func() {
   100  			var createdRoutes []v2action.Route
   101  
   102  			BeforeEach(func() {
   103  				createdRoutes = []v2action.Route{{Host: "banana", GUID: "some-route-guid"}}
   104  				fakeV2Actor.CreateRouteReturns(createdRoutes[0], v2action.Warnings{"create-route-warnings-1", "create-route-warnings-2"}, nil)
   105  			})
   106  
   107  			JustBeforeEach(func() {
   108  				Eventually(eventStream).Should(Receive(Equal(ConfiguringRoutes)))
   109  				Eventually(warningsStream).Should(Receive(ConsistOf("create-route-warnings-1", "create-route-warnings-2")))
   110  				Eventually(eventStream).Should(Receive(Equal(CreatedRoutes)))
   111  			})
   112  
   113  			Context("when binding the routes is successful", func() {
   114  				BeforeEach(func() {
   115  					fakeV2Actor.BindRouteToApplicationReturns(v2action.Warnings{"bind-route-warnings-1", "bind-route-warnings-2"}, nil)
   116  				})
   117  
   118  				JustBeforeEach(func() {
   119  					Eventually(warningsStream).Should(Receive(ConsistOf("bind-route-warnings-1", "bind-route-warnings-2")))
   120  					Eventually(eventStream).Should(Receive(Equal(BoundRoutes)))
   121  				})
   122  
   123  				Context("when the archive creation is successful", func() {
   124  					var archivePath string
   125  
   126  					BeforeEach(func() {
   127  						tmpfile, err := ioutil.TempFile("", "fake-archive")
   128  						Expect(err).ToNot(HaveOccurred())
   129  						_, err = tmpfile.Write([]byte("123456"))
   130  						Expect(err).ToNot(HaveOccurred())
   131  						Expect(tmpfile.Close()).ToNot(HaveOccurred())
   132  
   133  						archivePath = tmpfile.Name()
   134  						fakeV2Actor.ZipDirectoryResourcesReturns(archivePath, nil)
   135  					})
   136  
   137  					JustBeforeEach(func() {
   138  						Eventually(eventStream).Should(Receive(Equal(CreatingArchive)))
   139  					})
   140  
   141  					Context("when the upload is successful", func() {
   142  						BeforeEach(func() {
   143  							fakeV2Actor.UploadApplicationPackageReturns(v2action.Job{}, v2action.Warnings{"upload-warnings-1", "upload-warnings-2"}, nil)
   144  						})
   145  
   146  						JustBeforeEach(func() {
   147  							Eventually(eventStream).Should(Receive(Equal(UploadingApplication)))
   148  							Eventually(eventStream).Should(Receive(Equal(UploadComplete)))
   149  							Eventually(warningsStream).Should(Receive(ConsistOf("upload-warnings-1", "upload-warnings-2")))
   150  						})
   151  
   152  						It("sends the updated config and a complete event", func() {
   153  							Eventually(configStream).Should(Receive(Equal(ApplicationConfig{
   154  								CurrentApplication: createdApp,
   155  								DesiredApplication: createdApp,
   156  								CurrentRoutes:      createdRoutes,
   157  								DesiredRoutes:      createdRoutes,
   158  								Path:               "some-path",
   159  							})))
   160  							Eventually(eventStream).Should(Receive(Equal(Complete)))
   161  
   162  							Expect(fakeV2Actor.UploadApplicationPackageCallCount()).To(Equal(1))
   163  						})
   164  					})
   165  
   166  					Context("when the upload errors", func() {
   167  						Context("with a retryable error", func() {
   168  							BeforeEach(func() {
   169  								fakeV2Actor.UploadApplicationPackageReturns(v2action.Job{}, v2action.Warnings{"upload-warnings-1", "upload-warnings-2"}, ccerror.PipeSeekError{})
   170  							})
   171  
   172  							It("retries the download up to three times", func() {
   173  								Eventually(eventStream).Should(Receive(Equal(UploadingApplication)))
   174  								Eventually(fakeProgressBar.NewProgressBarWrapperCallCount).Should(Equal(1))
   175  								Eventually(warningsStream).Should(Receive(ConsistOf("upload-warnings-1", "upload-warnings-2")))
   176  								Eventually(eventStream).Should(Receive(Equal(RetryUpload)))
   177  
   178  								Eventually(eventStream).Should(Receive(Equal(UploadingApplication)))
   179  								Eventually(fakeProgressBar.NewProgressBarWrapperCallCount).Should(Equal(2))
   180  								Eventually(warningsStream).Should(Receive(ConsistOf("upload-warnings-1", "upload-warnings-2")))
   181  								Eventually(eventStream).Should(Receive(Equal(RetryUpload)))
   182  
   183  								Eventually(eventStream).Should(Receive(Equal(UploadingApplication)))
   184  								Eventually(fakeProgressBar.NewProgressBarWrapperCallCount).Should(Equal(3))
   185  								Eventually(warningsStream).Should(Receive(ConsistOf("upload-warnings-1", "upload-warnings-2")))
   186  								Eventually(eventStream).Should(Receive(Equal(RetryUpload)))
   187  
   188  								Eventually(errorStream).Should(Receive(Equal(UploadFailedError{})))
   189  							})
   190  						})
   191  
   192  						Context("with a generic error", func() {
   193  							var expectedErr error
   194  
   195  							BeforeEach(func() {
   196  								expectedErr = errors.New("dios mio")
   197  								fakeV2Actor.UploadApplicationPackageReturns(v2action.Job{}, v2action.Warnings{"upload-warnings-1", "upload-warnings-2"}, expectedErr)
   198  							})
   199  
   200  							It("sends warnings and errors, then stops", func() {
   201  								Eventually(eventStream).Should(Receive(Equal(UploadingApplication)))
   202  								Eventually(warningsStream).Should(Receive(ConsistOf("upload-warnings-1", "upload-warnings-2")))
   203  								Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
   204  								Consistently(eventStream).ShouldNot(Receive())
   205  							})
   206  						})
   207  					})
   208  				})
   209  
   210  				Context("when the archive creation errors", func() {
   211  					var expectedErr error
   212  
   213  					BeforeEach(func() {
   214  						expectedErr = errors.New("dios mio")
   215  						fakeV2Actor.ZipDirectoryResourcesReturns("", expectedErr)
   216  					})
   217  
   218  					It("sends warnings and errors, then stops", func() {
   219  						Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
   220  						Consistently(eventStream).ShouldNot(Receive())
   221  					})
   222  				})
   223  
   224  				Context("when a docker image is provided", func() {
   225  					BeforeEach(func() {
   226  						config.DesiredApplication.DockerImage = "some-docker-image-path"
   227  					})
   228  
   229  					It("skips achiving and uploading", func() {
   230  						Eventually(configStream).Should(Receive())
   231  						Eventually(eventStream).Should(Receive(Equal(Complete)))
   232  
   233  						Expect(fakeV2Actor.ZipDirectoryResourcesCallCount()).To(Equal(0))
   234  					})
   235  				})
   236  			})
   237  
   238  			Context("when there are no routes to bind", func() {
   239  				BeforeEach(func() {
   240  					config.CurrentRoutes = createdRoutes
   241  				})
   242  
   243  				It("should not send the RouteCreated event", func() {
   244  					Eventually(warningsStream).Should(Receive())
   245  					Consistently(eventStream).ShouldNot(Receive(Equal(CreatedRoutes)))
   246  				})
   247  			})
   248  
   249  			Context("when binding the routes errors", func() {
   250  				var expectedErr error
   251  
   252  				BeforeEach(func() {
   253  					expectedErr = errors.New("dios mio")
   254  					fakeV2Actor.BindRouteToApplicationReturns(v2action.Warnings{"bind-route-warnings-1", "bind-route-warnings-2"}, expectedErr)
   255  				})
   256  
   257  				It("sends warnings and errors, then stops", func() {
   258  					Eventually(warningsStream).Should(Receive(ConsistOf("bind-route-warnings-1", "bind-route-warnings-2")))
   259  					Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
   260  					Consistently(eventStream).ShouldNot(Receive())
   261  				})
   262  			})
   263  		})
   264  
   265  		Context("when there are no routes to create", func() {
   266  			BeforeEach(func() {
   267  				config.DesiredRoutes[0].GUID = "some-route-guid"
   268  			})
   269  
   270  			It("should not send the RouteCreated event", func() {
   271  				Eventually(eventStream).Should(Receive(Equal(ConfiguringRoutes)))
   272  				Eventually(warningsStream).Should(Receive())
   273  				Consistently(eventStream).ShouldNot(Receive())
   274  			})
   275  		})
   276  
   277  		Context("when the route creation errors", func() {
   278  			var expectedErr error
   279  
   280  			BeforeEach(func() {
   281  				expectedErr = errors.New("dios mio")
   282  				fakeV2Actor.CreateRouteReturns(v2action.Route{}, v2action.Warnings{"create-route-warnings-1", "create-route-warnings-2"}, expectedErr)
   283  			})
   284  
   285  			It("sends warnings and errors, then stops", func() {
   286  				Eventually(eventStream).Should(Receive(Equal(ConfiguringRoutes)))
   287  				Eventually(warningsStream).Should(Receive(ConsistOf("create-route-warnings-1", "create-route-warnings-2")))
   288  				Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
   289  				Consistently(eventStream).ShouldNot(Receive())
   290  			})
   291  		})
   292  	})
   293  
   294  	Context("when creating/updating errors", func() {
   295  		var expectedErr error
   296  
   297  		BeforeEach(func() {
   298  			expectedErr = errors.New("dios mio")
   299  			fakeV2Actor.CreateApplicationReturns(v2action.Application{}, v2action.Warnings{"create-application-warnings-1", "create-application-warnings-2"}, expectedErr)
   300  		})
   301  
   302  		It("sends warnings and errors, then stops", func() {
   303  			Eventually(eventStream).Should(Receive(Equal(SettingUpApplication)))
   304  			Eventually(warningsStream).Should(Receive(ConsistOf("create-application-warnings-1", "create-application-warnings-2")))
   305  			Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
   306  			Consistently(eventStream).ShouldNot(Receive())
   307  		})
   308  	})
   309  })