github.com/LukasHeimann/cloudfoundrycli/v8@v8.4.4/command/v7/unbind_route_service_command_test.go (about) 1 package v7_test 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/LukasHeimann/cloudfoundrycli/v8/actor/actionerror" 8 9 "github.com/LukasHeimann/cloudfoundrycli/v8/actor/v7action" 10 "github.com/LukasHeimann/cloudfoundrycli/v8/command/commandfakes" 11 v7 "github.com/LukasHeimann/cloudfoundrycli/v8/command/v7" 12 "github.com/LukasHeimann/cloudfoundrycli/v8/command/v7/v7fakes" 13 "github.com/LukasHeimann/cloudfoundrycli/v8/util/configv3" 14 "github.com/LukasHeimann/cloudfoundrycli/v8/util/ui" 15 . "github.com/onsi/ginkgo" 16 . "github.com/onsi/gomega" 17 . "github.com/onsi/gomega/gbytes" 18 ) 19 20 var _ = Describe("unbind-route-service Command", func() { 21 var ( 22 cmd v7.UnbindRouteServiceCommand 23 input *Buffer 24 testUI *ui.UI 25 fakeConfig *commandfakes.FakeConfig 26 fakeSharedActor *commandfakes.FakeSharedActor 27 executeErr error 28 fakeActor *v7fakes.FakeActor 29 ) 30 31 const ( 32 fakeUserName = "fake-user-name" 33 fakeServiceInstanceName = "fake-service-instance-name" 34 fakeDomainName = "fake-domain-name" 35 fakeHostname = "fake-hostname" 36 fakePath = "fake-path" 37 fakeOrgName = "fake-org-name" 38 fakeSpaceName = "fake-space-name" 39 fakeSpaceGUID = "fake-space-guid" 40 ) 41 42 BeforeEach(func() { 43 input = NewBuffer() 44 testUI = ui.NewTestUI(input, NewBuffer(), NewBuffer()) 45 fakeConfig = new(commandfakes.FakeConfig) 46 fakeSharedActor = new(commandfakes.FakeSharedActor) 47 fakeActor = new(v7fakes.FakeActor) 48 49 cmd = v7.UnbindRouteServiceCommand{ 50 BaseCommand: v7.BaseCommand{ 51 UI: testUI, 52 Config: fakeConfig, 53 SharedActor: fakeSharedActor, 54 Actor: fakeActor, 55 }, 56 } 57 58 fakeConfig.TargetedSpaceReturns(configv3.Space{ 59 Name: fakeSpaceName, 60 GUID: fakeSpaceGUID, 61 }) 62 63 fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: fakeOrgName}) 64 65 fakeActor.GetCurrentUserReturns(configv3.User{Name: fakeUserName}, nil) 66 67 fakeActor.DeleteRouteBindingReturns( 68 nil, 69 v7action.Warnings{"fake warning"}, 70 nil, 71 ) 72 73 setPositionalFlags(&cmd, fakeDomainName, fakeServiceInstanceName) 74 setFlag(&cmd, "--hostname", fakeHostname) 75 setFlag(&cmd, "--path", fakePath) 76 setFlag(&cmd, "-f") 77 }) 78 79 JustBeforeEach(func() { 80 executeErr = cmd.Execute(nil) 81 }) 82 83 It("succeeds", func() { 84 Expect(executeErr).NotTo(HaveOccurred()) 85 }) 86 87 It("checks the user is logged in, and targeting an org and space", func() { 88 Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) 89 actualOrg, actualSpace := fakeSharedActor.CheckTargetArgsForCall(0) 90 Expect(actualOrg).To(BeTrue()) 91 Expect(actualSpace).To(BeTrue()) 92 }) 93 94 It("delegates to the actor", func() { 95 Expect(fakeActor.DeleteRouteBindingCallCount()).To(Equal(1)) 96 Expect(fakeActor.DeleteRouteBindingArgsForCall(0)).To(Equal(v7action.DeleteRouteBindingParams{ 97 SpaceGUID: fakeSpaceGUID, 98 ServiceInstanceName: fakeServiceInstanceName, 99 DomainName: fakeDomainName, 100 Hostname: fakeHostname, 101 Path: fmt.Sprintf("/%s", fakePath), 102 })) 103 }) 104 105 When("binding does not exist", func() { 106 BeforeEach(func() { 107 fakeActor.DeleteRouteBindingReturns( 108 nil, 109 v7action.Warnings{"fake warning"}, 110 actionerror.RouteBindingNotFoundError{}, 111 ) 112 }) 113 114 It("prints a message and warnings", func() { 115 Expect(testUI.Out).To(SatisfyAll( 116 Say( 117 `Route %s.%s/%s was not bound to service instance %s\.\n`, 118 fakeHostname, 119 fakeDomainName, 120 fakePath, 121 fakeServiceInstanceName, 122 ), 123 Say(`OK\n`), 124 )) 125 126 Expect(testUI.Err).To(Say("fake warning")) 127 }) 128 }) 129 130 Describe("intro message", func() { 131 It("prints an intro and warnings", func() { 132 Expect(executeErr).NotTo(HaveOccurred()) 133 Expect(testUI.Err).To(Say("fake warning")) 134 Expect(testUI.Out).To(Say( 135 `Unbinding route %s.%s/%s from service instance %s in org %s / space %s as %s\.\.\.\n`, 136 fakeHostname, 137 fakeDomainName, 138 fakePath, 139 fakeServiceInstanceName, 140 fakeOrgName, 141 fakeSpaceName, 142 fakeUserName, 143 )) 144 }) 145 146 When("no hostname", func() { 147 BeforeEach(func() { 148 setFlag(&cmd, "--hostname", "") 149 }) 150 151 It("prints an appropriate intro", func() { 152 Expect(testUI.Out).To(Say( 153 `Unbinding route %s/%s from service instance`, 154 fakeDomainName, 155 fakePath, 156 )) 157 }) 158 }) 159 160 When("no path", func() { 161 BeforeEach(func() { 162 setFlag(&cmd, "--path", "") 163 }) 164 165 It("prints an appropriate intro", func() { 166 Expect(testUI.Out).To(Say( 167 `Unbinding route %s.%s from service instance`, 168 fakeHostname, 169 fakeDomainName, 170 )) 171 }) 172 }) 173 174 When("no hostname or path", func() { 175 BeforeEach(func() { 176 setFlag(&cmd, "--path", "") 177 setFlag(&cmd, "--hostname", "") 178 }) 179 180 It("prints an appropriate intro", func() { 181 Expect(testUI.Out).To(Say( 182 `Unbinding route %s from service instance`, 183 fakeDomainName, 184 )) 185 }) 186 }) 187 }) 188 189 Describe("prompting the user", func() { 190 BeforeEach(func() { 191 setFlag(&cmd, "-f", false) 192 }) 193 194 It("prompts the user", func() { 195 Expect(testUI.Out).To(Say( 196 `Really unbind route %s.%s/%s from service instance %s\? \[yN\]:`, 197 fakeHostname, 198 fakeDomainName, 199 fakePath, 200 fakeServiceInstanceName, 201 )) 202 }) 203 204 When("no hostname", func() { 205 BeforeEach(func() { 206 setFlag(&cmd, "--hostname", "") 207 }) 208 209 It("prompts the user", func() { 210 Expect(testUI.Out).To(Say( 211 `Really unbind route %s/%s from service instance %s\? \[yN\]:`, 212 fakeDomainName, 213 fakePath, 214 fakeServiceInstanceName, 215 )) 216 }) 217 }) 218 219 When("no path", func() { 220 BeforeEach(func() { 221 setFlag(&cmd, "--path", "") 222 }) 223 224 It("prompts the user", func() { 225 Expect(testUI.Out).To(Say( 226 `Really unbind route %s.%s from service instance %s\? \[yN\]:`, 227 fakeHostname, 228 fakeDomainName, 229 fakeServiceInstanceName, 230 )) 231 }) 232 }) 233 234 When("no hostname or path", func() { 235 BeforeEach(func() { 236 setFlag(&cmd, "--hostname", "") 237 setFlag(&cmd, "--path", "") 238 }) 239 240 It("prompts the user", func() { 241 Expect(testUI.Out).To(Say( 242 `Really unbind route %s from service instance %s\? \[yN\]:`, 243 fakeDomainName, 244 fakeServiceInstanceName, 245 )) 246 }) 247 }) 248 249 When("user says no", func() { 250 BeforeEach(func() { 251 _, err := input.Write([]byte("n\n")) 252 Expect(err).NotTo(HaveOccurred()) 253 }) 254 255 It("does not call the actor", func() { 256 Expect(fakeActor.DeleteRouteBindingCallCount()).To(BeZero()) 257 }) 258 259 It("says the unbind was cancelled", func() { 260 Expect(executeErr).NotTo(HaveOccurred()) 261 Expect(testUI.Out).To(Say("Unbind cancelled\n")) 262 }) 263 }) 264 265 When("user says yes", func() { 266 BeforeEach(func() { 267 _, err := input.Write([]byte("y\n")) 268 Expect(err).NotTo(HaveOccurred()) 269 }) 270 271 It("calls the actor", func() { 272 Expect(fakeActor.DeleteRouteBindingCallCount()).To(Equal(1)) 273 }) 274 }) 275 }) 276 277 Describe("processing the response stream", func() { 278 Context("nil stream", func() { 279 It("prints a message and warnings", func() { 280 Expect(testUI.Out).To(Say(`OK\n`)) 281 Expect(testUI.Err).To(Say("fake warning")) 282 }) 283 }) 284 285 Context("stream goes to complete", func() { 286 BeforeEach(func() { 287 eventStream := make(chan v7action.PollJobEvent) 288 go func() { 289 eventStream <- v7action.PollJobEvent{ 290 State: v7action.JobProcessing, 291 Warnings: v7action.Warnings{"job processing warning"}, 292 } 293 eventStream <- v7action.PollJobEvent{ 294 State: v7action.JobComplete, 295 Warnings: v7action.Warnings{"job complete warning"}, 296 } 297 close(eventStream) 298 }() 299 300 fakeActor.DeleteRouteBindingReturns( 301 eventStream, 302 v7action.Warnings{"fake warning"}, 303 nil, 304 ) 305 }) 306 307 It("prints a message and warnings", func() { 308 Expect(testUI.Out).To(Say(`OK\n`)) 309 310 Expect(testUI.Err).To(SatisfyAll( 311 Say("fake warning"), 312 Say("job processing warning"), 313 Say("job complete warning"), 314 )) 315 }) 316 }) 317 318 Context("stream goes to polling", func() { 319 BeforeEach(func() { 320 eventStream := make(chan v7action.PollJobEvent) 321 go func() { 322 eventStream <- v7action.PollJobEvent{ 323 State: v7action.JobProcessing, 324 Warnings: v7action.Warnings{"job processing warning"}, 325 } 326 eventStream <- v7action.PollJobEvent{ 327 State: v7action.JobPolling, 328 Warnings: v7action.Warnings{"job polling warning"}, 329 } 330 }() 331 332 fakeActor.DeleteRouteBindingReturns( 333 eventStream, 334 v7action.Warnings{"fake warning"}, 335 nil, 336 ) 337 }) 338 339 It("prints a message and warnings", func() { 340 Expect(testUI.Out).To(SatisfyAll( 341 Say(`OK\n`), 342 Say(`\n`), 343 Say(`Unbinding in progress\.\n`), 344 )) 345 346 Expect(testUI.Err).To(SatisfyAll( 347 Say("fake warning"), 348 Say("job processing warning"), 349 Say("job polling warning"), 350 )) 351 }) 352 }) 353 354 Context("stream goes to error", func() { 355 BeforeEach(func() { 356 eventStream := make(chan v7action.PollJobEvent) 357 go func() { 358 eventStream <- v7action.PollJobEvent{ 359 State: v7action.JobFailed, 360 Warnings: v7action.Warnings{"job failed warning"}, 361 Err: errors.New("boom"), 362 } 363 }() 364 365 fakeActor.DeleteRouteBindingReturns( 366 eventStream, 367 v7action.Warnings{"fake warning"}, 368 nil, 369 ) 370 }) 371 372 It("prints warnings and returns the error", func() { 373 Expect(executeErr).To(MatchError("boom")) 374 375 Expect(testUI.Err).To(SatisfyAll( 376 Say("fake warning"), 377 Say("job failed warning"), 378 )) 379 }) 380 }) 381 382 When("--wait flag specified", func() { 383 BeforeEach(func() { 384 eventStream := make(chan v7action.PollJobEvent) 385 go func() { 386 eventStream <- v7action.PollJobEvent{ 387 State: v7action.JobProcessing, 388 Warnings: v7action.Warnings{"job processing warning"}, 389 } 390 eventStream <- v7action.PollJobEvent{ 391 State: v7action.JobPolling, 392 Warnings: v7action.Warnings{"job polling warning"}, 393 } 394 eventStream <- v7action.PollJobEvent{ 395 State: v7action.JobComplete, 396 Warnings: v7action.Warnings{"job complete warning"}, 397 } 398 close(eventStream) 399 }() 400 401 fakeActor.DeleteRouteBindingReturns( 402 eventStream, 403 v7action.Warnings{"fake warning"}, 404 nil, 405 ) 406 407 setFlag(&cmd, "--wait") 408 }) 409 410 It("waits for the event stream to complete", func() { 411 Expect(testUI.Out).To(SatisfyAll( 412 Say(`Waiting for the operation to complete\.\.\.\n`), 413 Say(`\n`), 414 Say(`OK\n`), 415 )) 416 417 Expect(testUI.Err).To(SatisfyAll( 418 Say("fake warning"), 419 Say("job processing warning"), 420 Say("job polling warning"), 421 Say("job complete warning"), 422 )) 423 }) 424 }) 425 }) 426 427 Describe("error scenarios", func() { 428 When("checking the target returns an error", func() { 429 BeforeEach(func() { 430 fakeSharedActor.CheckTargetReturns(errors.New("explode")) 431 }) 432 433 It("returns the error", func() { 434 Expect(executeErr).To(MatchError("explode")) 435 }) 436 }) 437 438 When("actor returns error", func() { 439 BeforeEach(func() { 440 fakeActor.DeleteRouteBindingReturns( 441 nil, 442 v7action.Warnings{"fake warning"}, 443 errors.New("boom"), 444 ) 445 }) 446 447 It("prints warnings and returns the error", func() { 448 Expect(testUI.Err).To(Say("fake warning")) 449 Expect(executeErr).To(MatchError("boom")) 450 }) 451 }) 452 453 When("getting the username returns an error", func() { 454 BeforeEach(func() { 455 fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("bad thing")) 456 }) 457 458 It("returns the error", func() { 459 Expect(executeErr).To(MatchError("bad thing")) 460 }) 461 }) 462 }) 463 })