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 }