github.com/moby/docker@v26.1.3+incompatible/daemon/graphdriver/graphtest/graphtest_unix.go (about)

     1  //go:build linux || freebsd
     2  
     3  package graphtest // import "github.com/docker/docker/daemon/graphdriver/graphtest"
     4  
     5  import (
     6  	"bytes"
     7  	"crypto/rand"
     8  	"os"
     9  	"path"
    10  	"testing"
    11  
    12  	"github.com/docker/docker/daemon/graphdriver"
    13  	"github.com/docker/docker/pkg/stringid"
    14  	"github.com/docker/docker/quota"
    15  	units "github.com/docker/go-units"
    16  	"golang.org/x/sys/unix"
    17  	"gotest.tools/v3/assert"
    18  	is "gotest.tools/v3/assert/cmp"
    19  )
    20  
    21  var drv *Driver
    22  
    23  // Driver conforms to graphdriver.Driver interface and
    24  // contains information such as root and reference count of the number of clients using it.
    25  // This helps in testing drivers added into the framework.
    26  type Driver struct {
    27  	graphdriver.Driver
    28  	root     string
    29  	refCount int
    30  }
    31  
    32  func newDriver(t testing.TB, name string, options []string) *Driver {
    33  	root, err := os.MkdirTemp("", "docker-graphtest-")
    34  	assert.NilError(t, err)
    35  
    36  	assert.NilError(t, os.MkdirAll(root, 0o755))
    37  	d, err := graphdriver.GetDriver(name, nil, graphdriver.Options{DriverOptions: options, Root: root})
    38  	if err != nil {
    39  		t.Logf("graphdriver: %v\n", err)
    40  		if graphdriver.IsDriverNotSupported(err) {
    41  			t.Skipf("Driver %s not supported", name)
    42  		}
    43  		t.Fatal(err)
    44  	}
    45  	return &Driver{d, root, 1}
    46  }
    47  
    48  func cleanup(t testing.TB, d *Driver) {
    49  	if err := drv.Cleanup(); err != nil {
    50  		t.Fatal(err)
    51  	}
    52  	os.RemoveAll(d.root)
    53  }
    54  
    55  // GetDriver create a new driver with given name or return an existing driver with the name updating the reference count.
    56  func GetDriver(t testing.TB, name string, options ...string) graphdriver.Driver {
    57  	if drv == nil {
    58  		drv = newDriver(t, name, options)
    59  	} else {
    60  		drv.refCount++
    61  	}
    62  	return drv
    63  }
    64  
    65  // PutDriver removes the driver if it is no longer used and updates the reference count.
    66  func PutDriver(t testing.TB) {
    67  	if drv == nil {
    68  		t.Skip("No driver to put!")
    69  	}
    70  	drv.refCount--
    71  	if drv.refCount == 0 {
    72  		cleanup(t, drv)
    73  		drv = nil
    74  	}
    75  }
    76  
    77  // DriverTestCreateEmpty creates a new image and verifies it is empty and the right metadata
    78  func DriverTestCreateEmpty(t testing.TB, drivername string, driverOptions ...string) {
    79  	driver := GetDriver(t, drivername, driverOptions...)
    80  	defer PutDriver(t)
    81  
    82  	err := driver.Create("empty", "", nil)
    83  	assert.NilError(t, err)
    84  
    85  	defer func() {
    86  		assert.NilError(t, driver.Remove("empty"))
    87  	}()
    88  
    89  	if !driver.Exists("empty") {
    90  		t.Fatal("Newly created image doesn't exist")
    91  	}
    92  
    93  	dir, err := driver.Get("empty", "")
    94  	assert.NilError(t, err)
    95  
    96  	verifyFile(t, dir, 0o755|os.ModeDir, 0, 0)
    97  
    98  	// Verify that the directory is empty
    99  	fis, err := readDir(dir)
   100  	assert.NilError(t, err)
   101  	assert.Check(t, is.Len(fis, 0))
   102  
   103  	driver.Put("empty")
   104  }
   105  
   106  // DriverTestCreateBase create a base driver and verify.
   107  func DriverTestCreateBase(t testing.TB, drivername string, driverOptions ...string) {
   108  	driver := GetDriver(t, drivername, driverOptions...)
   109  	defer PutDriver(t)
   110  
   111  	createBase(t, driver, "Base")
   112  	defer func() {
   113  		assert.NilError(t, driver.Remove("Base"))
   114  	}()
   115  	verifyBase(t, driver, "Base")
   116  }
   117  
   118  // DriverTestCreateSnap Create a driver and snap and verify.
   119  func DriverTestCreateSnap(t testing.TB, drivername string, driverOptions ...string) {
   120  	driver := GetDriver(t, drivername, driverOptions...)
   121  	defer PutDriver(t)
   122  
   123  	createBase(t, driver, "Base")
   124  	defer func() {
   125  		assert.NilError(t, driver.Remove("Base"))
   126  	}()
   127  
   128  	err := driver.Create("Snap", "Base", nil)
   129  	assert.NilError(t, err)
   130  	defer func() {
   131  		assert.NilError(t, driver.Remove("Snap"))
   132  	}()
   133  
   134  	verifyBase(t, driver, "Snap")
   135  }
   136  
   137  // DriverTestDeepLayerRead reads a file from a lower layer under a given number of layers
   138  func DriverTestDeepLayerRead(t testing.TB, layerCount int, drivername string, driverOptions ...string) {
   139  	driver := GetDriver(t, drivername, driverOptions...)
   140  	defer PutDriver(t)
   141  
   142  	base := stringid.GenerateRandomID()
   143  	if err := driver.Create(base, "", nil); err != nil {
   144  		t.Fatal(err)
   145  	}
   146  
   147  	content := []byte("test content")
   148  	if err := addFile(driver, base, "testfile.txt", content); err != nil {
   149  		t.Fatal(err)
   150  	}
   151  
   152  	topLayer, err := addManyLayers(driver, base, layerCount)
   153  	if err != nil {
   154  		t.Fatal(err)
   155  	}
   156  
   157  	err = checkManyLayers(driver, topLayer, layerCount)
   158  	if err != nil {
   159  		t.Fatal(err)
   160  	}
   161  
   162  	if err := checkFile(driver, topLayer, "testfile.txt", content); err != nil {
   163  		t.Fatal(err)
   164  	}
   165  }
   166  
   167  // DriverTestDiffApply tests diffing and applying produces the same layer
   168  func DriverTestDiffApply(t testing.TB, fileCount int, drivername string, driverOptions ...string) {
   169  	driver := GetDriver(t, drivername, driverOptions...)
   170  	defer PutDriver(t)
   171  	base := stringid.GenerateRandomID()
   172  	upper := stringid.GenerateRandomID()
   173  	deleteFile := "file-remove.txt"
   174  	deleteFileContent := []byte("This file should get removed in upper!")
   175  	deleteDir := "var/lib"
   176  
   177  	if err := driver.Create(base, "", nil); err != nil {
   178  		t.Fatal(err)
   179  	}
   180  
   181  	if err := addManyFiles(driver, base, fileCount, 3); err != nil {
   182  		t.Fatal(err)
   183  	}
   184  
   185  	if err := addFile(driver, base, deleteFile, deleteFileContent); err != nil {
   186  		t.Fatal(err)
   187  	}
   188  
   189  	if err := addDirectory(driver, base, deleteDir); err != nil {
   190  		t.Fatal(err)
   191  	}
   192  
   193  	if err := driver.Create(upper, base, nil); err != nil {
   194  		t.Fatal(err)
   195  	}
   196  
   197  	if err := addManyFiles(driver, upper, fileCount, 6); err != nil {
   198  		t.Fatal(err)
   199  	}
   200  
   201  	if err := removeAll(driver, upper, deleteFile, deleteDir); err != nil {
   202  		t.Fatal(err)
   203  	}
   204  
   205  	diffSize, err := driver.DiffSize(upper, "")
   206  	if err != nil {
   207  		t.Fatal(err)
   208  	}
   209  
   210  	diff := stringid.GenerateRandomID()
   211  	if err := driver.Create(diff, base, nil); err != nil {
   212  		t.Fatal(err)
   213  	}
   214  
   215  	if err := checkManyFiles(driver, diff, fileCount, 3); err != nil {
   216  		t.Fatal(err)
   217  	}
   218  
   219  	if err := checkFile(driver, diff, deleteFile, deleteFileContent); err != nil {
   220  		t.Fatal(err)
   221  	}
   222  
   223  	arch, err := driver.Diff(upper, base)
   224  	if err != nil {
   225  		t.Fatal(err)
   226  	}
   227  
   228  	buf := bytes.NewBuffer(nil)
   229  	if _, err := buf.ReadFrom(arch); err != nil {
   230  		t.Fatal(err)
   231  	}
   232  	if err := arch.Close(); err != nil {
   233  		t.Fatal(err)
   234  	}
   235  
   236  	applyDiffSize, err := driver.ApplyDiff(diff, base, bytes.NewReader(buf.Bytes()))
   237  	if err != nil {
   238  		t.Fatal(err)
   239  	}
   240  
   241  	if applyDiffSize != diffSize {
   242  		t.Fatalf("Apply diff size different, got %d, expected %d", applyDiffSize, diffSize)
   243  	}
   244  
   245  	if err := checkManyFiles(driver, diff, fileCount, 6); err != nil {
   246  		t.Fatal(err)
   247  	}
   248  
   249  	if err := checkFileRemoved(driver, diff, deleteFile); err != nil {
   250  		t.Fatal(err)
   251  	}
   252  
   253  	if err := checkFileRemoved(driver, diff, deleteDir); err != nil {
   254  		t.Fatal(err)
   255  	}
   256  }
   257  
   258  // DriverTestChanges tests computed changes on a layer matches changes made
   259  func DriverTestChanges(t testing.TB, drivername string, driverOptions ...string) {
   260  	driver := GetDriver(t, drivername, driverOptions...)
   261  	defer PutDriver(t)
   262  	base := stringid.GenerateRandomID()
   263  	upper := stringid.GenerateRandomID()
   264  	if err := driver.Create(base, "", nil); err != nil {
   265  		t.Fatal(err)
   266  	}
   267  
   268  	if err := addManyFiles(driver, base, 20, 3); err != nil {
   269  		t.Fatal(err)
   270  	}
   271  
   272  	if err := driver.Create(upper, base, nil); err != nil {
   273  		t.Fatal(err)
   274  	}
   275  
   276  	expectedChanges, err := changeManyFiles(driver, upper, 20, 6)
   277  	if err != nil {
   278  		t.Fatal(err)
   279  	}
   280  
   281  	changes, err := driver.Changes(upper, base)
   282  	if err != nil {
   283  		t.Fatal(err)
   284  	}
   285  
   286  	if err = checkChanges(expectedChanges, changes); err != nil {
   287  		t.Fatal(err)
   288  	}
   289  }
   290  
   291  func writeRandomFile(path string, size uint64) error {
   292  	data := make([]byte, size)
   293  	_, err := rand.Read(data)
   294  	if err != nil {
   295  		return err
   296  	}
   297  	return os.WriteFile(path, data, 0o700)
   298  }
   299  
   300  // DriverTestSetQuota Create a driver and test setting quota.
   301  func DriverTestSetQuota(t *testing.T, drivername string, required bool) {
   302  	driver := GetDriver(t, drivername)
   303  	defer PutDriver(t)
   304  
   305  	createBase(t, driver, "Base")
   306  	createOpts := &graphdriver.CreateOpts{}
   307  	createOpts.StorageOpt = make(map[string]string, 1)
   308  	createOpts.StorageOpt["size"] = "50M"
   309  	layerName := drivername + "Test"
   310  	if err := driver.CreateReadWrite(layerName, "Base", createOpts); err == quota.ErrQuotaNotSupported && !required {
   311  		t.Skipf("Quota not supported on underlying filesystem: %v", err)
   312  	} else if err != nil {
   313  		t.Fatal(err)
   314  	}
   315  
   316  	mountPath, err := driver.Get(layerName, "")
   317  	if err != nil {
   318  		t.Fatal(err)
   319  	}
   320  
   321  	quota := uint64(50 * units.MiB)
   322  
   323  	// Try to write a file smaller than quota, and ensure it works
   324  	err = writeRandomFile(path.Join(mountPath, "smallfile"), quota/2)
   325  	if err != nil {
   326  		t.Fatal(err)
   327  	}
   328  	defer os.Remove(path.Join(mountPath, "smallfile"))
   329  
   330  	// Try to write a file bigger than quota. We've already filled up half the quota, so hitting the limit should be easy
   331  	err = writeRandomFile(path.Join(mountPath, "bigfile"), quota)
   332  	if err == nil {
   333  		t.Fatalf("expected write to fail(), instead had success")
   334  	}
   335  	if pathError, ok := err.(*os.PathError); ok && pathError.Err != unix.EDQUOT && pathError.Err != unix.ENOSPC {
   336  		os.Remove(path.Join(mountPath, "bigfile"))
   337  		t.Fatalf("expect write() to fail with %v or %v, got %v", unix.EDQUOT, unix.ENOSPC, pathError.Err)
   338  	}
   339  }