github.com/jenspinney/cli@v6.42.1-0.20190207184520-7450c600020e+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/actionerror" 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 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 When("the file exists", func() { 84 BeforeEach(func() { 85 fakeActor.CreateExecutableCopyReturns("copy-path", nil) 86 fakeActor.FileExistsReturns(true) 87 }) 88 89 When("the -f argument is given", func() { 90 BeforeEach(func() { 91 cmd.Force = true 92 }) 93 94 When("the plugin is invalid", func() { 95 var returnedErr error 96 97 BeforeEach(func() { 98 returnedErr = actionerror.PluginInvalidError{} 99 fakeActor.GetAndValidatePluginReturns(configv3.Plugin{}, returnedErr) 100 }) 101 102 It("returns an error", func() { 103 Expect(executeErr).To(MatchError(returnedErr)) 104 105 Expect(testUI.Out).ToNot(Say("Installing plugin")) 106 }) 107 }) 108 109 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{}, actionerror.PluginInvalidError{Err: wrappedErr}) 115 }) 116 117 It("returns an error", func() { 118 Expect(executeErr).To(MatchError(actionerror.PluginInvalidError{Err: wrappedErr})) 119 120 Expect(testUI.Out).ToNot(Say("Installing plugin")) 121 }) 122 }) 123 124 When("the plugin is already installed", func() { 125 var ( 126 plugin configv3.Plugin 127 newPlugin configv3.Plugin 128 ) 129 BeforeEach(func() { 130 plugin = configv3.Plugin{ 131 Name: "some-plugin", 132 Version: configv3.PluginVersion{ 133 Major: 1, 134 Minor: 2, 135 Build: 2, 136 }, 137 } 138 newPlugin = configv3.Plugin{ 139 Name: "some-plugin", 140 Version: configv3.PluginVersion{ 141 Major: 1, 142 Minor: 2, 143 Build: 3, 144 }, 145 } 146 fakeActor.GetAndValidatePluginReturns(newPlugin, nil) 147 fakeConfig.GetPluginCaseInsensitiveReturns(plugin, true) 148 }) 149 150 When("an error is encountered uninstalling the existing plugin", func() { 151 BeforeEach(func() { 152 expectedErr = errors.New("uninstall plugin error") 153 fakeActor.UninstallPluginReturns(expectedErr) 154 }) 155 156 It("returns the error", func() { 157 Expect(executeErr).To(MatchError(expectedErr)) 158 159 Expect(testUI.Out).ToNot(Say(`Plugin some-plugin successfully uninstalled\.`)) 160 }) 161 }) 162 163 When("no errors are encountered uninstalling the existing plugin", func() { 164 It("uninstalls the existing plugin and installs the current plugin", func() { 165 Expect(executeErr).ToNot(HaveOccurred()) 166 167 Expect(testUI.Out).To(Say(`Attention: Plugins are binaries written by potentially untrusted authors\.`)) 168 Expect(testUI.Out).To(Say(`Install and use plugins at your own risk\.`)) 169 Expect(testUI.Out).To(Say(`Plugin some-plugin 1\.2\.2 is already installed\. Uninstalling existing plugin\.\.\.`)) 170 Expect(testUI.Out).To(Say("OK")) 171 Expect(testUI.Out).To(Say(`Plugin some-plugin successfully uninstalled\.`)) 172 Expect(testUI.Out).To(Say(`Installing plugin some-plugin\.\.\.`)) 173 Expect(testUI.Out).To(Say("OK")) 174 Expect(testUI.Out).To(Say(`Plugin some-plugin 1\.2\.3 successfully installed\.`)) 175 176 Expect(fakeActor.FileExistsCallCount()).To(Equal(1)) 177 Expect(fakeActor.FileExistsArgsForCall(0)).To(Equal("some-path")) 178 179 Expect(fakeActor.GetAndValidatePluginCallCount()).To(Equal(1)) 180 _, _, path := fakeActor.GetAndValidatePluginArgsForCall(0) 181 Expect(path).To(Equal("copy-path")) 182 183 Expect(fakeConfig.GetPluginCaseInsensitiveCallCount()).To(Equal(1)) 184 Expect(fakeConfig.GetPluginCaseInsensitiveArgsForCall(0)).To(Equal("some-plugin")) 185 186 Expect(fakeActor.UninstallPluginCallCount()).To(Equal(1)) 187 _, pluginName := fakeActor.UninstallPluginArgsForCall(0) 188 Expect(pluginName).To(Equal("some-plugin")) 189 190 Expect(fakeActor.InstallPluginFromPathCallCount()).To(Equal(1)) 191 path, installedPlugin := fakeActor.InstallPluginFromPathArgsForCall(0) 192 Expect(path).To(Equal("copy-path")) 193 Expect(installedPlugin).To(Equal(newPlugin)) 194 }) 195 196 When("an error is encountered installing the plugin", func() { 197 BeforeEach(func() { 198 expectedErr = errors.New("install plugin error") 199 fakeActor.InstallPluginFromPathReturns(expectedErr) 200 }) 201 202 It("returns the error", func() { 203 Expect(executeErr).To(MatchError(expectedErr)) 204 205 Expect(testUI.Out).ToNot(Say(`Plugin some-plugin 1\.2\.3 successfully installed\.`)) 206 }) 207 }) 208 }) 209 }) 210 211 When("the plugin is not already installed", func() { 212 var plugin configv3.Plugin 213 214 BeforeEach(func() { 215 plugin = configv3.Plugin{ 216 Name: "some-plugin", 217 Version: configv3.PluginVersion{ 218 Major: 1, 219 Minor: 2, 220 Build: 3, 221 }, 222 } 223 fakeActor.GetAndValidatePluginReturns(plugin, nil) 224 }) 225 226 It("installs the plugin", func() { 227 Expect(executeErr).ToNot(HaveOccurred()) 228 229 Expect(testUI.Out).To(Say(`Attention: Plugins are binaries written by potentially untrusted authors\.`)) 230 Expect(testUI.Out).To(Say(`Install and use plugins at your own risk\.`)) 231 Expect(testUI.Out).To(Say(`Installing plugin some-plugin\.\.\.`)) 232 Expect(testUI.Out).To(Say("OK")) 233 Expect(testUI.Out).To(Say(`Plugin some-plugin 1\.2\.3 successfully installed\.`)) 234 235 Expect(fakeActor.FileExistsCallCount()).To(Equal(1)) 236 Expect(fakeActor.FileExistsArgsForCall(0)).To(Equal("some-path")) 237 238 Expect(fakeActor.CreateExecutableCopyCallCount()).To(Equal(1)) 239 pathArg, pluginDirArg := fakeActor.CreateExecutableCopyArgsForCall(0) 240 Expect(pathArg).To(Equal("some-path")) 241 Expect(pluginDirArg).To(ContainSubstring("some-pluginhome")) 242 Expect(pluginDirArg).To(ContainSubstring("temp")) 243 244 Expect(fakeActor.GetAndValidatePluginCallCount()).To(Equal(1)) 245 _, _, path := fakeActor.GetAndValidatePluginArgsForCall(0) 246 Expect(path).To(Equal("copy-path")) 247 248 Expect(fakeConfig.GetPluginCaseInsensitiveCallCount()).To(Equal(1)) 249 Expect(fakeConfig.GetPluginCaseInsensitiveArgsForCall(0)).To(Equal("some-plugin")) 250 251 Expect(fakeActor.InstallPluginFromPathCallCount()).To(Equal(1)) 252 path, installedPlugin := fakeActor.InstallPluginFromPathArgsForCall(0) 253 Expect(path).To(Equal("copy-path")) 254 Expect(installedPlugin).To(Equal(plugin)) 255 256 Expect(fakeActor.UninstallPluginCallCount()).To(Equal(0)) 257 }) 258 259 When("there is an error making an executable copy of the plugin binary", func() { 260 BeforeEach(func() { 261 expectedErr = errors.New("create executable copy error") 262 fakeActor.CreateExecutableCopyReturns("", expectedErr) 263 }) 264 265 It("returns the error", func() { 266 Expect(executeErr).To(MatchError(expectedErr)) 267 }) 268 }) 269 270 When("an error is encountered installing the plugin", func() { 271 BeforeEach(func() { 272 expectedErr = errors.New("install plugin error") 273 fakeActor.InstallPluginFromPathReturns(expectedErr) 274 }) 275 276 It("returns the error", func() { 277 Expect(executeErr).To(MatchError(expectedErr)) 278 279 Expect(testUI.Out).ToNot(Say(`Plugin some-plugin 1\.2\.3 successfully installed\.`)) 280 }) 281 }) 282 }) 283 }) 284 285 When("the -f argument is not given (user is prompted for confirmation)", func() { 286 BeforeEach(func() { 287 cmd.Force = false 288 }) 289 290 When("the user chooses no", func() { 291 BeforeEach(func() { 292 input.Write([]byte("n\n")) 293 }) 294 295 It("cancels plugin installation", func() { 296 Expect(executeErr).ToNot(HaveOccurred()) 297 298 Expect(testUI.Out).To(Say(`Plugin installation cancelled\.`)) 299 }) 300 }) 301 302 When("the user chooses the default", func() { 303 BeforeEach(func() { 304 input.Write([]byte("\n")) 305 }) 306 307 It("cancels plugin installation", func() { 308 Expect(executeErr).ToNot(HaveOccurred()) 309 310 Expect(testUI.Out).To(Say(`Plugin installation cancelled\.`)) 311 }) 312 }) 313 314 When("the user input is invalid", func() { 315 BeforeEach(func() { 316 input.Write([]byte("e\n")) 317 }) 318 319 It("returns an error", func() { 320 Expect(executeErr).To(HaveOccurred()) 321 322 Expect(testUI.Out).ToNot(Say("Installing plugin")) 323 }) 324 }) 325 326 When("the user chooses yes", func() { 327 BeforeEach(func() { 328 input.Write([]byte("y\n")) 329 }) 330 331 When("the plugin is not already installed", func() { 332 var plugin configv3.Plugin 333 334 BeforeEach(func() { 335 plugin = configv3.Plugin{ 336 Name: "some-plugin", 337 Version: configv3.PluginVersion{ 338 Major: 1, 339 Minor: 2, 340 Build: 3, 341 }, 342 } 343 fakeActor.GetAndValidatePluginReturns(plugin, nil) 344 }) 345 346 It("installs the plugin", func() { 347 Expect(executeErr).ToNot(HaveOccurred()) 348 349 Expect(testUI.Out).To(Say(`Attention: Plugins are binaries written by potentially untrusted authors\.`)) 350 Expect(testUI.Out).To(Say(`Install and use plugins at your own risk\.`)) 351 Expect(testUI.Out).To(Say(`Do you want to install the plugin some-path\? \[yN\]`)) 352 Expect(testUI.Out).To(Say(`Installing plugin some-plugin\.\.\.`)) 353 Expect(testUI.Out).To(Say("OK")) 354 Expect(testUI.Out).To(Say(`Plugin some-plugin 1\.2\.3 successfully installed\.`)) 355 356 Expect(fakeActor.FileExistsCallCount()).To(Equal(1)) 357 Expect(fakeActor.FileExistsArgsForCall(0)).To(Equal("some-path")) 358 359 Expect(fakeActor.GetAndValidatePluginCallCount()).To(Equal(1)) 360 _, _, path := fakeActor.GetAndValidatePluginArgsForCall(0) 361 Expect(path).To(Equal("copy-path")) 362 363 Expect(fakeConfig.GetPluginCaseInsensitiveCallCount()).To(Equal(1)) 364 Expect(fakeConfig.GetPluginCaseInsensitiveArgsForCall(0)).To(Equal("some-plugin")) 365 366 Expect(fakeActor.InstallPluginFromPathCallCount()).To(Equal(1)) 367 path, plugin := fakeActor.InstallPluginFromPathArgsForCall(0) 368 Expect(path).To(Equal("copy-path")) 369 Expect(plugin).To(Equal(plugin)) 370 371 Expect(fakeActor.UninstallPluginCallCount()).To(Equal(0)) 372 }) 373 }) 374 375 When("the plugin is already installed", func() { 376 BeforeEach(func() { 377 fakeConfig.GetPluginCaseInsensitiveReturns(configv3.Plugin{ 378 Name: "some-plugin", 379 Version: configv3.PluginVersion{ 380 Major: 1, 381 Minor: 2, 382 Build: 2, 383 }, 384 }, true) 385 fakeActor.GetAndValidatePluginReturns(configv3.Plugin{ 386 Name: "some-plugin", 387 Version: configv3.PluginVersion{ 388 Major: 1, 389 Minor: 2, 390 Build: 3, 391 }, 392 }, nil) 393 }) 394 395 It("returns PluginAlreadyInstalledError", func() { 396 Expect(executeErr).To(MatchError(translatableerror.PluginAlreadyInstalledError{ 397 BinaryName: "faceman", 398 Name: "some-plugin", 399 Version: "1.2.3", 400 })) 401 }) 402 }) 403 }) 404 }) 405 }) 406 }) 407 408 Describe("installing from an unsupported URL scheme", func() { 409 BeforeEach(func() { 410 cmd.OptionalArgs.PluginNameOrLocation = "ftp://some-url" 411 }) 412 413 It("returns an error indicating an unsupported URL scheme", func() { 414 Expect(executeErr).To(MatchError(translatableerror.UnsupportedURLSchemeError{ 415 UnsupportedURL: string(cmd.OptionalArgs.PluginNameOrLocation), 416 })) 417 }) 418 }) 419 420 Describe("installing from an HTTP URL", func() { 421 var ( 422 plugin configv3.Plugin 423 pluginName string 424 executablePluginPath string 425 ) 426 427 BeforeEach(func() { 428 cmd.OptionalArgs.PluginNameOrLocation = "http://some-url" 429 pluginName = "some-plugin" 430 executablePluginPath = "executable-path" 431 }) 432 433 It("displays the plugin warning", func() { 434 Expect(testUI.Out).To(Say(`Attention: Plugins are binaries written by potentially untrusted authors\.`)) 435 Expect(testUI.Out).To(Say(`Install and use plugins at your own risk\.`)) 436 }) 437 438 When("the -f argument is given", func() { 439 BeforeEach(func() { 440 cmd.Force = true 441 }) 442 443 It("begins downloading the plugin", func() { 444 Expect(testUI.Out).To(Say(`Starting download of plugin binary from URL\.\.\.`)) 445 446 Expect(fakeActor.DownloadExecutableBinaryFromURLCallCount()).To(Equal(1)) 447 url, tempPluginDir, proxyReader := fakeActor.DownloadExecutableBinaryFromURLArgsForCall(0) 448 Expect(url).To(Equal(cmd.OptionalArgs.PluginNameOrLocation.String())) 449 Expect(tempPluginDir).To(ContainSubstring("some-pluginhome")) 450 Expect(tempPluginDir).To(ContainSubstring("temp")) 451 Expect(proxyReader).To(Equal(fakeProgressBar)) 452 }) 453 454 When("getting the binary fails", func() { 455 BeforeEach(func() { 456 expectedErr = errors.New("some-error") 457 fakeActor.DownloadExecutableBinaryFromURLReturns("", expectedErr) 458 }) 459 460 It("returns the error", func() { 461 Expect(executeErr).To(MatchError(expectedErr)) 462 463 Expect(testUI.Out).ToNot(Say("downloaded")) 464 Expect(fakeActor.GetAndValidatePluginCallCount()).To(Equal(0)) 465 }) 466 467 When("a 4xx or 5xx status is encountered while downloading the plugin", func() { 468 BeforeEach(func() { 469 fakeActor.DownloadExecutableBinaryFromURLReturns("", pluginerror.RawHTTPStatusError{Status: "some-status"}) 470 }) 471 472 It("returns a DownloadPluginHTTPError", func() { 473 Expect(executeErr).To(MatchError(pluginerror.RawHTTPStatusError{Status: "some-status"})) 474 }) 475 }) 476 477 When("a SSL error is encountered while downloading the plugin", func() { 478 BeforeEach(func() { 479 fakeActor.DownloadExecutableBinaryFromURLReturns("", pluginerror.UnverifiedServerError{}) 480 }) 481 482 It("returns a DownloadPluginHTTPError", func() { 483 Expect(executeErr).To(MatchError(pluginerror.UnverifiedServerError{})) 484 }) 485 }) 486 }) 487 488 When("getting the binary succeeds", func() { 489 BeforeEach(func() { 490 fakeActor.DownloadExecutableBinaryFromURLReturns("some-path", nil) 491 fakeActor.CreateExecutableCopyReturns(executablePluginPath, nil) 492 }) 493 494 It("sets up the progress bar", func() { 495 Expect(fakeActor.GetAndValidatePluginCallCount()).To(Equal(1)) 496 _, _, path := fakeActor.GetAndValidatePluginArgsForCall(0) 497 Expect(path).To(Equal(executablePluginPath)) 498 499 Expect(fakeActor.DownloadExecutableBinaryFromURLCallCount()).To(Equal(1)) 500 urlArg, pluginDirArg, proxyReader := fakeActor.DownloadExecutableBinaryFromURLArgsForCall(0) 501 Expect(urlArg).To(Equal("http://some-url")) 502 Expect(pluginDirArg).To(ContainSubstring("some-pluginhome")) 503 Expect(pluginDirArg).To(ContainSubstring("temp")) 504 Expect(proxyReader).To(Equal(fakeProgressBar)) 505 506 Expect(fakeActor.CreateExecutableCopyCallCount()).To(Equal(1)) 507 pathArg, pluginDirArg := fakeActor.CreateExecutableCopyArgsForCall(0) 508 Expect(pathArg).To(Equal("some-path")) 509 Expect(pluginDirArg).To(ContainSubstring("some-pluginhome")) 510 Expect(pluginDirArg).To(ContainSubstring("temp")) 511 }) 512 513 When("the plugin is invalid", func() { 514 var returnedErr error 515 516 BeforeEach(func() { 517 returnedErr = actionerror.PluginInvalidError{} 518 fakeActor.GetAndValidatePluginReturns(configv3.Plugin{}, returnedErr) 519 }) 520 521 It("returns an error", func() { 522 Expect(executeErr).To(MatchError(returnedErr)) 523 524 Expect(fakeConfig.GetPluginCaseInsensitiveCallCount()).To(Equal(0)) 525 }) 526 }) 527 528 When("the plugin is valid", func() { 529 var newPlugin configv3.Plugin 530 531 BeforeEach(func() { 532 plugin = configv3.Plugin{ 533 Name: pluginName, 534 Version: configv3.PluginVersion{ 535 Major: 1, 536 Minor: 2, 537 Build: 2, 538 }, 539 } 540 newPlugin = configv3.Plugin{ 541 Name: pluginName, 542 Version: configv3.PluginVersion{ 543 Major: 1, 544 Minor: 2, 545 Build: 3, 546 }, 547 } 548 fakeActor.GetAndValidatePluginReturns(newPlugin, nil) 549 }) 550 551 When("the plugin is already installed", func() { 552 BeforeEach(func() { 553 fakeConfig.GetPluginCaseInsensitiveReturns(plugin, true) 554 }) 555 556 It("displays uninstall message", func() { 557 Expect(testUI.Out).To(Say(`Plugin %s 1\.2\.2 is already installed\. Uninstalling existing plugin\.\.\.`, pluginName)) 558 }) 559 560 When("an error is encountered uninstalling the existing plugin", func() { 561 BeforeEach(func() { 562 expectedErr = errors.New("uninstall plugin error") 563 fakeActor.UninstallPluginReturns(expectedErr) 564 }) 565 566 It("returns the error", func() { 567 Expect(executeErr).To(MatchError(expectedErr)) 568 569 Expect(testUI.Out).ToNot(Say(`Plugin some-plugin successfully uninstalled\.`)) 570 }) 571 }) 572 573 When("no errors are encountered uninstalling the existing plugin", func() { 574 It("displays uninstall message", func() { 575 Expect(testUI.Out).To(Say(`Plugin %s successfully uninstalled\.`, pluginName)) 576 }) 577 578 When("no errors are encountered installing the plugin", func() { 579 It("uninstalls the existing plugin and installs the current plugin", func() { 580 Expect(executeErr).ToNot(HaveOccurred()) 581 582 Expect(testUI.Out).To(Say(`Installing plugin %s\.\.\.`, pluginName)) 583 Expect(testUI.Out).To(Say("OK")) 584 Expect(testUI.Out).To(Say(`Plugin %s 1\.2\.3 successfully installed\.`, pluginName)) 585 }) 586 }) 587 588 When("an error is encountered installing the plugin", func() { 589 BeforeEach(func() { 590 expectedErr = errors.New("install plugin error") 591 fakeActor.InstallPluginFromPathReturns(expectedErr) 592 }) 593 594 It("returns the error", func() { 595 Expect(executeErr).To(MatchError(expectedErr)) 596 597 Expect(testUI.Out).ToNot(Say(`Plugin some-plugin 1\.2\.3 successfully installed\.`)) 598 }) 599 }) 600 }) 601 }) 602 603 When("the plugin is not already installed", func() { 604 It("installs the plugin", func() { 605 Expect(executeErr).ToNot(HaveOccurred()) 606 607 Expect(testUI.Out).To(Say(`Installing plugin %s\.\.\.`, pluginName)) 608 Expect(testUI.Out).To(Say("OK")) 609 Expect(testUI.Out).To(Say(`Plugin %s 1\.2\.3 successfully installed\.`, pluginName)) 610 611 Expect(fakeActor.UninstallPluginCallCount()).To(Equal(0)) 612 }) 613 }) 614 }) 615 }) 616 }) 617 618 When("the -f argument is not given (user is prompted for confirmation)", func() { 619 BeforeEach(func() { 620 plugin = configv3.Plugin{ 621 Name: pluginName, 622 Version: configv3.PluginVersion{ 623 Major: 1, 624 Minor: 2, 625 Build: 3, 626 }, 627 } 628 629 cmd.Force = false 630 fakeActor.DownloadExecutableBinaryFromURLReturns("some-path", nil) 631 fakeActor.CreateExecutableCopyReturns("executable-path", nil) 632 }) 633 634 When("the user chooses no", func() { 635 BeforeEach(func() { 636 input.Write([]byte("n\n")) 637 }) 638 639 It("cancels plugin installation", func() { 640 Expect(executeErr).ToNot(HaveOccurred()) 641 642 Expect(testUI.Out).To(Say(`Plugin installation cancelled\.`)) 643 }) 644 }) 645 646 When("the user chooses the default", func() { 647 BeforeEach(func() { 648 input.Write([]byte("\n")) 649 }) 650 651 It("cancels plugin installation", func() { 652 Expect(executeErr).ToNot(HaveOccurred()) 653 654 Expect(testUI.Out).To(Say(`Plugin installation cancelled\.`)) 655 }) 656 }) 657 658 When("the user input is invalid", func() { 659 BeforeEach(func() { 660 input.Write([]byte("e\n")) 661 }) 662 663 It("returns an error", func() { 664 Expect(executeErr).To(HaveOccurred()) 665 666 Expect(testUI.Out).ToNot(Say("Installing plugin")) 667 }) 668 }) 669 670 When("the user chooses yes", func() { 671 BeforeEach(func() { 672 input.Write([]byte("y\n")) 673 }) 674 675 When("the plugin is not already installed", func() { 676 BeforeEach(func() { 677 fakeActor.GetAndValidatePluginReturns(plugin, nil) 678 }) 679 680 It("installs the plugin", func() { 681 Expect(executeErr).ToNot(HaveOccurred()) 682 683 Expect(testUI.Out).To(Say(`Attention: Plugins are binaries written by potentially untrusted authors\.`)) 684 Expect(testUI.Out).To(Say(`Install and use plugins at your own risk\.`)) 685 Expect(testUI.Out).To(Say(`Do you want to install the plugin %s\? \[yN\]`, cmd.OptionalArgs.PluginNameOrLocation)) 686 Expect(testUI.Out).To(Say(`Starting download of plugin binary from URL\.\.\.`)) 687 Expect(testUI.Out).To(Say(`Installing plugin %s\.\.\.`, pluginName)) 688 Expect(testUI.Out).To(Say("OK")) 689 Expect(testUI.Out).To(Say(`Plugin %s 1\.2\.3 successfully installed\.`, pluginName)) 690 691 Expect(fakeActor.DownloadExecutableBinaryFromURLCallCount()).To(Equal(1)) 692 url, tempPluginDir, proxyReader := fakeActor.DownloadExecutableBinaryFromURLArgsForCall(0) 693 Expect(url).To(Equal(cmd.OptionalArgs.PluginNameOrLocation.String())) 694 Expect(tempPluginDir).To(ContainSubstring("some-pluginhome")) 695 Expect(tempPluginDir).To(ContainSubstring("temp")) 696 Expect(proxyReader).To(Equal(fakeProgressBar)) 697 698 Expect(fakeActor.CreateExecutableCopyCallCount()).To(Equal(1)) 699 path, tempPluginDir := fakeActor.CreateExecutableCopyArgsForCall(0) 700 Expect(path).To(Equal("some-path")) 701 Expect(tempPluginDir).To(ContainSubstring("some-pluginhome")) 702 Expect(tempPluginDir).To(ContainSubstring("temp")) 703 704 Expect(fakeActor.GetAndValidatePluginCallCount()).To(Equal(1)) 705 _, _, path = fakeActor.GetAndValidatePluginArgsForCall(0) 706 Expect(path).To(Equal(executablePluginPath)) 707 708 Expect(fakeConfig.GetPluginCaseInsensitiveCallCount()).To(Equal(1)) 709 Expect(fakeConfig.GetPluginCaseInsensitiveArgsForCall(0)).To(Equal(pluginName)) 710 711 Expect(fakeActor.InstallPluginFromPathCallCount()).To(Equal(1)) 712 path, installedPlugin := fakeActor.InstallPluginFromPathArgsForCall(0) 713 Expect(path).To(Equal(executablePluginPath)) 714 Expect(installedPlugin).To(Equal(plugin)) 715 716 Expect(fakeActor.UninstallPluginCallCount()).To(Equal(0)) 717 }) 718 }) 719 720 When("the plugin is already installed", func() { 721 BeforeEach(func() { 722 fakeConfig.GetPluginCaseInsensitiveReturns(configv3.Plugin{ 723 Name: "some-plugin", 724 Version: configv3.PluginVersion{ 725 Major: 1, 726 Minor: 2, 727 Build: 2, 728 }, 729 }, true) 730 fakeActor.GetAndValidatePluginReturns(configv3.Plugin{ 731 Name: "some-plugin", 732 Version: configv3.PluginVersion{ 733 Major: 1, 734 Minor: 2, 735 Build: 3, 736 }, 737 }, nil) 738 }) 739 740 It("returns PluginAlreadyInstalledError", func() { 741 Expect(executeErr).To(MatchError(translatableerror.PluginAlreadyInstalledError{ 742 BinaryName: "faceman", 743 Name: pluginName, 744 Version: "1.2.3", 745 })) 746 }) 747 }) 748 }) 749 }) 750 }) 751 })