github.com/docker/engine@v22.0.0-20211208180946-d456264580cf+incompatible/volume/local/local_test.go (about)

     1  package local // import "github.com/docker/docker/volume/local"
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"reflect"
     7  	"runtime"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/docker/docker/pkg/idtools"
    12  	"github.com/moby/sys/mountinfo"
    13  	"gotest.tools/v3/skip"
    14  )
    15  
    16  func TestGetAddress(t *testing.T) {
    17  	cases := map[string]string{
    18  		"addr=11.11.11.1":   "11.11.11.1",
    19  		" ":                 "",
    20  		"addr=":             "",
    21  		"addr=2001:db8::68": "2001:db8::68",
    22  	}
    23  	for name, success := range cases {
    24  		v := getAddress(name)
    25  		if v != success {
    26  			t.Errorf("Test case failed for %s actual: %s expected : %s", name, v, success)
    27  		}
    28  	}
    29  
    30  }
    31  
    32  func TestRemove(t *testing.T) {
    33  	skip.If(t, runtime.GOOS == "windows", "FIXME: investigate why this test fails on CI")
    34  	rootDir, err := os.MkdirTemp("", "local-volume-test")
    35  	if err != nil {
    36  		t.Fatal(err)
    37  	}
    38  	defer os.RemoveAll(rootDir)
    39  
    40  	r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
    41  	if err != nil {
    42  		t.Fatal(err)
    43  	}
    44  
    45  	vol, err := r.Create("testing", nil)
    46  	if err != nil {
    47  		t.Fatal(err)
    48  	}
    49  
    50  	if err := r.Remove(vol); err != nil {
    51  		t.Fatal(err)
    52  	}
    53  
    54  	vol, err = r.Create("testing2", nil)
    55  	if err != nil {
    56  		t.Fatal(err)
    57  	}
    58  	if err := os.RemoveAll(vol.Path()); err != nil {
    59  		t.Fatal(err)
    60  	}
    61  
    62  	if err := r.Remove(vol); err != nil {
    63  		t.Fatal(err)
    64  	}
    65  
    66  	if _, err := os.Stat(vol.Path()); err != nil && !os.IsNotExist(err) {
    67  		t.Fatal("volume dir not removed")
    68  	}
    69  
    70  	if l, _ := r.List(); len(l) != 0 {
    71  		t.Fatal("expected there to be no volumes")
    72  	}
    73  }
    74  
    75  func TestInitializeWithVolumes(t *testing.T) {
    76  	rootDir, err := os.MkdirTemp("", "local-volume-test")
    77  	if err != nil {
    78  		t.Fatal(err)
    79  	}
    80  	defer os.RemoveAll(rootDir)
    81  
    82  	r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
    83  	if err != nil {
    84  		t.Fatal(err)
    85  	}
    86  
    87  	vol, err := r.Create("testing", nil)
    88  	if err != nil {
    89  		t.Fatal(err)
    90  	}
    91  
    92  	r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
    93  	if err != nil {
    94  		t.Fatal(err)
    95  	}
    96  
    97  	v, err := r.Get(vol.Name())
    98  	if err != nil {
    99  		t.Fatal(err)
   100  	}
   101  
   102  	if v.Path() != vol.Path() {
   103  		t.Fatal("expected to re-initialize root with existing volumes")
   104  	}
   105  }
   106  
   107  func TestCreate(t *testing.T) {
   108  	rootDir, err := os.MkdirTemp("", "local-volume-test")
   109  	if err != nil {
   110  		t.Fatal(err)
   111  	}
   112  	defer os.RemoveAll(rootDir)
   113  
   114  	r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
   115  	if err != nil {
   116  		t.Fatal(err)
   117  	}
   118  
   119  	cases := map[string]bool{
   120  		"name":                  true,
   121  		"name-with-dash":        true,
   122  		"name_with_underscore":  true,
   123  		"name/with/slash":       false,
   124  		"name/with/../../slash": false,
   125  		"./name":                false,
   126  		"../name":               false,
   127  		"./":                    false,
   128  		"../":                   false,
   129  		"~":                     false,
   130  		".":                     false,
   131  		"..":                    false,
   132  		"...":                   false,
   133  	}
   134  
   135  	for name, success := range cases {
   136  		v, err := r.Create(name, nil)
   137  		if success {
   138  			if err != nil {
   139  				t.Fatal(err)
   140  			}
   141  			if v.Name() != name {
   142  				t.Fatalf("Expected volume with name %s, got %s", name, v.Name())
   143  			}
   144  		} else {
   145  			if err == nil {
   146  				t.Fatalf("Expected error creating volume with name %s, got nil", name)
   147  			}
   148  		}
   149  	}
   150  
   151  	_, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
   152  	if err != nil {
   153  		t.Fatal(err)
   154  	}
   155  }
   156  
   157  func TestValidateName(t *testing.T) {
   158  	r := &Root{}
   159  	names := map[string]bool{
   160  		"x":           false,
   161  		"/testvol":    false,
   162  		"thing.d":     true,
   163  		"hello-world": true,
   164  		"./hello":     false,
   165  		".hello":      false,
   166  	}
   167  
   168  	for vol, expected := range names {
   169  		err := r.validateName(vol)
   170  		if expected && err != nil {
   171  			t.Fatalf("expected %s to be valid got %v", vol, err)
   172  		}
   173  		if !expected && err == nil {
   174  			t.Fatalf("expected %s to be invalid", vol)
   175  		}
   176  	}
   177  }
   178  
   179  func TestCreateWithOpts(t *testing.T) {
   180  	skip.If(t, runtime.GOOS == "windows")
   181  	skip.If(t, os.Getuid() != 0, "requires mounts")
   182  	rootDir, err := os.MkdirTemp("", "local-volume-test")
   183  	if err != nil {
   184  		t.Fatal(err)
   185  	}
   186  	defer os.RemoveAll(rootDir)
   187  
   188  	r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
   189  	if err != nil {
   190  		t.Fatal(err)
   191  	}
   192  
   193  	if _, err := r.Create("test", map[string]string{"invalidopt": "notsupported"}); err == nil {
   194  		t.Fatal("expected invalid opt to cause error")
   195  	}
   196  
   197  	vol, err := r.Create("test", map[string]string{"device": "tmpfs", "type": "tmpfs", "o": "size=1m,uid=1000"})
   198  	if err != nil {
   199  		t.Fatal(err)
   200  	}
   201  	v := vol.(*localVolume)
   202  
   203  	dir, err := v.Mount("1234")
   204  	if err != nil {
   205  		t.Fatal(err)
   206  	}
   207  	defer func() {
   208  		if err := v.Unmount("1234"); err != nil {
   209  			t.Fatal(err)
   210  		}
   211  	}()
   212  
   213  	mountInfos, err := mountinfo.GetMounts(mountinfo.SingleEntryFilter(dir))
   214  	if err != nil {
   215  		t.Fatal(err)
   216  	}
   217  	if len(mountInfos) != 1 {
   218  		t.Fatalf("expected 1 mount, found %d: %+v", len(mountInfos), mountInfos)
   219  	}
   220  
   221  	info := mountInfos[0]
   222  	t.Logf("%+v", info)
   223  	if info.FSType != "tmpfs" {
   224  		t.Fatalf("expected tmpfs mount, got %q", info.FSType)
   225  	}
   226  	if info.Source != "tmpfs" {
   227  		t.Fatalf("expected tmpfs mount, got %q", info.Source)
   228  	}
   229  	if !strings.Contains(info.VFSOptions, "uid=1000") {
   230  		t.Fatalf("expected mount info to have uid=1000: %q", info.VFSOptions)
   231  	}
   232  	if !strings.Contains(info.VFSOptions, "size=1024k") {
   233  		t.Fatalf("expected mount info to have size=1024k: %q", info.VFSOptions)
   234  	}
   235  
   236  	if v.active.count != 1 {
   237  		t.Fatalf("Expected active mount count to be 1, got %d", v.active.count)
   238  	}
   239  
   240  	// test double mount
   241  	if _, err := v.Mount("1234"); err != nil {
   242  		t.Fatal(err)
   243  	}
   244  	if v.active.count != 2 {
   245  		t.Fatalf("Expected active mount count to be 2, got %d", v.active.count)
   246  	}
   247  
   248  	if err := v.Unmount("1234"); err != nil {
   249  		t.Fatal(err)
   250  	}
   251  	if v.active.count != 1 {
   252  		t.Fatalf("Expected active mount count to be 1, got %d", v.active.count)
   253  	}
   254  
   255  	mounted, err := mountinfo.Mounted(v.path)
   256  	if err != nil {
   257  		t.Fatal(err)
   258  	}
   259  	if !mounted {
   260  		t.Fatal("expected mount to still be active")
   261  	}
   262  
   263  	r, err = New(rootDir, idtools.Identity{UID: 0, GID: 0})
   264  	if err != nil {
   265  		t.Fatal(err)
   266  	}
   267  
   268  	v2, exists := r.volumes["test"]
   269  	if !exists {
   270  		t.Fatal("missing volume on restart")
   271  	}
   272  
   273  	if !reflect.DeepEqual(v.opts, v2.opts) {
   274  		t.Fatal("missing volume options on restart")
   275  	}
   276  }
   277  
   278  func TestRelaodNoOpts(t *testing.T) {
   279  	rootDir, err := os.MkdirTemp("", "volume-test-reload-no-opts")
   280  	if err != nil {
   281  		t.Fatal(err)
   282  	}
   283  	defer os.RemoveAll(rootDir)
   284  
   285  	r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
   286  	if err != nil {
   287  		t.Fatal(err)
   288  	}
   289  
   290  	if _, err := r.Create("test1", nil); err != nil {
   291  		t.Fatal(err)
   292  	}
   293  	if _, err := r.Create("test2", nil); err != nil {
   294  		t.Fatal(err)
   295  	}
   296  	// make sure a file with `null` (.e.g. empty opts map from older daemon) is ok
   297  	if err := os.WriteFile(filepath.Join(rootDir, "test2"), []byte("null"), 0600); err != nil {
   298  		t.Fatal(err)
   299  	}
   300  
   301  	if _, err := r.Create("test3", nil); err != nil {
   302  		t.Fatal(err)
   303  	}
   304  	// make sure an empty opts file doesn't break us too
   305  	if err := os.WriteFile(filepath.Join(rootDir, "test3"), nil, 0600); err != nil {
   306  		t.Fatal(err)
   307  	}
   308  
   309  	if _, err := r.Create("test4", map[string]string{}); err != nil {
   310  		t.Fatal(err)
   311  	}
   312  
   313  	r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
   314  	if err != nil {
   315  		t.Fatal(err)
   316  	}
   317  
   318  	for _, name := range []string{"test1", "test2", "test3", "test4"} {
   319  		v, err := r.Get(name)
   320  		if err != nil {
   321  			t.Fatal(err)
   322  		}
   323  		lv, ok := v.(*localVolume)
   324  		if !ok {
   325  			t.Fatalf("expected *localVolume got: %v", reflect.TypeOf(v))
   326  		}
   327  		if lv.opts != nil {
   328  			t.Fatalf("expected opts to be nil, got: %v", lv.opts)
   329  		}
   330  		if _, err := lv.Mount("1234"); err != nil {
   331  			t.Fatal(err)
   332  		}
   333  	}
   334  }