github.com/liamawhite/cli-with-i18n@v6.32.1-0.20171122084555-dede0a5c3448+incompatible/actor/pushaction/apply_test.go (about)

     1  package pushaction_test
     2  
     3  import (
     4  	"errors"
     5  	"io/ioutil"
     6  
     7  	. "github.com/liamawhite/cli-with-i18n/actor/pushaction"
     8  	"github.com/liamawhite/cli-with-i18n/actor/pushaction/pushactionfakes"
     9  	"github.com/liamawhite/cli-with-i18n/actor/v2action"
    10  	"github.com/liamawhite/cli-with-i18n/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  		fakeSharedActor *pushactionfakes.FakeSharedActor
    49  
    50  		config          ApplicationConfig
    51  		fakeProgressBar *pushactionfakes.FakeProgressBar
    52  
    53  		eventStream    <-chan Event
    54  		warningsStream <-chan Warnings
    55  		errorStream    <-chan error
    56  		configStream   <-chan ApplicationConfig
    57  	)
    58  
    59  	BeforeEach(func() {
    60  		fakeV2Actor = new(pushactionfakes.FakeV2Actor)
    61  		fakeSharedActor = new(pushactionfakes.FakeSharedActor)
    62  		actor = NewActor(fakeV2Actor, fakeSharedActor)
    63  		config = ApplicationConfig{
    64  			DesiredApplication: Application{
    65  				Application: v2action.Application{
    66  					Name:      "some-app-name",
    67  					SpaceGUID: "some-space-guid",
    68  				}},
    69  			DesiredRoutes: []v2action.Route{{Host: "banana"}},
    70  			Path:          "some-path",
    71  		}
    72  		fakeProgressBar = new(pushactionfakes.FakeProgressBar)
    73  	})
    74  
    75  	JustBeforeEach(func() {
    76  		configStream, eventStream, warningsStream, errorStream = actor.Apply(config, fakeProgressBar)
    77  	})
    78  
    79  	AfterEach(func() {
    80  		Eventually(streamsDrainedAndClosed(configStream, eventStream, warningsStream, errorStream)).Should(BeTrue())
    81  	})
    82  
    83  	Context("when creating/updating the application is successful", func() {
    84  		var createdApp v2action.Application
    85  
    86  		BeforeEach(func() {
    87  			fakeV2Actor.CreateApplicationStub = func(application v2action.Application) (v2action.Application, v2action.Warnings, error) {
    88  				createdApp = application
    89  				createdApp.GUID = "some-app-guid"
    90  
    91  				return createdApp, v2action.Warnings{"create-application-warnings-1", "create-application-warnings-2"}, nil
    92  			}
    93  		})
    94  
    95  		JustBeforeEach(func() {
    96  			Eventually(eventStream).Should(Receive(Equal(SettingUpApplication)))
    97  			Eventually(warningsStream).Should(Receive(ConsistOf("create-application-warnings-1", "create-application-warnings-2")))
    98  			Eventually(eventStream).Should(Receive(Equal(CreatedApplication)))
    99  		})
   100  
   101  		Context("when the route creation is successful", func() {
   102  			var createdRoutes []v2action.Route
   103  
   104  			BeforeEach(func() {
   105  				createdRoutes = []v2action.Route{{Host: "banana", GUID: "some-route-guid"}}
   106  				fakeV2Actor.CreateRouteReturns(createdRoutes[0], v2action.Warnings{"create-route-warnings-1", "create-route-warnings-2"}, nil)
   107  			})
   108  
   109  			JustBeforeEach(func() {
   110  				Eventually(eventStream).Should(Receive(Equal(ConfiguringRoutes)))
   111  				Eventually(warningsStream).Should(Receive(ConsistOf("create-route-warnings-1", "create-route-warnings-2")))
   112  				Eventually(eventStream).Should(Receive(Equal(CreatedRoutes)))
   113  			})
   114  
   115  			Context("when binding the routes is successful", func() {
   116  				var desiredServices map[string]v2action.ServiceInstance
   117  
   118  				BeforeEach(func() {
   119  					desiredServices = map[string]v2action.ServiceInstance{
   120  						"service_1": {Name: "service_1", GUID: "service_guid"},
   121  					}
   122  					config.DesiredServices = desiredServices
   123  					fakeV2Actor.BindRouteToApplicationReturns(v2action.Warnings{"bind-route-warnings-1", "bind-route-warnings-2"}, nil)
   124  				})
   125  
   126  				JustBeforeEach(func() {
   127  					Eventually(warningsStream).Should(Receive(ConsistOf("bind-route-warnings-1", "bind-route-warnings-2")))
   128  					Eventually(eventStream).Should(Receive(Equal(BoundRoutes)))
   129  				})
   130  
   131  				Context("when service binding is successful", func() {
   132  					BeforeEach(func() {
   133  						fakeV2Actor.BindServiceByApplicationAndServiceInstanceReturns(v2action.Warnings{"bind-service-warnings-1", "bind-service-warnings-2"}, nil)
   134  					})
   135  
   136  					JustBeforeEach(func() {
   137  						Eventually(eventStream).Should(Receive(Equal(ConfiguringServices)))
   138  						Eventually(warningsStream).Should(Receive(ConsistOf("bind-service-warnings-1", "bind-service-warnings-2")))
   139  						Eventually(eventStream).Should(Receive(Equal(BoundServices)))
   140  					})
   141  
   142  					Context("when resource matching happens", func() {
   143  						BeforeEach(func() {
   144  							fakeV2Actor.ResourceMatchReturns(nil, nil, v2action.Warnings{"resource-warnings-1", "resource-warnings-2"}, nil)
   145  						})
   146  
   147  						JustBeforeEach(func() {
   148  							Eventually(eventStream).Should(Receive(Equal(ResourceMatching)))
   149  							Eventually(warningsStream).Should(Receive(ConsistOf("resource-warnings-1", "resource-warnings-2")))
   150  						})
   151  
   152  						Context("when the archive creation is successful", func() {
   153  							var archivePath string
   154  
   155  							BeforeEach(func() {
   156  								tmpfile, err := ioutil.TempFile("", "fake-archive")
   157  								Expect(err).ToNot(HaveOccurred())
   158  								_, err = tmpfile.Write([]byte("123456"))
   159  								Expect(err).ToNot(HaveOccurred())
   160  								Expect(tmpfile.Close()).ToNot(HaveOccurred())
   161  
   162  								archivePath = tmpfile.Name()
   163  								fakeSharedActor.ZipDirectoryResourcesReturns(archivePath, nil)
   164  							})
   165  
   166  							JustBeforeEach(func() {
   167  								Eventually(eventStream).Should(Receive(Equal(CreatingArchive)))
   168  							})
   169  
   170  							Context("when the upload is successful", func() {
   171  								BeforeEach(func() {
   172  									fakeV2Actor.UploadApplicationPackageReturns(v2action.Job{}, v2action.Warnings{"upload-warnings-1", "upload-warnings-2"}, nil)
   173  								})
   174  
   175  								JustBeforeEach(func() {
   176  									Eventually(eventStream).Should(Receive(Equal(UploadingApplication)))
   177  									Eventually(eventStream).Should(Receive(Equal(UploadComplete)))
   178  									Eventually(warningsStream).Should(Receive(ConsistOf("upload-warnings-1", "upload-warnings-2")))
   179  								})
   180  
   181  								It("sends the updated config and a complete event", func() {
   182  									Eventually(configStream).Should(Receive(Equal(ApplicationConfig{
   183  										CurrentApplication: Application{Application: createdApp},
   184  										CurrentRoutes:      createdRoutes,
   185  										CurrentServices:    desiredServices,
   186  										DesiredApplication: Application{Application: createdApp},
   187  										DesiredRoutes:      createdRoutes,
   188  										DesiredServices:    desiredServices,
   189  										Path:               "some-path",
   190  									})))
   191  									Eventually(eventStream).Should(Receive(Equal(Complete)))
   192  
   193  									Expect(fakeV2Actor.UploadApplicationPackageCallCount()).To(Equal(1))
   194  								})
   195  							})
   196  
   197  							Context("when the upload errors", func() {
   198  								Context("with a retryable error", func() {
   199  									BeforeEach(func() {
   200  										fakeV2Actor.UploadApplicationPackageReturns(v2action.Job{}, v2action.Warnings{"upload-warnings-1", "upload-warnings-2"}, ccerror.PipeSeekError{})
   201  									})
   202  
   203  									It("retries the download up to three times", func() {
   204  										Eventually(eventStream).Should(Receive(Equal(UploadingApplication)))
   205  										Eventually(fakeProgressBar.NewProgressBarWrapperCallCount).Should(Equal(1))
   206  										Eventually(warningsStream).Should(Receive(ConsistOf("upload-warnings-1", "upload-warnings-2")))
   207  										Eventually(eventStream).Should(Receive(Equal(RetryUpload)))
   208  
   209  										Eventually(eventStream).Should(Receive(Equal(UploadingApplication)))
   210  										Eventually(fakeProgressBar.NewProgressBarWrapperCallCount).Should(Equal(2))
   211  										Eventually(warningsStream).Should(Receive(ConsistOf("upload-warnings-1", "upload-warnings-2")))
   212  										Eventually(eventStream).Should(Receive(Equal(RetryUpload)))
   213  
   214  										Eventually(eventStream).Should(Receive(Equal(UploadingApplication)))
   215  										Eventually(fakeProgressBar.NewProgressBarWrapperCallCount).Should(Equal(3))
   216  										Eventually(warningsStream).Should(Receive(ConsistOf("upload-warnings-1", "upload-warnings-2")))
   217  										Eventually(eventStream).Should(Receive(Equal(RetryUpload)))
   218  
   219  										Eventually(errorStream).Should(Receive(Equal(UploadFailedError{})))
   220  									})
   221  								})
   222  
   223  								Context("with a generic error", func() {
   224  									var expectedErr error
   225  
   226  									BeforeEach(func() {
   227  										expectedErr = errors.New("dios mio")
   228  										fakeV2Actor.UploadApplicationPackageReturns(v2action.Job{}, v2action.Warnings{"upload-warnings-1", "upload-warnings-2"}, expectedErr)
   229  									})
   230  
   231  									It("sends warnings and errors, then stops", func() {
   232  										Eventually(eventStream).Should(Receive(Equal(UploadingApplication)))
   233  										Eventually(warningsStream).Should(Receive(ConsistOf("upload-warnings-1", "upload-warnings-2")))
   234  										Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
   235  										Consistently(eventStream).ShouldNot(Receive())
   236  									})
   237  								})
   238  							})
   239  						})
   240  
   241  						Context("when the archive creation errors", func() {
   242  							var expectedErr error
   243  
   244  							BeforeEach(func() {
   245  								expectedErr = errors.New("dios mio")
   246  								fakeSharedActor.ZipDirectoryResourcesReturns("", expectedErr)
   247  							})
   248  
   249  							It("sends warnings and errors, then stops", func() {
   250  								Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
   251  								Consistently(eventStream).ShouldNot(Receive())
   252  							})
   253  						})
   254  					})
   255  
   256  					Context("when a docker image is provided", func() {
   257  						BeforeEach(func() {
   258  							config.DesiredApplication.DockerImage = "some-docker-image-path"
   259  						})
   260  
   261  						It("skips achiving and uploading", func() {
   262  							Eventually(configStream).Should(Receive())
   263  							Eventually(eventStream).Should(Receive(Equal(Complete)))
   264  
   265  							Expect(fakeSharedActor.ZipDirectoryResourcesCallCount()).To(Equal(0))
   266  						})
   267  					})
   268  				})
   269  
   270  				Context("when there are no services to bind", func() {
   271  					BeforeEach(func() {
   272  						services := map[string]v2action.ServiceInstance{
   273  							"service_1": {Name: "service_1", GUID: "service_guid"},
   274  						}
   275  						config.CurrentServices = services
   276  						config.DesiredServices = services
   277  					})
   278  
   279  					It("should not send the BoundServices event", func() {
   280  						Eventually(eventStream).ShouldNot(Receive(Equal(ConfiguringServices)))
   281  						Consistently(eventStream).ShouldNot(Receive(Equal(BoundServices)))
   282  					})
   283  				})
   284  
   285  				Context("when binding routes fails", func() {
   286  					var expectedErr error
   287  
   288  					BeforeEach(func() {
   289  						expectedErr = errors.New("dios mio")
   290  						fakeV2Actor.BindServiceByApplicationAndServiceInstanceReturns(v2action.Warnings{"bind-service-warnings-1", "bind-service-warnings-2"}, expectedErr)
   291  					})
   292  
   293  					It("sends warnings and errors, then stops", func() {
   294  						Eventually(eventStream).Should(Receive(Equal(ConfiguringServices)))
   295  						Eventually(warningsStream).Should(Receive(ConsistOf("bind-service-warnings-1", "bind-service-warnings-2")))
   296  						Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
   297  						Consistently(eventStream).ShouldNot(Receive())
   298  					})
   299  				})
   300  			})
   301  
   302  			Context("when there are no routes to bind", func() {
   303  				BeforeEach(func() {
   304  					config.CurrentRoutes = createdRoutes
   305  				})
   306  
   307  				It("should not send the RouteCreated event", func() {
   308  					Eventually(warningsStream).Should(Receive())
   309  					Consistently(eventStream).ShouldNot(Receive(Equal(CreatedRoutes)))
   310  				})
   311  			})
   312  
   313  			Context("when binding the routes errors", func() {
   314  				var expectedErr error
   315  
   316  				BeforeEach(func() {
   317  					expectedErr = errors.New("dios mio")
   318  					fakeV2Actor.BindRouteToApplicationReturns(v2action.Warnings{"bind-route-warnings-1", "bind-route-warnings-2"}, expectedErr)
   319  				})
   320  
   321  				It("sends warnings and errors, then stops", func() {
   322  					Eventually(warningsStream).Should(Receive(ConsistOf("bind-route-warnings-1", "bind-route-warnings-2")))
   323  					Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
   324  					Consistently(eventStream).ShouldNot(Receive())
   325  				})
   326  			})
   327  		})
   328  
   329  		Context("when there are no routes to create", func() {
   330  			BeforeEach(func() {
   331  				config.DesiredRoutes[0].GUID = "some-route-guid"
   332  			})
   333  
   334  			It("should not send the RouteCreated event", func() {
   335  				Eventually(eventStream).Should(Receive(Equal(ConfiguringRoutes)))
   336  				Eventually(warningsStream).Should(Receive())
   337  				Consistently(eventStream).ShouldNot(Receive())
   338  			})
   339  		})
   340  
   341  		Context("when the route creation errors", func() {
   342  			var expectedErr error
   343  
   344  			BeforeEach(func() {
   345  				expectedErr = errors.New("dios mio")
   346  				fakeV2Actor.CreateRouteReturns(v2action.Route{}, v2action.Warnings{"create-route-warnings-1", "create-route-warnings-2"}, expectedErr)
   347  			})
   348  
   349  			It("sends warnings and errors, then stops", func() {
   350  				Eventually(eventStream).Should(Receive(Equal(ConfiguringRoutes)))
   351  				Eventually(warningsStream).Should(Receive(ConsistOf("create-route-warnings-1", "create-route-warnings-2")))
   352  				Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
   353  				Consistently(eventStream).ShouldNot(Receive())
   354  			})
   355  		})
   356  	})
   357  
   358  	Context("when creating/updating errors", func() {
   359  		var expectedErr error
   360  
   361  		BeforeEach(func() {
   362  			expectedErr = errors.New("dios mio")
   363  			fakeV2Actor.CreateApplicationReturns(v2action.Application{}, v2action.Warnings{"create-application-warnings-1", "create-application-warnings-2"}, expectedErr)
   364  		})
   365  
   366  		It("sends warnings and errors, then stops", func() {
   367  			Eventually(eventStream).Should(Receive(Equal(SettingUpApplication)))
   368  			Eventually(warningsStream).Should(Receive(ConsistOf("create-application-warnings-1", "create-application-warnings-2")))
   369  			Eventually(errorStream).Should(Receive(MatchError(expectedErr)))
   370  			Consistently(eventStream).ShouldNot(Receive())
   371  		})
   372  	})
   373  })