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