github.com/cloudfoundry-attic/cli-with-i18n@v6.32.1-0.20171002233121-7401370d3b85+incompatible/command/common/install_plugin_command_test.go (about) 1 package common_test 2 3 import ( 4 "errors" 5 "io/ioutil" 6 "os" 7 8 "code.cloudfoundry.org/cli/actor/pluginaction" 9 "code.cloudfoundry.org/cli/api/plugin/pluginerror" 10 "code.cloudfoundry.org/cli/api/plugin/pluginfakes" 11 "code.cloudfoundry.org/cli/command/commandfakes" 12 . "code.cloudfoundry.org/cli/command/common" 13 "code.cloudfoundry.org/cli/command/common/commonfakes" 14 "code.cloudfoundry.org/cli/command/translatableerror" 15 "code.cloudfoundry.org/cli/util/configv3" 16 "code.cloudfoundry.org/cli/util/ui" 17 . "github.com/onsi/ginkgo" 18 . "github.com/onsi/gomega" 19 . "github.com/onsi/gomega/gbytes" 20 ) 21 22 var _ = Describe("install-plugin command", func() { 23 var ( 24 cmd InstallPluginCommand 25 testUI *ui.UI 26 input *Buffer 27 fakeConfig *commandfakes.FakeConfig 28 fakeActor *commonfakes.FakeInstallPluginActor 29 fakeProgressBar *pluginfakes.FakeProxyReader 30 executeErr error 31 expectedErr error 32 pluginHome string 33 ) 34 35 BeforeEach(func() { 36 input = NewBuffer() 37 testUI = ui.NewTestUI(input, NewBuffer(), NewBuffer()) 38 fakeConfig = new(commandfakes.FakeConfig) 39 fakeActor = new(commonfakes.FakeInstallPluginActor) 40 fakeProgressBar = new(pluginfakes.FakeProxyReader) 41 42 cmd = InstallPluginCommand{ 43 UI: testUI, 44 Config: fakeConfig, 45 Actor: fakeActor, 46 ProgressBar: fakeProgressBar, 47 } 48 49 var err error 50 pluginHome, err = ioutil.TempDir("", "some-pluginhome") 51 Expect(err).NotTo(HaveOccurred()) 52 53 fakeConfig.PluginHomeReturns(pluginHome) 54 fakeConfig.BinaryNameReturns("faceman") 55 }) 56 57 AfterEach(func() { 58 os.RemoveAll(pluginHome) 59 }) 60 61 JustBeforeEach(func() { 62 executeErr = cmd.Execute(nil) 63 }) 64 65 Describe("installing from a local file", func() { 66 BeforeEach(func() { 67 cmd.OptionalArgs.PluginNameOrLocation = "some-path" 68 }) 69 70 Context("when the local file does not exist", func() { 71 BeforeEach(func() { 72 fakeActor.FileExistsReturns(false) 73 }) 74 75 It("does not print installation messages and returns a FileNotFoundError", func() { 76 Expect(executeErr).To(MatchError(translatableerror.PluginNotFoundOnDiskOrInAnyRepositoryError{PluginName: "some-path", BinaryName: "faceman"})) 77 78 Expect(testUI.Out).ToNot(Say("Attention: Plugins are binaries written by potentially untrusted authors\\.")) 79 Expect(testUI.Out).ToNot(Say("Installing plugin some-path\\.\\.\\.")) 80 }) 81 }) 82 83 Context("when the file exists", func() { 84 BeforeEach(func() { 85 fakeActor.CreateExecutableCopyReturns("copy-path", nil) 86 fakeActor.FileExistsReturns(true) 87 }) 88 89 Context("when the -f argument is given", func() { 90 BeforeEach(func() { 91 cmd.Force = true 92 }) 93 94 Context("when the plugin is invalid", func() { 95 var returnedErr error 96 97 BeforeEach(func() { 98 returnedErr = pluginaction.PluginInvalidError{} 99 fakeActor.GetAndValidatePluginReturns(configv3.Plugin{}, returnedErr) 100 }) 101 102 It("returns an error", func() { 103 Expect(executeErr).To(MatchError(translatableerror.PluginInvalidError{})) 104 105 Expect(testUI.Out).ToNot(Say("Installing plugin")) 106 }) 107 }) 108 109 Context("when the plugin is valid but generates an error when fetching metadata", func() { 110 var wrappedErr error 111 112 BeforeEach(func() { 113 wrappedErr = errors.New("some-error") 114 fakeActor.GetAndValidatePluginReturns(configv3.Plugin{}, pluginaction.PluginInvalidError{Err: wrappedErr}) 115 }) 116 117 It("returns an error", func() { 118 Expect(executeErr).To(MatchError(translatableerror.PluginInvalidError{Err: wrappedErr})) 119 120 Expect(testUI.Out).ToNot(Say("Installing plugin")) 121 }) 122 }) 123 124 Context("when the plugin is already installed", func() { 125 var plugin configv3.Plugin 126 127 BeforeEach(func() { 128 plugin = configv3.Plugin{ 129 Name: "some-plugin", 130 Version: configv3.PluginVersion{ 131 Major: 1, 132 Minor: 2, 133 Build: 3, 134 }, 135 } 136 fakeActor.GetAndValidatePluginReturns(plugin, nil) 137 fakeActor.IsPluginInstalledReturns(true) 138 }) 139 140 Context("when an error is encountered uninstalling the existing plugin", func() { 141 BeforeEach(func() { 142 expectedErr = errors.New("uninstall plugin error") 143 fakeActor.UninstallPluginReturns(expectedErr) 144 }) 145 146 It("returns the error", func() { 147 Expect(executeErr).To(MatchError(expectedErr)) 148 149 Expect(testUI.Out).ToNot(Say("Plugin some-plugin successfully uninstalled\\.")) 150 }) 151 }) 152 153 Context("when no errors are encountered uninstalling the existing plugin", func() { 154 It("uninstalls the existing plugin and installs the current plugin", func() { 155 Expect(executeErr).ToNot(HaveOccurred()) 156 157 Expect(testUI.Out).To(Say("Attention: Plugins are binaries written by potentially untrusted authors\\.")) 158 Expect(testUI.Out).To(Say("Install and use plugins at your own risk\\.")) 159 Expect(testUI.Out).To(Say("Plugin some-plugin 1\\.2\\.3 is already installed\\. Uninstalling existing plugin\\.\\.\\.")) 160 Expect(testUI.Out).To(Say("OK")) 161 Expect(testUI.Out).To(Say("Plugin some-plugin successfully uninstalled\\.")) 162 Expect(testUI.Out).To(Say("Installing plugin some-plugin\\.\\.\\.")) 163 Expect(testUI.Out).To(Say("OK")) 164 Expect(testUI.Out).To(Say("Plugin some-plugin 1\\.2\\.3 successfully installed\\.")) 165 166 Expect(fakeActor.FileExistsCallCount()).To(Equal(1)) 167 Expect(fakeActor.FileExistsArgsForCall(0)).To(Equal("some-path")) 168 169 Expect(fakeActor.GetAndValidatePluginCallCount()).To(Equal(1)) 170 _, _, path := fakeActor.GetAndValidatePluginArgsForCall(0) 171 Expect(path).To(Equal("copy-path")) 172 173 Expect(fakeActor.IsPluginInstalledCallCount()).To(Equal(1)) 174 Expect(fakeActor.IsPluginInstalledArgsForCall(0)).To(Equal("some-plugin")) 175 176 Expect(fakeActor.UninstallPluginCallCount()).To(Equal(1)) 177 _, pluginName := fakeActor.UninstallPluginArgsForCall(0) 178 Expect(pluginName).To(Equal("some-plugin")) 179 180 Expect(fakeActor.InstallPluginFromPathCallCount()).To(Equal(1)) 181 path, installedPlugin := fakeActor.InstallPluginFromPathArgsForCall(0) 182 Expect(path).To(Equal("copy-path")) 183 Expect(installedPlugin).To(Equal(plugin)) 184 }) 185 186 Context("when an error is encountered installing the plugin", func() { 187 BeforeEach(func() { 188 expectedErr = errors.New("install plugin error") 189 fakeActor.InstallPluginFromPathReturns(expectedErr) 190 }) 191 192 It("returns the error", func() { 193 Expect(executeErr).To(MatchError(expectedErr)) 194 195 Expect(testUI.Out).ToNot(Say("Plugin some-plugin 1\\.2\\.3 successfully installed\\.")) 196 }) 197 }) 198 }) 199 }) 200 201 Context("when the plugin is not already installed", func() { 202 var plugin configv3.Plugin 203 204 BeforeEach(func() { 205 plugin = configv3.Plugin{ 206 Name: "some-plugin", 207 Version: configv3.PluginVersion{ 208 Major: 1, 209 Minor: 2, 210 Build: 3, 211 }, 212 } 213 fakeActor.GetAndValidatePluginReturns(plugin, nil) 214 }) 215 216 It("installs the plugin", func() { 217 Expect(executeErr).ToNot(HaveOccurred()) 218 219 Expect(testUI.Out).To(Say("Attention: Plugins are binaries written by potentially untrusted authors\\.")) 220 Expect(testUI.Out).To(Say("Install and use plugins at your own risk\\.")) 221 Expect(testUI.Out).To(Say("Installing plugin some-plugin\\.\\.\\.")) 222 Expect(testUI.Out).To(Say("OK")) 223 Expect(testUI.Out).To(Say("Plugin some-plugin 1\\.2\\.3 successfully installed\\.")) 224 225 Expect(fakeActor.FileExistsCallCount()).To(Equal(1)) 226 Expect(fakeActor.FileExistsArgsForCall(0)).To(Equal("some-path")) 227 228 Expect(fakeActor.CreateExecutableCopyCallCount()).To(Equal(1)) 229 pathArg, pluginDirArg := fakeActor.CreateExecutableCopyArgsForCall(0) 230 Expect(pathArg).To(Equal("some-path")) 231 Expect(pluginDirArg).To(ContainSubstring("some-pluginhome")) 232 Expect(pluginDirArg).To(ContainSubstring("temp")) 233 234 Expect(fakeActor.GetAndValidatePluginCallCount()).To(Equal(1)) 235 _, _, path := fakeActor.GetAndValidatePluginArgsForCall(0) 236 Expect(path).To(Equal("copy-path")) 237 238 Expect(fakeActor.IsPluginInstalledCallCount()).To(Equal(1)) 239 Expect(fakeActor.IsPluginInstalledArgsForCall(0)).To(Equal("some-plugin")) 240 241 Expect(fakeActor.InstallPluginFromPathCallCount()).To(Equal(1)) 242 path, installedPlugin := fakeActor.InstallPluginFromPathArgsForCall(0) 243 Expect(path).To(Equal("copy-path")) 244 Expect(installedPlugin).To(Equal(plugin)) 245 246 Expect(fakeActor.UninstallPluginCallCount()).To(Equal(0)) 247 }) 248 249 Context("when there is an error making an executable copy of the plugin binary", func() { 250 BeforeEach(func() { 251 expectedErr = errors.New("create executable copy error") 252 fakeActor.CreateExecutableCopyReturns("", expectedErr) 253 }) 254 255 It("returns the error", func() { 256 Expect(executeErr).To(MatchError(expectedErr)) 257 }) 258 }) 259 260 Context("when an error is encountered installing the plugin", func() { 261 BeforeEach(func() { 262 expectedErr = errors.New("install plugin error") 263 fakeActor.InstallPluginFromPathReturns(expectedErr) 264 }) 265 266 It("returns the error", func() { 267 Expect(executeErr).To(MatchError(expectedErr)) 268 269 Expect(testUI.Out).ToNot(Say("Plugin some-plugin 1\\.2\\.3 successfully installed\\.")) 270 }) 271 }) 272 }) 273 }) 274 275 Context("when the -f argument is not given (user is prompted for confirmation)", func() { 276 BeforeEach(func() { 277 cmd.Force = false 278 }) 279 280 Context("when the user chooses no", func() { 281 BeforeEach(func() { 282 input.Write([]byte("n\n")) 283 }) 284 285 It("cancels plugin installation", func() { 286 Expect(executeErr).ToNot(HaveOccurred()) 287 288 Expect(testUI.Out).To(Say("Plugin installation cancelled\\.")) 289 }) 290 }) 291 292 Context("when the user chooses the default", func() { 293 BeforeEach(func() { 294 input.Write([]byte("\n")) 295 }) 296 297 It("cancels plugin installation", func() { 298 Expect(executeErr).ToNot(HaveOccurred()) 299 300 Expect(testUI.Out).To(Say("Plugin installation cancelled\\.")) 301 }) 302 }) 303 304 Context("when the user input is invalid", func() { 305 BeforeEach(func() { 306 input.Write([]byte("e\n")) 307 }) 308 309 It("returns an error", func() { 310 Expect(executeErr).To(HaveOccurred()) 311 312 Expect(testUI.Out).ToNot(Say("Installing plugin")) 313 }) 314 }) 315 316 Context("when the user chooses yes", func() { 317 BeforeEach(func() { 318 input.Write([]byte("y\n")) 319 }) 320 321 Context("when the plugin is not already installed", func() { 322 var plugin configv3.Plugin 323 324 BeforeEach(func() { 325 plugin = configv3.Plugin{ 326 Name: "some-plugin", 327 Version: configv3.PluginVersion{ 328 Major: 1, 329 Minor: 2, 330 Build: 3, 331 }, 332 } 333 fakeActor.GetAndValidatePluginReturns(plugin, nil) 334 }) 335 336 It("installs the plugin", func() { 337 Expect(executeErr).ToNot(HaveOccurred()) 338 339 Expect(testUI.Out).To(Say("Attention: Plugins are binaries written by potentially untrusted authors\\.")) 340 Expect(testUI.Out).To(Say("Install and use plugins at your own risk\\.")) 341 Expect(testUI.Out).To(Say("Do you want to install the plugin some-path\\? \\[yN\\]")) 342 Expect(testUI.Out).To(Say("Installing plugin some-plugin\\.\\.\\.")) 343 Expect(testUI.Out).To(Say("OK")) 344 Expect(testUI.Out).To(Say("Plugin some-plugin 1\\.2\\.3 successfully installed\\.")) 345 346 Expect(fakeActor.FileExistsCallCount()).To(Equal(1)) 347 Expect(fakeActor.FileExistsArgsForCall(0)).To(Equal("some-path")) 348 349 Expect(fakeActor.GetAndValidatePluginCallCount()).To(Equal(1)) 350 _, _, path := fakeActor.GetAndValidatePluginArgsForCall(0) 351 Expect(path).To(Equal("copy-path")) 352 353 Expect(fakeActor.IsPluginInstalledCallCount()).To(Equal(1)) 354 Expect(fakeActor.IsPluginInstalledArgsForCall(0)).To(Equal("some-plugin")) 355 356 Expect(fakeActor.InstallPluginFromPathCallCount()).To(Equal(1)) 357 path, plugin := fakeActor.InstallPluginFromPathArgsForCall(0) 358 Expect(path).To(Equal("copy-path")) 359 Expect(plugin).To(Equal(plugin)) 360 361 Expect(fakeActor.UninstallPluginCallCount()).To(Equal(0)) 362 }) 363 }) 364 365 Context("when the plugin is already installed", func() { 366 BeforeEach(func() { 367 plugin := configv3.Plugin{ 368 Name: "some-plugin", 369 Version: configv3.PluginVersion{ 370 Major: 1, 371 Minor: 2, 372 Build: 3, 373 }, 374 } 375 fakeActor.GetAndValidatePluginReturns(plugin, nil) 376 fakeActor.IsPluginInstalledReturns(true) 377 }) 378 379 It("returns PluginAlreadyInstalledError", func() { 380 Expect(executeErr).To(MatchError(translatableerror.PluginAlreadyInstalledError{ 381 BinaryName: "faceman", 382 Name: "some-plugin", 383 Version: "1.2.3", 384 })) 385 }) 386 }) 387 }) 388 }) 389 }) 390 }) 391 392 Describe("installing from an unsupported URL scheme", func() { 393 BeforeEach(func() { 394 cmd.OptionalArgs.PluginNameOrLocation = "ftp://some-url" 395 }) 396 397 It("returns an error indicating an unsupported URL scheme", func() { 398 Expect(executeErr).To(MatchError(translatableerror.UnsupportedURLSchemeError{ 399 UnsupportedURL: string(cmd.OptionalArgs.PluginNameOrLocation), 400 })) 401 }) 402 }) 403 404 Describe("installing from an HTTP URL", func() { 405 var ( 406 plugin configv3.Plugin 407 pluginName string 408 executablePluginPath string 409 ) 410 411 BeforeEach(func() { 412 cmd.OptionalArgs.PluginNameOrLocation = "http://some-url" 413 pluginName = "some-plugin" 414 executablePluginPath = "executable-path" 415 }) 416 417 It("displays the plugin warning", func() { 418 Expect(testUI.Out).To(Say("Attention: Plugins are binaries written by potentially untrusted authors\\.")) 419 Expect(testUI.Out).To(Say("Install and use plugins at your own risk\\.")) 420 }) 421 422 Context("when the -f argument is given", func() { 423 BeforeEach(func() { 424 cmd.Force = true 425 }) 426 427 It("begins downloading the plugin", func() { 428 Expect(testUI.Out).To(Say("Starting download of plugin binary from URL\\.\\.\\.")) 429 430 Expect(fakeActor.DownloadExecutableBinaryFromURLCallCount()).To(Equal(1)) 431 url, tempPluginDir, proxyReader := fakeActor.DownloadExecutableBinaryFromURLArgsForCall(0) 432 Expect(url).To(Equal(cmd.OptionalArgs.PluginNameOrLocation.String())) 433 Expect(tempPluginDir).To(ContainSubstring("some-pluginhome")) 434 Expect(tempPluginDir).To(ContainSubstring("temp")) 435 Expect(proxyReader).To(Equal(fakeProgressBar)) 436 }) 437 438 Context("When getting the binary fails", func() { 439 BeforeEach(func() { 440 expectedErr = errors.New("some-error") 441 fakeActor.DownloadExecutableBinaryFromURLReturns("", expectedErr) 442 }) 443 444 It("returns the error", func() { 445 Expect(executeErr).To(MatchError(expectedErr)) 446 447 Expect(testUI.Out).ToNot(Say("downloaded")) 448 Expect(fakeActor.GetAndValidatePluginCallCount()).To(Equal(0)) 449 }) 450 451 Context("when a 4xx or 5xx status is encountered while downloading the plugin", func() { 452 BeforeEach(func() { 453 fakeActor.DownloadExecutableBinaryFromURLReturns("", pluginerror.RawHTTPStatusError{Status: "some-status"}) 454 }) 455 456 It("returns a DownloadPluginHTTPError", func() { 457 Expect(executeErr).To(MatchError(translatableerror.DownloadPluginHTTPError{Message: "some-status"})) 458 }) 459 }) 460 461 Context("when a SSL error is encountered while downloading the plugin", func() { 462 BeforeEach(func() { 463 fakeActor.DownloadExecutableBinaryFromURLReturns("", pluginerror.UnverifiedServerError{}) 464 }) 465 466 It("returns a DownloadPluginHTTPError", func() { 467 Expect(executeErr).To(MatchError(translatableerror.DownloadPluginHTTPError{Message: "x509: certificate signed by unknown authority"})) 468 }) 469 }) 470 }) 471 472 Context("when getting the binary succeeds", func() { 473 BeforeEach(func() { 474 fakeActor.DownloadExecutableBinaryFromURLReturns("some-path", nil) 475 fakeActor.CreateExecutableCopyReturns(executablePluginPath, nil) 476 }) 477 478 It("sets up the progress bar", func() { 479 Expect(fakeActor.GetAndValidatePluginCallCount()).To(Equal(1)) 480 _, _, path := fakeActor.GetAndValidatePluginArgsForCall(0) 481 Expect(path).To(Equal(executablePluginPath)) 482 483 Expect(fakeActor.DownloadExecutableBinaryFromURLCallCount()).To(Equal(1)) 484 urlArg, pluginDirArg, proxyReader := fakeActor.DownloadExecutableBinaryFromURLArgsForCall(0) 485 Expect(urlArg).To(Equal("http://some-url")) 486 Expect(pluginDirArg).To(ContainSubstring("some-pluginhome")) 487 Expect(pluginDirArg).To(ContainSubstring("temp")) 488 Expect(proxyReader).To(Equal(fakeProgressBar)) 489 490 Expect(fakeActor.CreateExecutableCopyCallCount()).To(Equal(1)) 491 pathArg, pluginDirArg := fakeActor.CreateExecutableCopyArgsForCall(0) 492 Expect(pathArg).To(Equal("some-path")) 493 Expect(pluginDirArg).To(ContainSubstring("some-pluginhome")) 494 Expect(pluginDirArg).To(ContainSubstring("temp")) 495 }) 496 497 Context("when the plugin is invalid", func() { 498 var returnedErr error 499 500 BeforeEach(func() { 501 returnedErr = pluginaction.PluginInvalidError{} 502 fakeActor.GetAndValidatePluginReturns(configv3.Plugin{}, returnedErr) 503 }) 504 505 It("returns an error", func() { 506 Expect(executeErr).To(MatchError(translatableerror.PluginInvalidError{})) 507 508 Expect(fakeActor.IsPluginInstalledCallCount()).To(Equal(0)) 509 }) 510 }) 511 512 Context("when the plugin is valid", func() { 513 BeforeEach(func() { 514 plugin = configv3.Plugin{ 515 Name: pluginName, 516 Version: configv3.PluginVersion{ 517 Major: 1, 518 Minor: 2, 519 Build: 3, 520 }, 521 } 522 fakeActor.GetAndValidatePluginReturns(plugin, nil) 523 }) 524 525 Context("when the plugin is already installed", func() { 526 BeforeEach(func() { 527 fakeActor.IsPluginInstalledReturns(true) 528 }) 529 530 It("displays uninstall message", func() { 531 Expect(testUI.Out).To(Say("Plugin %s 1\\.2\\.3 is already installed\\. Uninstalling existing plugin\\.\\.\\.", pluginName)) 532 }) 533 534 Context("when an error is encountered uninstalling the existing plugin", func() { 535 BeforeEach(func() { 536 expectedErr = errors.New("uninstall plugin error") 537 fakeActor.UninstallPluginReturns(expectedErr) 538 }) 539 540 It("returns the error", func() { 541 Expect(executeErr).To(MatchError(expectedErr)) 542 543 Expect(testUI.Out).ToNot(Say("Plugin some-plugin successfully uninstalled\\.")) 544 }) 545 }) 546 547 Context("when no errors are encountered uninstalling the existing plugin", func() { 548 It("displays uninstall message", func() { 549 Expect(testUI.Out).To(Say("Plugin %s successfully uninstalled\\.", pluginName)) 550 }) 551 552 Context("when no errors are encountered installing the plugin", func() { 553 It("uninstalls the existing plugin and installs the current plugin", func() { 554 Expect(executeErr).ToNot(HaveOccurred()) 555 556 Expect(testUI.Out).To(Say("Installing plugin %s\\.\\.\\.", pluginName)) 557 Expect(testUI.Out).To(Say("OK")) 558 Expect(testUI.Out).To(Say("Plugin %s 1\\.2\\.3 successfully installed\\.", pluginName)) 559 }) 560 }) 561 562 Context("when an error is encountered installing the plugin", func() { 563 BeforeEach(func() { 564 expectedErr = errors.New("install plugin error") 565 fakeActor.InstallPluginFromPathReturns(expectedErr) 566 }) 567 568 It("returns the error", func() { 569 Expect(executeErr).To(MatchError(expectedErr)) 570 571 Expect(testUI.Out).ToNot(Say("Plugin some-plugin 1\\.2\\.3 successfully installed\\.")) 572 }) 573 }) 574 }) 575 }) 576 577 Context("when the plugin is not already installed", func() { 578 It("installs the plugin", func() { 579 Expect(executeErr).ToNot(HaveOccurred()) 580 581 Expect(testUI.Out).To(Say("Installing plugin %s\\.\\.\\.", pluginName)) 582 Expect(testUI.Out).To(Say("OK")) 583 Expect(testUI.Out).To(Say("Plugin %s 1\\.2\\.3 successfully installed\\.", pluginName)) 584 585 Expect(fakeActor.UninstallPluginCallCount()).To(Equal(0)) 586 }) 587 }) 588 }) 589 }) 590 }) 591 592 Context("when the -f argument is not given (user is prompted for confirmation)", func() { 593 BeforeEach(func() { 594 plugin = configv3.Plugin{ 595 Name: pluginName, 596 Version: configv3.PluginVersion{ 597 Major: 1, 598 Minor: 2, 599 Build: 3, 600 }, 601 } 602 603 cmd.Force = false 604 fakeActor.DownloadExecutableBinaryFromURLReturns("some-path", nil) 605 fakeActor.CreateExecutableCopyReturns("executable-path", nil) 606 }) 607 608 Context("when the user chooses no", func() { 609 BeforeEach(func() { 610 input.Write([]byte("n\n")) 611 }) 612 613 It("cancels plugin installation", func() { 614 Expect(executeErr).ToNot(HaveOccurred()) 615 616 Expect(testUI.Out).To(Say("Plugin installation cancelled\\.")) 617 }) 618 }) 619 620 Context("when the user chooses the default", func() { 621 BeforeEach(func() { 622 input.Write([]byte("\n")) 623 }) 624 625 It("cancels plugin installation", func() { 626 Expect(executeErr).ToNot(HaveOccurred()) 627 628 Expect(testUI.Out).To(Say("Plugin installation cancelled\\.")) 629 }) 630 }) 631 632 Context("when the user input is invalid", func() { 633 BeforeEach(func() { 634 input.Write([]byte("e\n")) 635 }) 636 637 It("returns an error", func() { 638 Expect(executeErr).To(HaveOccurred()) 639 640 Expect(testUI.Out).ToNot(Say("Installing plugin")) 641 }) 642 }) 643 644 Context("when the user chooses yes", func() { 645 BeforeEach(func() { 646 input.Write([]byte("y\n")) 647 }) 648 649 Context("when the plugin is not already installed", func() { 650 BeforeEach(func() { 651 fakeActor.GetAndValidatePluginReturns(plugin, nil) 652 }) 653 654 It("installs the plugin", func() { 655 Expect(executeErr).ToNot(HaveOccurred()) 656 657 Expect(testUI.Out).To(Say("Attention: Plugins are binaries written by potentially untrusted authors\\.")) 658 Expect(testUI.Out).To(Say("Install and use plugins at your own risk\\.")) 659 Expect(testUI.Out).To(Say("Do you want to install the plugin %s\\? \\[yN\\]", cmd.OptionalArgs.PluginNameOrLocation)) 660 Expect(testUI.Out).To(Say("Starting download of plugin binary from URL\\.\\.\\.")) 661 Expect(testUI.Out).To(Say("Installing plugin %s\\.\\.\\.", pluginName)) 662 Expect(testUI.Out).To(Say("OK")) 663 Expect(testUI.Out).To(Say("Plugin %s 1\\.2\\.3 successfully installed\\.", pluginName)) 664 665 Expect(fakeActor.DownloadExecutableBinaryFromURLCallCount()).To(Equal(1)) 666 url, tempPluginDir, proxyReader := fakeActor.DownloadExecutableBinaryFromURLArgsForCall(0) 667 Expect(url).To(Equal(cmd.OptionalArgs.PluginNameOrLocation.String())) 668 Expect(tempPluginDir).To(ContainSubstring("some-pluginhome")) 669 Expect(tempPluginDir).To(ContainSubstring("temp")) 670 Expect(proxyReader).To(Equal(fakeProgressBar)) 671 672 Expect(fakeActor.CreateExecutableCopyCallCount()).To(Equal(1)) 673 path, tempPluginDir := fakeActor.CreateExecutableCopyArgsForCall(0) 674 Expect(path).To(Equal("some-path")) 675 Expect(tempPluginDir).To(ContainSubstring("some-pluginhome")) 676 Expect(tempPluginDir).To(ContainSubstring("temp")) 677 678 Expect(fakeActor.GetAndValidatePluginCallCount()).To(Equal(1)) 679 _, _, path = fakeActor.GetAndValidatePluginArgsForCall(0) 680 Expect(path).To(Equal(executablePluginPath)) 681 682 Expect(fakeActor.IsPluginInstalledCallCount()).To(Equal(1)) 683 Expect(fakeActor.IsPluginInstalledArgsForCall(0)).To(Equal(pluginName)) 684 685 Expect(fakeActor.InstallPluginFromPathCallCount()).To(Equal(1)) 686 path, installedPlugin := fakeActor.InstallPluginFromPathArgsForCall(0) 687 Expect(path).To(Equal(executablePluginPath)) 688 Expect(installedPlugin).To(Equal(plugin)) 689 690 Expect(fakeActor.UninstallPluginCallCount()).To(Equal(0)) 691 }) 692 }) 693 694 Context("when the plugin is already installed", func() { 695 BeforeEach(func() { 696 fakeActor.GetAndValidatePluginReturns(plugin, nil) 697 fakeActor.IsPluginInstalledReturns(true) 698 }) 699 700 It("returns PluginAlreadyInstalledError", func() { 701 Expect(executeErr).To(MatchError(translatableerror.PluginAlreadyInstalledError{ 702 BinaryName: "faceman", 703 Name: pluginName, 704 Version: "1.2.3", 705 })) 706 }) 707 }) 708 }) 709 }) 710 }) 711 })