Skip to content

Commit

Permalink
Merge pull request moby#33374 from raja-sami-10p/pkg/plugins
Browse files Browse the repository at this point in the history
Increase the Coverage of pkg/plugins
  • Loading branch information
thaJeztah authored Jun 13, 2017
2 parents 3029e4b + 8dd100a commit 8183b9d
Show file tree
Hide file tree
Showing 6 changed files with 259 additions and 9 deletions.
8 changes: 4 additions & 4 deletions pkg/plugins/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down
87 changes: 83 additions & 4 deletions pkg/plugins/client_test.go
Original file line number Diff line number Diff line change
@@ -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 (
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 changes: 39 additions & 0 deletions pkg/plugins/discovery_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package plugins

import (
"fmt"
"io/ioutil"
"net"
"os"
"path/filepath"
Expand Down Expand Up @@ -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 changes: 112 additions & 0 deletions pkg/plugins/plugin_test.go
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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 changes: 20 additions & 0 deletions pkg/plugins/transport/http_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
2 changes: 1 addition & 1 deletion plugin/manager_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 8183b9d

Please sign in to comment.