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