github.com/lazyboychen7/engine@v17.12.1-ce-rc2+incompatible/daemon/graphdriver/quota/projectquota_test.go (about) 1 // +build linux 2 3 package quota 4 5 import ( 6 "io" 7 "io/ioutil" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "testing" 12 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 "golang.org/x/sys/unix" 16 ) 17 18 // 10MB 19 const testQuotaSize = 10 * 1024 * 1024 20 const imageSize = 64 * 1024 * 1024 21 22 func TestBlockDev(t *testing.T) { 23 mkfs, err := exec.LookPath("mkfs.xfs") 24 if err != nil { 25 t.Fatal("mkfs.xfs not installed") 26 } 27 28 // create a sparse image 29 imageFile, err := ioutil.TempFile("", "xfs-image") 30 if err != nil { 31 t.Fatal(err) 32 } 33 imageFileName := imageFile.Name() 34 defer os.Remove(imageFileName) 35 if _, err = imageFile.Seek(imageSize-1, 0); err != nil { 36 t.Fatal(err) 37 } 38 if _, err = imageFile.Write([]byte{0}); err != nil { 39 t.Fatal(err) 40 } 41 if err = imageFile.Close(); err != nil { 42 t.Fatal(err) 43 } 44 45 // The reason for disabling these options is sometimes people run with a newer userspace 46 // than kernelspace 47 out, err := exec.Command(mkfs, "-m", "crc=0,finobt=0", imageFileName).CombinedOutput() 48 if len(out) > 0 { 49 t.Log(string(out)) 50 } 51 if err != nil { 52 t.Fatal(err) 53 } 54 55 runTest(t, "testBlockDevQuotaDisabled", wrapMountTest(imageFileName, false, testBlockDevQuotaDisabled)) 56 runTest(t, "testBlockDevQuotaEnabled", wrapMountTest(imageFileName, true, testBlockDevQuotaEnabled)) 57 runTest(t, "testSmallerThanQuota", wrapMountTest(imageFileName, true, wrapQuotaTest(testSmallerThanQuota))) 58 runTest(t, "testBiggerThanQuota", wrapMountTest(imageFileName, true, wrapQuotaTest(testBiggerThanQuota))) 59 runTest(t, "testRetrieveQuota", wrapMountTest(imageFileName, true, wrapQuotaTest(testRetrieveQuota))) 60 } 61 62 func runTest(t *testing.T, testName string, testFunc func(*testing.T)) { 63 if success := t.Run(testName, testFunc); !success { 64 out, _ := exec.Command("dmesg").CombinedOutput() 65 t.Log(string(out)) 66 } 67 } 68 69 func wrapMountTest(imageFileName string, enableQuota bool, testFunc func(t *testing.T, mountPoint, backingFsDev string)) func(*testing.T) { 70 return func(t *testing.T) { 71 mountOptions := "loop" 72 73 if enableQuota { 74 mountOptions = mountOptions + ",prjquota" 75 } 76 77 // create a mountPoint 78 mountPoint, err := ioutil.TempDir("", "xfs-mountPoint") 79 if err != nil { 80 t.Fatal(err) 81 } 82 defer os.RemoveAll(mountPoint) 83 84 out, err := exec.Command("mount", "-o", mountOptions, imageFileName, mountPoint).CombinedOutput() 85 if len(out) > 0 { 86 t.Log(string(out)) 87 } 88 if err != nil { 89 t.Fatal("mount failed") 90 } 91 92 defer func() { 93 if err := unix.Unmount(mountPoint, 0); err != nil { 94 t.Fatal(err) 95 } 96 }() 97 98 backingFsDev, err := makeBackingFsDev(mountPoint) 99 require.NoError(t, err) 100 101 testFunc(t, mountPoint, backingFsDev) 102 } 103 } 104 105 func testBlockDevQuotaDisabled(t *testing.T, mountPoint, backingFsDev string) { 106 hasSupport, err := hasQuotaSupport(backingFsDev) 107 require.NoError(t, err) 108 assert.False(t, hasSupport) 109 } 110 111 func testBlockDevQuotaEnabled(t *testing.T, mountPoint, backingFsDev string) { 112 hasSupport, err := hasQuotaSupport(backingFsDev) 113 require.NoError(t, err) 114 assert.True(t, hasSupport) 115 } 116 117 func wrapQuotaTest(testFunc func(t *testing.T, ctrl *Control, mountPoint, testDir, testSubDir string)) func(t *testing.T, mountPoint, backingFsDev string) { 118 return func(t *testing.T, mountPoint, backingFsDev string) { 119 testDir, err := ioutil.TempDir(mountPoint, "per-test") 120 require.NoError(t, err) 121 defer os.RemoveAll(testDir) 122 123 ctrl, err := NewControl(testDir) 124 require.NoError(t, err) 125 126 testSubDir, err := ioutil.TempDir(testDir, "quota-test") 127 require.NoError(t, err) 128 testFunc(t, ctrl, mountPoint, testDir, testSubDir) 129 } 130 131 } 132 133 func testSmallerThanQuota(t *testing.T, ctrl *Control, homeDir, testDir, testSubDir string) { 134 require.NoError(t, ctrl.SetQuota(testSubDir, Quota{testQuotaSize})) 135 smallerThanQuotaFile := filepath.Join(testSubDir, "smaller-than-quota") 136 require.NoError(t, ioutil.WriteFile(smallerThanQuotaFile, make([]byte, testQuotaSize/2), 0644)) 137 require.NoError(t, os.Remove(smallerThanQuotaFile)) 138 } 139 140 func testBiggerThanQuota(t *testing.T, ctrl *Control, homeDir, testDir, testSubDir string) { 141 // Make sure the quota is being enforced 142 // TODO: When we implement this under EXT4, we need to shed CAP_SYS_RESOURCE, otherwise 143 // we're able to violate quota without issue 144 require.NoError(t, ctrl.SetQuota(testSubDir, Quota{testQuotaSize})) 145 146 biggerThanQuotaFile := filepath.Join(testSubDir, "bigger-than-quota") 147 err := ioutil.WriteFile(biggerThanQuotaFile, make([]byte, testQuotaSize+1), 0644) 148 require.Error(t, err) 149 if err == io.ErrShortWrite { 150 require.NoError(t, os.Remove(biggerThanQuotaFile)) 151 } 152 } 153 154 func testRetrieveQuota(t *testing.T, ctrl *Control, homeDir, testDir, testSubDir string) { 155 // Validate that we can retrieve quota 156 require.NoError(t, ctrl.SetQuota(testSubDir, Quota{testQuotaSize})) 157 158 var q Quota 159 require.NoError(t, ctrl.GetQuota(testSubDir, &q)) 160 assert.EqualValues(t, testQuotaSize, q.Size) 161 }