github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/util/configv3/plugins_config_test.go (about)

     1  package configv3_test
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"syscall"
     8  
     9  	. "code.cloudfoundry.org/cli/util/configv3"
    10  	. "github.com/onsi/ginkgo"
    11  	. "github.com/onsi/ginkgo/extensions/table"
    12  	. "github.com/onsi/gomega"
    13  )
    14  
    15  var _ = Describe("PluginsConfig", func() {
    16  	var homeDir string
    17  
    18  	BeforeEach(func() {
    19  		homeDir = setup()
    20  	})
    21  
    22  	AfterEach(func() {
    23  		teardown(homeDir)
    24  	})
    25  
    26  	DescribeTable("when the plugin config exists",
    27  		func(setup func() (string, string)) {
    28  			location, CFPluginHome := setup()
    29  			if CFPluginHome != "" {
    30  				os.Setenv("CF_PLUGIN_HOME", CFPluginHome)
    31  				defer os.Unsetenv("CF_PLUGIN_HOME")
    32  			}
    33  
    34  			rawConfig := `
    35  {
    36    "Plugins": {
    37      "Diego-Enabler": {
    38        "Location": "~/.cf/plugins/diego-enabler_darwin_amd64",
    39        "Version": {
    40          "Major": 1,
    41          "Minor": 0,
    42          "Build": 1
    43        },
    44        "Commands": [
    45          {
    46            "Name": "enable-diego",
    47            "Alias": "",
    48            "HelpText": "enable Diego support for an app",
    49            "UsageDetails": {
    50              "Usage": "cf enable-diego APP_NAME",
    51              "Options": null
    52            }
    53          },
    54          {
    55            "Name": "disable-diego",
    56            "Alias": "",
    57            "HelpText": "disable Diego support for an app",
    58            "UsageDetails": {
    59              "Usage": "cf disable-diego APP_NAME",
    60              "Options": null
    61            }
    62          }
    63  			]
    64  		}
    65  	}
    66  }`
    67  			setPluginConfig(location, rawConfig)
    68  			config, err := LoadConfig()
    69  			Expect(err).ToNot(HaveOccurred())
    70  			Expect(config).ToNot(BeNil())
    71  
    72  			plugins := config.Plugins()
    73  			Expect(plugins).ToNot(BeEmpty())
    74  
    75  			plugin := plugins[0]
    76  			Expect(plugin.Name).To(Equal("Diego-Enabler"))
    77  			Expect(plugin.Location).To(Equal("~/.cf/plugins/diego-enabler_darwin_amd64"))
    78  			Expect(plugin.Version.Major).To(Equal(1))
    79  			Expect(plugin.Commands).To(HaveLen(2))
    80  			Expect(plugin.Commands).To(ContainElement(
    81  				PluginCommand{
    82  					Name:     "enable-diego",
    83  					Alias:    "",
    84  					HelpText: "enable Diego support for an app",
    85  					UsageDetails: PluginUsageDetails{
    86  						Usage: "cf enable-diego APP_NAME",
    87  					},
    88  				},
    89  			))
    90  		},
    91  
    92  		Entry("standard location", func() (string, string) {
    93  			return filepath.Join(homeDir, ".cf", "plugins"), ""
    94  		}),
    95  
    96  		Entry("non-standard location", func() (string, string) {
    97  			return filepath.Join(homeDir, "foo", ".cf", "plugins"), filepath.Join(homeDir, "foo")
    98  		}),
    99  	)
   100  
   101  	Describe("Config", func() {
   102  		Describe("RemovePlugin", func() {
   103  			var (
   104  				config *Config
   105  				err    error
   106  			)
   107  
   108  			BeforeEach(func() {
   109  				rawConfig := `
   110  {
   111    "Plugins": {
   112      "Diego-Enabler": {
   113        "Location": "~/.cf/plugins/diego-enabler_darwin_amd64",
   114        "Version": {
   115          "Major": 1,
   116          "Minor": 0,
   117          "Build": 1
   118        },
   119        "Commands": [
   120          {
   121            "Name": "enable-diego",
   122            "Alias": "",
   123            "HelpText": "enable Diego support for an app",
   124            "UsageDetails": {
   125              "Usage": "cf enable-diego APP_NAME",
   126              "Options": null
   127            }
   128          }
   129        ]
   130      },
   131      "Dora-Non-Enabler": {
   132        "Location": "~/.cf/plugins/diego-enabler_darwin_amd64",
   133        "Version": {
   134          "Major": 1,
   135          "Minor": 0,
   136          "Build": 1
   137        },
   138        "Commands": [
   139          {
   140            "Name": "disable-diego",
   141            "Alias": "",
   142            "HelpText": "disable Diego support for an app",
   143            "UsageDetails": {
   144              "Usage": "cf disable-diego APP_NAME",
   145              "Options": null
   146            }
   147          }
   148        ]
   149      }
   150    }
   151  }`
   152  				setPluginConfig(filepath.Join(homeDir, ".cf", "plugins"), rawConfig)
   153  
   154  				config, err = LoadConfig()
   155  				Expect(err).ToNot(HaveOccurred())
   156  			})
   157  
   158  			When("the plugin exists", func() {
   159  				It("removes the plugin from the config", func() {
   160  					plugins := config.Plugins()
   161  
   162  					Expect(plugins).To(HaveLen(2))
   163  					Expect(plugins[0].Name).To(Equal("Diego-Enabler"))
   164  
   165  					config.RemovePlugin("Diego-Enabler")
   166  
   167  					Expect(config.Plugins()).To(HaveLen(1))
   168  				})
   169  			})
   170  
   171  			When("the plugin does not exist", func() {
   172  				It("doesn't blow up", func() {
   173  					config.RemovePlugin("does-not-exist")
   174  				})
   175  			})
   176  		})
   177  
   178  		Describe("AddPlugin", func() {
   179  			var (
   180  				config *Config
   181  				err    error
   182  			)
   183  
   184  			BeforeEach(func() {
   185  				rawConfig := `
   186  				{
   187  					"Plugins": {
   188  						"plugin-1": {}
   189  					}
   190  				}`
   191  
   192  				pluginsPath := filepath.Join(homeDir, ".cf", "plugins")
   193  				setPluginConfig(pluginsPath, rawConfig)
   194  				config, err = LoadConfig()
   195  				Expect(err).ToNot(HaveOccurred())
   196  			})
   197  
   198  			It("adds the plugin to the config", func() {
   199  				config.AddPlugin(Plugin{
   200  					Name:     "plugin-2",
   201  					Location: "/over-there",
   202  				})
   203  
   204  				plugin, exist := config.GetPlugin("plugin-2")
   205  				Expect(exist).To(BeTrue())
   206  				Expect(plugin).To(Equal(Plugin{Name: "plugin-2", Location: "/over-there"}))
   207  			})
   208  		})
   209  
   210  		Describe("GetPlugin", func() {
   211  			var (
   212  				config *Config
   213  				err    error
   214  			)
   215  
   216  			BeforeEach(func() {
   217  				rawConfig := `
   218  				{
   219  					"Plugins": {
   220  						"plugin-1": {},
   221  						"plugin-2": {}
   222  					}
   223  				}`
   224  
   225  				pluginsPath := filepath.Join(homeDir, ".cf", "plugins")
   226  				setPluginConfig(pluginsPath, rawConfig)
   227  				config, err = LoadConfig()
   228  				Expect(err).ToNot(HaveOccurred())
   229  			})
   230  
   231  			It("returns the plugin and true if it exists", func() {
   232  				plugin, exist := config.GetPlugin("plugin-1")
   233  				Expect(exist).To(BeTrue())
   234  				Expect(plugin).To(Equal(Plugin{Name: "plugin-1"}))
   235  				plugin, exist = config.GetPlugin("plugin-2")
   236  				Expect(exist).To(BeTrue())
   237  				Expect(plugin).To(Equal(Plugin{Name: "plugin-2"}))
   238  			})
   239  
   240  			It("returns an empty plugin and false if it doesn't exist", func() {
   241  				plugin, exist := config.GetPlugin("does-not-exist")
   242  				Expect(exist).To(BeFalse())
   243  				Expect(plugin).To(Equal(Plugin{}))
   244  			})
   245  		})
   246  
   247  		Describe("GetPluginCaseInsensitive", func() {
   248  			var (
   249  				config *Config
   250  				err    error
   251  			)
   252  
   253  			BeforeEach(func() {
   254  				rawConfig := `
   255  				{
   256  					"Plugins": {
   257  						"plugin-1": {},
   258  						"plugin-2": {},
   259  						"PLUGIN-2": {}
   260  					}
   261  				}`
   262  
   263  				pluginsPath := filepath.Join(homeDir, ".cf", "plugins")
   264  				setPluginConfig(pluginsPath, rawConfig)
   265  				config, err = LoadConfig()
   266  				Expect(err).ToNot(HaveOccurred())
   267  			})
   268  
   269  			When("there is a matching plugin", func() {
   270  				It("returns the plugin and true", func() {
   271  					plugin, exist := config.GetPluginCaseInsensitive("PlUgIn-1")
   272  					Expect(plugin).To(Equal(Plugin{Name: "plugin-1"}))
   273  					Expect(exist).To(BeTrue())
   274  				})
   275  			})
   276  
   277  			When("there is no matching plugin", func() {
   278  				It("returns an empty plugin and false", func() {
   279  					plugin, exist := config.GetPluginCaseInsensitive("plugin-3")
   280  					Expect(plugin).To(Equal(Plugin{}))
   281  					Expect(exist).To(BeFalse())
   282  				})
   283  			})
   284  
   285  			When("there are multiple matching plugins", func() {
   286  				// this should never happen
   287  				It("returns one of them", func() {
   288  					_, exist := config.GetPluginCaseInsensitive("pLuGiN-2")
   289  					// do not test the plugin because the plugins are in a map and the
   290  					// order is undefined
   291  					Expect(exist).To(BeTrue())
   292  				})
   293  			})
   294  		})
   295  
   296  		Describe("Plugins", func() {
   297  			BeforeEach(func() {
   298  				rawConfig := `
   299  				{
   300  					"Plugins": {
   301  						"Q-plugin": {},
   302  						"plugin-2": {},
   303  						"plugin-1": {}
   304  					}
   305  				}`
   306  
   307  				pluginsPath := filepath.Join(homeDir, ".cf", "plugins")
   308  				setPluginConfig(pluginsPath, rawConfig)
   309  			})
   310  
   311  			It("returns the pluging sorted by name", func() {
   312  				config, err := LoadConfig()
   313  				Expect(err).ToNot(HaveOccurred())
   314  				Expect(config.Plugins()).To(Equal([]Plugin{
   315  					{Name: "plugin-1"},
   316  					{Name: "plugin-2"},
   317  					{Name: "Q-plugin"},
   318  				}))
   319  			})
   320  		})
   321  
   322  		Describe("WritePluginConfig", func() {
   323  			var config *Config
   324  
   325  			BeforeEach(func() {
   326  				rawConfig := `
   327  {
   328  	"Plugins": {
   329  		"Diego-Enabler": {
   330  			"Location": "~/.cf/plugins/diego-enabler_darwin_amd64",
   331  			"Version": {
   332  				"Major": 1,
   333  				"Minor": 0,
   334  				"Build": 1
   335  			},
   336  			"Commands": [
   337  				{
   338  					"Name": "enable-diego",
   339  					"Alias": "",
   340  					"HelpText": "enable Diego support for an app",
   341  					"UsageDetails": {
   342  						"Usage": "cf enable-diego APP_NAME",
   343  						"Options": null
   344  					}
   345  				}
   346  			]
   347  		}
   348  	}
   349  }`
   350  				setPluginConfig(filepath.Join(homeDir, ".cf", "plugins"), rawConfig)
   351  
   352  				var err error
   353  				config, err = LoadConfig()
   354  				Expect(err).ToNot(HaveOccurred())
   355  			})
   356  
   357  			When("no errors are encountered", func() {
   358  				It("writes the plugin config to pluginHome/.cf/plugin/config.json", func() {
   359  					config.RemovePlugin("Diego-Enabler")
   360  
   361  					err := config.WritePluginConfig()
   362  					Expect(err).ToNot(HaveOccurred())
   363  
   364  					newConfig, err := LoadConfig()
   365  					Expect(err).ToNot(HaveOccurred())
   366  					Expect(newConfig.Plugins()).To(HaveLen(0))
   367  				})
   368  			})
   369  
   370  			When("an error is encountered", func() {
   371  				BeforeEach(func() {
   372  					pluginConfigPath := filepath.Join(homeDir, ".cf", "plugins", "config.json")
   373  					err := os.Remove(pluginConfigPath)
   374  					Expect(err).ToNot(HaveOccurred())
   375  					err = os.Mkdir(pluginConfigPath, 0700)
   376  					Expect(err).ToNot(HaveOccurred())
   377  				})
   378  
   379  				It("returns the error", func() {
   380  					err := config.WritePluginConfig()
   381  					_, ok := err.(*os.PathError)
   382  					Expect(ok).To(BeTrue())
   383  				})
   384  			})
   385  		})
   386  
   387  		Describe("CreatePluginHome", func() {
   388  			var (
   389  				config *Config
   390  
   391  				pluginHome string
   392  
   393  				executeErr error
   394  			)
   395  
   396  			BeforeEach(func() {
   397  				config = new(Config)
   398  
   399  				var err error
   400  				pluginHome, err = ioutil.TempDir("", "my-plugin-home")
   401  				Expect(err).ToNot(HaveOccurred())
   402  				Expect(os.RemoveAll(pluginHome)).ToNot(HaveOccurred())
   403  			})
   404  
   405  			AfterEach(func() {
   406  				Expect(os.RemoveAll(pluginHome)).ToNot(HaveOccurred())
   407  			})
   408  
   409  			JustBeforeEach(func() {
   410  				executeErr = config.CreatePluginHome()
   411  			})
   412  
   413  			When("it correctly writes a directory", func() {
   414  				BeforeEach(func() {
   415  					config.ENV.CFPluginHome = pluginHome
   416  				})
   417  
   418  				It("returns no error", func() {
   419  					Expect(executeErr).ToNot(HaveOccurred())
   420  
   421  					_, statErr := os.Stat(pluginHome)
   422  					Expect(os.IsNotExist(statErr)).To(BeFalse())
   423  				})
   424  			})
   425  
   426  			When("it fails to write a directory", func() {
   427  				var tempFile string
   428  
   429  				BeforeEach(func() {
   430  					f, err := ioutil.TempFile("", "fail-plugin-home")
   431  					Expect(err).ToNot(HaveOccurred())
   432  					Expect(f.Close()).ToNot(HaveOccurred())
   433  					tempFile = f.Name()
   434  
   435  					config.ENV.CFPluginHome = tempFile + "/some-path"
   436  				})
   437  
   438  				AfterEach(func() {
   439  					Expect(os.RemoveAll(tempFile)).ToNot(HaveOccurred())
   440  				})
   441  
   442  				It("returns an error", func() {
   443  					Expect(executeErr).To(MatchError(&os.PathError{Op: "mkdir", Path: tempFile, Err: syscall.ENOTDIR}))
   444  				})
   445  			})
   446  		})
   447  	})
   448  
   449  	Describe("Plugin", func() {
   450  		Describe("CalculateSHA1", func() {
   451  			var plugin Plugin
   452  
   453  			When("no errors are encountered calculating the sha1 value", func() {
   454  				var file *os.File
   455  
   456  				BeforeEach(func() {
   457  					var err error
   458  					file, err = ioutil.TempFile("", "")
   459  					Expect(err).NotTo(HaveOccurred())
   460  					defer file.Close()
   461  
   462  					err = ioutil.WriteFile(file.Name(), []byte("foo"), 0600)
   463  					Expect(err).NotTo(HaveOccurred())
   464  
   465  					plugin.Location = file.Name()
   466  				})
   467  
   468  				AfterEach(func() {
   469  					err := os.Remove(file.Name())
   470  					Expect(err).NotTo(HaveOccurred())
   471  				})
   472  
   473  				It("returns the sha1 value", func() {
   474  					Expect(plugin.CalculateSHA1()).To(Equal("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33"))
   475  				})
   476  			})
   477  
   478  			When("an error is encountered calculating the sha1 value", func() {
   479  				var dirPath string
   480  
   481  				BeforeEach(func() {
   482  					var err error
   483  					dirPath, err = ioutil.TempDir("", "")
   484  					Expect(err).NotTo(HaveOccurred())
   485  
   486  					plugin.Location = dirPath
   487  				})
   488  
   489  				AfterEach(func() {
   490  					err := os.RemoveAll(dirPath)
   491  					Expect(err).NotTo(HaveOccurred())
   492  				})
   493  
   494  				It("returns 'N/A'", func() {
   495  					Expect(plugin.CalculateSHA1()).To(Equal("N/A"))
   496  				})
   497  			})
   498  		})
   499  
   500  		Describe("PluginCommands", func() {
   501  			It("returns the plugin's commands sorted by command name", func() {
   502  				plugin := Plugin{
   503  					Commands: []PluginCommand{
   504  						{Name: "T-sort"},
   505  						{Name: "sort-2"},
   506  						{Name: "sort-1"},
   507  					},
   508  				}
   509  
   510  				Expect(plugin.PluginCommands()).To(Equal([]PluginCommand{
   511  					PluginCommand{Name: "sort-1"},
   512  					PluginCommand{Name: "sort-2"},
   513  					PluginCommand{Name: "T-sort"},
   514  				}))
   515  			})
   516  		})
   517  	})
   518  
   519  	Describe("PluginVersion", func() {
   520  		var version PluginVersion
   521  
   522  		Describe("String", func() {
   523  			It("returns the version in the format x.y.z", func() {
   524  				version = PluginVersion{
   525  					Major: 1,
   526  					Minor: 2,
   527  					Build: 3,
   528  				}
   529  				Expect(version.String()).To(Equal("1.2.3"))
   530  			})
   531  
   532  			When("the major, minor, and build are all 0", func() {
   533  				BeforeEach(func() {
   534  					version = PluginVersion{
   535  						Major: 0,
   536  						Minor: 0,
   537  						Build: 0,
   538  					}
   539  				})
   540  
   541  				It("returns 'N/A'", func() {
   542  					Expect(version.String()).To(Equal("N/A"))
   543  				})
   544  			})
   545  		})
   546  	})
   547  
   548  	Describe("PluginCommand", func() {
   549  		var cmd PluginCommand
   550  
   551  		Describe("CommandName", func() {
   552  			It("returns the name of the command", func() {
   553  				cmd = PluginCommand{Name: "some-command"}
   554  				Expect(cmd.CommandName()).To(Equal("some-command"))
   555  			})
   556  
   557  			When("the command name and command alias are not empty", func() {
   558  				BeforeEach(func() {
   559  					cmd = PluginCommand{Name: "some-command", Alias: "sp"}
   560  				})
   561  
   562  				It("returns the command name concatenated with the command alias", func() {
   563  					Expect(cmd.CommandName()).To(Equal("some-command, sp"))
   564  				})
   565  			})
   566  		})
   567  	})
   568  })