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