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>
This commit is contained in:
Raja Sami 2017-05-22 14:38:23 +05:00
parent 3f6b6c2981
commit 8dd100a229
6 changed files with 259 additions and 9 deletions

View File

@ -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,
}

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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())
}
}

View File

@ -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)
}

View File

@ -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)