github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/pkg/plugins/plugin_test.go (about)

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