github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/graphdriver/aufs/aufs_test.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package aufs // import "github.com/docker/docker/daemon/graphdriver/aufs"
     5  
     6  import (
     7  	"crypto/sha256"
     8  	"encoding/hex"
     9  	"fmt"
    10  	"os"
    11  	"path"
    12  	"path/filepath"
    13  	"strconv"
    14  	"sync"
    15  	"testing"
    16  
    17  	"github.com/docker/docker/daemon/graphdriver"
    18  	"github.com/docker/docker/pkg/archive"
    19  	"github.com/docker/docker/pkg/idtools"
    20  	"github.com/docker/docker/pkg/reexec"
    21  	"github.com/docker/docker/pkg/stringid"
    22  	"gotest.tools/v3/assert"
    23  	is "gotest.tools/v3/assert/cmp"
    24  )
    25  
    26  var (
    27  	tmpOuter = path.Join(os.TempDir(), "aufs-tests")
    28  	tmp      = path.Join(tmpOuter, "aufs")
    29  )
    30  
    31  func init() {
    32  	reexec.Init()
    33  }
    34  
    35  func testInit(dir string, t testing.TB) graphdriver.Driver {
    36  	d, err := Init(dir, nil, idtools.IdentityMapping{})
    37  	if err != nil {
    38  		if err == graphdriver.ErrNotSupported {
    39  			t.Skip(err)
    40  		} else {
    41  			t.Fatal(err)
    42  		}
    43  	}
    44  	return d
    45  }
    46  
    47  func newDriver(t testing.TB) *Driver {
    48  	if err := os.MkdirAll(tmp, 0755); err != nil {
    49  		t.Fatal(err)
    50  	}
    51  
    52  	d := testInit(tmp, t)
    53  	return d.(*Driver)
    54  }
    55  
    56  func TestNewDriver(t *testing.T) {
    57  	if err := os.MkdirAll(tmp, 0755); err != nil {
    58  		t.Fatal(err)
    59  	}
    60  
    61  	d := testInit(tmp, t)
    62  	defer os.RemoveAll(tmp)
    63  	if d == nil {
    64  		t.Fatal("Driver should not be nil")
    65  	}
    66  }
    67  
    68  func TestAufsString(t *testing.T) {
    69  	d := newDriver(t)
    70  	defer os.RemoveAll(tmp)
    71  
    72  	if d.String() != "aufs" {
    73  		t.Fatalf("Expected aufs got %s", d.String())
    74  	}
    75  }
    76  
    77  func TestCreateDirStructure(t *testing.T) {
    78  	newDriver(t)
    79  	defer os.RemoveAll(tmp)
    80  
    81  	paths := []string{
    82  		"mnt",
    83  		"layers",
    84  		"diff",
    85  	}
    86  
    87  	for _, p := range paths {
    88  		if _, err := os.Stat(path.Join(tmp, p)); err != nil {
    89  			t.Fatal(err)
    90  		}
    91  	}
    92  }
    93  
    94  // We should be able to create two drivers with the same dir structure
    95  func TestNewDriverFromExistingDir(t *testing.T) {
    96  	if err := os.MkdirAll(tmp, 0755); err != nil {
    97  		t.Fatal(err)
    98  	}
    99  
   100  	testInit(tmp, t)
   101  	testInit(tmp, t)
   102  	os.RemoveAll(tmp)
   103  }
   104  
   105  func TestCreateNewDir(t *testing.T) {
   106  	d := newDriver(t)
   107  	defer os.RemoveAll(tmp)
   108  
   109  	if err := d.Create("1", "", nil); err != nil {
   110  		t.Fatal(err)
   111  	}
   112  }
   113  
   114  func TestCreateNewDirStructure(t *testing.T) {
   115  	d := newDriver(t)
   116  	defer os.RemoveAll(tmp)
   117  
   118  	if err := d.Create("1", "", nil); err != nil {
   119  		t.Fatal(err)
   120  	}
   121  
   122  	paths := []string{
   123  		"mnt",
   124  		"diff",
   125  		"layers",
   126  	}
   127  
   128  	for _, p := range paths {
   129  		if _, err := os.Stat(path.Join(tmp, p, "1")); err != nil {
   130  			t.Fatal(err)
   131  		}
   132  	}
   133  }
   134  
   135  func TestRemoveImage(t *testing.T) {
   136  	d := newDriver(t)
   137  	defer os.RemoveAll(tmp)
   138  
   139  	if err := d.Create("1", "", nil); err != nil {
   140  		t.Fatal(err)
   141  	}
   142  
   143  	if err := d.Remove("1"); err != nil {
   144  		t.Fatal(err)
   145  	}
   146  
   147  	paths := []string{
   148  		"mnt",
   149  		"diff",
   150  		"layers",
   151  	}
   152  
   153  	for _, p := range paths {
   154  		if _, err := os.Stat(path.Join(tmp, p, "1")); err == nil {
   155  			t.Fatalf("Error should not be nil because dirs with id 1 should be deleted: %s", p)
   156  		}
   157  		if _, err := os.Stat(path.Join(tmp, p, "1-removing")); err == nil {
   158  			t.Fatalf("Error should not be nil because dirs with id 1-removing should be deleted: %s", p)
   159  		}
   160  	}
   161  }
   162  
   163  func TestGetWithoutParent(t *testing.T) {
   164  	d := newDriver(t)
   165  	defer os.RemoveAll(tmp)
   166  
   167  	if err := d.Create("1", "", nil); err != nil {
   168  		t.Fatal(err)
   169  	}
   170  
   171  	diffPath, err := d.Get("1", "")
   172  	if err != nil {
   173  		t.Fatal(err)
   174  	}
   175  	expected := path.Join(tmp, "diff", "1")
   176  	if diffPath != expected {
   177  		t.Fatalf("Expected path %s got %s", expected, diffPath)
   178  	}
   179  }
   180  
   181  func TestCleanupWithNoDirs(t *testing.T) {
   182  	d := newDriver(t)
   183  	defer os.RemoveAll(tmp)
   184  
   185  	err := d.Cleanup()
   186  	assert.Check(t, err)
   187  }
   188  
   189  func TestCleanupWithDir(t *testing.T) {
   190  	d := newDriver(t)
   191  	defer os.RemoveAll(tmp)
   192  
   193  	if err := d.Create("1", "", nil); err != nil {
   194  		t.Fatal(err)
   195  	}
   196  
   197  	if err := d.Cleanup(); err != nil {
   198  		t.Fatal(err)
   199  	}
   200  }
   201  
   202  func TestMountedFalseResponse(t *testing.T) {
   203  	d := newDriver(t)
   204  	defer os.RemoveAll(tmp)
   205  
   206  	err := d.Create("1", "", nil)
   207  	assert.NilError(t, err)
   208  
   209  	response, err := d.mounted(d.getDiffPath("1"))
   210  	assert.NilError(t, err)
   211  	assert.Check(t, !response)
   212  }
   213  
   214  func TestMountedTrueResponse(t *testing.T) {
   215  	d := newDriver(t)
   216  	defer os.RemoveAll(tmp)
   217  	defer d.Cleanup()
   218  
   219  	err := d.Create("1", "", nil)
   220  	assert.NilError(t, err)
   221  	err = d.Create("2", "1", nil)
   222  	assert.NilError(t, err)
   223  
   224  	_, err = d.Get("2", "")
   225  	assert.NilError(t, err)
   226  
   227  	response, err := d.mounted(d.pathCache["2"])
   228  	assert.NilError(t, err)
   229  	assert.Check(t, response)
   230  }
   231  
   232  func TestMountWithParent(t *testing.T) {
   233  	d := newDriver(t)
   234  	defer os.RemoveAll(tmp)
   235  
   236  	if err := d.Create("1", "", nil); err != nil {
   237  		t.Fatal(err)
   238  	}
   239  	if err := d.Create("2", "1", nil); err != nil {
   240  		t.Fatal(err)
   241  	}
   242  
   243  	defer func() {
   244  		if err := d.Cleanup(); err != nil {
   245  			t.Fatal(err)
   246  		}
   247  	}()
   248  
   249  	mntPath, err := d.Get("2", "")
   250  	if err != nil {
   251  		t.Fatal(err)
   252  	}
   253  	if mntPath == "" {
   254  		t.Fatal("mntPath should not be empty")
   255  	}
   256  
   257  	expected := path.Join(tmp, "mnt", "2")
   258  	if mntPath != expected {
   259  		t.Fatalf("Expected %s got %s", expected, mntPath)
   260  	}
   261  }
   262  
   263  func TestRemoveMountedDir(t *testing.T) {
   264  	d := newDriver(t)
   265  	defer os.RemoveAll(tmp)
   266  
   267  	if err := d.Create("1", "", nil); err != nil {
   268  		t.Fatal(err)
   269  	}
   270  	if err := d.Create("2", "1", nil); err != nil {
   271  		t.Fatal(err)
   272  	}
   273  
   274  	defer func() {
   275  		if err := d.Cleanup(); err != nil {
   276  			t.Fatal(err)
   277  		}
   278  	}()
   279  
   280  	mntPath, err := d.Get("2", "")
   281  	if err != nil {
   282  		t.Fatal(err)
   283  	}
   284  	if mntPath == "" {
   285  		t.Fatal("mntPath should not be empty")
   286  	}
   287  
   288  	mounted, err := d.mounted(d.pathCache["2"])
   289  	if err != nil {
   290  		t.Fatal(err)
   291  	}
   292  
   293  	if !mounted {
   294  		t.Fatal("Dir id 2 should be mounted")
   295  	}
   296  
   297  	if err := d.Remove("2"); err != nil {
   298  		t.Fatal(err)
   299  	}
   300  }
   301  
   302  func TestCreateWithInvalidParent(t *testing.T) {
   303  	d := newDriver(t)
   304  	defer os.RemoveAll(tmp)
   305  
   306  	if err := d.Create("1", "docker", nil); err == nil {
   307  		t.Fatal("Error should not be nil with parent does not exist")
   308  	}
   309  }
   310  
   311  func TestGetDiff(t *testing.T) {
   312  	d := newDriver(t)
   313  	defer os.RemoveAll(tmp)
   314  
   315  	if err := d.CreateReadWrite("1", "", nil); err != nil {
   316  		t.Fatal(err)
   317  	}
   318  
   319  	diffPath, err := d.Get("1", "")
   320  	if err != nil {
   321  		t.Fatal(err)
   322  	}
   323  
   324  	// Add a file to the diff path with a fixed size
   325  	size := int64(1024)
   326  
   327  	f, err := os.Create(path.Join(diffPath, "test_file"))
   328  	if err != nil {
   329  		t.Fatal(err)
   330  	}
   331  	if err := f.Truncate(size); err != nil {
   332  		t.Fatal(err)
   333  	}
   334  	f.Close()
   335  
   336  	a, err := d.Diff("1", "")
   337  	if err != nil {
   338  		t.Fatal(err)
   339  	}
   340  	if a == nil {
   341  		t.Fatal("Archive should not be nil")
   342  	}
   343  }
   344  
   345  func TestChanges(t *testing.T) {
   346  	d := newDriver(t)
   347  	defer os.RemoveAll(tmp)
   348  
   349  	if err := d.Create("1", "", nil); err != nil {
   350  		t.Fatal(err)
   351  	}
   352  
   353  	if err := d.CreateReadWrite("2", "1", nil); err != nil {
   354  		t.Fatal(err)
   355  	}
   356  
   357  	defer func() {
   358  		if err := d.Cleanup(); err != nil {
   359  			t.Fatal(err)
   360  		}
   361  	}()
   362  
   363  	mntPoint, err := d.Get("2", "")
   364  	if err != nil {
   365  		t.Fatal(err)
   366  	}
   367  
   368  	// Create a file to save in the mountpoint
   369  	f, err := os.Create(path.Join(mntPoint, "test.txt"))
   370  	if err != nil {
   371  		t.Fatal(err)
   372  	}
   373  
   374  	if _, err := f.WriteString("testline"); err != nil {
   375  		t.Fatal(err)
   376  	}
   377  	if err := f.Close(); err != nil {
   378  		t.Fatal(err)
   379  	}
   380  
   381  	changes, err := d.Changes("2", "")
   382  	if err != nil {
   383  		t.Fatal(err)
   384  	}
   385  	if len(changes) != 1 {
   386  		t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
   387  	}
   388  	change := changes[0]
   389  
   390  	expectedPath := "/test.txt"
   391  	if change.Path != expectedPath {
   392  		t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
   393  	}
   394  
   395  	if change.Kind != archive.ChangeAdd {
   396  		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
   397  	}
   398  
   399  	if err := d.CreateReadWrite("3", "2", nil); err != nil {
   400  		t.Fatal(err)
   401  	}
   402  	mntPoint, err = d.Get("3", "")
   403  	if err != nil {
   404  		t.Fatal(err)
   405  	}
   406  
   407  	// Create a file to save in the mountpoint
   408  	f, err = os.Create(path.Join(mntPoint, "test2.txt"))
   409  	if err != nil {
   410  		t.Fatal(err)
   411  	}
   412  
   413  	if _, err := f.WriteString("testline"); err != nil {
   414  		t.Fatal(err)
   415  	}
   416  	if err := f.Close(); err != nil {
   417  		t.Fatal(err)
   418  	}
   419  
   420  	changes, err = d.Changes("3", "2")
   421  	if err != nil {
   422  		t.Fatal(err)
   423  	}
   424  
   425  	if len(changes) != 1 {
   426  		t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
   427  	}
   428  	change = changes[0]
   429  
   430  	expectedPath = "/test2.txt"
   431  	if change.Path != expectedPath {
   432  		t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
   433  	}
   434  
   435  	if change.Kind != archive.ChangeAdd {
   436  		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
   437  	}
   438  }
   439  
   440  func TestDiffSize(t *testing.T) {
   441  	d := newDriver(t)
   442  	defer os.RemoveAll(tmp)
   443  
   444  	if err := d.CreateReadWrite("1", "", nil); err != nil {
   445  		t.Fatal(err)
   446  	}
   447  
   448  	diffPath, err := d.Get("1", "")
   449  	if err != nil {
   450  		t.Fatal(err)
   451  	}
   452  
   453  	// Add a file to the diff path with a fixed size
   454  	size := int64(1024)
   455  
   456  	f, err := os.Create(path.Join(diffPath, "test_file"))
   457  	if err != nil {
   458  		t.Fatal(err)
   459  	}
   460  	if err := f.Truncate(size); err != nil {
   461  		t.Fatal(err)
   462  	}
   463  	s, err := f.Stat()
   464  	if err != nil {
   465  		t.Fatal(err)
   466  	}
   467  	size = s.Size()
   468  	if err := f.Close(); err != nil {
   469  		t.Fatal(err)
   470  	}
   471  
   472  	diffSize, err := d.DiffSize("1", "")
   473  	if err != nil {
   474  		t.Fatal(err)
   475  	}
   476  	if diffSize != size {
   477  		t.Fatalf("Expected size to be %d got %d", size, diffSize)
   478  	}
   479  }
   480  
   481  func TestChildDiffSize(t *testing.T) {
   482  	d := newDriver(t)
   483  	defer os.RemoveAll(tmp)
   484  	defer d.Cleanup()
   485  
   486  	if err := d.CreateReadWrite("1", "", nil); err != nil {
   487  		t.Fatal(err)
   488  	}
   489  
   490  	diffPath, err := d.Get("1", "")
   491  	if err != nil {
   492  		t.Fatal(err)
   493  	}
   494  
   495  	// Add a file to the diff path with a fixed size
   496  	size := int64(1024)
   497  
   498  	f, err := os.Create(path.Join(diffPath, "test_file"))
   499  	if err != nil {
   500  		t.Fatal(err)
   501  	}
   502  	if err := f.Truncate(size); err != nil {
   503  		t.Fatal(err)
   504  	}
   505  	s, err := f.Stat()
   506  	if err != nil {
   507  		t.Fatal(err)
   508  	}
   509  	size = s.Size()
   510  	if err := f.Close(); err != nil {
   511  		t.Fatal(err)
   512  	}
   513  
   514  	diffSize, err := d.DiffSize("1", "")
   515  	if err != nil {
   516  		t.Fatal(err)
   517  	}
   518  	if diffSize != size {
   519  		t.Fatalf("Expected size to be %d got %d", size, diffSize)
   520  	}
   521  
   522  	if err := d.Create("2", "1", nil); err != nil {
   523  		t.Fatal(err)
   524  	}
   525  
   526  	diffSize, err = d.DiffSize("2", "1")
   527  	if err != nil {
   528  		t.Fatal(err)
   529  	}
   530  	// The diff size for the child should be zero
   531  	if diffSize != 0 {
   532  		t.Fatalf("Expected size to be %d got %d", 0, diffSize)
   533  	}
   534  }
   535  
   536  func TestExists(t *testing.T) {
   537  	d := newDriver(t)
   538  	defer os.RemoveAll(tmp)
   539  	defer d.Cleanup()
   540  
   541  	if err := d.Create("1", "", nil); err != nil {
   542  		t.Fatal(err)
   543  	}
   544  
   545  	if d.Exists("none") {
   546  		t.Fatal("id none should not exist in the driver")
   547  	}
   548  
   549  	if !d.Exists("1") {
   550  		t.Fatal("id 1 should exist in the driver")
   551  	}
   552  }
   553  
   554  func TestStatus(t *testing.T) {
   555  	d := newDriver(t)
   556  	defer os.RemoveAll(tmp)
   557  	defer d.Cleanup()
   558  
   559  	if err := d.Create("1", "", nil); err != nil {
   560  		t.Fatal(err)
   561  	}
   562  
   563  	status := d.Status()
   564  	assert.Check(t, is.Len(status, 4))
   565  
   566  	rootDir := status[0]
   567  	dirs := status[2]
   568  	if rootDir[0] != "Root Dir" {
   569  		t.Fatalf("Expected Root Dir got %s", rootDir[0])
   570  	}
   571  	if rootDir[1] != d.rootPath() {
   572  		t.Fatalf("Expected %s got %s", d.rootPath(), rootDir[1])
   573  	}
   574  	if dirs[0] != "Dirs" {
   575  		t.Fatalf("Expected Dirs got %s", dirs[0])
   576  	}
   577  	if dirs[1] != "1" {
   578  		t.Fatalf("Expected 1 got %s", dirs[1])
   579  	}
   580  }
   581  
   582  func TestApplyDiff(t *testing.T) {
   583  	d := newDriver(t)
   584  	defer os.RemoveAll(tmp)
   585  	defer d.Cleanup()
   586  
   587  	if err := d.CreateReadWrite("1", "", nil); err != nil {
   588  		t.Fatal(err)
   589  	}
   590  
   591  	diffPath, err := d.Get("1", "")
   592  	if err != nil {
   593  		t.Fatal(err)
   594  	}
   595  
   596  	// Add a file to the diff path with a fixed size
   597  	size := int64(1024)
   598  
   599  	f, err := os.Create(path.Join(diffPath, "test_file"))
   600  	if err != nil {
   601  		t.Fatal(err)
   602  	}
   603  	if err := f.Truncate(size); err != nil {
   604  		t.Fatal(err)
   605  	}
   606  	f.Close()
   607  
   608  	diff, err := d.Diff("1", "")
   609  	if err != nil {
   610  		t.Fatal(err)
   611  	}
   612  
   613  	if err := d.Create("2", "", nil); err != nil {
   614  		t.Fatal(err)
   615  	}
   616  	if err := d.Create("3", "2", nil); err != nil {
   617  		t.Fatal(err)
   618  	}
   619  
   620  	if err := d.applyDiff("3", diff); err != nil {
   621  		t.Fatal(err)
   622  	}
   623  
   624  	// Ensure that the file is in the mount point for id 3
   625  
   626  	mountPoint, err := d.Get("3", "")
   627  	if err != nil {
   628  		t.Fatal(err)
   629  	}
   630  	if _, err := os.Stat(path.Join(mountPoint, "test_file")); err != nil {
   631  		t.Fatal(err)
   632  	}
   633  }
   634  
   635  func hash(c string) string {
   636  	h := sha256.New()
   637  	fmt.Fprint(h, c)
   638  	return hex.EncodeToString(h.Sum(nil))
   639  }
   640  
   641  func testMountMoreThan42Layers(t *testing.T, mountPath string) {
   642  	if err := os.MkdirAll(mountPath, 0755); err != nil {
   643  		t.Fatal(err)
   644  	}
   645  
   646  	defer os.RemoveAll(mountPath)
   647  	d := testInit(mountPath, t).(*Driver)
   648  	defer d.Cleanup()
   649  	var last string
   650  	var expected int
   651  
   652  	for i := 1; i < 127; i++ {
   653  		expected++
   654  		var (
   655  			parent  = strconv.Itoa(i - 1)
   656  			current = strconv.Itoa(i)
   657  		)
   658  
   659  		if parent == "0" {
   660  			parent = ""
   661  		} else {
   662  			parent = hash(parent)
   663  		}
   664  		current = hash(current)
   665  
   666  		err := d.CreateReadWrite(current, parent, nil)
   667  		assert.NilError(t, err, "current layer %d", i)
   668  
   669  		point, err := d.Get(current, "")
   670  		assert.NilError(t, err, "current layer %d", i)
   671  
   672  		f, err := os.Create(path.Join(point, current))
   673  		assert.NilError(t, err, "current layer %d", i)
   674  		f.Close()
   675  
   676  		if i%10 == 0 {
   677  			err := os.Remove(path.Join(point, parent))
   678  			assert.NilError(t, err, "current layer %d", i)
   679  			expected--
   680  		}
   681  		last = current
   682  	}
   683  
   684  	// Perform the actual mount for the top most image
   685  	point, err := d.Get(last, "")
   686  	assert.NilError(t, err)
   687  	files, err := os.ReadDir(point)
   688  	assert.NilError(t, err)
   689  	assert.Check(t, is.Len(files, expected))
   690  }
   691  
   692  func TestMountMoreThan42Layers(t *testing.T) {
   693  	defer os.RemoveAll(tmpOuter)
   694  	testMountMoreThan42Layers(t, tmp)
   695  }
   696  
   697  func TestMountMoreThan42LayersMatchingPathLength(t *testing.T) {
   698  	defer os.RemoveAll(tmpOuter)
   699  	zeroes := "0"
   700  	for {
   701  		// This finds a mount path so that when combined into aufs mount options
   702  		// 4096 byte boundary would be in between the paths or in permission
   703  		// section. For '/tmp' it will use '/tmp/aufs-tests/00000000/aufs'
   704  		mountPath := path.Join(tmpOuter, zeroes, "aufs")
   705  		pathLength := 77 + len(mountPath)
   706  
   707  		if mod := 4095 % pathLength; mod == 0 || mod > pathLength-2 {
   708  			t.Logf("Using path: %s", mountPath)
   709  			testMountMoreThan42Layers(t, mountPath)
   710  			return
   711  		}
   712  		zeroes += "0"
   713  	}
   714  }
   715  
   716  func BenchmarkConcurrentAccess(b *testing.B) {
   717  	b.StopTimer()
   718  	b.ResetTimer()
   719  
   720  	d := newDriver(b)
   721  	defer os.RemoveAll(tmp)
   722  	defer d.Cleanup()
   723  
   724  	numConcurrent := 256
   725  	// create a bunch of ids
   726  	ids := make([]string, numConcurrent)
   727  	for i := 0; i < numConcurrent; i++ {
   728  		ids[i] = stringid.GenerateRandomID()
   729  	}
   730  
   731  	if err := d.Create(ids[0], "", nil); err != nil {
   732  		b.Fatal(err)
   733  	}
   734  
   735  	if err := d.Create(ids[1], ids[0], nil); err != nil {
   736  		b.Fatal(err)
   737  	}
   738  
   739  	parent := ids[1]
   740  	ids = ids[2:]
   741  
   742  	chErr := make(chan error, numConcurrent)
   743  	var outerGroup sync.WaitGroup
   744  	outerGroup.Add(len(ids))
   745  	b.StartTimer()
   746  
   747  	// here's the actual bench
   748  	for _, id := range ids {
   749  		go func(id string) {
   750  			defer outerGroup.Done()
   751  			if err := d.Create(id, parent, nil); err != nil {
   752  				b.Logf("Create %s failed", id)
   753  				chErr <- err
   754  				return
   755  			}
   756  			var innerGroup sync.WaitGroup
   757  			for i := 0; i < b.N; i++ {
   758  				innerGroup.Add(1)
   759  				go func() {
   760  					d.Get(id, "")
   761  					d.Put(id)
   762  					innerGroup.Done()
   763  				}()
   764  			}
   765  			innerGroup.Wait()
   766  			d.Remove(id)
   767  		}(id)
   768  	}
   769  
   770  	outerGroup.Wait()
   771  	b.StopTimer()
   772  	close(chErr)
   773  	for err := range chErr {
   774  		if err != nil {
   775  			b.Log(err)
   776  			b.Fail()
   777  		}
   778  	}
   779  }
   780  
   781  func TestInitStaleCleanup(t *testing.T) {
   782  	if err := os.MkdirAll(tmp, 0755); err != nil {
   783  		t.Fatal(err)
   784  	}
   785  	defer os.RemoveAll(tmp)
   786  
   787  	for _, d := range []string{"diff", "mnt"} {
   788  		if err := os.MkdirAll(filepath.Join(tmp, d, "123-removing"), 0755); err != nil {
   789  			t.Fatal(err)
   790  		}
   791  	}
   792  
   793  	testInit(tmp, t)
   794  	for _, d := range []string{"diff", "mnt"} {
   795  		if _, err := os.Stat(filepath.Join(tmp, d, "123-removing")); err == nil {
   796  			t.Fatal("cleanup failed")
   797  		}
   798  	}
   799  }