github.com/sams1990/dockerrepo@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  }