Browse Source

Increase the Coverage of pkg/plugins

Increases the test coverage of pkg/plugins.
Changed signature of function NewClientWithTimeout in pkg/plugin/client, to
take time.Duration instead of integers.

Signed-off-by: Raja Sami <raja.sami@tenpearl.com>
Raja Sami 8 years ago
parent
commit
8dd100a229

+ 4 - 4
pkg/plugins/client.go

@@ -57,20 +57,20 @@ func NewClient(addr string, tlsConfig *tlsconfig.Options) (*Client, error) {
 }
 
 // NewClientWithTimeout creates a new plugin client (http).
-func NewClientWithTimeout(addr string, tlsConfig *tlsconfig.Options, timeoutInSecs int) (*Client, error) {
+func NewClientWithTimeout(addr string, tlsConfig *tlsconfig.Options, timeout time.Duration) (*Client, error) {
 	clientTransport, err := newTransport(addr, tlsConfig)
 	if err != nil {
 		return nil, err
 	}
-	return newClientWithTransport(clientTransport, timeoutInSecs), nil
+	return newClientWithTransport(clientTransport, timeout), nil
 }
 
 // newClientWithTransport creates a new plugin client with a given transport.
-func newClientWithTransport(tr transport.Transport, timeoutInSecs int) *Client {
+func newClientWithTransport(tr transport.Transport, timeout time.Duration) *Client {
 	return &Client{
 		http: &http.Client{
 			Transport: tr,
-			Timeout:   time.Duration(timeoutInSecs) * time.Second,
+			Timeout:   timeout,
 		},
 		requestFactory: tr,
 	}

+ 83 - 4
pkg/plugins/client_test.go

@@ -1,17 +1,19 @@
 package plugins
 
 import (
+	"bytes"
+	"encoding/json"
 	"io"
 	"net/http"
 	"net/http/httptest"
 	"net/url"
-	"reflect"
 	"strings"
 	"testing"
 	"time"
 
 	"github.com/docker/docker/pkg/plugins/transport"
 	"github.com/docker/go-connections/tlsconfig"
+	"github.com/stretchr/testify/assert"
 )
 
 var (
@@ -83,9 +85,7 @@ func TestEchoInputOutput(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	if !reflect.DeepEqual(output, m) {
-		t.Fatalf("Expected %v, was %v\n", m, output)
-	}
+	assert.Equal(t, m, output)
 	err = c.Call("Test.Echo", nil, nil)
 	if err != nil {
 		t.Fatal(err)
@@ -153,3 +153,82 @@ func TestClientScheme(t *testing.T) {
 		}
 	}
 }
+
+func TestNewClientWithTimeout(t *testing.T) {
+	addr := setupRemotePluginServer()
+	defer teardownRemotePluginServer()
+
+	m := Manifest{[]string{"VolumeDriver", "NetworkDriver"}}
+
+	mux.HandleFunc("/Test.Echo", func(w http.ResponseWriter, r *http.Request) {
+		time.Sleep(time.Duration(600) * time.Millisecond)
+		io.Copy(w, r.Body)
+	})
+
+	// setting timeout of 500ms
+	timeout := time.Duration(500) * time.Millisecond
+	c, _ := NewClientWithTimeout(addr, &tlsconfig.Options{InsecureSkipVerify: true}, timeout)
+	var output Manifest
+	err := c.Call("Test.Echo", m, &output)
+	if err == nil {
+		t.Fatal("Expected timeout error")
+	}
+}
+
+func TestClientStream(t *testing.T) {
+	addr := setupRemotePluginServer()
+	defer teardownRemotePluginServer()
+
+	m := Manifest{[]string{"VolumeDriver", "NetworkDriver"}}
+	var output Manifest
+
+	mux.HandleFunc("/Test.Echo", func(w http.ResponseWriter, r *http.Request) {
+		if r.Method != "POST" {
+			t.Fatalf("Expected POST, got %s", r.Method)
+		}
+
+		header := w.Header()
+		header.Set("Content-Type", transport.VersionMimetype)
+
+		io.Copy(w, r.Body)
+	})
+
+	c, _ := NewClient(addr, &tlsconfig.Options{InsecureSkipVerify: true})
+	body, err := c.Stream("Test.Echo", m)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer body.Close()
+	if err := json.NewDecoder(body).Decode(&output); err != nil {
+		t.Fatalf("Test.Echo: error reading plugin resp: %v", err)
+	}
+	assert.Equal(t, m, output)
+}
+
+func TestClientSendFile(t *testing.T) {
+	addr := setupRemotePluginServer()
+	defer teardownRemotePluginServer()
+
+	m := Manifest{[]string{"VolumeDriver", "NetworkDriver"}}
+	var output Manifest
+	var buf bytes.Buffer
+	if err := json.NewEncoder(&buf).Encode(m); err != nil {
+		t.Fatal(err)
+	}
+	mux.HandleFunc("/Test.Echo", func(w http.ResponseWriter, r *http.Request) {
+		if r.Method != "POST" {
+			t.Fatalf("Expected POST, got %s\n", r.Method)
+		}
+
+		header := w.Header()
+		header.Set("Content-Type", transport.VersionMimetype)
+
+		io.Copy(w, r.Body)
+	})
+
+	c, _ := NewClient(addr, &tlsconfig.Options{InsecureSkipVerify: true})
+	if err := c.SendFile("Test.Echo", &buf, &output); err != nil {
+		t.Fatal(err)
+	}
+	assert.Equal(t, m, output)
+}

+ 39 - 0
pkg/plugins/discovery_unix_test.go

@@ -4,6 +4,7 @@ package plugins
 
 import (
 	"fmt"
+	"io/ioutil"
 	"net"
 	"os"
 	"path/filepath"
@@ -59,3 +60,41 @@ func TestLocalSocket(t *testing.T) {
 		l.Close()
 	}
 }
+
+func TestScan(t *testing.T) {
+	tmpdir, unregister := Setup(t)
+	defer unregister()
+
+	pluginNames, err := Scan()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if pluginNames != nil {
+		t.Fatal("Plugin names should be empty.")
+	}
+
+	path := filepath.Join(tmpdir, "echo.spec")
+	addr := "unix://var/lib/docker/plugins/echo.sock"
+	name := "echo"
+
+	err = os.MkdirAll(filepath.Dir(path), 0755)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	err = ioutil.WriteFile(path, []byte(addr), 0644)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	r := newLocalRegistry()
+	p, err := r.Plugin(name)
+
+	pluginNamesNotEmpty, err := Scan()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if p.Name() != pluginNamesNotEmpty[0] {
+		t.Fatalf("Unable to scan plugin with name %s", p.name)
+	}
+}

+ 112 - 0
pkg/plugins/plugin_test.go

@@ -1,12 +1,26 @@
 package plugins
 
 import (
+	"bytes"
+	"encoding/json"
 	"errors"
+	"io"
+	"io/ioutil"
+	"net/http"
 	"path/filepath"
 	"runtime"
 	"sync"
 	"testing"
 	"time"
+
+	"github.com/docker/docker/pkg/plugins/transport"
+	"github.com/docker/go-connections/tlsconfig"
+	"github.com/stretchr/testify/assert"
+)
+
+const (
+	fruitPlugin     = "fruit"
+	fruitImplements = "apple"
 )
 
 // regression test for deadlock in handlers
@@ -42,3 +56,101 @@ func testActive(t *testing.T, p *Plugin) {
 	}
 
 }
+
+func TestGet(t *testing.T) {
+	p := &Plugin{name: fruitPlugin, activateWait: sync.NewCond(&sync.Mutex{})}
+	p.Manifest = &Manifest{Implements: []string{fruitImplements}}
+	storage.plugins[fruitPlugin] = p
+
+	plugin, err := Get(fruitPlugin, fruitImplements)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if p.Name() != plugin.Name() {
+		t.Fatalf("No matching plugin with name %s found", plugin.Name())
+	}
+	if plugin.Client() != nil {
+		t.Fatal("expected nil Client but found one")
+	}
+	if !plugin.IsV1() {
+		t.Fatal("Expected true for V1 plugin")
+	}
+
+	// check negative case where plugin fruit doesn't implement banana
+	_, err = Get("fruit", "banana")
+	assert.Equal(t, err, ErrNotImplements)
+
+	// check negative case where plugin vegetable doesn't exist
+	_, err = Get("vegetable", "potato")
+	assert.Equal(t, err, ErrNotFound)
+
+}
+
+func TestPluginWithNoManifest(t *testing.T) {
+	addr := setupRemotePluginServer()
+	defer teardownRemotePluginServer()
+
+	m := Manifest{[]string{fruitImplements}}
+	var buf bytes.Buffer
+	if err := json.NewEncoder(&buf).Encode(m); err != nil {
+		t.Fatal(err)
+	}
+
+	mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
+		if r.Method != "POST" {
+			t.Fatalf("Expected POST, got %s\n", r.Method)
+		}
+
+		header := w.Header()
+		header.Set("Content-Type", transport.VersionMimetype)
+
+		io.Copy(w, &buf)
+	})
+
+	p := &Plugin{
+		name:         fruitPlugin,
+		activateWait: sync.NewCond(&sync.Mutex{}),
+		Addr:         addr,
+		TLSConfig:    &tlsconfig.Options{InsecureSkipVerify: true},
+	}
+	storage.plugins[fruitPlugin] = p
+
+	plugin, err := Get(fruitPlugin, fruitImplements)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if p.Name() != plugin.Name() {
+		t.Fatalf("No matching plugin with name %s found", plugin.Name())
+	}
+}
+
+func TestGetAll(t *testing.T) {
+	tmpdir, unregister := Setup(t)
+	defer unregister()
+
+	p := filepath.Join(tmpdir, "example.json")
+	spec := `{
+	"Name": "example",
+	"Addr": "https://example.com/docker/plugin"
+}`
+
+	if err := ioutil.WriteFile(p, []byte(spec), 0644); err != nil {
+		t.Fatal(err)
+	}
+
+	r := newLocalRegistry()
+	plugin, err := r.Plugin("example")
+	if err != nil {
+		t.Fatal(err)
+	}
+	plugin.Manifest = &Manifest{Implements: []string{"apple"}}
+	storage.plugins["example"] = plugin
+
+	fetchedPlugins, err := GetAll("apple")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if fetchedPlugins[0].Name() != plugin.Name() {
+		t.Fatalf("Expected to get plugin with name %s", plugin.Name())
+	}
+}

+ 20 - 0
pkg/plugins/transport/http_test.go

@@ -0,0 +1,20 @@
+package transport
+
+import (
+	"io"
+	"net/http"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestHTTPTransport(t *testing.T) {
+	var r io.Reader
+	roundTripper := &http.Transport{}
+	newTransport := NewHTTPTransport(roundTripper, "http", "0.0.0.0")
+	request, err := newTransport.NewRequest("", r)
+	if err != nil {
+		t.Fatal(err)
+	}
+	assert.Equal(t, "POST", request.Method)
+}

+ 1 - 1
plugin/manager_linux.go

@@ -80,7 +80,7 @@ func (pm *Manager) enable(p *v2.Plugin, c *controller, force bool) error {
 
 func (pm *Manager) pluginPostStart(p *v2.Plugin, c *controller) error {
 	sockAddr := filepath.Join(pm.config.ExecRoot, p.GetID(), p.GetSocket())
-	client, err := plugins.NewClientWithTimeout("unix://"+sockAddr, nil, c.timeoutInSecs)
+	client, err := plugins.NewClientWithTimeout("unix://"+sockAddr, nil, time.Duration(c.timeoutInSecs)*time.Second)
 	if err != nil {
 		c.restart = false
 		shutdownPlugin(p, c, pm.containerdClient)