code.cloudfoundry.org/cli@v7.1.0+incompatible/command/v7/stage_package_command_test.go (about) 1 package v7_test 2 3 import ( 4 "context" 5 "errors" 6 "time" 7 8 "code.cloudfoundry.org/cli/actor/actionerror" 9 "code.cloudfoundry.org/cli/actor/sharedaction" 10 "code.cloudfoundry.org/cli/actor/sharedaction/sharedactionfakes" 11 "code.cloudfoundry.org/cli/actor/v7action" 12 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" 13 "code.cloudfoundry.org/cli/command/commandfakes" 14 "code.cloudfoundry.org/cli/command/flag" 15 v7 "code.cloudfoundry.org/cli/command/v7" 16 "code.cloudfoundry.org/cli/command/v7/v7fakes" 17 "code.cloudfoundry.org/cli/resources" 18 "code.cloudfoundry.org/cli/util/configv3" 19 "code.cloudfoundry.org/cli/util/ui" 20 . "github.com/onsi/ginkgo" 21 . "github.com/onsi/gomega" 22 . "github.com/onsi/gomega/gbytes" 23 ) 24 25 var _ = Describe("stage-package Command", func() { 26 const dropletCreateTime = "2017-08-14T21:16:42Z" 27 28 var ( 29 cmd v7.StagePackageCommand 30 testUI *ui.UI 31 fakeConfig *commandfakes.FakeConfig 32 fakeSharedActor *commandfakes.FakeSharedActor 33 fakeActor *v7fakes.FakeActor 34 fakeLogCacheClient *sharedactionfakes.FakeLogCacheClient 35 36 binaryName string 37 executeErr error 38 appName string 39 packageGUID string 40 spaceGUID string 41 app resources.Application 42 43 allLogsWritten chan bool 44 closedTheStreams bool 45 ) 46 47 BeforeEach(func() { 48 testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) 49 fakeConfig = new(commandfakes.FakeConfig) 50 fakeSharedActor = new(commandfakes.FakeSharedActor) 51 fakeActor = new(v7fakes.FakeActor) 52 fakeLogCacheClient = new(sharedactionfakes.FakeLogCacheClient) 53 54 fakeConfig.StagingTimeoutReturns(10 * time.Minute) 55 56 binaryName = "faceman" 57 fakeConfig.BinaryNameReturns(binaryName) 58 appName = "some-app" 59 packageGUID = "some-package-guid" 60 spaceGUID = "some-space-guid" 61 62 cmd = v7.StagePackageCommand{ 63 RequiredArgs: flag.AppName{AppName: appName}, 64 PackageGUID: packageGUID, 65 BaseCommand: v7.BaseCommand{ 66 UI: testUI, 67 Config: fakeConfig, 68 SharedActor: fakeSharedActor, 69 Actor: fakeActor, 70 }, 71 LogCacheClient: fakeLogCacheClient, 72 } 73 74 fakeConfig.HasTargetedOrganizationReturns(true) 75 fakeConfig.TargetedOrganizationReturns(configv3.Organization{ 76 GUID: "some-org-guid", 77 Name: "some-org", 78 }) 79 fakeConfig.HasTargetedSpaceReturns(true) 80 fakeConfig.TargetedSpaceReturns(configv3.Space{ 81 GUID: spaceGUID, 82 Name: "some-space", 83 }) 84 fakeConfig.CurrentUserReturns(configv3.User{Name: "steve"}, nil) 85 86 allLogsWritten = make(chan bool) 87 fakeActor.GetStreamingLogsForApplicationByNameAndSpaceStub = func(appName string, spaceGUID string, client sharedaction.LogCacheClient) (<-chan sharedaction.LogMessage, <-chan error, context.CancelFunc, v7action.Warnings, error) { 88 logStream := make(chan sharedaction.LogMessage) 89 errorStream := make(chan error) 90 closedTheStreams = false 91 92 cancelFunc := func() { 93 if closedTheStreams { 94 return 95 } 96 closedTheStreams = true 97 close(logStream) 98 close(errorStream) 99 } 100 101 go func() { 102 logStream <- *sharedaction.NewLogMessage("Here are some staging logs!", "OUT", time.Now(), sharedaction.StagingLog, "sourceInstance") 103 logStream <- *sharedaction.NewLogMessage("Here are some other staging logs!", "OUT", time.Now(), sharedaction.StagingLog, "sourceInstance") 104 errorStream <- errors.New("problem getting more staging logs") 105 allLogsWritten <- true 106 }() 107 108 return logStream, errorStream, cancelFunc, v7action.Warnings{"steve for all I care"}, nil 109 } 110 111 fakeActor.StagePackageStub = func(packageGUID, appName, spaceGUID string) (<-chan resources.Droplet, <-chan v7action.Warnings, <-chan error) { 112 dropletStream := make(chan resources.Droplet) 113 warningsStream := make(chan v7action.Warnings) 114 errorStream := make(chan error) 115 116 go func() { 117 <-allLogsWritten 118 defer close(dropletStream) 119 defer close(warningsStream) 120 defer close(errorStream) 121 warningsStream <- v7action.Warnings{"some-warning", "some-other-warning"} 122 dropletStream <- resources.Droplet{ 123 GUID: "some-droplet-guid", 124 CreatedAt: dropletCreateTime, 125 State: constant.DropletStaged, 126 } 127 }() 128 129 return dropletStream, warningsStream, errorStream 130 } 131 }) 132 133 JustBeforeEach(func() { 134 executeErr = cmd.Execute(nil) 135 }) 136 137 When("checking target fails", func() { 138 BeforeEach(func() { 139 fakeSharedActor.CheckTargetReturns(actionerror.NotLoggedInError{BinaryName: binaryName}) 140 }) 141 142 It("displays the experimental warning", func() { 143 Expect(testUI.Err).NotTo(Say("This command is in EXPERIMENTAL stage and may change without notice")) 144 }) 145 146 It("returns an error", func() { 147 Expect(executeErr).To(MatchError(actionerror.NotLoggedInError{BinaryName: binaryName})) 148 149 Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) 150 checkTargetedOrg, checkTargetedSpace := fakeSharedActor.CheckTargetArgsForCall(0) 151 Expect(checkTargetedOrg).To(BeTrue()) 152 Expect(checkTargetedSpace).To(BeTrue()) 153 }) 154 }) 155 156 When("the package's GUID is not passed in", func() { 157 var ( 158 newestPackageGUID string 159 ) 160 161 BeforeEach(func() { 162 cmd.PackageGUID = "" 163 app = resources.Application{GUID: "some-app-guid", Name: "some-name"} 164 newestPackageGUID = "newest-package-guid" 165 166 fakeActor.GetApplicationByNameAndSpaceReturns( 167 app, 168 v7action.Warnings{"app-by-name-warning"}, 169 nil) 170 171 fakeActor.GetNewestReadyPackageForApplicationReturns( 172 v7action.Package{GUID: newestPackageGUID}, 173 v7action.Warnings{"newest-pkg-warning"}, 174 nil) 175 }) 176 177 It("grabs the most recent version", func() { 178 Expect(fakeActor.GetApplicationByNameAndSpaceCallCount()).To(Equal(1)) 179 appNameArg, spaceGUIDArg := fakeActor.GetApplicationByNameAndSpaceArgsForCall(0) 180 Expect(appNameArg).To(Equal(cmd.RequiredArgs.AppName)) 181 Expect(spaceGUIDArg).To(Equal(spaceGUID)) 182 Expect(testUI.Err).To(Say("app-by-name-warning")) 183 184 Expect(fakeActor.GetNewestReadyPackageForApplicationCallCount()).To(Equal(1)) 185 appArg := fakeActor.GetNewestReadyPackageForApplicationArgsForCall(0) 186 Expect(appArg).To(Equal(app)) 187 Expect(testUI.Err).To(Say("newest-pkg-warning")) 188 189 Expect(fakeActor.StagePackageCallCount()).To(Equal(1)) 190 guidArg, appNameArg, spaceGUIDArg := fakeActor.StagePackageArgsForCall(0) 191 Expect(guidArg).To(Equal(newestPackageGUID)) 192 Expect(appNameArg).To(Equal(appName)) 193 Expect(spaceGUIDArg).To(Equal(spaceGUID)) 194 }) 195 When("It can't get the application's information", func() { 196 BeforeEach(func() { 197 fakeActor.GetApplicationByNameAndSpaceReturns( 198 resources.Application{}, 199 v7action.Warnings{"app-warning"}, 200 errors.New("cant-get-app-error")) 201 }) 202 203 It("returns an error", func() { 204 Expect(executeErr).To(HaveOccurred()) 205 Expect(testUI.Err).To(Say("app-warning")) 206 Expect(executeErr).To(MatchError("cant-get-app-error")) 207 }) 208 }) 209 }) 210 211 When("the logging stream has errors", func() { 212 var ( 213 expectedErr error 214 allLogsWritten chan bool 215 closedTheStreams bool 216 ) 217 218 BeforeEach(func() { 219 allLogsWritten = make(chan bool) 220 expectedErr = errors.New("banana") 221 222 fakeActor.GetStreamingLogsForApplicationByNameAndSpaceStub = func(appName string, spaceGUID string, client sharedaction.LogCacheClient) (<-chan sharedaction.LogMessage, <-chan error, context.CancelFunc, v7action.Warnings, error) { 223 logStream := make(chan sharedaction.LogMessage) 224 errorStream := make(chan error) 225 closedTheStreams = false 226 227 cancelFunc := func() { 228 if closedTheStreams { 229 return 230 } 231 closedTheStreams = true 232 close(logStream) 233 close(errorStream) 234 } 235 go func() { 236 logStream <- *sharedaction.NewLogMessage("Here are some staging logs!", "err", time.Now(), sharedaction.StagingLog, "sourceInstance") 237 errorStream <- expectedErr 238 allLogsWritten <- true 239 }() 240 241 return logStream, errorStream, cancelFunc, v7action.Warnings{"steve for all I care"}, nil 242 } 243 244 fakeActor.StagePackageStub = func(packageGUID, _, _ string) (<-chan resources.Droplet, <-chan v7action.Warnings, <-chan error) { 245 dropletStream := make(chan resources.Droplet) 246 warningsStream := make(chan v7action.Warnings) 247 errorStream := make(chan error) 248 249 go func() { 250 <-allLogsWritten 251 defer close(dropletStream) 252 defer close(warningsStream) 253 defer close(errorStream) 254 warningsStream <- v7action.Warnings{"some-warning", "some-other-warning"} 255 dropletStream <- resources.Droplet{ 256 GUID: "some-droplet-guid", 257 CreatedAt: "2017-08-14T21:16:42Z", 258 State: constant.DropletStaged, 259 } 260 }() 261 262 return dropletStream, warningsStream, errorStream 263 } 264 }) 265 266 JustAfterEach(func() { 267 Expect(closedTheStreams).To(BeTrue()) 268 }) 269 270 It("displays the errors and continues staging", func() { 271 Expect(executeErr).ToNot(HaveOccurred()) 272 273 Expect(testUI.Err).To(Say("banana")) 274 Expect(testUI.Err).To(Say("some-warning")) 275 Expect(testUI.Err).To(Say("some-other-warning")) 276 }) 277 }) 278 279 When("the logging returns an error due to an API error", func() { 280 var expectedErr error 281 282 BeforeEach(func() { 283 expectedErr = errors.New("something is wrong!") 284 logStream := make(chan sharedaction.LogMessage) 285 errorStream := make(chan error) 286 cancelFunc := func() { 287 close(logStream) 288 close(errorStream) 289 } 290 fakeActor.GetStreamingLogsForApplicationByNameAndSpaceReturns(logStream, errorStream, cancelFunc, v7action.Warnings{"some-warning", "some-other-warning"}, expectedErr) 291 }) 292 293 It("returns the error and displays warnings", func() { 294 Expect(executeErr).To(Equal(expectedErr)) 295 296 Expect(testUI.Err).To(Say("some-warning")) 297 Expect(testUI.Err).To(Say("some-other-warning")) 298 }) 299 }) 300 301 When("the staging returns an error", func() { 302 var expectedErr error 303 304 BeforeEach(func() { 305 expectedErr = errors.New("any gibberish") 306 fakeActor.StagePackageStub = func(packageGUID, _, _ string) (<-chan resources.Droplet, <-chan v7action.Warnings, <-chan error) { 307 dropletStream := make(chan resources.Droplet) 308 warningsStream := make(chan v7action.Warnings) 309 errorStream := make(chan error) 310 311 go func() { 312 <-allLogsWritten 313 defer close(dropletStream) 314 defer close(warningsStream) 315 defer close(errorStream) 316 warningsStream <- v7action.Warnings{"some-warning", "some-other-warning"} 317 errorStream <- expectedErr 318 }() 319 320 return dropletStream, warningsStream, errorStream 321 } 322 }) 323 324 It("returns the error and displays warnings", func() { 325 Expect(executeErr).To(Equal(expectedErr)) 326 327 Expect(testUI.Err).To(Say("some-warning")) 328 Expect(testUI.Err).To(Say("some-other-warning")) 329 Expect(closedTheStreams).To(BeTrue()) 330 }) 331 }) 332 333 It("outputs the droplet GUID", func() { 334 Expect(executeErr).ToNot(HaveOccurred()) 335 336 createdAtTimeParsed, err := time.Parse(time.RFC3339, dropletCreateTime) 337 Expect(err).ToNot(HaveOccurred()) 338 339 Expect(testUI.Out).To(Say("Staging package for %s in org some-org / space some-space as steve...", appName)) 340 Expect(testUI.Out).To(Say("\n\n")) 341 Expect(testUI.Out).To(Say("Package staged")) 342 Expect(testUI.Out).To(Say(`droplet guid:\s+some-droplet-guid`)) 343 Expect(testUI.Out).To(Say(`state:\s+staged`)) 344 Expect(testUI.Out).To(Say(`created:\s+%s`, testUI.UserFriendlyDate(createdAtTimeParsed))) 345 346 Expect(testUI.Err).To(Say("some-warning")) 347 Expect(testUI.Err).To(Say("some-other-warning")) 348 }) 349 350 It("stages the package", func() { 351 Expect(executeErr).ToNot(HaveOccurred()) 352 Expect(fakeActor.StagePackageCallCount()).To(Equal(1)) 353 guidArg, appNameArg, spaceGUIDArg := fakeActor.StagePackageArgsForCall(0) 354 Expect(guidArg).To(Equal(packageGUID)) 355 Expect(appNameArg).To(Equal(appName)) 356 Expect(spaceGUIDArg).To(Equal("some-space-guid")) 357 }) 358 359 It("displays staging logs and their warnings", func() { 360 Expect(testUI.Out).To(Say("Here are some staging logs!")) 361 Expect(testUI.Out).To(Say("Here are some other staging logs!")) 362 363 Expect(testUI.Err).To(Say("steve for all I care")) 364 Eventually(testUI.Err).Should(Say("Failed to retrieve logs from Log Cache: problem getting more staging logs")) 365 366 Expect(fakeActor.GetStreamingLogsForApplicationByNameAndSpaceCallCount()).To(Equal(1)) 367 appNameArg, spaceGUID, logCacheClient := fakeActor.GetStreamingLogsForApplicationByNameAndSpaceArgsForCall(0) 368 Expect(appNameArg).To(Equal(appName)) 369 Expect(spaceGUID).To(Equal("some-space-guid")) 370 Expect(logCacheClient).To(Equal(fakeLogCacheClient)) 371 372 Expect(fakeActor.StagePackageCallCount()).To(Equal(1)) 373 guidArg, appNameArg, spaceGUIDArg := fakeActor.StagePackageArgsForCall(0) 374 Expect(guidArg).To(Equal(packageGUID)) 375 Expect(appNameArg).To(Equal(appName)) 376 Expect(spaceGUIDArg).To(Equal(spaceGUID)) 377 378 Expect(closedTheStreams).To(BeTrue()) 379 }) 380 })