github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/cli/opts/mount_test.go (about)

     1  package opts
     2  
     3  import (
     4  	"os"
     5  	"testing"
     6  
     7  	mounttypes "github.com/docker/docker/api/types/mount"
     8  	"gotest.tools/v3/assert"
     9  	is "gotest.tools/v3/assert/cmp"
    10  )
    11  
    12  func TestMountOptString(t *testing.T) {
    13  	mount := MountOpt{
    14  		values: []mounttypes.Mount{
    15  			{
    16  				Type:   mounttypes.TypeBind,
    17  				Source: "/home/path",
    18  				Target: "/target",
    19  			},
    20  			{
    21  				Type:   mounttypes.TypeVolume,
    22  				Source: "foo",
    23  				Target: "/target/foo",
    24  			},
    25  		},
    26  	}
    27  	expected := "bind /home/path /target, volume foo /target/foo"
    28  	assert.Check(t, is.Equal(expected, mount.String()))
    29  }
    30  
    31  func TestMountOptSetBindNoErrorBind(t *testing.T) {
    32  	for _, testcase := range []string{
    33  		// tests several aliases that should have same result.
    34  		"type=bind,target=/target,source=/source",
    35  		"type=bind,src=/source,dst=/target",
    36  		"type=bind,source=/source,dst=/target",
    37  		"type=bind,src=/source,target=/target",
    38  	} {
    39  		var mount MountOpt
    40  
    41  		assert.NilError(t, mount.Set(testcase))
    42  
    43  		mounts := mount.Value()
    44  		assert.Assert(t, is.Len(mounts, 1))
    45  		assert.Check(t, is.DeepEqual(mounttypes.Mount{
    46  			Type:   mounttypes.TypeBind,
    47  			Source: "/source",
    48  			Target: "/target",
    49  		}, mounts[0]))
    50  	}
    51  }
    52  
    53  func TestMountOptSetVolumeNoError(t *testing.T) {
    54  	for _, testcase := range []string{
    55  		// tests several aliases that should have same result.
    56  		"type=volume,target=/target,source=/source",
    57  		"type=volume,src=/source,dst=/target",
    58  		"type=volume,source=/source,dst=/target",
    59  		"type=volume,src=/source,target=/target",
    60  	} {
    61  		var mount MountOpt
    62  
    63  		assert.NilError(t, mount.Set(testcase))
    64  
    65  		mounts := mount.Value()
    66  		assert.Assert(t, is.Len(mounts, 1))
    67  		assert.Check(t, is.DeepEqual(mounttypes.Mount{
    68  			Type:   mounttypes.TypeVolume,
    69  			Source: "/source",
    70  			Target: "/target",
    71  		}, mounts[0]))
    72  	}
    73  }
    74  
    75  // TestMountOptDefaultType ensures that a mount without the type defaults to a
    76  // volume mount.
    77  func TestMountOptDefaultType(t *testing.T) {
    78  	var mount MountOpt
    79  	assert.NilError(t, mount.Set("target=/target,source=/foo"))
    80  	assert.Check(t, is.Equal(mounttypes.TypeVolume, mount.values[0].Type))
    81  }
    82  
    83  func TestMountOptSetErrorNoTarget(t *testing.T) {
    84  	var mount MountOpt
    85  	assert.Error(t, mount.Set("type=volume,source=/foo"), "target is required")
    86  }
    87  
    88  func TestMountOptSetErrorInvalidKey(t *testing.T) {
    89  	var mount MountOpt
    90  	assert.Error(t, mount.Set("type=volume,bogus=foo"), "unexpected key 'bogus' in 'bogus=foo'")
    91  }
    92  
    93  func TestMountOptSetErrorInvalidField(t *testing.T) {
    94  	var mount MountOpt
    95  	assert.Error(t, mount.Set("type=volume,bogus"), "invalid field 'bogus' must be a key=value pair")
    96  }
    97  
    98  func TestMountOptSetErrorInvalidReadOnly(t *testing.T) {
    99  	var mount MountOpt
   100  	assert.Error(t, mount.Set("type=volume,readonly=no"), "invalid value for readonly: no")
   101  	assert.Error(t, mount.Set("type=volume,readonly=invalid"), "invalid value for readonly: invalid")
   102  }
   103  
   104  func TestMountOptDefaultEnableReadOnly(t *testing.T) {
   105  	var m MountOpt
   106  	assert.NilError(t, m.Set("type=bind,target=/foo,source=/foo"))
   107  	assert.Check(t, !m.values[0].ReadOnly)
   108  
   109  	m = MountOpt{}
   110  	assert.NilError(t, m.Set("type=bind,target=/foo,source=/foo,readonly"))
   111  	assert.Check(t, m.values[0].ReadOnly)
   112  
   113  	m = MountOpt{}
   114  	assert.NilError(t, m.Set("type=bind,target=/foo,source=/foo,readonly=1"))
   115  	assert.Check(t, m.values[0].ReadOnly)
   116  
   117  	m = MountOpt{}
   118  	assert.NilError(t, m.Set("type=bind,target=/foo,source=/foo,readonly=true"))
   119  	assert.Check(t, m.values[0].ReadOnly)
   120  
   121  	m = MountOpt{}
   122  	assert.NilError(t, m.Set("type=bind,target=/foo,source=/foo,readonly=0"))
   123  	assert.Check(t, !m.values[0].ReadOnly)
   124  }
   125  
   126  func TestMountOptVolumeNoCopy(t *testing.T) {
   127  	var m MountOpt
   128  	assert.NilError(t, m.Set("type=volume,target=/foo,volume-nocopy"))
   129  	assert.Check(t, is.Equal("", m.values[0].Source))
   130  
   131  	m = MountOpt{}
   132  	assert.NilError(t, m.Set("type=volume,target=/foo,source=foo"))
   133  	assert.Check(t, m.values[0].VolumeOptions == nil)
   134  
   135  	m = MountOpt{}
   136  	assert.NilError(t, m.Set("type=volume,target=/foo,source=foo,volume-nocopy=true"))
   137  	assert.Check(t, m.values[0].VolumeOptions != nil)
   138  	assert.Check(t, m.values[0].VolumeOptions.NoCopy)
   139  
   140  	m = MountOpt{}
   141  	assert.NilError(t, m.Set("type=volume,target=/foo,source=foo,volume-nocopy"))
   142  	assert.Check(t, m.values[0].VolumeOptions != nil)
   143  	assert.Check(t, m.values[0].VolumeOptions.NoCopy)
   144  
   145  	m = MountOpt{}
   146  	assert.NilError(t, m.Set("type=volume,target=/foo,source=foo,volume-nocopy=1"))
   147  	assert.Check(t, m.values[0].VolumeOptions != nil)
   148  	assert.Check(t, m.values[0].VolumeOptions.NoCopy)
   149  }
   150  
   151  func TestMountOptTypeConflict(t *testing.T) {
   152  	var m MountOpt
   153  	assert.ErrorContains(t, m.Set("type=bind,target=/foo,source=/foo,volume-nocopy=true"), "cannot mix")
   154  	assert.ErrorContains(t, m.Set("type=volume,target=/foo,source=/foo,bind-propagation=rprivate"), "cannot mix")
   155  }
   156  
   157  func TestMountOptSetTmpfsNoError(t *testing.T) {
   158  	for _, testcase := range []string{
   159  		// tests several aliases that should have same result.
   160  		"type=tmpfs,target=/target,tmpfs-size=1m,tmpfs-mode=0700",
   161  		"type=tmpfs,target=/target,tmpfs-size=1MB,tmpfs-mode=700",
   162  	} {
   163  		var mount MountOpt
   164  
   165  		assert.NilError(t, mount.Set(testcase))
   166  
   167  		mounts := mount.Value()
   168  		assert.Assert(t, is.Len(mounts, 1))
   169  		assert.Check(t, is.DeepEqual(mounttypes.Mount{
   170  			Type:   mounttypes.TypeTmpfs,
   171  			Target: "/target",
   172  			TmpfsOptions: &mounttypes.TmpfsOptions{
   173  				SizeBytes: 1024 * 1024, // not 1000 * 1000
   174  				Mode:      os.FileMode(0700),
   175  			},
   176  		}, mounts[0]))
   177  	}
   178  }
   179  
   180  func TestMountOptSetTmpfsError(t *testing.T) {
   181  	var m MountOpt
   182  	assert.ErrorContains(t, m.Set("type=tmpfs,target=/foo,tmpfs-size=foo"), "invalid value for tmpfs-size")
   183  	assert.ErrorContains(t, m.Set("type=tmpfs,target=/foo,tmpfs-mode=foo"), "invalid value for tmpfs-mode")
   184  	assert.ErrorContains(t, m.Set("type=tmpfs"), "target is required")
   185  }