github.com/LukasHeimann/cloudfoundrycli/v8@v8.4.4/command/v7/delete_service_command_test.go (about) 1 package v7_test 2 3 import ( 4 "errors" 5 6 "github.com/LukasHeimann/cloudfoundrycli/v8/actor/actionerror" 7 "github.com/LukasHeimann/cloudfoundrycli/v8/actor/v7action" 8 "github.com/LukasHeimann/cloudfoundrycli/v8/command/commandfakes" 9 . "github.com/LukasHeimann/cloudfoundrycli/v8/command/v7" 10 "github.com/LukasHeimann/cloudfoundrycli/v8/command/v7/v7fakes" 11 "github.com/LukasHeimann/cloudfoundrycli/v8/util/configv3" 12 "github.com/LukasHeimann/cloudfoundrycli/v8/util/ui" 13 . "github.com/onsi/ginkgo" 14 . "github.com/onsi/gomega" 15 . "github.com/onsi/gomega/gbytes" 16 ) 17 18 var _ = Describe("delete-service command", func() { 19 const ( 20 serviceInstanceName = "service-instance-name" 21 orgName = "fake-org-name" 22 spaceName = "fake-space-name" 23 spaceGUID = "fake-space-guid" 24 username = "fake-username" 25 ) 26 27 var ( 28 input *Buffer 29 testUI *ui.UI 30 fakeConfig *commandfakes.FakeConfig 31 fakeSharedActor *commandfakes.FakeSharedActor 32 fakeActor *v7fakes.FakeActor 33 cmd DeleteServiceCommand 34 executeErr error 35 ) 36 37 testActorInteractions := func() { 38 It("delegates to the actor", func() { 39 Expect(fakeActor.DeleteServiceInstanceCallCount()).To(Equal(1)) 40 actualName, actualSpaceGUID := fakeActor.DeleteServiceInstanceArgsForCall(0) 41 Expect(actualName).To(Equal(serviceInstanceName)) 42 Expect(actualSpaceGUID).To(Equal(spaceGUID)) 43 }) 44 45 When("the service instance did not exist", func() { 46 BeforeEach(func() { 47 fakeActor.DeleteServiceInstanceReturns( 48 nil, 49 v7action.Warnings{"delete warning"}, 50 actionerror.ServiceInstanceNotFoundError{}, 51 ) 52 }) 53 54 It("succeeds with a message", func() { 55 Expect(executeErr).NotTo(HaveOccurred()) 56 Expect(testUI.Err).To(Say("delete warning")) 57 Expect(testUI.Out).To(SatisfyAll( 58 Say("\n"), 59 Say(`Service instance %s did not exist\.\n`, serviceInstanceName), 60 Say("OK\n"), 61 )) 62 }) 63 }) 64 65 When("the service instance is successfully deleted", func() { 66 BeforeEach(func() { 67 fakeActor.DeleteServiceInstanceReturns( 68 nil, 69 v7action.Warnings{"delete warning"}, 70 nil, 71 ) 72 }) 73 74 It("succeeds with a message", func() { 75 Expect(executeErr).NotTo(HaveOccurred()) 76 Expect(testUI.Err).To(Say("delete warning")) 77 Expect(testUI.Out).To(SatisfyAll( 78 Say("\n"), 79 Say(`Service instance %s deleted\.\n`, serviceInstanceName), 80 Say("OK\n"), 81 )) 82 }) 83 }) 84 85 When("the service instance deletion is in progress", func() { 86 BeforeEach(func() { 87 fakeActor.DeleteServiceInstanceCalls(func(name, spaceGUID string) (chan v7action.PollJobEvent, v7action.Warnings, error) { 88 stream := make(chan v7action.PollJobEvent) 89 90 go func() { 91 stream <- v7action.PollJobEvent{ 92 State: v7action.JobPolling, 93 } 94 // channel not closed 95 }() 96 97 return stream, v7action.Warnings{"delete warning"}, nil 98 }) 99 }) 100 101 It("succeeds with a message", func() { 102 Expect(executeErr).NotTo(HaveOccurred()) 103 Expect(testUI.Err).To(Say("delete warning")) 104 Expect(testUI.Out).To(SatisfyAll( 105 Say("\n"), 106 Say(`Delete in progress. Use 'cf services' or 'cf service %s' to check operation status\.\n`, serviceInstanceName), 107 Say("OK\n"), 108 )) 109 }) 110 111 When("there is a warning in the event stream", func() { 112 BeforeEach(func() { 113 fakeActor.DeleteServiceInstanceCalls(func(name, spaceGUID string) (chan v7action.PollJobEvent, v7action.Warnings, error) { 114 stream := make(chan v7action.PollJobEvent) 115 116 go func() { 117 stream <- v7action.PollJobEvent{ 118 Warnings: v7action.Warnings{"stream warning"}, 119 } 120 close(stream) 121 }() 122 123 return stream, v7action.Warnings{"delete warning"}, nil 124 }) 125 }) 126 127 It("prints it", func() { 128 Expect(testUI.Err).To(Say("stream warning")) 129 }) 130 }) 131 132 When("there is an error in the event stream", func() { 133 BeforeEach(func() { 134 fakeActor.DeleteServiceInstanceCalls(func(name, spaceGUID string) (chan v7action.PollJobEvent, v7action.Warnings, error) { 135 stream := make(chan v7action.PollJobEvent) 136 137 go func() { 138 stream <- v7action.PollJobEvent{ 139 Err: errors.New("stream error"), 140 } 141 close(stream) 142 }() 143 144 return stream, v7action.Warnings{"delete warning"}, nil 145 }) 146 }) 147 148 It("returns it", func() { 149 Expect(executeErr).To(MatchError("stream error")) 150 }) 151 }) 152 }) 153 154 When("the actor returns an error", func() { 155 BeforeEach(func() { 156 fakeActor.DeleteServiceInstanceReturns( 157 nil, 158 v7action.Warnings{"delete warning"}, 159 errors.New("bang"), 160 ) 161 }) 162 163 It("fails with warnings", func() { 164 Expect(executeErr).To(MatchError("bang")) 165 Expect(testUI.Err).To(Say("delete warning")) 166 Expect(testUI.Out).NotTo(Say("OK")) 167 }) 168 }) 169 170 When("the -w flag is specified", func() { 171 BeforeEach(func() { 172 setFlag(&cmd, "-w") 173 174 fakeActor.DeleteServiceInstanceCalls(func(name, spaceGUID string) (chan v7action.PollJobEvent, v7action.Warnings, error) { 175 stream := make(chan v7action.PollJobEvent) 176 177 go func() { 178 stream <- v7action.PollJobEvent{State: v7action.JobPolling} 179 stream <- v7action.PollJobEvent{State: v7action.JobComplete} 180 close(stream) 181 }() 182 183 return stream, v7action.Warnings{"delete warning"}, nil 184 }) 185 }) 186 187 It("succeeds with a message", func() { 188 Expect(executeErr).NotTo(HaveOccurred()) 189 Expect(testUI.Err).To(Say("delete warning")) 190 Expect(testUI.Out).To(SatisfyAll( 191 Say(`Waiting for the operation to complete\.\.\n`), 192 Say("\n"), 193 Say(`Service instance %s deleted\.\n`, serviceInstanceName), 194 Say("OK\n"), 195 )) 196 }) 197 198 When("there is a warning in the event stream", func() { 199 BeforeEach(func() { 200 fakeActor.DeleteServiceInstanceCalls(func(name, spaceGUID string) (chan v7action.PollJobEvent, v7action.Warnings, error) { 201 stream := make(chan v7action.PollJobEvent) 202 203 go func() { 204 stream <- v7action.PollJobEvent{ 205 Warnings: v7action.Warnings{"stream warning"}, 206 } 207 close(stream) 208 }() 209 210 return stream, v7action.Warnings{"delete warning"}, nil 211 }) 212 }) 213 214 It("prints it", func() { 215 Expect(testUI.Err).To(Say("stream warning")) 216 }) 217 }) 218 219 When("there is an error in the event stream", func() { 220 BeforeEach(func() { 221 fakeActor.DeleteServiceInstanceCalls(func(name, spaceGUID string) (chan v7action.PollJobEvent, v7action.Warnings, error) { 222 stream := make(chan v7action.PollJobEvent) 223 224 go func() { 225 stream <- v7action.PollJobEvent{ 226 Err: errors.New("stream error"), 227 } 228 close(stream) 229 }() 230 231 return stream, v7action.Warnings{"delete warning"}, nil 232 }) 233 }) 234 235 It("returns it", func() { 236 Expect(executeErr).To(MatchError("stream error")) 237 }) 238 }) 239 }) 240 } 241 242 confirmYes := func() { 243 _, err := input.Write([]byte("y\n")) 244 Expect(err).NotTo(HaveOccurred()) 245 } 246 247 BeforeEach(func() { 248 input = NewBuffer() 249 testUI = ui.NewTestUI(input, NewBuffer(), NewBuffer()) 250 fakeConfig = new(commandfakes.FakeConfig) 251 fakeSharedActor = new(commandfakes.FakeSharedActor) 252 fakeActor = new(v7fakes.FakeActor) 253 254 fakeConfig.TargetedOrganizationReturns(configv3.Organization{Name: orgName}) 255 fakeConfig.TargetedSpaceReturns(configv3.Space{Name: spaceName, GUID: spaceGUID}) 256 fakeActor.GetCurrentUserReturns(configv3.User{Name: username}, nil) 257 258 cmd = DeleteServiceCommand{ 259 BaseCommand: BaseCommand{ 260 UI: testUI, 261 Config: fakeConfig, 262 SharedActor: fakeSharedActor, 263 Actor: fakeActor, 264 }, 265 } 266 267 setPositionalFlags(&cmd, serviceInstanceName) 268 }) 269 270 JustBeforeEach(func() { 271 executeErr = cmd.Execute(nil) 272 }) 273 274 It("checks the user is logged in, and targeting an org and space", func() { 275 Expect(fakeSharedActor.CheckTargetCallCount()).To(Equal(1)) 276 orgChecked, spaceChecked := fakeSharedActor.CheckTargetArgsForCall(0) 277 Expect(orgChecked).To(BeTrue()) 278 Expect(spaceChecked).To(BeTrue()) 279 }) 280 281 It("prompts the user", func() { 282 Expect(testUI.Out).To(SatisfyAll( 283 Say(`This action impacts all resources scoped to this service instance, including service bindings, service keys and route bindings\.`), 284 Say(`This will remove the service instance from any spaces where it has been shared\.`), 285 Say(`Really delete the service instance %s\? \[yN\]:`, serviceInstanceName), 286 )) 287 }) 288 289 When("the user says yes", func() { 290 BeforeEach(func() { 291 confirmYes() 292 }) 293 294 It("informs the user what it is doing", func() { 295 Expect(testUI.Out).To(SatisfyAll( 296 Say(`Deleting service instance %s in org %s / space %s as %s\.\.\.\n`, serviceInstanceName, orgName, spaceName, username), 297 Say(`\n`), 298 )) 299 }) 300 301 testActorInteractions() 302 }) 303 304 When("the user says no", func() { 305 BeforeEach(func() { 306 _, err := input.Write([]byte("n\n")) 307 Expect(err).NotTo(HaveOccurred()) 308 }) 309 310 It("does not call the actor", func() { 311 Expect(fakeActor.DeleteServiceInstanceCallCount()).To(BeZero()) 312 }) 313 314 It("says the delete was cancelled", func() { 315 Expect(executeErr).NotTo(HaveOccurred()) 316 Expect(testUI.Out).To(Say("Delete cancelled\n")) 317 }) 318 }) 319 320 When("the -f flag is specified", func() { 321 BeforeEach(func() { 322 setFlag(&cmd, "-f") 323 }) 324 325 It("does not prompt the user", func() { 326 Expect(testUI.Out).NotTo(Say("Really delete")) 327 }) 328 329 testActorInteractions() 330 }) 331 332 Context("errors", func() { 333 When("checking the target returns an error", func() { 334 BeforeEach(func() { 335 fakeSharedActor.CheckTargetReturns(errors.New("explode")) 336 }) 337 338 It("returns the error", func() { 339 Expect(executeErr).To(MatchError("explode")) 340 }) 341 }) 342 343 When("getting the username fails", func() { 344 BeforeEach(func() { 345 fakeActor.GetCurrentUserReturns(configv3.User{}, errors.New("boom")) 346 confirmYes() 347 }) 348 349 It("returns the error", func() { 350 Expect(executeErr).To(MatchError("boom")) 351 }) 352 }) 353 }) 354 })