github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/volume/testutils/testutils.go (about)

     1  package testutils // import "github.com/demonoid81/moby/volume/testutils"
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"net"
     8  	"net/http"
     9  	"time"
    10  
    11  	"github.com/demonoid81/moby/pkg/plugingetter"
    12  	"github.com/demonoid81/moby/pkg/plugins"
    13  	"github.com/demonoid81/moby/volume"
    14  )
    15  
    16  // NoopVolume is a volume that doesn't perform any operation
    17  type NoopVolume struct{}
    18  
    19  // Name is the name of the volume
    20  func (NoopVolume) Name() string { return "noop" }
    21  
    22  // DriverName is the name of the driver
    23  func (NoopVolume) DriverName() string { return "noop" }
    24  
    25  // Path is the filesystem path to the volume
    26  func (NoopVolume) Path() string { return "noop" }
    27  
    28  // Mount mounts the volume in the container
    29  func (NoopVolume) Mount(_ string) (string, error) { return "noop", nil }
    30  
    31  // Unmount unmounts the volume from the container
    32  func (NoopVolume) Unmount(_ string) error { return nil }
    33  
    34  // Status provides low-level details about the volume
    35  func (NoopVolume) Status() map[string]interface{} { return nil }
    36  
    37  // CreatedAt provides the time the volume (directory) was created at
    38  func (NoopVolume) CreatedAt() (time.Time, error) { return time.Now(), nil }
    39  
    40  // FakeVolume is a fake volume with a random name
    41  type FakeVolume struct {
    42  	name       string
    43  	driverName string
    44  	createdAt  time.Time
    45  }
    46  
    47  // NewFakeVolume creates a new fake volume for testing
    48  func NewFakeVolume(name string, driverName string) volume.Volume {
    49  	return FakeVolume{name: name, driverName: driverName, createdAt: time.Now()}
    50  }
    51  
    52  // Name is the name of the volume
    53  func (f FakeVolume) Name() string { return f.name }
    54  
    55  // DriverName is the name of the driver
    56  func (f FakeVolume) DriverName() string { return f.driverName }
    57  
    58  // Path is the filesystem path to the volume
    59  func (FakeVolume) Path() string { return "fake" }
    60  
    61  // Mount mounts the volume in the container
    62  func (FakeVolume) Mount(_ string) (string, error) { return "fake", nil }
    63  
    64  // Unmount unmounts the volume from the container
    65  func (FakeVolume) Unmount(_ string) error { return nil }
    66  
    67  // Status provides low-level details about the volume
    68  func (FakeVolume) Status() map[string]interface{} {
    69  	return map[string]interface{}{"datakey": "datavalue"}
    70  }
    71  
    72  // CreatedAt provides the time the volume (directory) was created at
    73  func (f FakeVolume) CreatedAt() (time.Time, error) {
    74  	return f.createdAt, nil
    75  }
    76  
    77  // FakeDriver is a driver that generates fake volumes
    78  type FakeDriver struct {
    79  	name string
    80  	vols map[string]volume.Volume
    81  }
    82  
    83  // NewFakeDriver creates a new FakeDriver with the specified name
    84  func NewFakeDriver(name string) volume.Driver {
    85  	return &FakeDriver{
    86  		name: name,
    87  		vols: make(map[string]volume.Volume),
    88  	}
    89  }
    90  
    91  // Name is the name of the driver
    92  func (d *FakeDriver) Name() string { return d.name }
    93  
    94  // Create initializes a fake volume.
    95  // It returns an error if the options include an "error" key with a message
    96  func (d *FakeDriver) Create(name string, opts map[string]string) (volume.Volume, error) {
    97  	if opts != nil && opts["error"] != "" {
    98  		return nil, fmt.Errorf(opts["error"])
    99  	}
   100  	v := NewFakeVolume(name, d.name)
   101  	d.vols[name] = v
   102  	return v, nil
   103  }
   104  
   105  // Remove deletes a volume.
   106  func (d *FakeDriver) Remove(v volume.Volume) error {
   107  	if _, exists := d.vols[v.Name()]; !exists {
   108  		return fmt.Errorf("no such volume")
   109  	}
   110  	delete(d.vols, v.Name())
   111  	return nil
   112  }
   113  
   114  // List lists the volumes
   115  func (d *FakeDriver) List() ([]volume.Volume, error) {
   116  	var vols []volume.Volume
   117  	for _, v := range d.vols {
   118  		vols = append(vols, v)
   119  	}
   120  	return vols, nil
   121  }
   122  
   123  // Get gets the volume
   124  func (d *FakeDriver) Get(name string) (volume.Volume, error) {
   125  	if v, exists := d.vols[name]; exists {
   126  		return v, nil
   127  	}
   128  	return nil, fmt.Errorf("no such volume")
   129  }
   130  
   131  // Scope returns the local scope
   132  func (*FakeDriver) Scope() string {
   133  	return "local"
   134  }
   135  
   136  type fakePlugin struct {
   137  	client *plugins.Client
   138  	name   string
   139  	refs   int
   140  }
   141  
   142  // MakeFakePlugin creates a fake plugin from the passed in driver
   143  // Note: currently only "Create" is implemented because that's all that's needed
   144  // so far. If you need it to test something else, add it here, but probably you
   145  // shouldn't need to use this except for very specific cases with v2 plugin handling.
   146  func MakeFakePlugin(d volume.Driver, l net.Listener) (plugingetter.CompatPlugin, error) {
   147  	c, err := plugins.NewClient(l.Addr().Network()+"://"+l.Addr().String(), nil)
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  	mux := http.NewServeMux()
   152  
   153  	mux.HandleFunc("/VolumeDriver.Create", func(w http.ResponseWriter, r *http.Request) {
   154  		createReq := struct {
   155  			Name string
   156  			Opts map[string]string
   157  		}{}
   158  		if err := json.NewDecoder(r.Body).Decode(&createReq); err != nil {
   159  			fmt.Fprintf(w, `{"Err": "%s"}`, err.Error())
   160  			return
   161  		}
   162  		_, err := d.Create(createReq.Name, createReq.Opts)
   163  		if err != nil {
   164  			fmt.Fprintf(w, `{"Err": "%s"}`, err.Error())
   165  			return
   166  		}
   167  		w.Write([]byte("{}"))
   168  	})
   169  
   170  	go http.Serve(l, mux)
   171  	return &fakePlugin{client: c, name: d.Name()}, nil
   172  }
   173  
   174  func (p *fakePlugin) Client() *plugins.Client {
   175  	return p.client
   176  }
   177  
   178  func (p *fakePlugin) Name() string {
   179  	return p.name
   180  }
   181  
   182  func (p *fakePlugin) IsV1() bool {
   183  	return false
   184  }
   185  
   186  func (p *fakePlugin) ScopedPath(s string) string {
   187  	return s
   188  }
   189  
   190  type fakePluginGetter struct {
   191  	plugins map[string]plugingetter.CompatPlugin
   192  }
   193  
   194  // NewFakePluginGetter returns a plugin getter for fake plugins
   195  func NewFakePluginGetter(pls ...plugingetter.CompatPlugin) plugingetter.PluginGetter {
   196  	idx := make(map[string]plugingetter.CompatPlugin, len(pls))
   197  	for _, p := range pls {
   198  		idx[p.Name()] = p
   199  	}
   200  	return &fakePluginGetter{plugins: idx}
   201  }
   202  
   203  // This ignores the second argument since we only care about volume drivers here,
   204  // there shouldn't be any other kind of plugin in here
   205  func (g *fakePluginGetter) Get(name, _ string, mode int) (plugingetter.CompatPlugin, error) {
   206  	p, ok := g.plugins[name]
   207  	if !ok {
   208  		return nil, errors.New("not found")
   209  	}
   210  	p.(*fakePlugin).refs += mode
   211  	return p, nil
   212  }
   213  
   214  func (g *fakePluginGetter) GetAllByCap(capability string) ([]plugingetter.CompatPlugin, error) {
   215  	panic("GetAllByCap shouldn't be called")
   216  }
   217  
   218  func (g *fakePluginGetter) GetAllManagedPluginsByCap(capability string) []plugingetter.CompatPlugin {
   219  	panic("GetAllManagedPluginsByCap should not be called")
   220  }
   221  
   222  func (g *fakePluginGetter) Handle(capability string, callback func(string, *plugins.Client)) {
   223  	panic("Handle should not be called")
   224  }
   225  
   226  // FakeRefs checks ref count on a fake plugin.
   227  func FakeRefs(p plugingetter.CompatPlugin) int {
   228  	// this should panic if something other than a `*fakePlugin` is passed in
   229  	return p.(*fakePlugin).refs
   230  }