github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/volume/local/local_test.go (about)

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