1 package manager
2
3 import (
4 "fmt"
5 "reflect"
6 "strings"
7 "testing"
8
9 "github.com/spf13/cobra"
10 "gotest.tools/v3/assert"
11 "gotest.tools/v3/assert/cmp"
12 )
13
14 type fakeCandidate struct {
15 path string
16 exec bool
17 meta string
18 }
19
20 func (c *fakeCandidate) Path() string {
21 return c.path
22 }
23
24 func (c *fakeCandidate) Metadata() ([]byte, error) {
25 if !c.exec {
26 return nil, fmt.Errorf("faked a failure to exec %q", c.path)
27 }
28 return []byte(c.meta), nil
29 }
30
31 func TestValidateCandidate(t *testing.T) {
32 const (
33 goodPluginName = NamePrefix + "goodplugin"
34
35 builtinName = NamePrefix + "builtin"
36 builtinAlias = NamePrefix + "alias"
37
38 badPrefixPath = "/usr/local/libexec/cli-plugins/wobble"
39 badNamePath = "/usr/local/libexec/cli-plugins/docker-123456"
40 goodPluginPath = "/usr/local/libexec/cli-plugins/" + goodPluginName
41 metaExperimental = `{"SchemaVersion": "0.1.0", "Vendor": "e2e-testing", "Experimental": true}`
42 )
43
44 fakeroot := &cobra.Command{Use: "docker"}
45 fakeroot.AddCommand(&cobra.Command{
46 Use: strings.TrimPrefix(builtinName, NamePrefix),
47 Aliases: []string{
48 strings.TrimPrefix(builtinAlias, NamePrefix),
49 },
50 })
51
52 for _, tc := range []struct {
53 name string
54 c *fakeCandidate
55
56
57 err string
58 invalid string
59 }{
60
61 {name: "empty path", c: &fakeCandidate{path: ""}, err: "plugin candidate path cannot be empty"},
62 {name: "bad prefix", c: &fakeCandidate{path: badPrefixPath}, err: fmt.Sprintf("does not have %q prefix", NamePrefix)},
63 {name: "bad path", c: &fakeCandidate{path: badNamePath}, invalid: "did not match"},
64 {name: "builtin command", c: &fakeCandidate{path: builtinName}, invalid: `plugin "builtin" duplicates builtin command`},
65 {name: "builtin alias", c: &fakeCandidate{path: builtinAlias}, invalid: `plugin "alias" duplicates an alias of builtin command "builtin"`},
66 {name: "fetch failure", c: &fakeCandidate{path: goodPluginPath, exec: false}, invalid: fmt.Sprintf("failed to fetch metadata: faked a failure to exec %q", goodPluginPath)},
67 {name: "metadata not json", c: &fakeCandidate{path: goodPluginPath, exec: true, meta: `xyzzy`}, invalid: "invalid character"},
68 {name: "empty schemaversion", c: &fakeCandidate{path: goodPluginPath, exec: true, meta: `{}`}, invalid: `plugin SchemaVersion "" is not valid`},
69 {name: "invalid schemaversion", c: &fakeCandidate{path: goodPluginPath, exec: true, meta: `{"SchemaVersion": "xyzzy"}`}, invalid: `plugin SchemaVersion "xyzzy" is not valid`},
70 {name: "no vendor", c: &fakeCandidate{path: goodPluginPath, exec: true, meta: `{"SchemaVersion": "0.1.0"}`}, invalid: "plugin metadata does not define a vendor"},
71 {name: "empty vendor", c: &fakeCandidate{path: goodPluginPath, exec: true, meta: `{"SchemaVersion": "0.1.0", "Vendor": ""}`}, invalid: "plugin metadata does not define a vendor"},
72
73 {name: "valid", c: &fakeCandidate{path: goodPluginPath, exec: true, meta: `{"SchemaVersion": "0.1.0", "Vendor": "e2e-testing"}`}},
74 {name: "experimental + allowing experimental", c: &fakeCandidate{path: goodPluginPath, exec: true, meta: metaExperimental}},
75 } {
76 t.Run(tc.name, func(t *testing.T) {
77 p, err := newPlugin(tc.c, fakeroot.Commands())
78 switch {
79 case tc.err != "":
80 assert.ErrorContains(t, err, tc.err)
81 case tc.invalid != "":
82 assert.NilError(t, err)
83 assert.Assert(t, cmp.ErrorType(p.Err, reflect.TypeOf(&pluginError{})))
84 assert.ErrorContains(t, p.Err, tc.invalid)
85 default:
86 assert.NilError(t, err)
87 assert.Equal(t, NamePrefix+p.Name, goodPluginName)
88 assert.Equal(t, p.SchemaVersion, "0.1.0")
89 assert.Equal(t, p.Vendor, "e2e-testing")
90 }
91 })
92 }
93 }
94
95 func TestCandidatePath(t *testing.T) {
96 exp := "/some/path"
97 cand := &candidate{path: exp}
98 assert.Equal(t, exp, cand.Path())
99 }
100
View as plain text