mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
574db7a537
These messages were enhanced to include the path that was
missing (in df6af282b9
), but
also changed the first part of the message.
This change complicates running e2e tests with mixed versions
of the engine.
Looking at the full error message, "mount" is a bit redundant
as well, because the error message already indicates this is
about a "mount";
docker run --rm --mount type=bind,source=/no-such-thing,target=/foo busybox
docker: Error response from daemon: invalid mount config for type "bind": bind mount source path does not exist: /no-such-thing.
Removing the "mount" part from the error message, because
it was redundant, and makes cross-version testing easier :)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
480 lines
22 KiB
Go
480 lines
22 KiB
Go
package mounts // import "github.com/docker/docker/volume/mounts"
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/docker/docker/api/types/mount"
|
|
)
|
|
|
|
type parseMountRawTestSet struct {
|
|
valid []string
|
|
invalid map[string]string
|
|
}
|
|
|
|
func TestConvertTmpfsOptions(t *testing.T) {
|
|
type testCase struct {
|
|
opt mount.TmpfsOptions
|
|
readOnly bool
|
|
expectedSubstrings []string
|
|
unexpectedSubstrings []string
|
|
}
|
|
cases := []testCase{
|
|
{
|
|
opt: mount.TmpfsOptions{SizeBytes: 1024 * 1024, Mode: 0700},
|
|
readOnly: false,
|
|
expectedSubstrings: []string{"size=1m", "mode=700"},
|
|
unexpectedSubstrings: []string{"ro"},
|
|
},
|
|
{
|
|
opt: mount.TmpfsOptions{},
|
|
readOnly: true,
|
|
expectedSubstrings: []string{"ro"},
|
|
unexpectedSubstrings: []string{},
|
|
},
|
|
}
|
|
p := &linuxParser{}
|
|
for _, c := range cases {
|
|
data, err := p.ConvertTmpfsOptions(&c.opt, c.readOnly)
|
|
if err != nil {
|
|
t.Fatalf("could not convert %+v (readOnly: %v) to string: %v",
|
|
c.opt, c.readOnly, err)
|
|
}
|
|
t.Logf("data=%q", data)
|
|
for _, s := range c.expectedSubstrings {
|
|
if !strings.Contains(data, s) {
|
|
t.Fatalf("expected substring: %s, got %v (case=%+v)", s, data, c)
|
|
}
|
|
}
|
|
for _, s := range c.unexpectedSubstrings {
|
|
if strings.Contains(data, s) {
|
|
t.Fatalf("unexpected substring: %s, got %v (case=%+v)", s, data, c)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
type mockFiProvider struct{}
|
|
|
|
func (mockFiProvider) fileInfo(path string) (exists, isDir bool, err error) {
|
|
dirs := map[string]struct{}{
|
|
`c:\`: {},
|
|
`c:\windows\`: {},
|
|
`c:\windows`: {},
|
|
`c:\program files`: {},
|
|
`c:\Windows`: {},
|
|
`c:\Program Files (x86)`: {},
|
|
`\\?\c:\windows\`: {},
|
|
}
|
|
files := map[string]struct{}{
|
|
`c:\windows\system32\ntdll.dll`: {},
|
|
}
|
|
if _, ok := dirs[path]; ok {
|
|
return true, true, nil
|
|
}
|
|
if _, ok := files[path]; ok {
|
|
return true, false, nil
|
|
}
|
|
return false, false, nil
|
|
}
|
|
|
|
func TestParseMountRaw(t *testing.T) {
|
|
|
|
previousProvider := currentFileInfoProvider
|
|
defer func() { currentFileInfoProvider = previousProvider }()
|
|
currentFileInfoProvider = mockFiProvider{}
|
|
windowsSet := parseMountRawTestSet{
|
|
valid: []string{
|
|
`d:\`,
|
|
`d:`,
|
|
`d:\path`,
|
|
`d:\path with space`,
|
|
`c:\:d:\`,
|
|
`c:\windows\:d:`,
|
|
`c:\windows:d:\s p a c e`,
|
|
`c:\windows:d:\s p a c e:RW`,
|
|
`c:\program files:d:\s p a c e i n h o s t d i r`,
|
|
`0123456789name:d:`,
|
|
`MiXeDcAsEnAmE:d:`,
|
|
`name:D:`,
|
|
`name:D::rW`,
|
|
`name:D::RW`,
|
|
`name:D::RO`,
|
|
`c:/:d:/forward/slashes/are/good/too`,
|
|
`c:/:d:/including with/spaces:ro`,
|
|
`c:\Windows`, // With capital
|
|
`c:\Program Files (x86)`, // With capitals and brackets
|
|
`\\?\c:\windows\:d:`, // Long path handling (source)
|
|
`c:\windows\:\\?\d:\`, // Long path handling (target)
|
|
`\\.\pipe\foo:\\.\pipe\foo`, // named pipe
|
|
`//./pipe/foo://./pipe/foo`, // named pipe forward slashes
|
|
},
|
|
invalid: map[string]string{
|
|
``: "invalid volume specification: ",
|
|
`.`: "invalid volume specification: ",
|
|
`..\`: "invalid volume specification: ",
|
|
`c:\:..\`: "invalid volume specification: ",
|
|
`c:\:d:\:xyzzy`: "invalid volume specification: ",
|
|
`c:`: "cannot be `c:`",
|
|
`c:\`: "cannot be `c:`",
|
|
`c:\notexist:d:`: `source path does not exist: c:\notexist`,
|
|
`c:\windows\system32\ntdll.dll:d:`: `source path must be a directory`,
|
|
`name<:d:`: `invalid volume specification`,
|
|
`name>:d:`: `invalid volume specification`,
|
|
`name::d:`: `invalid volume specification`,
|
|
`name":d:`: `invalid volume specification`,
|
|
`name\:d:`: `invalid volume specification`,
|
|
`name*:d:`: `invalid volume specification`,
|
|
`name|:d:`: `invalid volume specification`,
|
|
`name?:d:`: `invalid volume specification`,
|
|
`name/:d:`: `invalid volume specification`,
|
|
`d:\pathandmode:rw`: `invalid volume specification`,
|
|
`d:\pathandmode:ro`: `invalid volume specification`,
|
|
`con:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`PRN:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`aUx:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`nul:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`com1:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`com2:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`com3:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`com4:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`com5:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`com6:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`com7:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`com8:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`com9:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt1:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt2:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt3:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt4:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt5:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt6:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt7:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt8:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt9:d:`: `cannot be a reserved word for Windows filenames`,
|
|
`c:\windows\system32\ntdll.dll`: `Only directories can be mapped on this platform`,
|
|
`\\.\pipe\foo:c:\pipe`: `'c:\pipe' is not a valid pipe path`,
|
|
},
|
|
}
|
|
lcowSet := parseMountRawTestSet{
|
|
valid: []string{
|
|
`/foo`,
|
|
`/foo/`,
|
|
`/foo bar`,
|
|
`c:\:/foo`,
|
|
`c:\windows\:/foo`,
|
|
`c:\windows:/s p a c e`,
|
|
`c:\windows:/s p a c e:RW`,
|
|
`c:\program files:/s p a c e i n h o s t d i r`,
|
|
`0123456789name:/foo`,
|
|
`MiXeDcAsEnAmE:/foo`,
|
|
`name:/foo`,
|
|
`name:/foo:rW`,
|
|
`name:/foo:RW`,
|
|
`name:/foo:RO`,
|
|
`c:/:/forward/slashes/are/good/too`,
|
|
`c:/:/including with/spaces:ro`,
|
|
`/Program Files (x86)`, // With capitals and brackets
|
|
},
|
|
invalid: map[string]string{
|
|
``: "invalid volume specification: ",
|
|
`.`: "invalid volume specification: ",
|
|
`c:`: "invalid volume specification: ",
|
|
`c:\`: "invalid volume specification: ",
|
|
`../`: "invalid volume specification: ",
|
|
`c:\:../`: "invalid volume specification: ",
|
|
`c:\:/foo:xyzzy`: "invalid volume specification: ",
|
|
`/`: "destination can't be '/'",
|
|
`/..`: "destination can't be '/'",
|
|
`c:\notexist:/foo`: `source path does not exist: c:\notexist`,
|
|
`c:\windows\system32\ntdll.dll:/foo`: `source path must be a directory`,
|
|
`name<:/foo`: `invalid volume specification`,
|
|
`name>:/foo`: `invalid volume specification`,
|
|
`name::/foo`: `invalid volume specification`,
|
|
`name":/foo`: `invalid volume specification`,
|
|
`name\:/foo`: `invalid volume specification`,
|
|
`name*:/foo`: `invalid volume specification`,
|
|
`name|:/foo`: `invalid volume specification`,
|
|
`name?:/foo`: `invalid volume specification`,
|
|
`name/:/foo`: `invalid volume specification`,
|
|
`/foo:rw`: `invalid volume specification`,
|
|
`/foo:ro`: `invalid volume specification`,
|
|
`con:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`PRN:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`aUx:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`nul:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`com1:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`com2:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`com3:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`com4:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`com5:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`com6:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`com7:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`com8:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`com9:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt1:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt2:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt3:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt4:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt5:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt6:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt7:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt8:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`lpt9:/foo`: `cannot be a reserved word for Windows filenames`,
|
|
`\\.\pipe\foo:/foo`: `Linux containers on Windows do not support named pipe mounts`,
|
|
},
|
|
}
|
|
linuxSet := parseMountRawTestSet{
|
|
valid: []string{
|
|
"/home",
|
|
"/home:/home",
|
|
"/home:/something/else",
|
|
"/with space",
|
|
"/home:/with space",
|
|
"relative:/absolute-path",
|
|
"hostPath:/containerPath:ro",
|
|
"/hostPath:/containerPath:rw",
|
|
"/rw:/ro",
|
|
"/hostPath:/containerPath:shared",
|
|
"/hostPath:/containerPath:rshared",
|
|
"/hostPath:/containerPath:slave",
|
|
"/hostPath:/containerPath:rslave",
|
|
"/hostPath:/containerPath:private",
|
|
"/hostPath:/containerPath:rprivate",
|
|
"/hostPath:/containerPath:ro,shared",
|
|
"/hostPath:/containerPath:ro,slave",
|
|
"/hostPath:/containerPath:ro,private",
|
|
"/hostPath:/containerPath:ro,z,shared",
|
|
"/hostPath:/containerPath:ro,Z,slave",
|
|
"/hostPath:/containerPath:Z,ro,slave",
|
|
"/hostPath:/containerPath:slave,Z,ro",
|
|
"/hostPath:/containerPath:Z,slave,ro",
|
|
"/hostPath:/containerPath:slave,ro,Z",
|
|
"/hostPath:/containerPath:rslave,ro,Z",
|
|
"/hostPath:/containerPath:ro,rshared,Z",
|
|
"/hostPath:/containerPath:ro,Z,rprivate",
|
|
},
|
|
invalid: map[string]string{
|
|
"": "invalid volume specification",
|
|
"./": "mount path must be absolute",
|
|
"../": "mount path must be absolute",
|
|
"/:../": "mount path must be absolute",
|
|
"/:path": "mount path must be absolute",
|
|
":": "invalid volume specification",
|
|
"/tmp:": "invalid volume specification",
|
|
":test": "invalid volume specification",
|
|
":/test": "invalid volume specification",
|
|
"tmp:": "invalid volume specification",
|
|
":test:": "invalid volume specification",
|
|
"::": "invalid volume specification",
|
|
":::": "invalid volume specification",
|
|
"/tmp:::": "invalid volume specification",
|
|
":/tmp::": "invalid volume specification",
|
|
"/path:rw": "invalid volume specification",
|
|
"/path:ro": "invalid volume specification",
|
|
"/rw:rw": "invalid volume specification",
|
|
"path:ro": "invalid volume specification",
|
|
"/path:/path:sw": `invalid mode`,
|
|
"/path:/path:rwz": `invalid mode`,
|
|
"/path:/path:ro,rshared,rslave": `invalid mode`,
|
|
"/path:/path:ro,z,rshared,rslave": `invalid mode`,
|
|
"/path:shared": "invalid volume specification",
|
|
"/path:slave": "invalid volume specification",
|
|
"/path:private": "invalid volume specification",
|
|
"name:/absolute-path:shared": "invalid volume specification",
|
|
"name:/absolute-path:rshared": "invalid volume specification",
|
|
"name:/absolute-path:slave": "invalid volume specification",
|
|
"name:/absolute-path:rslave": "invalid volume specification",
|
|
"name:/absolute-path:private": "invalid volume specification",
|
|
"name:/absolute-path:rprivate": "invalid volume specification",
|
|
},
|
|
}
|
|
|
|
linParser := &linuxParser{}
|
|
winParser := &windowsParser{}
|
|
lcowParser := &lcowParser{}
|
|
tester := func(parser Parser, set parseMountRawTestSet) {
|
|
|
|
for _, path := range set.valid {
|
|
|
|
if _, err := parser.ParseMountRaw(path, "local"); err != nil {
|
|
t.Errorf("ParseMountRaw(`%q`) should succeed: error %q", path, err)
|
|
}
|
|
}
|
|
|
|
for path, expectedError := range set.invalid {
|
|
if mp, err := parser.ParseMountRaw(path, "local"); err == nil {
|
|
t.Errorf("ParseMountRaw(`%q`) should have failed validation. Err '%v' - MP: %v", path, err, mp)
|
|
} else {
|
|
if !strings.Contains(err.Error(), expectedError) {
|
|
t.Errorf("ParseMountRaw(`%q`) error should contain %q, got %v", path, expectedError, err.Error())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
tester(linParser, linuxSet)
|
|
tester(winParser, windowsSet)
|
|
tester(lcowParser, lcowSet)
|
|
|
|
}
|
|
|
|
// testParseMountRaw is a structure used by TestParseMountRawSplit for
|
|
// specifying test cases for the ParseMountRaw() function.
|
|
type testParseMountRaw struct {
|
|
bind string
|
|
driver string
|
|
expType mount.Type
|
|
expDest string
|
|
expSource string
|
|
expName string
|
|
expDriver string
|
|
expRW bool
|
|
fail bool
|
|
}
|
|
|
|
func TestParseMountRawSplit(t *testing.T) {
|
|
previousProvider := currentFileInfoProvider
|
|
defer func() { currentFileInfoProvider = previousProvider }()
|
|
currentFileInfoProvider = mockFiProvider{}
|
|
windowsCases := []testParseMountRaw{
|
|
{`c:\:d:`, "local", mount.TypeBind, `d:`, `c:\`, ``, "", true, false},
|
|
{`c:\:d:\`, "local", mount.TypeBind, `d:\`, `c:\`, ``, "", true, false},
|
|
{`c:\:d:\:ro`, "local", mount.TypeBind, `d:\`, `c:\`, ``, "", false, false},
|
|
{`c:\:d:\:rw`, "local", mount.TypeBind, `d:\`, `c:\`, ``, "", true, false},
|
|
{`c:\:d:\:foo`, "local", mount.TypeBind, `d:\`, `c:\`, ``, "", false, true},
|
|
{`name:d::rw`, "local", mount.TypeVolume, `d:`, ``, `name`, "local", true, false},
|
|
{`name:d:`, "local", mount.TypeVolume, `d:`, ``, `name`, "local", true, false},
|
|
{`name:d::ro`, "local", mount.TypeVolume, `d:`, ``, `name`, "local", false, false},
|
|
{`name:c:`, "", mount.TypeVolume, ``, ``, ``, "", true, true},
|
|
{`driver/name:c:`, "", mount.TypeVolume, ``, ``, ``, "", true, true},
|
|
{`\\.\pipe\foo:\\.\pipe\bar`, "local", mount.TypeNamedPipe, `\\.\pipe\bar`, `\\.\pipe\foo`, "", "", true, false},
|
|
{`\\.\pipe\foo:c:\foo\bar`, "local", mount.TypeNamedPipe, ``, ``, "", "", true, true},
|
|
{`c:\foo\bar:\\.\pipe\foo`, "local", mount.TypeNamedPipe, ``, ``, "", "", true, true},
|
|
}
|
|
lcowCases := []testParseMountRaw{
|
|
{`c:\:/foo`, "local", mount.TypeBind, `/foo`, `c:\`, ``, "", true, false},
|
|
{`c:\:/foo:ro`, "local", mount.TypeBind, `/foo`, `c:\`, ``, "", false, false},
|
|
{`c:\:/foo:rw`, "local", mount.TypeBind, `/foo`, `c:\`, ``, "", true, false},
|
|
{`c:\:/foo:foo`, "local", mount.TypeBind, `/foo`, `c:\`, ``, "", false, true},
|
|
{`name:/foo:rw`, "local", mount.TypeVolume, `/foo`, ``, `name`, "local", true, false},
|
|
{`name:/foo`, "local", mount.TypeVolume, `/foo`, ``, `name`, "local", true, false},
|
|
{`name:/foo:ro`, "local", mount.TypeVolume, `/foo`, ``, `name`, "local", false, false},
|
|
{`name:/`, "", mount.TypeVolume, ``, ``, ``, "", true, true},
|
|
{`driver/name:/`, "", mount.TypeVolume, ``, ``, ``, "", true, true},
|
|
{`\\.\pipe\foo:\\.\pipe\bar`, "local", mount.TypeNamedPipe, `\\.\pipe\bar`, `\\.\pipe\foo`, "", "", true, true},
|
|
{`\\.\pipe\foo:/data`, "local", mount.TypeNamedPipe, ``, ``, "", "", true, true},
|
|
{`c:\foo\bar:\\.\pipe\foo`, "local", mount.TypeNamedPipe, ``, ``, "", "", true, true},
|
|
}
|
|
linuxCases := []testParseMountRaw{
|
|
{"/tmp:/tmp1", "", mount.TypeBind, "/tmp1", "/tmp", "", "", true, false},
|
|
{"/tmp:/tmp2:ro", "", mount.TypeBind, "/tmp2", "/tmp", "", "", false, false},
|
|
{"/tmp:/tmp3:rw", "", mount.TypeBind, "/tmp3", "/tmp", "", "", true, false},
|
|
{"/tmp:/tmp4:foo", "", mount.TypeBind, "", "", "", "", false, true},
|
|
{"name:/named1", "", mount.TypeVolume, "/named1", "", "name", "", true, false},
|
|
{"name:/named2", "external", mount.TypeVolume, "/named2", "", "name", "external", true, false},
|
|
{"name:/named3:ro", "local", mount.TypeVolume, "/named3", "", "name", "local", false, false},
|
|
{"local/name:/tmp:rw", "", mount.TypeVolume, "/tmp", "", "local/name", "", true, false},
|
|
{"/tmp:tmp", "", mount.TypeBind, "", "", "", "", true, true},
|
|
}
|
|
linParser := &linuxParser{}
|
|
winParser := &windowsParser{}
|
|
lcowParser := &lcowParser{}
|
|
tester := func(parser Parser, cases []testParseMountRaw) {
|
|
for i, c := range cases {
|
|
t.Logf("case %d", i)
|
|
m, err := parser.ParseMountRaw(c.bind, c.driver)
|
|
if c.fail {
|
|
if err == nil {
|
|
t.Errorf("Expected error, was nil, for spec %s\n", c.bind)
|
|
}
|
|
continue
|
|
}
|
|
|
|
if m == nil || err != nil {
|
|
t.Errorf("ParseMountRaw failed for spec '%s', driver '%s', error '%v'", c.bind, c.driver, err.Error())
|
|
continue
|
|
}
|
|
|
|
if m.Destination != c.expDest {
|
|
t.Errorf("Expected destination '%s, was %s', for spec '%s'", c.expDest, m.Destination, c.bind)
|
|
}
|
|
|
|
if m.Source != c.expSource {
|
|
t.Errorf("Expected source '%s', was '%s', for spec '%s'", c.expSource, m.Source, c.bind)
|
|
}
|
|
|
|
if m.Name != c.expName {
|
|
t.Errorf("Expected name '%s', was '%s' for spec '%s'", c.expName, m.Name, c.bind)
|
|
}
|
|
|
|
if m.Driver != c.expDriver {
|
|
t.Errorf("Expected driver '%s', was '%s', for spec '%s'", c.expDriver, m.Driver, c.bind)
|
|
}
|
|
|
|
if m.RW != c.expRW {
|
|
t.Errorf("Expected RW '%v', was '%v' for spec '%s'", c.expRW, m.RW, c.bind)
|
|
}
|
|
if m.Type != c.expType {
|
|
t.Fatalf("Expected type '%s', was '%s', for spec '%s'", c.expType, m.Type, c.bind)
|
|
}
|
|
}
|
|
}
|
|
|
|
tester(linParser, linuxCases)
|
|
tester(winParser, windowsCases)
|
|
tester(lcowParser, lcowCases)
|
|
}
|
|
|
|
func TestParseMountSpec(t *testing.T) {
|
|
type c struct {
|
|
input mount.Mount
|
|
expected MountPoint
|
|
}
|
|
testDir, err := ioutil.TempDir("", "test-mount-config")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(testDir)
|
|
parser := NewParser(runtime.GOOS)
|
|
cases := []c{
|
|
{mount.Mount{Type: mount.TypeBind, Source: testDir, Target: testDestinationPath, ReadOnly: true}, MountPoint{Type: mount.TypeBind, Source: testDir, Destination: testDestinationPath, Propagation: parser.DefaultPropagationMode()}},
|
|
{mount.Mount{Type: mount.TypeBind, Source: testDir, Target: testDestinationPath}, MountPoint{Type: mount.TypeBind, Source: testDir, Destination: testDestinationPath, RW: true, Propagation: parser.DefaultPropagationMode()}},
|
|
{mount.Mount{Type: mount.TypeBind, Source: testDir + string(os.PathSeparator), Target: testDestinationPath, ReadOnly: true}, MountPoint{Type: mount.TypeBind, Source: testDir, Destination: testDestinationPath, Propagation: parser.DefaultPropagationMode()}},
|
|
{mount.Mount{Type: mount.TypeBind, Source: testDir, Target: testDestinationPath + string(os.PathSeparator), ReadOnly: true}, MountPoint{Type: mount.TypeBind, Source: testDir, Destination: testDestinationPath, Propagation: parser.DefaultPropagationMode()}},
|
|
{mount.Mount{Type: mount.TypeVolume, Target: testDestinationPath}, MountPoint{Type: mount.TypeVolume, Destination: testDestinationPath, RW: true, CopyData: parser.DefaultCopyMode()}},
|
|
{mount.Mount{Type: mount.TypeVolume, Target: testDestinationPath + string(os.PathSeparator)}, MountPoint{Type: mount.TypeVolume, Destination: testDestinationPath, RW: true, CopyData: parser.DefaultCopyMode()}},
|
|
}
|
|
|
|
for i, c := range cases {
|
|
t.Logf("case %d", i)
|
|
mp, err := parser.ParseMountSpec(c.input)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
if c.expected.Type != mp.Type {
|
|
t.Errorf("Expected mount types to match. Expected: '%s', Actual: '%s'", c.expected.Type, mp.Type)
|
|
}
|
|
if c.expected.Destination != mp.Destination {
|
|
t.Errorf("Expected mount destination to match. Expected: '%s', Actual: '%s'", c.expected.Destination, mp.Destination)
|
|
}
|
|
if c.expected.Source != mp.Source {
|
|
t.Errorf("Expected mount source to match. Expected: '%s', Actual: '%s'", c.expected.Source, mp.Source)
|
|
}
|
|
if c.expected.RW != mp.RW {
|
|
t.Errorf("Expected mount writable to match. Expected: '%v', Actual: '%v'", c.expected.RW, mp.RW)
|
|
}
|
|
if c.expected.Propagation != mp.Propagation {
|
|
t.Errorf("Expected mount propagation to match. Expected: '%v', Actual: '%s'", c.expected.Propagation, mp.Propagation)
|
|
}
|
|
if c.expected.Driver != mp.Driver {
|
|
t.Errorf("Expected mount driver to match. Expected: '%v', Actual: '%s'", c.expected.Driver, mp.Driver)
|
|
}
|
|
if c.expected.CopyData != mp.CopyData {
|
|
t.Errorf("Expected mount copy data to match. Expected: '%v', Actual: '%v'", c.expected.CopyData, mp.CopyData)
|
|
}
|
|
}
|
|
}
|