1
15
16 package plugin
17
18 import (
19 "fmt"
20 "os"
21 "path/filepath"
22 "reflect"
23 "runtime"
24 "testing"
25
26 "helm.sh/helm/v3/pkg/cli"
27 )
28
29 func checkCommand(p *Plugin, extraArgs []string, osStrCmp string, t *testing.T) {
30 cmd, args, err := p.PrepareCommand(extraArgs)
31 if err != nil {
32 t.Fatal(err)
33 }
34 if cmd != "echo" {
35 t.Fatalf("Expected echo, got %q", cmd)
36 }
37
38 if l := len(args); l != 5 {
39 t.Fatalf("expected 5 args, got %d", l)
40 }
41
42 expect := []string{"-n", osStrCmp, "--debug", "--foo", "bar"}
43 for i := 0; i < len(args); i++ {
44 if expect[i] != args[i] {
45 t.Errorf("Expected arg=%q, got %q", expect[i], args[i])
46 }
47 }
48
49
50 p.Metadata.IgnoreFlags = true
51 cmd, args, err = p.PrepareCommand(extraArgs)
52 if err != nil {
53 t.Fatal(err)
54 }
55 if cmd != "echo" {
56 t.Fatalf("Expected echo, got %q", cmd)
57 }
58 if l := len(args); l != 2 {
59 t.Fatalf("expected 2 args, got %d", l)
60 }
61 expect = []string{"-n", osStrCmp}
62 for i := 0; i < len(args); i++ {
63 if expect[i] != args[i] {
64 t.Errorf("Expected arg=%q, got %q", expect[i], args[i])
65 }
66 }
67 }
68
69 func TestPrepareCommand(t *testing.T) {
70 p := &Plugin{
71 Dir: "/tmp",
72 Metadata: &Metadata{
73 Name: "test",
74 Command: "echo -n foo",
75 },
76 }
77 argv := []string{"--debug", "--foo", "bar"}
78
79 checkCommand(p, argv, "foo", t)
80 }
81
82 func TestPlatformPrepareCommand(t *testing.T) {
83 p := &Plugin{
84 Dir: "/tmp",
85 Metadata: &Metadata{
86 Name: "test",
87 Command: "echo -n os-arch",
88 PlatformCommand: []PlatformCommand{
89 {OperatingSystem: "linux", Architecture: "386", Command: "echo -n linux-386"},
90 {OperatingSystem: "linux", Architecture: "amd64", Command: "echo -n linux-amd64"},
91 {OperatingSystem: "linux", Architecture: "arm64", Command: "echo -n linux-arm64"},
92 {OperatingSystem: "linux", Architecture: "ppc64le", Command: "echo -n linux-ppc64le"},
93 {OperatingSystem: "linux", Architecture: "s390x", Command: "echo -n linux-s390x"},
94 {OperatingSystem: "linux", Architecture: "riscv64", Command: "echo -n linux-riscv64"},
95 {OperatingSystem: "windows", Architecture: "amd64", Command: "echo -n win-64"},
96 },
97 },
98 }
99 var osStrCmp string
100 os := runtime.GOOS
101 arch := runtime.GOARCH
102 if os == "linux" && arch == "386" {
103 osStrCmp = "linux-386"
104 } else if os == "linux" && arch == "amd64" {
105 osStrCmp = "linux-amd64"
106 } else if os == "linux" && arch == "arm64" {
107 osStrCmp = "linux-arm64"
108 } else if os == "linux" && arch == "ppc64le" {
109 osStrCmp = "linux-ppc64le"
110 } else if os == "linux" && arch == "s390x" {
111 osStrCmp = "linux-s390x"
112 } else if os == "linux" && arch == "riscv64" {
113 osStrCmp = "linux-riscv64"
114 } else if os == "windows" && arch == "amd64" {
115 osStrCmp = "win-64"
116 } else {
117 osStrCmp = "os-arch"
118 }
119
120 argv := []string{"--debug", "--foo", "bar"}
121 checkCommand(p, argv, osStrCmp, t)
122 }
123
124 func TestPartialPlatformPrepareCommand(t *testing.T) {
125 p := &Plugin{
126 Dir: "/tmp",
127 Metadata: &Metadata{
128 Name: "test",
129 Command: "echo -n os-arch",
130 PlatformCommand: []PlatformCommand{
131 {OperatingSystem: "linux", Architecture: "386", Command: "echo -n linux-386"},
132 {OperatingSystem: "windows", Architecture: "amd64", Command: "echo -n win-64"},
133 },
134 },
135 }
136 var osStrCmp string
137 os := runtime.GOOS
138 arch := runtime.GOARCH
139 if os == "linux" {
140 osStrCmp = "linux-386"
141 } else if os == "windows" && arch == "amd64" {
142 osStrCmp = "win-64"
143 } else {
144 osStrCmp = "os-arch"
145 }
146
147 argv := []string{"--debug", "--foo", "bar"}
148 checkCommand(p, argv, osStrCmp, t)
149 }
150
151 func TestNoPrepareCommand(t *testing.T) {
152 p := &Plugin{
153 Dir: "/tmp",
154 Metadata: &Metadata{
155 Name: "test",
156 },
157 }
158 argv := []string{"--debug", "--foo", "bar"}
159
160 _, _, err := p.PrepareCommand(argv)
161 if err == nil {
162 t.Fatalf("Expected error to be returned")
163 }
164 }
165
166 func TestNoMatchPrepareCommand(t *testing.T) {
167 p := &Plugin{
168 Dir: "/tmp",
169 Metadata: &Metadata{
170 Name: "test",
171 PlatformCommand: []PlatformCommand{
172 {OperatingSystem: "no-os", Architecture: "amd64", Command: "echo -n linux-386"},
173 },
174 },
175 }
176 argv := []string{"--debug", "--foo", "bar"}
177
178 if _, _, err := p.PrepareCommand(argv); err == nil {
179 t.Fatalf("Expected error to be returned")
180 }
181 }
182
183 func TestLoadDir(t *testing.T) {
184 dirname := "testdata/plugdir/good/hello"
185 plug, err := LoadDir(dirname)
186 if err != nil {
187 t.Fatalf("error loading Hello plugin: %s", err)
188 }
189
190 if plug.Dir != dirname {
191 t.Fatalf("Expected dir %q, got %q", dirname, plug.Dir)
192 }
193
194 expect := &Metadata{
195 Name: "hello",
196 Version: "0.1.0",
197 Usage: "usage",
198 Description: "description",
199 Command: "$HELM_PLUGIN_DIR/hello.sh",
200 IgnoreFlags: true,
201 Hooks: map[string]string{
202 Install: "echo installing...",
203 },
204 }
205
206 if !reflect.DeepEqual(expect, plug.Metadata) {
207 t.Fatalf("Expected plugin metadata %v, got %v", expect, plug.Metadata)
208 }
209 }
210
211 func TestLoadDirDuplicateEntries(t *testing.T) {
212 dirname := "testdata/plugdir/bad/duplicate-entries"
213 if _, err := LoadDir(dirname); err == nil {
214 t.Errorf("successfully loaded plugin with duplicate entries when it should've failed")
215 }
216 }
217
218 func TestDownloader(t *testing.T) {
219 dirname := "testdata/plugdir/good/downloader"
220 plug, err := LoadDir(dirname)
221 if err != nil {
222 t.Fatalf("error loading Hello plugin: %s", err)
223 }
224
225 if plug.Dir != dirname {
226 t.Fatalf("Expected dir %q, got %q", dirname, plug.Dir)
227 }
228
229 expect := &Metadata{
230 Name: "downloader",
231 Version: "1.2.3",
232 Usage: "usage",
233 Description: "download something",
234 Command: "echo Hello",
235 Downloaders: []Downloaders{
236 {
237 Protocols: []string{"myprotocol", "myprotocols"},
238 Command: "echo Download",
239 },
240 },
241 }
242
243 if !reflect.DeepEqual(expect, plug.Metadata) {
244 t.Fatalf("Expected metadata %v, got %v", expect, plug.Metadata)
245 }
246 }
247
248 func TestLoadAll(t *testing.T) {
249
250
251 if plugs, err := LoadAll("testdata"); err != nil {
252 t.Fatalf("error loading dir with no plugins: %s", err)
253 } else if len(plugs) > 0 {
254 t.Fatalf("expected empty dir to have 0 plugins")
255 }
256
257 basedir := "testdata/plugdir/good"
258 plugs, err := LoadAll(basedir)
259 if err != nil {
260 t.Fatalf("Could not load %q: %s", basedir, err)
261 }
262
263 if l := len(plugs); l != 3 {
264 t.Fatalf("expected 3 plugins, found %d", l)
265 }
266
267 if plugs[0].Metadata.Name != "downloader" {
268 t.Errorf("Expected first plugin to be echo, got %q", plugs[0].Metadata.Name)
269 }
270 if plugs[1].Metadata.Name != "echo" {
271 t.Errorf("Expected first plugin to be echo, got %q", plugs[0].Metadata.Name)
272 }
273 if plugs[2].Metadata.Name != "hello" {
274 t.Errorf("Expected second plugin to be hello, got %q", plugs[1].Metadata.Name)
275 }
276 }
277
278 func TestFindPlugins(t *testing.T) {
279 cases := []struct {
280 name string
281 plugdirs string
282 expected int
283 }{
284 {
285 name: "plugdirs is empty",
286 plugdirs: "",
287 expected: 0,
288 },
289 {
290 name: "plugdirs isn't dir",
291 plugdirs: "./plugin_test.go",
292 expected: 0,
293 },
294 {
295 name: "plugdirs doesn't have plugin",
296 plugdirs: ".",
297 expected: 0,
298 },
299 {
300 name: "normal",
301 plugdirs: "./testdata/plugdir/good",
302 expected: 3,
303 },
304 }
305 for _, c := range cases {
306 t.Run(t.Name(), func(t *testing.T) {
307 plugin, _ := FindPlugins(c.plugdirs)
308 if len(plugin) != c.expected {
309 t.Errorf("expected: %v, got: %v", c.expected, len(plugin))
310 }
311 })
312 }
313 }
314
315 func TestSetupEnv(t *testing.T) {
316 name := "pequod"
317 base := filepath.Join("testdata/helmhome/helm/plugins", name)
318
319 s := cli.New()
320 s.PluginsDirectory = "testdata/helmhome/helm/plugins"
321
322 SetupPluginEnv(s, name, base)
323 for _, tt := range []struct {
324 name, expect string
325 }{
326 {"HELM_PLUGIN_NAME", name},
327 {"HELM_PLUGIN_DIR", base},
328 } {
329 if got := os.Getenv(tt.name); got != tt.expect {
330 t.Errorf("Expected $%s=%q, got %q", tt.name, tt.expect, got)
331 }
332 }
333 }
334
335 func TestSetupEnvWithSpace(t *testing.T) {
336 name := "sureshdsk"
337 base := filepath.Join("testdata/helm home/helm/plugins", name)
338
339 s := cli.New()
340 s.PluginsDirectory = "testdata/helm home/helm/plugins"
341
342 SetupPluginEnv(s, name, base)
343 for _, tt := range []struct {
344 name, expect string
345 }{
346 {"HELM_PLUGIN_NAME", name},
347 {"HELM_PLUGIN_DIR", base},
348 } {
349 if got := os.Getenv(tt.name); got != tt.expect {
350 t.Errorf("Expected $%s=%q, got %q", tt.name, tt.expect, got)
351 }
352 }
353 }
354
355 func TestValidatePluginData(t *testing.T) {
356
357 mockMissingMeta := &Plugin{
358 Dir: "no-such-dir",
359 }
360
361 for i, item := range []struct {
362 pass bool
363 plug *Plugin
364 }{
365 {true, mockPlugin("abcdefghijklmnopqrstuvwxyz0123456789_-ABC")},
366 {true, mockPlugin("foo-bar-FOO-BAR_1234")},
367 {false, mockPlugin("foo -bar")},
368 {false, mockPlugin("$foo -bar")},
369 {false, mockPlugin("foo -bar ")},
370 {false, mockPlugin("foo\nbar")},
371 {false, mockMissingMeta},
372 } {
373 err := validatePluginData(item.plug, fmt.Sprintf("test-%d", i))
374 if item.pass && err != nil {
375 t.Errorf("failed to validate case %d: %s", i, err)
376 } else if !item.pass && err == nil {
377 t.Errorf("expected case %d to fail", i)
378 }
379 }
380 }
381
382 func TestDetectDuplicates(t *testing.T) {
383 plugs := []*Plugin{
384 mockPlugin("foo"),
385 mockPlugin("bar"),
386 }
387 if err := detectDuplicates(plugs); err != nil {
388 t.Error("no duplicates in the first set")
389 }
390 plugs = append(plugs, mockPlugin("foo"))
391 if err := detectDuplicates(plugs); err == nil {
392 t.Error("duplicates in the second set")
393 }
394 }
395
396 func mockPlugin(name string) *Plugin {
397 return &Plugin{
398 Metadata: &Metadata{
399 Name: name,
400 Version: "v0.1.2",
401 Usage: "Mock plugin",
402 Description: "Mock plugin for testing",
403 Command: "echo mock plugin",
404 },
405 Dir: "no-such-dir",
406 }
407 }
408
View as plain text