github.com/demonoid81/containerd@v1.3.4/snapshots/testsuite/testsuite.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package testsuite
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"math/rand"
    24  	"os"
    25  	"path/filepath"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/containerd/containerd/errdefs"
    30  	"github.com/containerd/containerd/log/logtest"
    31  	"github.com/containerd/containerd/mount"
    32  	"github.com/containerd/containerd/namespaces"
    33  	"github.com/containerd/containerd/pkg/testutil"
    34  	"github.com/containerd/containerd/snapshots"
    35  	"github.com/containerd/continuity/fs/fstest"
    36  	"gotest.tools/assert"
    37  	is "gotest.tools/assert/cmp"
    38  )
    39  
    40  // SnapshotterSuite runs a test suite on the snapshotter given a factory function.
    41  func SnapshotterSuite(t *testing.T, name string, snapshotterFn func(ctx context.Context, root string) (snapshots.Snapshotter, func() error, error)) {
    42  	restoreMask := clearMask()
    43  	defer restoreMask()
    44  
    45  	t.Run("Basic", makeTest(name, snapshotterFn, checkSnapshotterBasic))
    46  	t.Run("StatActive", makeTest(name, snapshotterFn, checkSnapshotterStatActive))
    47  	t.Run("StatComitted", makeTest(name, snapshotterFn, checkSnapshotterStatCommitted))
    48  	t.Run("TransitivityTest", makeTest(name, snapshotterFn, checkSnapshotterTransitivity))
    49  	t.Run("PreareViewFailingtest", makeTest(name, snapshotterFn, checkSnapshotterPrepareView))
    50  	t.Run("Update", makeTest(name, snapshotterFn, checkUpdate))
    51  	t.Run("Remove", makeTest(name, snapshotterFn, checkRemove))
    52  
    53  	t.Run("LayerFileupdate", makeTest(name, snapshotterFn, checkLayerFileUpdate))
    54  	t.Run("RemoveDirectoryInLowerLayer", makeTest(name, snapshotterFn, checkRemoveDirectoryInLowerLayer))
    55  	t.Run("Chown", makeTest(name, snapshotterFn, checkChown))
    56  	t.Run("DirectoryPermissionOnCommit", makeTest(name, snapshotterFn, checkDirectoryPermissionOnCommit))
    57  	t.Run("RemoveIntermediateSnapshot", makeTest(name, snapshotterFn, checkRemoveIntermediateSnapshot))
    58  	t.Run("DeletedFilesInChildSnapshot", makeTest(name, snapshotterFn, checkDeletedFilesInChildSnapshot))
    59  	t.Run("MoveFileFromLowerLayer", makeTest(name, snapshotterFn, checkFileFromLowerLayer))
    60  	t.Run("Rename", makeTest(name, snapshotterFn, checkRename))
    61  
    62  	t.Run("ViewReadonly", makeTest(name, snapshotterFn, checkSnapshotterViewReadonly))
    63  
    64  	t.Run("StatInWalk", makeTest(name, snapshotterFn, checkStatInWalk))
    65  	t.Run("CloseTwice", makeTest(name, snapshotterFn, closeTwice))
    66  	t.Run("RootPermission", makeTest(name, snapshotterFn, checkRootPermission))
    67  
    68  	t.Run("128LayersMount", makeTest(name, snapshotterFn, check128LayersMount(name)))
    69  }
    70  
    71  func makeTest(name string, snapshotterFn func(ctx context.Context, root string) (snapshots.Snapshotter, func() error, error), fn func(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string)) func(t *testing.T) {
    72  	return func(t *testing.T) {
    73  		t.Parallel()
    74  
    75  		ctx := logtest.WithT(context.Background(), t)
    76  		ctx = namespaces.WithNamespace(ctx, "testsuite")
    77  		// Make two directories: a snapshotter root and a play area for the tests:
    78  		//
    79  		// 	/tmp
    80  		// 		work/ -> passed to test functions
    81  		// 		root/ -> passed to snapshotter
    82  		//
    83  		tmpDir, err := ioutil.TempDir("", "snapshot-suite-"+name+"-")
    84  		if err != nil {
    85  			t.Fatal(err)
    86  		}
    87  		defer os.RemoveAll(tmpDir)
    88  
    89  		root := filepath.Join(tmpDir, "root")
    90  		if err := os.MkdirAll(root, 0777); err != nil {
    91  			t.Fatal(err)
    92  		}
    93  
    94  		snapshotter, cleanup, err := snapshotterFn(ctx, root)
    95  		if err != nil {
    96  			t.Fatalf("Failed to initialize snapshotter: %+v", err)
    97  		}
    98  		defer func() {
    99  			if cleanup != nil {
   100  				if err := cleanup(); err != nil {
   101  					t.Errorf("Cleanup failed: %v", err)
   102  				}
   103  			}
   104  		}()
   105  
   106  		work := filepath.Join(tmpDir, "work")
   107  		if err := os.MkdirAll(work, 0777); err != nil {
   108  			t.Fatal(err)
   109  		}
   110  
   111  		defer testutil.DumpDirOnFailure(t, tmpDir)
   112  		fn(ctx, t, snapshotter, work)
   113  	}
   114  }
   115  
   116  var opt = snapshots.WithLabels(map[string]string{
   117  	"containerd.io/gc.root": time.Now().UTC().Format(time.RFC3339),
   118  })
   119  
   120  // checkSnapshotterBasic tests the basic workflow of a snapshot snapshotter.
   121  func checkSnapshotterBasic(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
   122  	initialApplier := fstest.Apply(
   123  		fstest.CreateFile("/foo", []byte("foo\n"), 0777),
   124  		fstest.CreateDir("/a", 0755),
   125  		fstest.CreateDir("/a/b", 0755),
   126  		fstest.CreateDir("/a/b/c", 0755),
   127  	)
   128  
   129  	diffApplier := fstest.Apply(
   130  		fstest.CreateFile("/bar", []byte("bar\n"), 0777),
   131  		// also, change content of foo to bar
   132  		fstest.CreateFile("/foo", []byte("bar\n"), 0777),
   133  		fstest.RemoveAll("/a/b"),
   134  	)
   135  
   136  	preparing := filepath.Join(work, "preparing")
   137  	if err := os.MkdirAll(preparing, 0777); err != nil {
   138  		t.Fatalf("failure reason: %+v", err)
   139  	}
   140  
   141  	mounts, err := snapshotter.Prepare(ctx, preparing, "", opt)
   142  	if err != nil {
   143  		t.Fatalf("failure reason: %+v", err)
   144  	}
   145  
   146  	if len(mounts) < 1 {
   147  		t.Fatal("expected mounts to have entries")
   148  	}
   149  
   150  	if err := mount.All(mounts, preparing); err != nil {
   151  		t.Fatalf("failure reason: %+v", err)
   152  	}
   153  
   154  	if err := initialApplier.Apply(preparing); err != nil {
   155  		t.Fatalf("failure reason: %+v", err)
   156  	}
   157  	// unmount before commit
   158  	testutil.Unmount(t, preparing)
   159  
   160  	committed := filepath.Join(work, "committed")
   161  	if err := snapshotter.Commit(ctx, committed, preparing, opt); err != nil {
   162  		t.Fatalf("failure reason: %+v", err)
   163  	}
   164  
   165  	si, err := snapshotter.Stat(ctx, committed)
   166  	if err != nil {
   167  		t.Fatalf("failure reason: %+v", err)
   168  	}
   169  
   170  	assert.Check(t, is.Equal("", si.Parent))
   171  	assert.Check(t, is.Equal(snapshots.KindCommitted, si.Kind))
   172  
   173  	_, err = snapshotter.Stat(ctx, preparing)
   174  	if err == nil {
   175  		t.Fatalf("%s should no longer be available after Commit", preparing)
   176  	}
   177  
   178  	next := filepath.Join(work, "nextlayer")
   179  	if err := os.MkdirAll(next, 0777); err != nil {
   180  		t.Fatalf("failure reason: %+v", err)
   181  	}
   182  
   183  	mounts, err = snapshotter.Prepare(ctx, next, committed, opt)
   184  	if err != nil {
   185  		t.Fatalf("failure reason: %+v", err)
   186  	}
   187  	if err := mount.All(mounts, next); err != nil {
   188  		t.Fatalf("failure reason: %+v", err)
   189  	}
   190  
   191  	if err := fstest.CheckDirectoryEqualWithApplier(next, initialApplier); err != nil {
   192  		t.Fatalf("failure reason: %+v", err)
   193  	}
   194  
   195  	if err := diffApplier.Apply(next); err != nil {
   196  		t.Fatalf("failure reason: %+v", err)
   197  	}
   198  	// unmount before commit
   199  	testutil.Unmount(t, next)
   200  
   201  	ni, err := snapshotter.Stat(ctx, next)
   202  	if err != nil {
   203  		t.Fatal(err)
   204  	}
   205  
   206  	assert.Check(t, is.Equal(committed, ni.Parent))
   207  	assert.Check(t, is.Equal(snapshots.KindActive, ni.Kind))
   208  
   209  	nextCommitted := filepath.Join(work, "committed-next")
   210  	if err := snapshotter.Commit(ctx, nextCommitted, next, opt); err != nil {
   211  		t.Fatalf("failure reason: %+v", err)
   212  	}
   213  
   214  	si2, err := snapshotter.Stat(ctx, nextCommitted)
   215  	if err != nil {
   216  		t.Fatalf("failure reason: %+v", err)
   217  	}
   218  
   219  	assert.Check(t, is.Equal(committed, si2.Parent))
   220  	assert.Check(t, is.Equal(snapshots.KindCommitted, si2.Kind))
   221  
   222  	_, err = snapshotter.Stat(ctx, next)
   223  	if err == nil {
   224  		t.Fatalf("%s should no longer be available after Commit", next)
   225  	}
   226  
   227  	expected := map[string]snapshots.Info{
   228  		si.Name:  si,
   229  		si2.Name: si2,
   230  	}
   231  	walked := map[string]snapshots.Info{} // walk is not ordered
   232  	assert.NilError(t, snapshotter.Walk(ctx, func(ctx context.Context, si snapshots.Info) error {
   233  		walked[si.Name] = si
   234  		return nil
   235  	}))
   236  
   237  	for ek, ev := range expected {
   238  		av, ok := walked[ek]
   239  		if !ok {
   240  			t.Errorf("Missing stat for %v", ek)
   241  			continue
   242  		}
   243  		assert.Check(t, is.DeepEqual(ev, av))
   244  	}
   245  
   246  	nextnext := filepath.Join(work, "nextnextlayer")
   247  	if err := os.MkdirAll(nextnext, 0777); err != nil {
   248  		t.Fatalf("failure reason: %+v", err)
   249  	}
   250  
   251  	mounts, err = snapshotter.View(ctx, nextnext, nextCommitted, opt)
   252  	if err != nil {
   253  		t.Fatalf("failure reason: %+v", err)
   254  	}
   255  	if err := mount.All(mounts, nextnext); err != nil {
   256  		t.Fatalf("failure reason: %+v", err)
   257  	}
   258  
   259  	if err := fstest.CheckDirectoryEqualWithApplier(nextnext,
   260  		fstest.Apply(initialApplier, diffApplier)); err != nil {
   261  		testutil.Unmount(t, nextnext)
   262  		t.Fatalf("failure reason: %+v", err)
   263  	}
   264  
   265  	testutil.Unmount(t, nextnext)
   266  	assert.NilError(t, snapshotter.Remove(ctx, nextnext))
   267  	assert.Assert(t, is.ErrorContains(snapshotter.Remove(ctx, committed), "remove"))
   268  	assert.NilError(t, snapshotter.Remove(ctx, nextCommitted))
   269  	assert.NilError(t, snapshotter.Remove(ctx, committed))
   270  }
   271  
   272  // Create a New Layer on top of base layer with Prepare, Stat on new layer, should return Active layer.
   273  func checkSnapshotterStatActive(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
   274  	preparing := filepath.Join(work, "preparing")
   275  	if err := os.MkdirAll(preparing, 0777); err != nil {
   276  		t.Fatal(err)
   277  	}
   278  
   279  	mounts, err := snapshotter.Prepare(ctx, preparing, "", opt)
   280  	if err != nil {
   281  		t.Fatal(err)
   282  	}
   283  
   284  	if len(mounts) < 1 {
   285  		t.Fatal("expected mounts to have entries")
   286  	}
   287  
   288  	if err = mount.All(mounts, preparing); err != nil {
   289  		t.Fatal(err)
   290  	}
   291  	defer testutil.Unmount(t, preparing)
   292  
   293  	if err = ioutil.WriteFile(filepath.Join(preparing, "foo"), []byte("foo\n"), 0777); err != nil {
   294  		t.Fatal(err)
   295  	}
   296  
   297  	si, err := snapshotter.Stat(ctx, preparing)
   298  	if err != nil {
   299  		t.Fatal(err)
   300  	}
   301  	assert.Check(t, is.Equal(si.Name, preparing))
   302  	assert.Check(t, is.Equal(snapshots.KindActive, si.Kind))
   303  	assert.Check(t, is.Equal("", si.Parent))
   304  }
   305  
   306  // Commit a New Layer on top of base layer with Prepare & Commit , Stat on new layer, should return Committed layer.
   307  func checkSnapshotterStatCommitted(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
   308  	preparing := filepath.Join(work, "preparing")
   309  	if err := os.MkdirAll(preparing, 0777); err != nil {
   310  		t.Fatal(err)
   311  	}
   312  
   313  	mounts, err := snapshotter.Prepare(ctx, preparing, "", opt)
   314  	if err != nil {
   315  		t.Fatal(err)
   316  	}
   317  
   318  	if len(mounts) < 1 {
   319  		t.Fatal("expected mounts to have entries")
   320  	}
   321  
   322  	if err = mount.All(mounts, preparing); err != nil {
   323  		t.Fatal(err)
   324  	}
   325  	defer testutil.Unmount(t, preparing)
   326  
   327  	if err = ioutil.WriteFile(filepath.Join(preparing, "foo"), []byte("foo\n"), 0777); err != nil {
   328  		t.Fatal(err)
   329  	}
   330  
   331  	committed := filepath.Join(work, "committed")
   332  	if err = snapshotter.Commit(ctx, committed, preparing, opt); err != nil {
   333  		t.Fatal(err)
   334  	}
   335  
   336  	si, err := snapshotter.Stat(ctx, committed)
   337  	if err != nil {
   338  		t.Fatal(err)
   339  	}
   340  	assert.Check(t, is.Equal(si.Name, committed))
   341  	assert.Check(t, is.Equal(snapshots.KindCommitted, si.Kind))
   342  	assert.Check(t, is.Equal("", si.Parent))
   343  
   344  }
   345  
   346  func snapshotterPrepareMount(ctx context.Context, snapshotter snapshots.Snapshotter, diffPathName string, parent string, work string) (string, error) {
   347  	preparing := filepath.Join(work, diffPathName)
   348  	if err := os.MkdirAll(preparing, 0777); err != nil {
   349  		return "", err
   350  	}
   351  
   352  	mounts, err := snapshotter.Prepare(ctx, preparing, parent, opt)
   353  	if err != nil {
   354  		return "", err
   355  	}
   356  
   357  	if len(mounts) < 1 {
   358  		return "", fmt.Errorf("expected mounts to have entries")
   359  	}
   360  
   361  	if err = mount.All(mounts, preparing); err != nil {
   362  		return "", err
   363  	}
   364  	return preparing, nil
   365  }
   366  
   367  // Given A <- B <- C, B is the parent of C and A is a transitive parent of C (in this case, a "grandparent")
   368  func checkSnapshotterTransitivity(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
   369  	preparing, err := snapshotterPrepareMount(ctx, snapshotter, "preparing", "", work)
   370  	if err != nil {
   371  		t.Fatal(err)
   372  	}
   373  	defer testutil.Unmount(t, preparing)
   374  
   375  	if err = ioutil.WriteFile(filepath.Join(preparing, "foo"), []byte("foo\n"), 0777); err != nil {
   376  		t.Fatal(err)
   377  	}
   378  
   379  	snapA := filepath.Join(work, "snapA")
   380  	if err = snapshotter.Commit(ctx, snapA, preparing, opt); err != nil {
   381  		t.Fatal(err)
   382  	}
   383  
   384  	next, err := snapshotterPrepareMount(ctx, snapshotter, "next", snapA, work)
   385  	if err != nil {
   386  		t.Fatal(err)
   387  	}
   388  	defer testutil.Unmount(t, next)
   389  
   390  	if err = ioutil.WriteFile(filepath.Join(next, "foo"), []byte("foo bar\n"), 0777); err != nil {
   391  		t.Fatal(err)
   392  	}
   393  
   394  	snapB := filepath.Join(work, "snapB")
   395  	if err = snapshotter.Commit(ctx, snapB, next, opt); err != nil {
   396  		t.Fatal(err)
   397  	}
   398  
   399  	siA, err := snapshotter.Stat(ctx, snapA)
   400  	if err != nil {
   401  		t.Fatal(err)
   402  	}
   403  
   404  	siB, err := snapshotter.Stat(ctx, snapB)
   405  	if err != nil {
   406  		t.Fatal(err)
   407  	}
   408  
   409  	siParentB, err := snapshotter.Stat(ctx, siB.Parent)
   410  	if err != nil {
   411  		t.Fatal(err)
   412  	}
   413  
   414  	// Test the transivity
   415  	assert.Check(t, is.Equal("", siA.Parent))
   416  	assert.Check(t, is.Equal(snapA, siB.Parent))
   417  	assert.Check(t, is.Equal("", siParentB.Parent))
   418  
   419  }
   420  
   421  // Creating two layers with Prepare or View with same key must fail.
   422  func checkSnapshotterPrepareView(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
   423  	preparing, err := snapshotterPrepareMount(ctx, snapshotter, "preparing", "", work)
   424  	if err != nil {
   425  		t.Fatal(err)
   426  	}
   427  	defer testutil.Unmount(t, preparing)
   428  
   429  	snapA := filepath.Join(work, "snapA")
   430  	if err = snapshotter.Commit(ctx, snapA, preparing, opt); err != nil {
   431  		t.Fatal(err)
   432  	}
   433  
   434  	// Prepare & View with same key
   435  	newLayer := filepath.Join(work, "newlayer")
   436  	if err = os.MkdirAll(preparing, 0777); err != nil {
   437  		t.Fatal(err)
   438  	}
   439  
   440  	// Prepare & View with same key
   441  	_, err = snapshotter.Prepare(ctx, newLayer, snapA, opt)
   442  	if err != nil {
   443  		t.Fatal(err)
   444  	}
   445  
   446  	_, err = snapshotter.View(ctx, newLayer, snapA, opt)
   447  	assert.Check(t, err != nil)
   448  
   449  	// Two Prepare with same key
   450  	prepLayer := filepath.Join(work, "prepLayer")
   451  	if err = os.MkdirAll(preparing, 0777); err != nil {
   452  		t.Fatal(err)
   453  	}
   454  
   455  	_, err = snapshotter.Prepare(ctx, prepLayer, snapA, opt)
   456  	if err != nil {
   457  		t.Fatal(err)
   458  	}
   459  
   460  	_, err = snapshotter.Prepare(ctx, prepLayer, snapA, opt)
   461  	assert.Check(t, err != nil)
   462  
   463  	// Two View with same key
   464  	viewLayer := filepath.Join(work, "viewLayer")
   465  	if err = os.MkdirAll(preparing, 0777); err != nil {
   466  		t.Fatal(err)
   467  	}
   468  
   469  	_, err = snapshotter.View(ctx, viewLayer, snapA, opt)
   470  	if err != nil {
   471  		t.Fatal(err)
   472  	}
   473  
   474  	_, err = snapshotter.View(ctx, viewLayer, snapA, opt)
   475  	assert.Check(t, err != nil)
   476  
   477  }
   478  
   479  // Deletion of files/folder of base layer in new layer, On Commit, those files should not be visible.
   480  func checkDeletedFilesInChildSnapshot(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
   481  
   482  	l1Init := fstest.Apply(
   483  		fstest.CreateFile("/foo", []byte("foo\n"), 0777),
   484  		fstest.CreateFile("/foobar", []byte("foobar\n"), 0777),
   485  	)
   486  	l2Init := fstest.Apply(
   487  		fstest.RemoveAll("/foobar"),
   488  	)
   489  	l3Init := fstest.Apply()
   490  
   491  	if err := checkSnapshots(ctx, snapshotter, work, l1Init, l2Init, l3Init); err != nil {
   492  		t.Fatalf("Check snapshots failed: %+v", err)
   493  	}
   494  
   495  }
   496  
   497  //Create three layers. Deleting intermediate layer must fail.
   498  func checkRemoveIntermediateSnapshot(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
   499  
   500  	base, err := snapshotterPrepareMount(ctx, snapshotter, "base", "", work)
   501  	if err != nil {
   502  		t.Fatal(err)
   503  	}
   504  
   505  	committedBase := filepath.Join(work, "committed-base")
   506  	if err = snapshotter.Commit(ctx, committedBase, base, opt); err != nil {
   507  		t.Fatal(err)
   508  	}
   509  
   510  	// Create intermediate layer
   511  	intermediate := filepath.Join(work, "intermediate")
   512  	if _, err = snapshotter.Prepare(ctx, intermediate, committedBase, opt); err != nil {
   513  		t.Fatal(err)
   514  	}
   515  
   516  	committedInter := filepath.Join(work, "committed-inter")
   517  	if err = snapshotter.Commit(ctx, committedInter, intermediate, opt); err != nil {
   518  		t.Fatal(err)
   519  	}
   520  
   521  	// Create top layer
   522  	topLayer := filepath.Join(work, "toplayer")
   523  	if _, err = snapshotter.Prepare(ctx, topLayer, committedInter, opt); err != nil {
   524  		t.Fatal(err)
   525  	}
   526  
   527  	// Deletion of intermediate layer must fail.
   528  	err = snapshotter.Remove(ctx, committedInter)
   529  	if err == nil {
   530  		t.Fatal("intermediate layer removal should fail.")
   531  	}
   532  
   533  	//Removal from toplayer to base should not fail.
   534  	err = snapshotter.Remove(ctx, topLayer)
   535  	if err != nil {
   536  		t.Fatal(err)
   537  	}
   538  	err = snapshotter.Remove(ctx, committedInter)
   539  	if err != nil {
   540  		t.Fatal(err)
   541  	}
   542  	testutil.Unmount(t, base)
   543  	err = snapshotter.Remove(ctx, committedBase)
   544  	if err != nil {
   545  		t.Fatal(err)
   546  	}
   547  }
   548  
   549  // baseTestSnapshots creates a base set of snapshots for tests, each snapshot is empty
   550  // Tests snapshots:
   551  //  c1 - committed snapshot, no parent
   552  //  c2 - committed snapshot, c1 is parent
   553  //  a1 - active snapshot, c2 is parent
   554  //  a1 - active snapshot, no parent
   555  //  v1 - view snapshot, v1 is parent
   556  //  v2 - view snapshot, no parent
   557  func baseTestSnapshots(ctx context.Context, snapshotter snapshots.Snapshotter) error {
   558  	if _, err := snapshotter.Prepare(ctx, "c1-a", "", opt); err != nil {
   559  		return err
   560  	}
   561  	if err := snapshotter.Commit(ctx, "c1", "c1-a", opt); err != nil {
   562  		return err
   563  	}
   564  	if _, err := snapshotter.Prepare(ctx, "c2-a", "c1", opt); err != nil {
   565  		return err
   566  	}
   567  	if err := snapshotter.Commit(ctx, "c2", "c2-a", opt); err != nil {
   568  		return err
   569  	}
   570  	if _, err := snapshotter.Prepare(ctx, "a1", "c2", opt); err != nil {
   571  		return err
   572  	}
   573  	if _, err := snapshotter.Prepare(ctx, "a2", "", opt); err != nil {
   574  		return err
   575  	}
   576  	if _, err := snapshotter.View(ctx, "v1", "c2", opt); err != nil {
   577  		return err
   578  	}
   579  	if _, err := snapshotter.View(ctx, "v2", "", opt); err != nil {
   580  		return err
   581  	}
   582  	return nil
   583  }
   584  
   585  func checkUpdate(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
   586  	t1 := time.Now().UTC()
   587  	if err := baseTestSnapshots(ctx, snapshotter); err != nil {
   588  		t.Fatalf("Failed to create base snapshots: %v", err)
   589  	}
   590  	t2 := time.Now().UTC()
   591  	testcases := []struct {
   592  		name   string
   593  		kind   snapshots.Kind
   594  		parent string
   595  	}{
   596  		{
   597  			name: "c1",
   598  			kind: snapshots.KindCommitted,
   599  		},
   600  		{
   601  			name:   "c2",
   602  			kind:   snapshots.KindCommitted,
   603  			parent: "c1",
   604  		},
   605  		{
   606  			name:   "a1",
   607  			kind:   snapshots.KindActive,
   608  			parent: "c2",
   609  		},
   610  		{
   611  			name: "a2",
   612  			kind: snapshots.KindActive,
   613  		},
   614  		{
   615  			name:   "v1",
   616  			kind:   snapshots.KindView,
   617  			parent: "c2",
   618  		},
   619  		{
   620  			name: "v2",
   621  			kind: snapshots.KindView,
   622  		},
   623  	}
   624  	for _, tc := range testcases {
   625  		st, err := snapshotter.Stat(ctx, tc.name)
   626  		if err != nil {
   627  			t.Fatalf("Failed to stat %s: %v", tc.name, err)
   628  		}
   629  		if st.Created.Before(t1) || st.Created.After(t2) {
   630  			t.Errorf("(%s) wrong created time %s: expected between %s and %s", tc.name, st.Created, t1, t2)
   631  			continue
   632  		}
   633  		if st.Created != st.Updated {
   634  			t.Errorf("(%s) unexpected updated time %s: expected %s", tc.name, st.Updated, st.Created)
   635  			continue
   636  		}
   637  		if st.Kind != tc.kind {
   638  			t.Errorf("(%s) unexpected kind %s, expected %s", tc.name, st.Kind, tc.kind)
   639  			continue
   640  		}
   641  		if st.Parent != tc.parent {
   642  			t.Errorf("(%s) unexpected parent %q, expected %q", tc.name, st.Parent, tc.parent)
   643  			continue
   644  		}
   645  		if st.Name != tc.name {
   646  			t.Errorf("(%s) unexpected name %q, expected %q", tc.name, st.Name, tc.name)
   647  			continue
   648  		}
   649  
   650  		createdAt := st.Created
   651  		rootTime := time.Now().UTC().Format(time.RFC3339)
   652  		expected := map[string]string{
   653  			"l1": "v1",
   654  			"l2": "v2",
   655  			"l3": "v3",
   656  			// Keep root label
   657  			"containerd.io/gc.root": rootTime,
   658  		}
   659  		st.Parent = "doesnotexist"
   660  		st.Labels = expected
   661  		u1 := time.Now().UTC()
   662  		st, err = snapshotter.Update(ctx, st)
   663  		if err != nil {
   664  			t.Fatalf("Failed to update %s: %v", tc.name, err)
   665  		}
   666  		u2 := time.Now().UTC()
   667  
   668  		if st.Created != createdAt {
   669  			t.Errorf("(%s) wrong created time %s: expected %s", tc.name, st.Created, createdAt)
   670  			continue
   671  		}
   672  		if st.Updated.Before(u1) || st.Updated.After(u2) {
   673  			t.Errorf("(%s) wrong updated time %s: expected between %s and %s", tc.name, st.Updated, u1, u2)
   674  			continue
   675  		}
   676  		if st.Kind != tc.kind {
   677  			t.Errorf("(%s) unexpected kind %s, expected %s", tc.name, st.Kind, tc.kind)
   678  			continue
   679  		}
   680  		if st.Parent != tc.parent {
   681  			t.Errorf("(%s) unexpected parent %q, expected %q", tc.name, st.Parent, tc.parent)
   682  			continue
   683  		}
   684  		if st.Name != tc.name {
   685  			t.Errorf("(%s) unexpected name %q, expected %q", tc.name, st.Name, tc.name)
   686  			continue
   687  		}
   688  		assertLabels(t, st.Labels, expected)
   689  
   690  		expected = map[string]string{
   691  			"l1": "updated",
   692  			"l3": "v3",
   693  
   694  			"containerd.io/gc.root": rootTime,
   695  		}
   696  		st.Labels = map[string]string{
   697  			"l1": "updated",
   698  			"l4": "v4",
   699  		}
   700  		st, err = snapshotter.Update(ctx, st, "labels.l1", "labels.l2")
   701  		if err != nil {
   702  			t.Fatalf("Failed to update %s: %v", tc.name, err)
   703  		}
   704  		assertLabels(t, st.Labels, expected)
   705  
   706  		expected = map[string]string{
   707  			"l4": "v4",
   708  
   709  			"containerd.io/gc.root": rootTime,
   710  		}
   711  		st.Labels = expected
   712  		st, err = snapshotter.Update(ctx, st, "labels")
   713  		if err != nil {
   714  			t.Fatalf("Failed to update %s: %v", tc.name, err)
   715  		}
   716  		assertLabels(t, st.Labels, expected)
   717  
   718  		// Test failure received when providing immutable field path
   719  		st.Parent = "doesnotexist"
   720  		st, err = snapshotter.Update(ctx, st, "parent")
   721  		if err == nil {
   722  			t.Errorf("Expected error updating with immutable field path")
   723  		} else if !errdefs.IsInvalidArgument(err) {
   724  			t.Fatalf("Unexpected error updating %s: %+v", tc.name, err)
   725  		}
   726  	}
   727  }
   728  
   729  func assertLabels(t *testing.T, actual, expected map[string]string) {
   730  	if len(actual) != len(expected) {
   731  		t.Fatalf("Label size mismatch: %d vs %d\n\tActual: %#v\n\tExpected: %#v", len(actual), len(expected), actual, expected)
   732  	}
   733  	for k, v := range expected {
   734  		if a := actual[k]; v != a {
   735  			t.Errorf("Wrong label value for %s, got %q, expected %q", k, a, v)
   736  		}
   737  	}
   738  	if t.Failed() {
   739  		t.FailNow()
   740  	}
   741  }
   742  
   743  func checkRemove(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
   744  	if _, err := snapshotter.Prepare(ctx, "committed-a", "", opt); err != nil {
   745  		t.Fatal(err)
   746  	}
   747  	if err := snapshotter.Commit(ctx, "committed-1", "committed-a", opt); err != nil {
   748  		t.Fatal(err)
   749  	}
   750  	if _, err := snapshotter.Prepare(ctx, "reuse-1", "committed-1", opt); err != nil {
   751  		t.Fatal(err)
   752  	}
   753  	if err := snapshotter.Remove(ctx, "reuse-1"); err != nil {
   754  		t.Fatal(err)
   755  	}
   756  	if _, err := snapshotter.View(ctx, "reuse-1", "committed-1", opt); err != nil {
   757  		t.Fatal(err)
   758  	}
   759  	if err := snapshotter.Remove(ctx, "reuse-1"); err != nil {
   760  		t.Fatal(err)
   761  	}
   762  	if _, err := snapshotter.Prepare(ctx, "reuse-1", "", opt); err != nil {
   763  		t.Fatal(err)
   764  	}
   765  	if err := snapshotter.Remove(ctx, "committed-1"); err != nil {
   766  		t.Fatal(err)
   767  	}
   768  	if err := snapshotter.Commit(ctx, "committed-1", "reuse-1", opt); err != nil {
   769  		t.Fatal(err)
   770  	}
   771  }
   772  
   773  // checkSnapshotterViewReadonly ensures a KindView snapshot to be mounted as a read-only filesystem.
   774  // This function is called only when WithTestViewReadonly is true.
   775  func checkSnapshotterViewReadonly(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
   776  	preparing := filepath.Join(work, "preparing")
   777  	if _, err := snapshotter.Prepare(ctx, preparing, "", opt); err != nil {
   778  		t.Fatal(err)
   779  	}
   780  	committed := filepath.Join(work, "committed")
   781  	if err := snapshotter.Commit(ctx, committed, preparing, opt); err != nil {
   782  		t.Fatal(err)
   783  	}
   784  	view := filepath.Join(work, "view")
   785  	m, err := snapshotter.View(ctx, view, committed, opt)
   786  	if err != nil {
   787  		t.Fatal(err)
   788  	}
   789  	viewMountPoint := filepath.Join(work, "view-mount")
   790  	if err := os.MkdirAll(viewMountPoint, 0777); err != nil {
   791  		t.Fatal(err)
   792  	}
   793  
   794  	// Just checking the option string of m is not enough, we need to test real mount. (#1368)
   795  	if err := mount.All(m, viewMountPoint); err != nil {
   796  		t.Fatal(err)
   797  	}
   798  
   799  	testfile := filepath.Join(viewMountPoint, "testfile")
   800  	if err := ioutil.WriteFile(testfile, []byte("testcontent"), 0777); err != nil {
   801  		t.Logf("write to %q failed with %v (EROFS is expected but can be other error code)", testfile, err)
   802  	} else {
   803  		t.Fatalf("write to %q should fail (EROFS) but did not fail", testfile)
   804  	}
   805  	testutil.Unmount(t, viewMountPoint)
   806  	assert.NilError(t, snapshotter.Remove(ctx, view))
   807  	assert.NilError(t, snapshotter.Remove(ctx, committed))
   808  }
   809  
   810  // Move files from base layer to new location in intermediate layer.
   811  // Verify if the file at source is deleted and copied to new location.
   812  func checkFileFromLowerLayer(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
   813  	l1Init := fstest.Apply(
   814  		fstest.CreateDir("/dir1", 0700),
   815  		fstest.CreateFile("/dir1/f1", []byte("Hello"), 0644),
   816  		fstest.CreateDir("dir2", 0700),
   817  		fstest.CreateFile("dir2/f2", []byte("..."), 0644),
   818  	)
   819  	l2Init := fstest.Apply(
   820  		fstest.CreateDir("/dir3", 0700),
   821  		fstest.CreateFile("/dir3/f1", []byte("Hello"), 0644),
   822  		fstest.RemoveAll("/dir1"),
   823  		fstest.Link("dir2/f2", "dir3/f2"),
   824  		fstest.RemoveAll("dir2/f2"),
   825  	)
   826  
   827  	if err := checkSnapshots(ctx, snapshotter, work, l1Init, l2Init); err != nil {
   828  		t.Fatalf("Check snapshots failed: %+v", err)
   829  	}
   830  }
   831  
   832  func closeTwice(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
   833  	n := fmt.Sprintf("closeTwice-%d", rand.Int())
   834  	prepare := fmt.Sprintf("%s-prepare", n)
   835  
   836  	// do some dummy ops to modify the snapshotter internal state
   837  	if _, err := snapshotter.Prepare(ctx, prepare, "", opt); err != nil {
   838  		t.Fatal(err)
   839  	}
   840  	if err := snapshotter.Commit(ctx, n, prepare, opt); err != nil {
   841  		t.Fatal(err)
   842  	}
   843  	if err := snapshotter.Remove(ctx, n); err != nil {
   844  		t.Fatal(err)
   845  	}
   846  	if err := snapshotter.Close(); err != nil {
   847  		t.Fatalf("The first close failed: %+v", err)
   848  	}
   849  	if err := snapshotter.Close(); err != nil {
   850  		t.Fatalf("The second close failed: %+v", err)
   851  	}
   852  }
   853  
   854  func checkRootPermission(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
   855  	preparing, err := snapshotterPrepareMount(ctx, snapshotter, "preparing", "", work)
   856  	if err != nil {
   857  		t.Fatal(err)
   858  	}
   859  	defer testutil.Unmount(t, preparing)
   860  	st, err := os.Stat(preparing)
   861  	if err != nil {
   862  		t.Fatal(err)
   863  	}
   864  	if mode := st.Mode() & 0777; mode != 0755 {
   865  		t.Fatalf("expected 0755, got 0%o", mode)
   866  	}
   867  }
   868  
   869  func check128LayersMount(name string) func(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
   870  	return func(ctx context.Context, t *testing.T, snapshotter snapshots.Snapshotter, work string) {
   871  		if name == "Aufs" {
   872  			t.Skip("aufs tests have issues with whiteouts here on some CI kernels")
   873  		}
   874  		lowestApply := fstest.Apply(
   875  			fstest.CreateFile("/bottom", []byte("way at the bottom\n"), 0777),
   876  			fstest.CreateFile("/overwriteme", []byte("FIRST!\n"), 0777),
   877  			fstest.CreateDir("/ADDHERE", 0755),
   878  			fstest.CreateDir("/ONLYME", 0755),
   879  			fstest.CreateFile("/ONLYME/bottom", []byte("bye!\n"), 0777),
   880  		)
   881  
   882  		appliers := []fstest.Applier{lowestApply}
   883  		for i := 1; i <= 127; i++ {
   884  			appliers = append(appliers, fstest.Apply(
   885  				fstest.CreateFile("/overwriteme", []byte(fmt.Sprintf("%d WAS HERE!\n", i)), 0777),
   886  				fstest.CreateFile(fmt.Sprintf("/ADDHERE/file-%d", i), []byte("same\n"), 0755),
   887  				fstest.RemoveAll("/ONLYME"),
   888  				fstest.CreateDir("/ONLYME", 0755),
   889  				fstest.CreateFile(fmt.Sprintf("/ONLYME/file-%d", i), []byte("only me!\n"), 0777),
   890  			))
   891  		}
   892  
   893  		flat := filepath.Join(work, "flat")
   894  		if err := os.MkdirAll(flat, 0777); err != nil {
   895  			t.Fatalf("failed to create flat dir(%s): %+v", flat, err)
   896  		}
   897  
   898  		// NOTE: add gc labels to avoid snapshots get removed by gc...
   899  		parent := ""
   900  		for i, applier := range appliers {
   901  			preparing := filepath.Join(work, fmt.Sprintf("prepare-layer-%d", i))
   902  			if err := os.MkdirAll(preparing, 0777); err != nil {
   903  				t.Fatalf("[layer %d] failed to create preparing dir(%s): %+v", i, preparing, err)
   904  			}
   905  
   906  			mounts, err := snapshotter.Prepare(ctx, preparing, parent, opt)
   907  			if err != nil {
   908  				t.Fatalf("[layer %d] failed to get mount info: %+v", i, err)
   909  			}
   910  
   911  			if err := mount.All(mounts, preparing); err != nil {
   912  				t.Fatalf("[layer %d] failed to mount on the target(%s): %+v", i, preparing, err)
   913  			}
   914  
   915  			if err := fstest.CheckDirectoryEqual(preparing, flat); err != nil {
   916  				testutil.Unmount(t, preparing)
   917  				t.Fatalf("[layer %d] preparing doesn't equal to flat before apply: %+v", i, err)
   918  			}
   919  
   920  			if err := applier.Apply(flat); err != nil {
   921  				testutil.Unmount(t, preparing)
   922  				t.Fatalf("[layer %d] failed to apply on flat dir: %+v", i, err)
   923  			}
   924  
   925  			if err = applier.Apply(preparing); err != nil {
   926  				testutil.Unmount(t, preparing)
   927  				t.Fatalf("[layer %d] failed to apply on preparing dir: %+v", i, err)
   928  			}
   929  
   930  			if err := fstest.CheckDirectoryEqual(preparing, flat); err != nil {
   931  				testutil.Unmount(t, preparing)
   932  				t.Fatalf("[layer %d] preparing doesn't equal to flat after apply: %+v", i, err)
   933  			}
   934  
   935  			testutil.Unmount(t, preparing)
   936  
   937  			parent = filepath.Join(work, fmt.Sprintf("committed-%d", i))
   938  			if err := snapshotter.Commit(ctx, parent, preparing, opt); err != nil {
   939  				t.Fatalf("[layer %d] failed to commit the preparing: %+v", i, err)
   940  			}
   941  
   942  		}
   943  
   944  		view := filepath.Join(work, "fullview")
   945  		if err := os.MkdirAll(view, 0777); err != nil {
   946  			t.Fatalf("failed to create fullview dir(%s): %+v", view, err)
   947  		}
   948  
   949  		mounts, err := snapshotter.View(ctx, view, parent, opt)
   950  		if err != nil {
   951  			t.Fatalf("failed to get view's mount info: %+v", err)
   952  		}
   953  
   954  		if err := mount.All(mounts, view); err != nil {
   955  			t.Fatalf("failed to mount on the target(%s): %+v", view, err)
   956  		}
   957  		defer testutil.Unmount(t, view)
   958  
   959  		if err := fstest.CheckDirectoryEqual(view, flat); err != nil {
   960  			t.Fatalf("fullview should equal to flat: %+v", err)
   961  		}
   962  	}
   963  }