github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/snapshots/devmapper/snapshotter_test.go (about) 1 // +build linux 2 3 /* 4 Copyright The containerd Authors. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 package devmapper 20 21 import ( 22 "context" 23 _ "crypto/sha256" 24 "fmt" 25 "io/ioutil" 26 "os" 27 "testing" 28 "time" 29 30 "github.com/containerd/continuity/fs/fstest" 31 "github.com/hashicorp/go-multierror" 32 "github.com/sirupsen/logrus" 33 "gotest.tools/v3/assert" 34 35 "github.com/containerd/containerd/mount" 36 "github.com/containerd/containerd/namespaces" 37 "github.com/containerd/containerd/pkg/testutil" 38 "github.com/containerd/containerd/snapshots" 39 "github.com/containerd/containerd/snapshots/devmapper/dmsetup" 40 "github.com/containerd/containerd/snapshots/devmapper/losetup" 41 "github.com/containerd/containerd/snapshots/testsuite" 42 ) 43 44 func TestSnapshotterSuite(t *testing.T) { 45 testutil.RequiresRoot(t) 46 47 logrus.SetLevel(logrus.DebugLevel) 48 49 snapshotterFn := func(ctx context.Context, root string) (snapshots.Snapshotter, func() error, error) { 50 // Create loopback devices for each test case 51 _, loopDataDevice := createLoopbackDevice(t, root) 52 _, loopMetaDevice := createLoopbackDevice(t, root) 53 54 poolName := fmt.Sprintf("containerd-snapshotter-suite-pool-%d", time.Now().Nanosecond()) 55 err := dmsetup.CreatePool(poolName, loopDataDevice, loopMetaDevice, 64*1024/dmsetup.SectorSize) 56 assert.NilError(t, err, "failed to create pool %q", poolName) 57 58 config := &Config{ 59 RootPath: root, 60 PoolName: poolName, 61 BaseImageSize: "16Mb", 62 } 63 64 snap, err := NewSnapshotter(context.Background(), config) 65 if err != nil { 66 return nil, nil, err 67 } 68 69 // Remove device mapper pool and detach loop devices after test completes 70 removePool := func() error { 71 result := multierror.Append( 72 snap.pool.RemovePool(ctx), 73 losetup.DetachLoopDevice(loopDataDevice, loopMetaDevice)) 74 75 return result.ErrorOrNil() 76 } 77 78 // Pool cleanup should be called before closing metadata store (as we need to retrieve device names) 79 snap.cleanupFn = append([]closeFunc{removePool}, snap.cleanupFn...) 80 81 return snap, snap.Close, nil 82 } 83 84 testsuite.SnapshotterSuite(t, "devmapper", snapshotterFn) 85 86 ctx := context.Background() 87 ctx = namespaces.WithNamespace(ctx, "testsuite") 88 89 t.Run("DevMapperUsage", func(t *testing.T) { 90 tempDir, err := ioutil.TempDir("", "snapshot-suite-usage") 91 assert.NilError(t, err) 92 defer os.RemoveAll(tempDir) 93 94 snapshotter, closer, err := snapshotterFn(ctx, tempDir) 95 assert.NilError(t, err) 96 defer closer() 97 98 testUsage(t, snapshotter) 99 }) 100 } 101 102 // testUsage tests devmapper's Usage implementation. This is an approximate test as it's hard to 103 // predict how many blocks will be consumed under different conditions and parameters. 104 func testUsage(t *testing.T, snapshotter snapshots.Snapshotter) { 105 ctx := context.Background() 106 107 // Create empty base layer 108 _, err := snapshotter.Prepare(ctx, "prepare-1", "") 109 assert.NilError(t, err) 110 111 emptyLayerUsage, err := snapshotter.Usage(ctx, "prepare-1") 112 assert.NilError(t, err) 113 114 // Should be > 0 as just written file system also consumes blocks 115 assert.Assert(t, emptyLayerUsage.Size > 0) 116 117 err = snapshotter.Commit(ctx, "layer-1", "prepare-1") 118 assert.NilError(t, err) 119 120 // Create child layer with 1MB file 121 122 var ( 123 sizeBytes int64 = 1048576 // 1MB 124 baseApplier = fstest.Apply(fstest.CreateRandomFile("/a", 12345679, sizeBytes, 0777)) 125 ) 126 127 mounts, err := snapshotter.Prepare(ctx, "prepare-2", "layer-1") 128 assert.NilError(t, err) 129 130 err = mount.WithTempMount(ctx, mounts, baseApplier.Apply) 131 assert.NilError(t, err) 132 133 err = snapshotter.Commit(ctx, "layer-2", "prepare-2") 134 assert.NilError(t, err) 135 136 layer2Usage, err := snapshotter.Usage(ctx, "layer-2") 137 assert.NilError(t, err) 138 139 // Should be at least 1 MB + fs metadata 140 assert.Assert(t, layer2Usage.Size > sizeBytes) 141 assert.Assert(t, layer2Usage.Size < sizeBytes+256*dmsetup.SectorSize) 142 }