github.com/liamawhite/cli-with-i18n@v6.32.1-0.20171122084555-dede0a5c3448+incompatible/integration/plugin/install_plugin_from_repo_command_test.go (about)

     1  package plugin
     2  
     3  import (
     4  	"net/http"
     5  	"runtime"
     6  
     7  	"github.com/liamawhite/cli-with-i18n/integration/helpers"
     8  	"github.com/liamawhite/cli-with-i18n/util/generic"
     9  	. "github.com/onsi/ginkgo"
    10  	. "github.com/onsi/gomega"
    11  	. "github.com/onsi/gomega/gbytes"
    12  	. "github.com/onsi/gomega/gexec"
    13  	. "github.com/onsi/gomega/ghttp"
    14  )
    15  
    16  var _ = Describe("install-plugin (from repo) command", func() {
    17  	Describe("installing a plugin from a specific repo", func() {
    18  		Context("when the repo and the plugin name are swapped", func() {
    19  			var repoServer *Server
    20  
    21  			BeforeEach(func() {
    22  				repoServer = helpers.NewPluginRepositoryServer(helpers.PluginRepository{})
    23  				Eventually(helpers.CF("add-plugin-repo", "kaka", repoServer.URL(), "-k")).Should(Exit(0))
    24  			})
    25  
    26  			AfterEach(func() {
    27  				repoServer.Close()
    28  			})
    29  
    30  			It("it parses the arguments correctly", func() {
    31  				session := helpers.CF("install-plugin", "-f", "some-plugin", "-r", "kaka", "-k")
    32  
    33  				Eventually(session.Err).Should(Say("Plugin some-plugin not found in repository kaka\\."))
    34  				Eventually(session).Should(Exit(1))
    35  			})
    36  		})
    37  
    38  		Context("when the repo is not registered", func() {
    39  			It("fails with an error message", func() {
    40  				session := helpers.CF("install-plugin", "-f", "-r", "repo-that-does-not-exist", "some-plugin")
    41  
    42  				Eventually(session.Err).Should(Say("Plugin repository repo-that-does-not-exist not found\\."))
    43  				Eventually(session.Err).Should(Say("Use 'cf list-plugin-repos' to list registered repos\\."))
    44  				Eventually(session).Should(Exit(1))
    45  			})
    46  		})
    47  
    48  		Context("when fetching a list of plugins from a repo returns a 4xx/5xx status or a SSL error", func() {
    49  			var repoServer *Server
    50  
    51  			BeforeEach(func() {
    52  				repoServer = NewTLSServer()
    53  
    54  				repoServer.AppendHandlers(
    55  					CombineHandlers(
    56  						VerifyRequest(http.MethodGet, "/list"),
    57  						RespondWith(http.StatusOK, `{"plugins":[]}`),
    58  					),
    59  					CombineHandlers(
    60  						VerifyRequest(http.MethodGet, "/list"),
    61  						RespondWith(http.StatusTeapot, nil),
    62  					),
    63  				)
    64  
    65  				Eventually(helpers.CF("add-plugin-repo", "kaka", repoServer.URL(), "-k")).Should(Exit(0))
    66  			})
    67  
    68  			AfterEach(func() {
    69  				repoServer.Close()
    70  			})
    71  
    72  			It("fails with an error message", func() {
    73  				session := helpers.CF("install-plugin", "-f", "-r", "kaka", "some-plugin", "-k")
    74  
    75  				Eventually(session.Err).Should(Say("Download attempt failed; server returned 418 I'm a teapot"))
    76  				Eventually(session.Err).Should(Say("Unable to install; plugin is not available from the given URL\\."))
    77  				Eventually(session).Should(Exit(1))
    78  			})
    79  		})
    80  
    81  		Context("when the repo returns invalid json", func() {
    82  			var repoServer *Server
    83  
    84  			BeforeEach(func() {
    85  				repoServer = NewTLSServer()
    86  
    87  				repoServer.AppendHandlers(
    88  					CombineHandlers(
    89  						VerifyRequest(http.MethodGet, "/list"),
    90  						RespondWith(http.StatusOK, `{"plugins":[]}`),
    91  					),
    92  					CombineHandlers(
    93  						VerifyRequest(http.MethodGet, "/list"),
    94  						RespondWith(http.StatusOK, `{"foo":}`),
    95  					),
    96  				)
    97  
    98  				Eventually(helpers.CF("add-plugin-repo", "kaka", repoServer.URL(), "-k")).Should(Exit(0))
    99  			})
   100  
   101  			AfterEach(func() {
   102  				repoServer.Close()
   103  			})
   104  
   105  			It("fails with an error message", func() {
   106  				session := helpers.CF("install-plugin", "-f", "-r", "kaka", "some-plugin", "-k")
   107  
   108  				Eventually(session.Err).Should(Say("Invalid JSON content from server: invalid character '}' looking for beginning of value"))
   109  				Eventually(session).Should(Exit(1))
   110  			})
   111  		})
   112  
   113  		Context("when the repo does not contain the specified plugin", func() {
   114  			var repoServer *Server
   115  
   116  			BeforeEach(func() {
   117  				repoServer = helpers.NewPluginRepositoryServer(helpers.PluginRepository{})
   118  				Eventually(helpers.CF("add-plugin-repo", "kaka", repoServer.URL(), "-k")).Should(Exit(0))
   119  			})
   120  
   121  			AfterEach(func() {
   122  				repoServer.Close()
   123  			})
   124  
   125  			It("fails with an error message", func() {
   126  				session := helpers.CF("install-plugin", "-f", "-r", "kaka", "plugin-that-does-not-exist", "-k")
   127  
   128  				Eventually(session.Out).Should(Say("FAILED"))
   129  				Eventually(session.Err).Should(Say("Plugin plugin-that-does-not-exist not found in repository kaka\\."))
   130  				Eventually(session.Err).Should(Say("Use 'cf repo-plugins -r kaka' to list plugins available in the repo\\."))
   131  
   132  				Eventually(session).Should(Exit(1))
   133  			})
   134  		})
   135  
   136  		Context("when the repo contains the specified plugin", func() {
   137  			var repoServer *helpers.PluginRepositoryServerWithPlugin
   138  
   139  			Context("when no compatible binary is found in the repo", func() {
   140  				BeforeEach(func() {
   141  					repoServer = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.0.0", "not-me-platform", true)
   142  					Eventually(helpers.CF("add-plugin-repo", "kaka", repoServer.URL())).Should(Exit(0))
   143  				})
   144  
   145  				AfterEach(func() {
   146  					repoServer.Cleanup()
   147  				})
   148  
   149  				It("returns plugin not found", func() {
   150  					session := helpers.CF("install-plugin", "-f", "-r", "kaka", "some-plugin", "-k")
   151  					Eventually(session.Out).Should(Say("FAILED"))
   152  					Eventually(session.Err).Should(Say("Plugin requested has no binary available for your platform\\."))
   153  
   154  					Eventually(session).Should(Exit(1))
   155  				})
   156  			})
   157  
   158  			Context("when -f is specified", func() {
   159  				Context("when the plugin is not already installed", func() {
   160  					Context("when the plugin checksum is valid", func() {
   161  						BeforeEach(func() {
   162  							repoServer = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.0.0", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), true)
   163  							Eventually(helpers.CF("add-plugin-repo", "kaka", repoServer.URL())).Should(Exit(0))
   164  						})
   165  
   166  						AfterEach(func() {
   167  							repoServer.Cleanup()
   168  						})
   169  
   170  						It("installs the plugin case-insensitively", func() {
   171  							session := helpers.CF("install-plugin", "-f", "-r", "kAkA", "some-plugin", "-k")
   172  							Eventually(session.Out).Should(Say("Searching kaka for plugin some-plugin\\.\\.\\."))
   173  							Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.0\\.0 found in: kaka\n"))
   174  							Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   175  							Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   176  							Eventually(session.Out).Should(Say("Starting download of plugin binary from repository kaka\\.\\.\\."))
   177  							Eventually(session.Out).Should(Say("\\d.* .*B / ?"))
   178  							Eventually(session.Out).Should(Say("Installing plugin some-plugin\\.\\.\\."))
   179  							Eventually(session.Out).Should(Say("OK"))
   180  							Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.0\\.0 successfully installed\\."))
   181  
   182  							Eventually(session).Should(Exit(0))
   183  						})
   184  					})
   185  
   186  					Context("when the plugin checksum is invalid", func() {
   187  						BeforeEach(func() {
   188  							repoServer = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.0.0", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), false)
   189  							Eventually(helpers.CF("add-plugin-repo", "kaka", repoServer.URL())).Should(Exit(0))
   190  
   191  						})
   192  
   193  						AfterEach(func() {
   194  							repoServer.Cleanup()
   195  						})
   196  
   197  						It("fails with an error message", func() {
   198  							session := helpers.CF("install-plugin", "-f", "-r", "kaka", "some-plugin", "-k")
   199  							Eventually(session.Out).Should(Say("FAILED"))
   200  							Eventually(session.Err).Should(Say("Downloaded plugin binary's checksum does not match repo metadata\\."))
   201  							Eventually(session.Err).Should(Say("Please try again or contact the plugin author\\."))
   202  							Eventually(session).Should(Exit(1))
   203  						})
   204  					})
   205  				})
   206  
   207  				Context("when the plugin is already installed", func() {
   208  					BeforeEach(func() {
   209  						pluginPath := helpers.BuildConfigurablePlugin("configurable_plugin", "some-plugin", "1.0.0",
   210  							[]helpers.PluginCommand{
   211  								{Name: "some-command", Help: "some-command-help"},
   212  							},
   213  						)
   214  						Eventually(helpers.CF("install-plugin", pluginPath, "-f", "-k")).Should(Exit(0))
   215  					})
   216  
   217  					Context("when the plugin checksum is valid", func() {
   218  						BeforeEach(func() {
   219  							repoServer = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "2.0.0", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), true)
   220  							Eventually(helpers.CF("add-plugin-repo", "kaka", repoServer.URL())).Should(Exit(0))
   221  						})
   222  
   223  						AfterEach(func() {
   224  							repoServer.Cleanup()
   225  						})
   226  
   227  						It("reinstalls the plugin", func() {
   228  							session := helpers.CF("install-plugin", "-f", "-r", "kaka", "some-plugin", "-k")
   229  
   230  							Eventually(session.Out).Should(Say("Searching kaka for plugin some-plugin\\.\\.\\."))
   231  							Eventually(session.Out).Should(Say("Plugin some-plugin 2\\.0\\.0 found in: kaka\n"))
   232  							Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.0\\.0 is already installed\\."))
   233  							Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   234  							Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   235  							Eventually(session.Out).Should(Say("Starting download of plugin binary from repository kaka\\.\\.\\."))
   236  							Eventually(session.Out).Should(Say("\\d.* .*B / ?"))
   237  							Eventually(session.Out).Should(Say("Uninstalling existing plugin\\.\\.\\."))
   238  							Eventually(session.Out).Should(Say("OK"))
   239  							Eventually(session.Out).Should(Say("Plugin some-plugin successfully uninstalled\\."))
   240  							Eventually(session.Out).Should(Say("Installing plugin some-plugin\\.\\.\\."))
   241  							Eventually(session.Out).Should(Say("OK"))
   242  							Eventually(session.Out).Should(Say("Plugin some-plugin 2\\.0\\.0 successfully installed\\."))
   243  
   244  							Eventually(session).Should(Exit(0))
   245  						})
   246  					})
   247  
   248  					Context("when the plugin checksum is invalid", func() {
   249  						BeforeEach(func() {
   250  							repoServer = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "2.0.0", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), false)
   251  							Eventually(helpers.CF("add-plugin-repo", "kaka", repoServer.URL())).Should(Exit(0))
   252  						})
   253  
   254  						AfterEach(func() {
   255  							repoServer.Cleanup()
   256  						})
   257  
   258  						It("fails with an error message", func() {
   259  							session := helpers.CF("install-plugin", "-f", "-r", "kaka", "some-plugin", "-k")
   260  
   261  							Eventually(session.Out).Should(Say("Searching kaka for plugin some-plugin\\.\\.\\."))
   262  							Eventually(session.Out).Should(Say("Plugin some-plugin 2\\.0\\.0 found in: kaka\n"))
   263  							Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.0\\.0 is already installed\\."))
   264  							Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   265  							Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   266  							Eventually(session.Out).Should(Say("Starting download of plugin binary from repository kaka\\.\\.\\."))
   267  							Eventually(session.Out).Should(Say("\\d.* .*B / ?"))
   268  
   269  							Eventually(session.Out).Should(Say("FAILED"))
   270  							Eventually(session.Err).Should(Say("Downloaded plugin binary's checksum does not match repo metadata\\."))
   271  							Eventually(session.Err).Should(Say("Please try again or contact the plugin author\\."))
   272  
   273  							Eventually(session).Should(Exit(1))
   274  						})
   275  					})
   276  				})
   277  			})
   278  
   279  			Context("when -f is not specified", func() {
   280  				var buffer *Buffer
   281  
   282  				BeforeEach(func() {
   283  					buffer = NewBuffer()
   284  				})
   285  
   286  				Context("when the plugin is not already installed", func() {
   287  					BeforeEach(func() {
   288  						repoServer = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.2.3", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), true)
   289  						Eventually(helpers.CF("add-plugin-repo", "kaka", repoServer.URL())).Should(Exit(0))
   290  					})
   291  
   292  					AfterEach(func() {
   293  						repoServer.Cleanup()
   294  					})
   295  
   296  					Context("when the user says yes", func() {
   297  						BeforeEach(func() {
   298  							_, _ = buffer.Write([]byte("y\n"))
   299  						})
   300  
   301  						It("installs the plugin", func() {
   302  							session := helpers.CFWithStdin(buffer, "install-plugin", "-r", "kaka", "some-plugin", "-k")
   303  							Eventually(session.Out).Should(Say("Searching kaka for plugin some-plugin\\.\\.\\."))
   304  							Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 found in: kaka\n"))
   305  							Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   306  							Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   307  							Eventually(session.Out).Should(Say("Do you want to install the plugin some-plugin\\? \\[yN\\]: y"))
   308  							Eventually(session.Out).Should(Say("Starting download of plugin binary from repository kaka\\.\\.\\."))
   309  							Eventually(session.Out).Should(Say("\\d.* .*B / ?"))
   310  							Eventually(session.Out).Should(Say("Installing plugin some-plugin\\.\\.\\."))
   311  							Eventually(session.Out).Should(Say("OK"))
   312  							Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 successfully installed\\."))
   313  
   314  							Eventually(session).Should(Exit(0))
   315  						})
   316  					})
   317  
   318  					Context("when the user says no", func() {
   319  						BeforeEach(func() {
   320  							_, _ = buffer.Write([]byte("n\n"))
   321  						})
   322  
   323  						It("does not install the plugin", func() {
   324  							session := helpers.CFWithStdin(buffer, "install-plugin", "-r", "kaka", "some-plugin", "-k")
   325  							Eventually(session.Out).Should(Say("Searching kaka for plugin some-plugin\\.\\.\\."))
   326  							Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 found in: kaka\n"))
   327  							Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   328  							Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   329  							Eventually(session.Out).Should(Say("Do you want to install the plugin some-plugin\\? \\[yN\\]: n"))
   330  
   331  							Eventually(session.Out).Should(Say("Plugin installation cancelled"))
   332  
   333  							Eventually(session).Should(Exit(0))
   334  						})
   335  					})
   336  				})
   337  
   338  				Context("when the plugin is already installed", func() {
   339  					BeforeEach(func() {
   340  						pluginPath := helpers.BuildConfigurablePlugin("configurable_plugin", "some-plugin", "1.2.2",
   341  							[]helpers.PluginCommand{
   342  								{Name: "some-command", Help: "some-command-help"},
   343  							},
   344  						)
   345  						Eventually(helpers.CF("install-plugin", pluginPath, "-f", "-k")).Should(Exit(0))
   346  					})
   347  
   348  					Context("when the user chooses yes", func() {
   349  						BeforeEach(func() {
   350  							_, _ = buffer.Write([]byte("y\n"))
   351  						})
   352  
   353  						Context("when the plugin checksum is valid", func() {
   354  							BeforeEach(func() {
   355  								repoServer = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.2.3", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), true)
   356  								Eventually(helpers.CF("add-plugin-repo", "kaka", repoServer.URL())).Should(Exit(0))
   357  							})
   358  
   359  							AfterEach(func() {
   360  								repoServer.Cleanup()
   361  							})
   362  
   363  							It("installs the plugin", func() {
   364  								session := helpers.CFWithStdin(buffer, "install-plugin", "-r", "kaka", "some-plugin", "-k")
   365  
   366  								Eventually(session.Out).Should(Say("Searching kaka for plugin some-plugin\\.\\.\\."))
   367  								Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 found in: kaka\n"))
   368  								Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.2 is already installed\\."))
   369  								Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   370  								Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   371  								Eventually(session.Out).Should(Say("Do you want to uninstall the existing plugin and install some-plugin 1\\.2\\.3\\? \\[yN\\]: y"))
   372  								Eventually(session.Out).Should(Say("Starting download of plugin binary from repository kaka\\.\\.\\."))
   373  								Eventually(session.Out).Should(Say("\\d.* .*B / ?"))
   374  								Eventually(session.Out).Should(Say("Uninstalling existing plugin\\.\\.\\."))
   375  								Eventually(session.Out).Should(Say("OK"))
   376  								Eventually(session.Out).Should(Say("Plugin some-plugin successfully uninstalled\\."))
   377  								Eventually(session.Out).Should(Say("Installing plugin some-plugin\\.\\.\\."))
   378  								Eventually(session.Out).Should(Say("OK"))
   379  								Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 successfully installed\\."))
   380  
   381  								Eventually(session).Should(Exit(0))
   382  							})
   383  						})
   384  
   385  						Context("when the plugin checksum is invalid", func() {
   386  							BeforeEach(func() {
   387  								repoServer = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.2.3", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), false)
   388  
   389  								Eventually(helpers.CF("add-plugin-repo", "kaka", repoServer.URL())).Should(Exit(0))
   390  							})
   391  
   392  							AfterEach(func() {
   393  								repoServer.Cleanup()
   394  							})
   395  
   396  							It("fails with an error message", func() {
   397  								session := helpers.CFWithStdin(buffer, "install-plugin", "-r", "kaka", "some-plugin", "-k")
   398  								Eventually(session.Out).Should(Say("Searching kaka for plugin some-plugin\\.\\.\\."))
   399  								Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 found in: kaka\n"))
   400  								Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.2 is already installed\\."))
   401  								Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   402  								Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   403  								Eventually(session.Out).Should(Say("Do you want to uninstall the existing plugin and install some-plugin 1\\.2\\.3\\? \\[yN\\]: y"))
   404  								Eventually(session.Out).Should(Say("Starting download of plugin binary from repository kaka\\.\\.\\."))
   405  								Eventually(session.Out).Should(Say("\\d.* .*B / ?"))
   406  								Eventually(session.Out).Should(Say("FAILED"))
   407  								Eventually(session.Err).Should(Say("Downloaded plugin binary's checksum does not match repo metadata\\."))
   408  								Eventually(session.Err).Should(Say("Please try again or contact the plugin author\\."))
   409  
   410  								Eventually(session).Should(Exit(1))
   411  							})
   412  						})
   413  					})
   414  
   415  					Context("when the user chooses no", func() {
   416  						BeforeEach(func() {
   417  							repoServer = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.2.3", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), false)
   418  							Eventually(helpers.CF("add-plugin-repo", "kaka", repoServer.URL())).Should(Exit(0))
   419  
   420  							_, _ = buffer.Write([]byte("n\n"))
   421  						})
   422  
   423  						AfterEach(func() {
   424  							repoServer.Cleanup()
   425  						})
   426  
   427  						It("does not install the plugin", func() {
   428  							session := helpers.CFWithStdin(buffer, "install-plugin", "-r", "kaka", "some-plugin", "-k")
   429  
   430  							Eventually(session.Out).Should(Say("Searching kaka for plugin some-plugin\\.\\.\\."))
   431  							Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 found in: kaka\n"))
   432  							Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.2 is already installed\\."))
   433  							Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   434  							Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   435  							Eventually(session.Out).Should(Say("Do you want to uninstall the existing plugin and install some-plugin 1\\.2\\.3\\? \\[yN\\]: n"))
   436  							Eventually(session.Out).Should(Say("Plugin installation cancelled"))
   437  
   438  							Eventually(session).Should(Exit(0))
   439  						})
   440  					})
   441  				})
   442  			})
   443  		})
   444  	})
   445  
   446  	Describe("installing a plugin from any repo", func() {
   447  		Context("when there are no repositories registered", func() {
   448  			It("fails and displays the plugin not found message", func() {
   449  				session := helpers.CF("install-plugin", "some-plugin")
   450  
   451  				Eventually(session.Out).Should(Say("FAILED"))
   452  				Eventually(session.Err).Should(Say("Plugin some-plugin not found on disk or in any registered repo\\."))
   453  				Eventually(session.Err).Should(Say("Use 'cf repo-plugins' to list plugins available in the repos\\."))
   454  
   455  				Eventually(session).Should(Exit(1))
   456  			})
   457  		})
   458  
   459  		Context("when there are repositories registered", func() {
   460  			Context("when fetching a list of plugins from a repo returns a 4xx/5xx status or a SSL error", func() {
   461  				var repoServer *Server
   462  
   463  				BeforeEach(func() {
   464  					repoServer = NewTLSServer()
   465  
   466  					repoServer.AppendHandlers(
   467  						CombineHandlers(
   468  							VerifyRequest(http.MethodGet, "/list"),
   469  							RespondWith(http.StatusOK, `{"plugins":[]}`),
   470  						),
   471  						CombineHandlers(
   472  							VerifyRequest(http.MethodGet, "/list"),
   473  							RespondWith(http.StatusTeapot, nil),
   474  						),
   475  					)
   476  
   477  					Eventually(helpers.CF("add-plugin-repo", "kaka", repoServer.URL(), "-k")).Should(Exit(0))
   478  				})
   479  
   480  				AfterEach(func() {
   481  					repoServer.Close()
   482  				})
   483  
   484  				It("fails with an error message", func() {
   485  					session := helpers.CF("install-plugin", "-f", "some-plugin", "-k")
   486  
   487  					Eventually(session.Err).Should(Say("Plugin list download failed; repository kaka returned 418 I'm a teapot"))
   488  					Consistently(session.Err).ShouldNot(Say("Unable to install; plugin is not available from the given URL\\."))
   489  					Eventually(session).Should(Exit(1))
   490  				})
   491  			})
   492  
   493  			Context("when the plugin isn't found in any of the repositories", func() {
   494  				var repoServer1 *Server
   495  				var repoServer2 *Server
   496  
   497  				BeforeEach(func() {
   498  					repoServer1 = helpers.NewPluginRepositoryServer(helpers.PluginRepository{})
   499  					repoServer2 = helpers.NewPluginRepositoryServer(helpers.PluginRepository{})
   500  					Eventually(helpers.CF("add-plugin-repo", "kaka1", repoServer1.URL(), "-k")).Should(Exit(0))
   501  					Eventually(helpers.CF("add-plugin-repo", "kaka2", repoServer2.URL(), "-k")).Should(Exit(0))
   502  				})
   503  
   504  				AfterEach(func() {
   505  					repoServer1.Close()
   506  					repoServer2.Close()
   507  				})
   508  
   509  				It("fails and displays the plugin not found message", func() {
   510  					session := helpers.CF("install-plugin", "some-plugin", "-k")
   511  
   512  					Eventually(session.Out).Should(Say("Searching kaka1, kaka2 for plugin some-plugin\\.\\.\\."))
   513  					Eventually(session.Out).Should(Say("FAILED"))
   514  					Eventually(session.Err).Should(Say("Plugin some-plugin not found on disk or in any registered repo\\."))
   515  					Eventually(session.Err).Should(Say("Use 'cf repo-plugins' to list plugins available in the repos\\."))
   516  
   517  					Eventually(session).Should(Exit(1))
   518  				})
   519  			})
   520  
   521  			Context("when -f is specified", func() {
   522  				Context("when identical versions of the plugin are found in the repositories", func() {
   523  					var repoServer1 *helpers.PluginRepositoryServerWithPlugin
   524  					var repoServer2 *helpers.PluginRepositoryServerWithPlugin
   525  
   526  					BeforeEach(func() {
   527  						repoServer1 = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.2.3", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), true)
   528  						Eventually(helpers.CF("add-plugin-repo", "kaka1", repoServer1.URL())).Should(Exit(0))
   529  
   530  						repoServer2 = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.2.3", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), true)
   531  						Eventually(helpers.CF("add-plugin-repo", "kaka2", repoServer2.URL())).Should(Exit(0))
   532  					})
   533  
   534  					AfterEach(func() {
   535  						repoServer1.Cleanup()
   536  						repoServer2.Cleanup()
   537  					})
   538  
   539  					Context("when the plugin is not already installed", func() {
   540  						Context("when the checksum is valid", func() {
   541  							It("installs the plugin", func() {
   542  								session := helpers.CF("install-plugin", "some-plugin", "-f", "-k")
   543  
   544  								Eventually(session.Out).Should(Say("Searching kaka1, kaka2 for plugin some-plugin\\.\\.\\."))
   545  								Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 found in: kaka1, kaka2"))
   546  								Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   547  								Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   548  								Eventually(session.Out).Should(Say("Starting download of plugin binary from repository kaka1\\.\\.\\."))
   549  								Eventually(session.Out).Should(Say("\\d.* .*B / ?"))
   550  								Eventually(session.Out).Should(Say("Installing plugin some-plugin\\.\\.\\."))
   551  								Eventually(session.Out).Should(Say("OK"))
   552  								Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 successfully installed\\."))
   553  
   554  								Eventually(session).Should(Exit(0))
   555  							})
   556  						})
   557  
   558  						Context("when the plugin checksum is invalid", func() {
   559  							var repoServer3 *helpers.PluginRepositoryServerWithPlugin
   560  							var repoServer4 *helpers.PluginRepositoryServerWithPlugin
   561  
   562  							BeforeEach(func() {
   563  								repoServer3 = helpers.NewPluginRepositoryServerWithPlugin("some-plugin-with-bad-checksum", "2.2.3", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), false)
   564  								Eventually(helpers.CF("add-plugin-repo", "kaka3", repoServer3.URL())).Should(Exit(0))
   565  
   566  								repoServer4 = helpers.NewPluginRepositoryServerWithPlugin("some-plugin-with-bad-checksum", "2.2.3", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), true)
   567  								Eventually(helpers.CF("add-plugin-repo", "kaka4", repoServer4.URL())).Should(Exit(0))
   568  							})
   569  
   570  							AfterEach(func() {
   571  								repoServer3.Cleanup()
   572  								repoServer4.Cleanup()
   573  							})
   574  
   575  							It("fails with the invalid checksum message", func() {
   576  								session := helpers.CF("install-plugin", "some-plugin-with-bad-checksum", "-f", "-k")
   577  
   578  								Eventually(session.Out).Should(Say("Searching kaka1, kaka2, kaka3, kaka4 for plugin some-plugin-with-bad-checksum\\.\\.\\."))
   579  								Eventually(session.Out).Should(Say("Plugin some-plugin-with-bad-checksum 2\\.2\\.3 found in: kaka3, kaka4"))
   580  								Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   581  								Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   582  								Eventually(session.Out).Should(Say("Starting download of plugin binary from repository kaka3\\.\\.\\."))
   583  								Eventually(session.Out).Should(Say("\\d.* .*B / ?"))
   584  								Eventually(session.Out).Should(Say("FAILED"))
   585  								Eventually(session.Err).Should(Say("Downloaded plugin binary's checksum does not match repo metadata\\."))
   586  								Eventually(session.Err).Should(Say("Please try again or contact the plugin author\\."))
   587  
   588  								Eventually(session).Should(Exit(1))
   589  							})
   590  						})
   591  					})
   592  
   593  					Context("when the plugin is already installed", func() {
   594  						Context("when the checksum is valid", func() {
   595  							BeforeEach(func() {
   596  								pluginPath := helpers.BuildConfigurablePlugin("configurable_plugin", "some-plugin", "1.0.0",
   597  									[]helpers.PluginCommand{
   598  										{Name: "some-command", Help: "some-command-help"},
   599  									},
   600  								)
   601  								Eventually(helpers.CF("install-plugin", pluginPath, "-f", "-k")).Should(Exit(0))
   602  							})
   603  
   604  							It("reinstalls the plugin", func() {
   605  								session := helpers.CF("install-plugin", "-f", "some-plugin", "-k")
   606  
   607  								Eventually(session.Out).Should(Say("Searching kaka1, kaka2 for plugin some-plugin\\.\\.\\."))
   608  								Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 found in: kaka1, kaka2"))
   609  								Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.0\\.0 is already installed\\."))
   610  								Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   611  
   612  								Eventually(session).Should(Exit(0))
   613  							})
   614  						})
   615  					})
   616  				})
   617  
   618  				Context("when the binary version for the current GOOS/GOARCH is exists in only one repo", func() {
   619  					var repoServer1 *helpers.PluginRepositoryServerWithPlugin
   620  					var repoServer2 *helpers.PluginRepositoryServerWithPlugin
   621  
   622  					BeforeEach(func() {
   623  						repoServer1 = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.2.3", "solaris", false)
   624  						Eventually(helpers.CF("add-plugin-repo", "kaka1", repoServer1.URL())).Should(Exit(0))
   625  
   626  						repoServer2 = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.2.3", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), true)
   627  						Eventually(helpers.CF("add-plugin-repo", "kaka2", repoServer2.URL())).Should(Exit(0))
   628  					})
   629  
   630  					AfterEach(func() {
   631  						repoServer1.Cleanup()
   632  						repoServer2.Cleanup()
   633  					})
   634  
   635  					It("installs the plugin from the correct repo", func() {
   636  						session := helpers.CF("install-plugin", "-f", "some-plugin", "-k")
   637  
   638  						Eventually(session.Out).Should(Say("Searching kaka1, kaka2 for plugin some-plugin\\.\\.\\."))
   639  						Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 found in: kaka2"))
   640  						Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   641  						Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   642  						Eventually(session.Out).Should(Say("Starting download of plugin binary from repository kaka2\\.\\.\\."))
   643  
   644  						Eventually(session).Should(Exit(0))
   645  					})
   646  				})
   647  
   648  				Context("when different versions of the plugin are found in the repositories", func() {
   649  					Context("when the checksum is valid", func() {
   650  						var repoServer1 *helpers.PluginRepositoryServerWithPlugin
   651  						var repoServer2 *helpers.PluginRepositoryServerWithPlugin
   652  
   653  						BeforeEach(func() {
   654  							repoServer1 = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.2.3", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), true)
   655  							Eventually(helpers.CF("add-plugin-repo", "kaka1", repoServer1.URL())).Should(Exit(0))
   656  
   657  							repoServer2 = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.2.4", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), true)
   658  							Eventually(helpers.CF("add-plugin-repo", "kaka2", repoServer2.URL())).Should(Exit(0))
   659  						})
   660  
   661  						AfterEach(func() {
   662  							repoServer1.Cleanup()
   663  							repoServer2.Cleanup()
   664  						})
   665  
   666  						It("installs the newest plugin", func() {
   667  							session := helpers.CF("install-plugin", "some-plugin", "-f", "-k")
   668  
   669  							Eventually(session.Out).Should(Say("Searching kaka1, kaka2 for plugin some-plugin\\.\\.\\."))
   670  							Eventually(session.Out).Should(Say("Plugin some-plugin 1.2.4 found in: kaka2"))
   671  							Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   672  							Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   673  							Eventually(session.Out).Should(Say("Starting download of plugin binary from repository kaka2\\.\\.\\."))
   674  							Eventually(session.Out).Should(Say("\\d.* .*B / ?"))
   675  							Eventually(session.Out).Should(Say("Installing plugin some-plugin\\.\\.\\."))
   676  							Eventually(session.Out).Should(Say("OK"))
   677  							Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.4 successfully installed\\."))
   678  
   679  							Eventually(session).Should(Exit(0))
   680  						})
   681  					})
   682  
   683  					Context("when the checksum for the latest version is invalid", func() {
   684  						var repoServer1 *helpers.PluginRepositoryServerWithPlugin
   685  						var repoServer2 *helpers.PluginRepositoryServerWithPlugin
   686  
   687  						BeforeEach(func() {
   688  							repoServer1 = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.2.3", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), true)
   689  							Eventually(helpers.CF("add-plugin-repo", "kaka1", repoServer1.URL())).Should(Exit(0))
   690  
   691  							repoServer2 = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.2.4", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), false)
   692  							Eventually(helpers.CF("add-plugin-repo", "kaka2", repoServer2.URL())).Should(Exit(0))
   693  						})
   694  
   695  						AfterEach(func() {
   696  							repoServer1.Cleanup()
   697  							repoServer2.Cleanup()
   698  						})
   699  
   700  						It("prints the invalid checksum error", func() {
   701  							session := helpers.CF("install-plugin", "some-plugin", "-f", "-k")
   702  
   703  							Eventually(session.Out).Should(Say("Searching kaka1, kaka2 for plugin some-plugin\\.\\.\\."))
   704  							Eventually(session.Out).Should(Say("Plugin some-plugin 1.2.4 found in: kaka2"))
   705  							Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   706  							Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   707  							Eventually(session.Out).Should(Say("Starting download of plugin binary from repository kaka2\\.\\.\\."))
   708  							Eventually(session.Out).Should(Say("\\d.* .*B / ?"))
   709  							Eventually(session.Out).Should(Say("FAILED"))
   710  							Eventually(session.Err).Should(Say("Downloaded plugin binary's checksum does not match repo metadata\\."))
   711  							Eventually(session.Err).Should(Say("Please try again or contact the plugin author\\."))
   712  
   713  							Eventually(session).Should(Exit(1))
   714  						})
   715  					})
   716  				})
   717  			})
   718  
   719  			Context("when -f is not specified", func() {
   720  				var buffer *Buffer
   721  
   722  				BeforeEach(func() {
   723  					buffer = NewBuffer()
   724  				})
   725  
   726  				Context("when identical versions of the plugin are found in the repositories", func() {
   727  					var repoServer1 *helpers.PluginRepositoryServerWithPlugin
   728  					var repoServer2 *helpers.PluginRepositoryServerWithPlugin
   729  
   730  					BeforeEach(func() {
   731  						repoServer1 = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.2.3", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), true)
   732  						Eventually(helpers.CF("add-plugin-repo", "kaka1", repoServer1.URL())).Should(Exit(0))
   733  
   734  						repoServer2 = helpers.NewPluginRepositoryServerWithPlugin("some-plugin", "1.2.3", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), true)
   735  						Eventually(helpers.CF("add-plugin-repo", "kaka2", repoServer2.URL())).Should(Exit(0))
   736  					})
   737  
   738  					AfterEach(func() {
   739  						repoServer1.Cleanup()
   740  						repoServer2.Cleanup()
   741  					})
   742  
   743  					Context("when the plugin is not already installed", func() {
   744  						Context("when the user says yes", func() {
   745  							BeforeEach(func() {
   746  								_, _ = buffer.Write([]byte("y\n"))
   747  							})
   748  
   749  							Context("when the checksum is valid", func() {
   750  								It("installs the plugin", func() {
   751  									session := helpers.CFWithStdin(buffer, "install-plugin", "some-plugin", "-k")
   752  
   753  									Eventually(session.Out).Should(Say("Searching kaka1, kaka2 for plugin some-plugin\\.\\.\\."))
   754  									Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 found in: kaka1, kaka2"))
   755  									Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   756  									Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   757  									Eventually(session.Out).Should(Say("Do you want to install the plugin some-plugin\\? \\[yN\\]: y"))
   758  									Eventually(session.Out).Should(Say("Starting download of plugin binary from repository kaka1\\.\\.\\."))
   759  									Eventually(session.Out).Should(Say("\\d.* .*B / ?"))
   760  									Eventually(session.Out).Should(Say("Installing plugin some-plugin\\.\\.\\."))
   761  									Eventually(session.Out).Should(Say("OK"))
   762  									Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 successfully installed\\."))
   763  
   764  									Eventually(session).Should(Exit(0))
   765  								})
   766  							})
   767  
   768  							Context("when the checksum is invalid", func() {
   769  								var repoServer3 *helpers.PluginRepositoryServerWithPlugin
   770  								var repoServer4 *helpers.PluginRepositoryServerWithPlugin
   771  
   772  								BeforeEach(func() {
   773  									repoServer3 = helpers.NewPluginRepositoryServerWithPlugin("some-plugin-with-bad-checksum", "2.2.3", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), false)
   774  									Eventually(helpers.CF("add-plugin-repo", "kaka3", repoServer3.URL())).Should(Exit(0))
   775  
   776  									repoServer4 = helpers.NewPluginRepositoryServerWithPlugin("some-plugin-with-bad-checksum", "2.2.3", generic.GeneratePlatform(runtime.GOOS, runtime.GOARCH), false)
   777  									Eventually(helpers.CF("add-plugin-repo", "kaka4", repoServer4.URL())).Should(Exit(0))
   778  								})
   779  
   780  								AfterEach(func() {
   781  									repoServer3.Cleanup()
   782  									repoServer4.Cleanup()
   783  								})
   784  
   785  								It("fails with the invalid checksum message", func() {
   786  									session := helpers.CFWithStdin(buffer, "install-plugin", "some-plugin-with-bad-checksum", "-k")
   787  
   788  									Eventually(session.Out).Should(Say("FAILED"))
   789  									Eventually(session.Err).Should(Say("Downloaded plugin binary's checksum does not match repo metadata\\."))
   790  									Eventually(session.Err).Should(Say("Please try again or contact the plugin author\\."))
   791  
   792  									Eventually(session).Should(Exit(1))
   793  								})
   794  							})
   795  						})
   796  
   797  						Context("when the user says no", func() {
   798  							BeforeEach(func() {
   799  								_, _ = buffer.Write([]byte("n\n"))
   800  							})
   801  
   802  							It("does not install the plugin", func() {
   803  								session := helpers.CFWithStdin(buffer, "install-plugin", "some-plugin", "-k")
   804  
   805  								Eventually(session.Out).Should(Say("Do you want to install the plugin some-plugin\\? \\[yN\\]: n"))
   806  								Eventually(session.Out).Should(Say("Plugin installation cancelled"))
   807  
   808  								Eventually(session).Should(Exit(0))
   809  							})
   810  						})
   811  					})
   812  
   813  					Context("when the plugin is already installed", func() {
   814  						BeforeEach(func() {
   815  							pluginPath := helpers.BuildConfigurablePlugin("configurable_plugin", "some-plugin", "1.0.0",
   816  								[]helpers.PluginCommand{
   817  									{Name: "some-command", Help: "some-command-help"},
   818  								},
   819  							)
   820  							Eventually(helpers.CF("install-plugin", pluginPath, "-f", "-k")).Should(Exit(0))
   821  						})
   822  
   823  						Context("when the user says yes", func() {
   824  							BeforeEach(func() {
   825  								_, _ = buffer.Write([]byte("y\n"))
   826  							})
   827  
   828  							Context("when the checksum is valid", func() {
   829  								It("installs the plugin", func() {
   830  									session := helpers.CFWithStdin(buffer, "install-plugin", "some-plugin", "-k")
   831  
   832  									Eventually(session.Out).Should(Say("Searching kaka1, kaka2 for plugin some-plugin\\.\\.\\."))
   833  									Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 found in: kaka1, kaka2"))
   834  									Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.0\\.0 is already installed."))
   835  									Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   836  									Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   837  									Eventually(session.Out).Should(Say("Do you want to uninstall the existing plugin and install some-plugin 1\\.2\\.3\\? \\[yN\\]: y"))
   838  									Eventually(session.Out).Should(Say("Starting download of plugin binary from repository kaka1\\.\\.\\."))
   839  									Eventually(session.Out).Should(Say("\\d.* .*B / ?"))
   840  									Eventually(session.Out).Should(Say("Uninstalling existing plugin\\.\\.\\."))
   841  									Eventually(session.Out).Should(Say("OK"))
   842  									Eventually(session.Out).Should(Say("Plugin some-plugin successfully uninstalled\\."))
   843  									Eventually(session.Out).Should(Say("Installing plugin some-plugin\\.\\.\\."))
   844  									Eventually(session.Out).Should(Say("OK"))
   845  									Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 successfully installed\\."))
   846  
   847  									Eventually(session).Should(Exit(0))
   848  								})
   849  							})
   850  						})
   851  
   852  						Context("when the user says no", func() {
   853  							BeforeEach(func() {
   854  								_, _ = buffer.Write([]byte("n\n"))
   855  							})
   856  
   857  							It("does not install the plugin", func() {
   858  								session := helpers.CFWithStdin(buffer, "install-plugin", "some-plugin", "-k")
   859  
   860  								Eventually(session.Out).Should(Say("Searching kaka1, kaka2 for plugin some-plugin\\.\\.\\."))
   861  								Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.2\\.3 found in: kaka1, kaka2"))
   862  								Eventually(session.Out).Should(Say("Plugin some-plugin 1\\.0\\.0 is already installed."))
   863  								Eventually(session.Out).Should(Say("Attention: Plugins are binaries written by potentially untrusted authors\\."))
   864  								Eventually(session.Out).Should(Say("Install and use plugins at your own risk\\."))
   865  								Eventually(session.Out).Should(Say("Do you want to uninstall the existing plugin and install some-plugin 1\\.2\\.3\\? \\[yN\\]: n"))
   866  								Eventually(session.Out).Should(Say("Plugin installation cancelled"))
   867  
   868  								Eventually(session).Should(Exit(0))
   869  							})
   870  						})
   871  					})
   872  				})
   873  			})
   874  		})
   875  	})
   876  })