github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/pkg/mount/mounter_linux_test.go (about)

     1  // +build linux
     2  
     3  package mount
     4  
     5  import (
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"strings"
    10  	"testing"
    11  )
    12  
    13  func TestMount(t *testing.T) {
    14  	if os.Getuid() != 0 {
    15  		t.Skip("not root tests would fail")
    16  	}
    17  
    18  	source, err := ioutil.TempDir("", "mount-test-source-")
    19  	if err != nil {
    20  		t.Fatal(err)
    21  	}
    22  	defer os.RemoveAll(source)
    23  
    24  	// Ensure we have a known start point by mounting tmpfs with given options
    25  	if err := Mount("tmpfs", source, "tmpfs", "private"); err != nil {
    26  		t.Fatal(err)
    27  	}
    28  	defer ensureUnmount(t, source)
    29  	validateMount(t, source, "", "")
    30  	if t.Failed() {
    31  		t.FailNow()
    32  	}
    33  
    34  	target, err := ioutil.TempDir("", "mount-test-target-")
    35  	if err != nil {
    36  		t.Fatal(err)
    37  	}
    38  	defer os.RemoveAll(target)
    39  
    40  	tests := []struct {
    41  		source           string
    42  		ftype            string
    43  		options          string
    44  		expectedOpts     string
    45  		expectedOptional string
    46  	}{
    47  		// No options
    48  		{"tmpfs", "tmpfs", "", "", ""},
    49  		// Default rw / ro test
    50  		{source, "", "bind", "", ""},
    51  		{source, "", "bind,private", "", ""},
    52  		{source, "", "bind,shared", "", "shared"},
    53  		{source, "", "bind,slave", "", "master"},
    54  		{source, "", "bind,unbindable", "", "unbindable"},
    55  		// Read Write tests
    56  		{source, "", "bind,rw", "rw", ""},
    57  		{source, "", "bind,rw,private", "rw", ""},
    58  		{source, "", "bind,rw,shared", "rw", "shared"},
    59  		{source, "", "bind,rw,slave", "rw", "master"},
    60  		{source, "", "bind,rw,unbindable", "rw", "unbindable"},
    61  		// Read Only tests
    62  		{source, "", "bind,ro", "ro", ""},
    63  		{source, "", "bind,ro,private", "ro", ""},
    64  		{source, "", "bind,ro,shared", "ro", "shared"},
    65  		{source, "", "bind,ro,slave", "ro", "master"},
    66  		{source, "", "bind,ro,unbindable", "ro", "unbindable"},
    67  	}
    68  
    69  	for _, tc := range tests {
    70  		ftype, options := tc.ftype, tc.options
    71  		if tc.ftype == "" {
    72  			ftype = "none"
    73  		}
    74  		if tc.options == "" {
    75  			options = "none"
    76  		}
    77  
    78  		t.Run(fmt.Sprintf("%v-%v", ftype, options), func(t *testing.T) {
    79  			if strings.Contains(tc.options, "slave") {
    80  				// Slave requires a shared source
    81  				if err := MakeShared(source); err != nil {
    82  					t.Fatal(err)
    83  				}
    84  				defer func() {
    85  					if err := MakePrivate(source); err != nil {
    86  						t.Fatal(err)
    87  					}
    88  				}()
    89  			}
    90  			if err := Mount(tc.source, target, tc.ftype, tc.options); err != nil {
    91  				t.Fatal(err)
    92  			}
    93  			defer ensureUnmount(t, target)
    94  			validateMount(t, target, tc.expectedOpts, tc.expectedOptional)
    95  		})
    96  	}
    97  }
    98  
    99  // ensureUnmount umounts mnt checking for errors
   100  func ensureUnmount(t *testing.T, mnt string) {
   101  	if err := Unmount(mnt); err != nil {
   102  		t.Error(err)
   103  	}
   104  }
   105  
   106  // validateMount checks that mnt has the given options
   107  func validateMount(t *testing.T, mnt string, opts, optional string) {
   108  	info, err := GetMounts()
   109  	if err != nil {
   110  		t.Fatal(err)
   111  	}
   112  
   113  	wantedOpts := make(map[string]struct{})
   114  	if opts != "" {
   115  		for _, opt := range strings.Split(opts, ",") {
   116  			wantedOpts[opt] = struct{}{}
   117  		}
   118  	}
   119  
   120  	wantedOptional := make(map[string]struct{})
   121  	if optional != "" {
   122  		for _, opt := range strings.Split(optional, ",") {
   123  			wantedOptional[opt] = struct{}{}
   124  		}
   125  	}
   126  
   127  	mnts := make(map[int]*Info, len(info))
   128  	for _, mi := range info {
   129  		mnts[mi.ID] = mi
   130  	}
   131  
   132  	for _, mi := range info {
   133  		if mi.Mountpoint != mnt {
   134  			continue
   135  		}
   136  
   137  		// Use parent info as the defaults
   138  		p := mnts[mi.Parent]
   139  		pOpts := make(map[string]struct{})
   140  		if p.Opts != "" {
   141  			for _, opt := range strings.Split(p.Opts, ",") {
   142  				pOpts[clean(opt)] = struct{}{}
   143  			}
   144  		}
   145  		pOptional := make(map[string]struct{})
   146  		if p.Optional != "" {
   147  			for _, field := range strings.Split(p.Optional, ",") {
   148  				pOptional[clean(field)] = struct{}{}
   149  			}
   150  		}
   151  
   152  		// Validate Opts
   153  		if mi.Opts != "" {
   154  			for _, opt := range strings.Split(mi.Opts, ",") {
   155  				opt = clean(opt)
   156  				if !has(wantedOpts, opt) && !has(pOpts, opt) {
   157  					t.Errorf("unexpected mount option %q expected %q", opt, opts)
   158  				}
   159  				delete(wantedOpts, opt)
   160  			}
   161  		}
   162  		for opt := range wantedOpts {
   163  			t.Errorf("missing mount option %q found %q", opt, mi.Opts)
   164  		}
   165  
   166  		// Validate Optional
   167  		if mi.Optional != "" {
   168  			for _, field := range strings.Split(mi.Optional, ",") {
   169  				field = clean(field)
   170  				if !has(wantedOptional, field) && !has(pOptional, field) {
   171  					t.Errorf("unexpected optional failed %q expected %q", field, optional)
   172  				}
   173  				delete(wantedOptional, field)
   174  			}
   175  		}
   176  		for field := range wantedOptional {
   177  			t.Errorf("missing optional field %q found %q", field, mi.Optional)
   178  		}
   179  
   180  		return
   181  	}
   182  
   183  	t.Errorf("failed to find mount %q", mnt)
   184  }
   185  
   186  // clean strips off any value param after the colon
   187  func clean(v string) string {
   188  	return strings.SplitN(v, ":", 2)[0]
   189  }
   190  
   191  // has returns true if key is a member of m
   192  func has(m map[string]struct{}, key string) bool {
   193  	_, ok := m[key]
   194  	return ok
   195  }