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