mirror of https://github.com/docker/cli.git
224 lines
6.6 KiB
Go
224 lines
6.6 KiB
Go
package loader
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/docker/cli/cli/compose/types"
|
|
"gotest.tools/v3/assert"
|
|
is "gotest.tools/v3/assert/cmp"
|
|
)
|
|
|
|
func TestParseVolumeAnonymousVolume(t *testing.T) {
|
|
for _, path := range []string{"/path", "/path/foo"} {
|
|
volume, err := ParseVolume(path)
|
|
expected := types.ServiceVolumeConfig{Type: "volume", Target: path}
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.DeepEqual(expected, volume))
|
|
}
|
|
}
|
|
|
|
func TestParseVolumeAnonymousVolumeWindows(t *testing.T) {
|
|
for _, path := range []string{"C:\\path", "Z:\\path\\foo"} {
|
|
volume, err := ParseVolume(path)
|
|
expected := types.ServiceVolumeConfig{Type: "volume", Target: path}
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.DeepEqual(expected, volume))
|
|
}
|
|
}
|
|
|
|
func TestParseVolumeTooManyColons(t *testing.T) {
|
|
_, err := ParseVolume("/foo:/foo:ro:foo")
|
|
assert.Error(t, err, "invalid spec: /foo:/foo:ro:foo: too many colons")
|
|
}
|
|
|
|
func TestParseVolumeShortVolumes(t *testing.T) {
|
|
for _, path := range []string{".", "/a"} {
|
|
volume, err := ParseVolume(path)
|
|
expected := types.ServiceVolumeConfig{Type: "volume", Target: path}
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.DeepEqual(expected, volume))
|
|
}
|
|
}
|
|
|
|
func TestParseVolumeMissingSource(t *testing.T) {
|
|
for _, spec := range []string{":foo", "/foo::ro"} {
|
|
_, err := ParseVolume(spec)
|
|
assert.ErrorContains(t, err, "empty section between colons")
|
|
}
|
|
}
|
|
|
|
func TestParseVolumeBindMount(t *testing.T) {
|
|
for _, path := range []string{"./foo", "~/thing", "../other", "/foo", "/home/user"} {
|
|
volume, err := ParseVolume(path + ":/target")
|
|
expected := types.ServiceVolumeConfig{
|
|
Type: "bind",
|
|
Source: path,
|
|
Target: "/target",
|
|
}
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.DeepEqual(expected, volume))
|
|
}
|
|
}
|
|
|
|
func TestParseVolumeRelativeBindMountWindows(t *testing.T) {
|
|
for _, path := range []string{
|
|
"./foo",
|
|
"~/thing",
|
|
"../other",
|
|
"D:\\path", "/home/user",
|
|
} {
|
|
volume, err := ParseVolume(path + ":d:\\target")
|
|
expected := types.ServiceVolumeConfig{
|
|
Type: "bind",
|
|
Source: path,
|
|
Target: "d:\\target",
|
|
}
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.DeepEqual(expected, volume))
|
|
}
|
|
}
|
|
|
|
func TestParseVolumeWithBindOptions(t *testing.T) {
|
|
volume, err := ParseVolume("/source:/target:slave")
|
|
expected := types.ServiceVolumeConfig{
|
|
Type: "bind",
|
|
Source: "/source",
|
|
Target: "/target",
|
|
Bind: &types.ServiceVolumeBind{Propagation: "slave"},
|
|
}
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.DeepEqual(expected, volume))
|
|
}
|
|
|
|
func TestParseVolumeWithBindOptionsWindows(t *testing.T) {
|
|
volume, err := ParseVolume("C:\\source\\foo:D:\\target:ro,rprivate")
|
|
expected := types.ServiceVolumeConfig{
|
|
Type: "bind",
|
|
Source: "C:\\source\\foo",
|
|
Target: "D:\\target",
|
|
ReadOnly: true,
|
|
Bind: &types.ServiceVolumeBind{Propagation: "rprivate"},
|
|
}
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.DeepEqual(expected, volume))
|
|
}
|
|
|
|
func TestParseVolumeWithInvalidVolumeOptions(t *testing.T) {
|
|
_, err := ParseVolume("name:/target:bogus")
|
|
assert.NilError(t, err)
|
|
}
|
|
|
|
func TestParseVolumeWithVolumeOptions(t *testing.T) {
|
|
volume, err := ParseVolume("name:/target:nocopy")
|
|
expected := types.ServiceVolumeConfig{
|
|
Type: "volume",
|
|
Source: "name",
|
|
Target: "/target",
|
|
Volume: &types.ServiceVolumeVolume{NoCopy: true},
|
|
}
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.DeepEqual(expected, volume))
|
|
}
|
|
|
|
func TestParseVolumeWithReadOnly(t *testing.T) {
|
|
for _, path := range []string{"./foo", "/home/user"} {
|
|
volume, err := ParseVolume(path + ":/target:ro")
|
|
expected := types.ServiceVolumeConfig{
|
|
Type: "bind",
|
|
Source: path,
|
|
Target: "/target",
|
|
ReadOnly: true,
|
|
}
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.DeepEqual(expected, volume))
|
|
}
|
|
}
|
|
|
|
func TestParseVolumeWithRW(t *testing.T) {
|
|
for _, path := range []string{"./foo", "/home/user"} {
|
|
volume, err := ParseVolume(path + ":/target:rw")
|
|
expected := types.ServiceVolumeConfig{
|
|
Type: "bind",
|
|
Source: path,
|
|
Target: "/target",
|
|
ReadOnly: false,
|
|
}
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.DeepEqual(expected, volume))
|
|
}
|
|
}
|
|
|
|
func TestParseVolumeWindowsNamedPipe(t *testing.T) {
|
|
volume, err := ParseVolume(`\\.\pipe\docker_engine:\\.\pipe\inside`)
|
|
assert.NilError(t, err)
|
|
expected := types.ServiceVolumeConfig{
|
|
Type: "bind",
|
|
Source: `\\.\pipe\docker_engine`,
|
|
Target: `\\.\pipe\inside`,
|
|
}
|
|
assert.Check(t, is.DeepEqual(expected, volume))
|
|
}
|
|
|
|
func TestIsFilePath(t *testing.T) {
|
|
assert.Check(t, !isFilePath("a界"))
|
|
}
|
|
|
|
// Preserve the test cases for VolumeSplitN
|
|
func TestParseVolumeSplitCases(t *testing.T) {
|
|
for casenumber, x := range []struct {
|
|
input string
|
|
n int
|
|
expected []string
|
|
}{
|
|
{`C:\foo:d:`, -1, []string{`C:\foo`, `d:`}},
|
|
{`:C:\foo:d:`, -1, nil},
|
|
{`/foo:/bar:ro`, 3, []string{`/foo`, `/bar`, `ro`}},
|
|
{`/foo:/bar:ro`, 2, []string{`/foo`, `/bar:ro`}},
|
|
{`C:\foo\:/foo`, -1, []string{`C:\foo\`, `/foo`}},
|
|
{`d:\`, -1, []string{`d:\`}},
|
|
{`d:`, -1, []string{`d:`}},
|
|
{`d:\path`, -1, []string{`d:\path`}},
|
|
{`d:\path with space`, -1, []string{`d:\path with space`}},
|
|
{`d:\pathandmode:rw`, -1, []string{`d:\pathandmode`, `rw`}},
|
|
|
|
{`c:\:d:\`, -1, []string{`c:\`, `d:\`}},
|
|
{`c:\windows\:d:`, -1, []string{`c:\windows\`, `d:`}},
|
|
{`c:\windows:d:\s p a c e`, -1, []string{`c:\windows`, `d:\s p a c e`}},
|
|
{`c:\windows:d:\s p a c e:RW`, -1, []string{`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`, -1, []string{`c:\program files`, `d:\s p a c e i n h o s t d i r`}},
|
|
{`0123456789name:d:`, -1, []string{`0123456789name`, `d:`}},
|
|
{`MiXeDcAsEnAmE:d:`, -1, []string{`MiXeDcAsEnAmE`, `d:`}},
|
|
{`name:D:`, -1, []string{`name`, `D:`}},
|
|
{`name:D::rW`, -1, []string{`name`, `D:`, `rW`}},
|
|
{`name:D::RW`, -1, []string{`name`, `D:`, `RW`}},
|
|
|
|
{`c:/:d:/forward/slashes/are/good/too`, -1, []string{`c:/`, `d:/forward/slashes/are/good/too`}},
|
|
{`c:\Windows`, -1, []string{`c:\Windows`}},
|
|
{`c:\Program Files (x86)`, -1, []string{`c:\Program Files (x86)`}},
|
|
{``, -1, nil},
|
|
{`.`, -1, []string{`.`}},
|
|
{`..\`, -1, []string{`..\`}},
|
|
{`c:\:..\`, -1, []string{`c:\`, `..\`}},
|
|
{`c:\:d:\:xyzzy`, -1, []string{`c:\`, `d:\`, `xyzzy`}},
|
|
// Cover directories with one-character name
|
|
{`/tmp/x/y:/foo/x/y`, -1, []string{`/tmp/x/y`, `/foo/x/y`}},
|
|
} {
|
|
parsed, _ := ParseVolume(x.input)
|
|
|
|
expected := len(x.expected) > 1
|
|
msg := fmt.Sprintf("Case %d: %s", casenumber, x.input)
|
|
assert.Check(t, is.Equal(expected, parsed.Source != ""), msg)
|
|
}
|
|
}
|
|
|
|
func TestParseVolumeInvalidEmptySpec(t *testing.T) {
|
|
_, err := ParseVolume("")
|
|
assert.ErrorContains(t, err, "invalid empty volume spec")
|
|
}
|
|
|
|
func TestParseVolumeInvalidSections(t *testing.T) {
|
|
_, err := ParseVolume("/foo::rw")
|
|
assert.ErrorContains(t, err, "invalid spec")
|
|
}
|