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