github.com/containerd/nerdctl@v1.7.7/pkg/imgutil/snapshotter_test.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 imgutil 18 19 import ( 20 "context" 21 "reflect" 22 "testing" 23 24 "github.com/containerd/containerd" 25 ctdsnapshotters "github.com/containerd/containerd/pkg/snapshotters" 26 "github.com/containerd/nerdctl/pkg/imgutil/pull" 27 digest "github.com/opencontainers/go-digest" 28 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 29 "gotest.tools/v3/assert" 30 ) 31 32 const ( 33 targetRefLabel = "containerd.io/snapshot/remote/stargz.reference" 34 testRef = "test:latest" 35 ) 36 37 func TestGetSnapshotterOpts(t *testing.T) { 38 type testCase struct { 39 sns []string 40 check func(t *testing.T, o snapshotterOpts) 41 } 42 testCases := []testCase{ 43 { 44 sns: []string{"overlayfs"}, 45 check: sameOpts(&defaultSnapshotterOpts{snapshotter: "overlayfs"}), 46 }, 47 { 48 sns: []string{"overlayfs2"}, 49 check: sameOpts(&defaultSnapshotterOpts{snapshotter: "overlayfs2"}), 50 }, 51 { 52 sns: []string{"stargz", "stargz-v1"}, 53 check: remoteSnOpts("stargz", true), 54 }, 55 { 56 sns: []string{"soci"}, 57 check: remoteSnOpts("soci", true), 58 }, 59 { 60 sns: []string{"overlaybd", "overlaybd-v2"}, 61 check: sameOpts(&remoteSnapshotterOpts{snapshotter: "overlaybd"}), 62 }, 63 { 64 sns: []string{"nydus", "nydus-v3"}, 65 check: sameOpts(&remoteSnapshotterOpts{snapshotter: "nydus"}), 66 }, 67 } 68 for _, tc := range testCases { 69 for i := range tc.sns { 70 got := getSnapshotterOpts(tc.sns[i]) 71 tc.check(t, got) 72 } 73 } 74 } 75 76 func remoteSnOpts(name string, withExtra bool) func(*testing.T, snapshotterOpts) { 77 return func(t *testing.T, got snapshotterOpts) { 78 opts, ok := got.(*remoteSnapshotterOpts) 79 assert.Equal(t, ok, true) 80 assert.Equal(t, opts.snapshotter, name) 81 assert.Equal(t, opts.extraLabels != nil, withExtra) 82 } 83 } 84 85 func sameOpts(want snapshotterOpts) func(*testing.T, snapshotterOpts) { 86 return func(t *testing.T, got snapshotterOpts) { 87 if !reflect.DeepEqual(got, want) { 88 t.Errorf("getSnapshotterOpts() got = %v, want %v", got, want) 89 } 90 } 91 } 92 93 func getAndApplyRemoteOpts(t *testing.T, sn string) *containerd.RemoteContext { 94 config := &pull.Config{} 95 snOpts := getSnapshotterOpts(sn) 96 rFlags := RemoteSnapshotterFlags{} 97 snOpts.apply(config, testRef, rFlags) 98 99 rc := &containerd.RemoteContext{} 100 for _, o := range config.RemoteOpts { 101 // here passing a nil client is safe 102 // because the remote opts will not use client 103 if err := o(nil, rc); err != nil { 104 t.Errorf("failed to apply remote opts: %s", err) 105 } 106 } 107 108 return rc 109 } 110 111 func TestDefaultSnapshotterOpts(t *testing.T) { 112 rc := getAndApplyRemoteOpts(t, "overlayfs") 113 assert.Equal(t, rc.Snapshotter, "overlayfs") 114 } 115 116 // dummyImageHandler will return a dummy layer 117 // see https://github.com/containerd/containerd/blob/77d53d2d230c3bcd3f02e6f493019a72905c875b/images/mediatypes.go#L115 118 type dummyImageHandler struct{} 119 120 func (dih *dummyImageHandler) Handle(_ctx context.Context, _desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) { 121 return []ocispec.Descriptor{ 122 { 123 MediaType: "application/vnd.oci.image.layer.dummy", 124 Digest: digest.FromString("dummy"), 125 }, 126 }, nil 127 } 128 129 func TestRemoteSnapshotterOpts(t *testing.T) { 130 tests := []struct { 131 name string 132 check []func(t *testing.T, a map[string]string) 133 }{ 134 { 135 name: "stargz", 136 check: []func(t *testing.T, a map[string]string){ 137 checkRemoteSnapshotterAnnotataions, checkStargzSnapshotterAnnotataions, 138 }, 139 }, 140 { 141 name: "soci", 142 check: []func(t *testing.T, a map[string]string){ 143 checkRemoteSnapshotterAnnotataions, checkSociSnapshotterAnnotataions, 144 }, 145 }, 146 { 147 name: "nydus", 148 check: []func(t *testing.T, a map[string]string){checkRemoteSnapshotterAnnotataions}, 149 }, 150 { 151 name: "overlaybd", 152 check: []func(t *testing.T, a map[string]string){checkRemoteSnapshotterAnnotataions}, 153 }, 154 } 155 156 for _, tt := range tests { 157 tt := tt 158 sn := tt.name 159 t.Run(sn, func(t *testing.T) { 160 rc := getAndApplyRemoteOpts(t, sn) 161 assert.Equal(t, rc.Snapshotter, sn) 162 163 desc := ocispec.Descriptor{ 164 MediaType: ocispec.MediaTypeImageManifest, 165 } 166 167 h := &dummyImageHandler{} 168 got, err := rc.HandlerWrapper(h).Handle(context.Background(), desc) 169 170 assert.NilError(t, err) 171 assert.Check(t, len(got) == 1) 172 for _, f := range tt.check { 173 f(t, got[0].Annotations) 174 } 175 }) 176 } 177 } 178 179 func checkRemoteSnapshotterAnnotataions(t *testing.T, a map[string]string) { 180 assert.Check(t, a != nil) 181 assert.Equal(t, a[ctdsnapshotters.TargetRefLabel], testRef) 182 } 183 184 func checkStargzSnapshotterAnnotataions(t *testing.T, a map[string]string) { 185 assert.Check(t, a != nil) 186 _, ok := a["containerd.io/snapshot/remote/urls"] 187 assert.Equal(t, ok, true) 188 } 189 190 // using values from soci source to check for annotations ( 191 // see https://github.com/awslabs/soci-snapshotter/blob/b05ba712d246ecc5146469f87e5e9305702fd72b/fs/source/source.go#L80C1-L80C6 192 func checkSociSnapshotterAnnotataions(t *testing.T, a map[string]string) { 193 assert.Check(t, a != nil) 194 _, ok := a["containerd.io/snapshot/remote/soci.size"] 195 assert.Equal(t, ok, true) 196 _, ok = a["containerd.io/snapshot/remote/image.layers.size"] 197 assert.Equal(t, ok, true) 198 _, ok = a["containerd.io/snapshot/remote/soci.index.digest"] 199 assert.Equal(t, ok, true) 200 201 }