github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/pkg/plugins/plugin_test.go (about) 1 package plugins // import "github.com/Prakhar-Agarwal-byte/moby/pkg/plugins" 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "io" 7 "net/http" 8 "os" 9 "path/filepath" 10 "runtime" 11 "sync" 12 "testing" 13 "time" 14 15 "github.com/Prakhar-Agarwal-byte/moby/pkg/plugins/transport" 16 "github.com/docker/go-connections/tlsconfig" 17 "github.com/pkg/errors" 18 "gotest.tools/v3/assert" 19 is "gotest.tools/v3/assert/cmp" 20 ) 21 22 const ( 23 fruitPlugin = "fruit" 24 fruitImplements = "apple" 25 ) 26 27 // regression test for deadlock in handlers 28 func TestPluginAddHandler(t *testing.T) { 29 t.Parallel() 30 // make a plugin which is pre-activated 31 p := &Plugin{activateWait: sync.NewCond(&sync.Mutex{})} 32 p.Manifest = &Manifest{Implements: []string{"bananas"}} 33 storage.Lock() 34 storage.plugins["qwerty"] = p 35 storage.Unlock() 36 37 testActive(t, p) 38 Handle("bananas", func(_ string, _ *Client) {}) 39 testActive(t, p) 40 } 41 42 func TestPluginWaitBadPlugin(t *testing.T) { 43 p := &Plugin{activateWait: sync.NewCond(&sync.Mutex{})} 44 p.activateErr = errors.New("some junk happened") 45 testActive(t, p) 46 } 47 48 func testActive(t *testing.T, p *Plugin) { 49 done := make(chan struct{}) 50 go func() { 51 p.waitActive() 52 close(done) 53 }() 54 55 select { 56 case <-time.After(100 * time.Millisecond): 57 _, f, l, _ := runtime.Caller(1) 58 t.Fatalf("%s:%d: deadlock in waitActive", filepath.Base(f), l) 59 case <-done: 60 } 61 } 62 63 func TestGet(t *testing.T) { 64 // TODO: t.Parallel() 65 // TestPluginWithNoManifest also registers fruitPlugin 66 67 p := &Plugin{name: fruitPlugin, activateWait: sync.NewCond(&sync.Mutex{})} 68 p.Manifest = &Manifest{Implements: []string{fruitImplements}} 69 storage.Lock() 70 storage.plugins[fruitPlugin] = p 71 storage.Unlock() 72 73 t.Run("success", func(t *testing.T) { 74 plugin, err := Get(fruitPlugin, fruitImplements) 75 assert.NilError(t, err) 76 77 assert.Check(t, is.Equal(p.Name(), plugin.Name())) 78 assert.Check(t, is.Nil(plugin.Client())) 79 assert.Check(t, plugin.IsV1()) 80 }) 81 82 // check negative case where plugin fruit doesn't implement banana 83 t.Run("not implemented", func(t *testing.T) { 84 _, err := Get("fruit", "banana") 85 assert.Check(t, is.ErrorIs(err, ErrNotImplements)) 86 }) 87 88 // check negative case where plugin vegetable doesn't exist 89 t.Run("not exists", func(t *testing.T) { 90 _, err := Get(testNonExistingPlugin, "no-such-implementation") 91 assert.Check(t, is.ErrorIs(err, ErrNotFound)) 92 }) 93 } 94 95 func TestPluginWithNoManifest(t *testing.T) { 96 // TODO: t.Parallel() 97 // TestGet also registers fruitPlugin 98 mux, addr := setupRemotePluginServer(t) 99 100 m := Manifest{[]string{fruitImplements}} 101 var buf bytes.Buffer 102 err := json.NewEncoder(&buf).Encode(m) 103 assert.NilError(t, err) 104 105 mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { 106 assert.Assert(t, is.Equal(r.Method, http.MethodPost)) 107 108 header := w.Header() 109 header.Set("Content-Type", transport.VersionMimetype) 110 111 io.Copy(w, &buf) 112 }) 113 114 p := &Plugin{ 115 name: fruitPlugin, 116 activateWait: sync.NewCond(&sync.Mutex{}), 117 Addr: addr, 118 TLSConfig: &tlsconfig.Options{InsecureSkipVerify: true}, 119 } 120 storage.Lock() 121 storage.plugins[fruitPlugin] = p 122 storage.Unlock() 123 124 plugin, err := Get(fruitPlugin, fruitImplements) 125 assert.NilError(t, err) 126 assert.Check(t, is.Equal(p.name, plugin.Name())) 127 } 128 129 func TestGetAll(t *testing.T) { 130 t.Parallel() 131 132 tmpdir := t.TempDir() 133 r := LocalRegistry{ 134 socketsPath: tmpdir, 135 specsPaths: []string{tmpdir}, 136 } 137 138 p := filepath.Join(tmpdir, "example.json") 139 spec := `{ 140 "Name": "example", 141 "Addr": "https://example.com/docker/plugin" 142 }` 143 144 err := os.WriteFile(p, []byte(spec), 0o644) 145 assert.NilError(t, err) 146 147 plugin, err := r.Plugin("example") 148 assert.NilError(t, err) 149 150 plugin.Manifest = &Manifest{Implements: []string{"apple"}} 151 storage.Lock() 152 storage.plugins["example"] = plugin 153 storage.Unlock() 154 155 fetchedPlugins, err := r.GetAll("apple") 156 assert.NilError(t, err) 157 assert.Check(t, is.Len(fetchedPlugins, 1)) 158 assert.Check(t, is.Equal(fetchedPlugins[0].Name(), plugin.Name())) 159 }