Skip to content

Commit 548957f

Browse files
committed
manifest: Add unit tests for manifest inspect command
Add tests for tag/digest references and verbose modes Signed-off-by: ChengyuZhu6 <[email protected]>
1 parent 03af893 commit 548957f

File tree

4 files changed

+212
-10
lines changed

4 files changed

+212
-10
lines changed
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
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 manifest
18+
19+
import (
20+
"encoding/json"
21+
"testing"
22+
23+
"gotest.tools/v3/assert"
24+
25+
"github.com/containerd/nerdctl/mod/tigron/test"
26+
"github.com/containerd/nerdctl/mod/tigron/tig"
27+
28+
"github.com/containerd/nerdctl/v2/pkg/testutil"
29+
"github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest"
30+
)
31+
32+
var (
33+
alpineDigest = testutil.GetTestImageDigest("alpine")
34+
alpineAmd64ConfigDigest = testutil.GetTestImageConfigDigest("alpine", "linux/amd64")
35+
alpineAmd64Digest = testutil.GetTestImageManifestDigest("alpine", "linux/amd64")
36+
)
37+
38+
func TestManifestInspect(t *testing.T) {
39+
testCase := nerdtest.Setup()
40+
testCase.Setup = func(data test.Data, helpers test.Helpers) {
41+
helpers.Ensure("pull", "--quiet", "--platform=linux/amd64,linux/arm64", testutil.AlpineImage)
42+
}
43+
testCase.Cleanup = func(data test.Data, helpers test.Helpers) {
44+
helpers.Anyhow("rmi", "-f", testutil.AlpineImage)
45+
}
46+
testCase.SubTests = []*test.Case{
47+
{
48+
Description: "tag-non-verbose",
49+
Command: test.Command("manifest", "inspect", testutil.AlpineImage),
50+
Expected: test.Expects(0, nil, func(stdout string, t tig.T) {
51+
var arr []map[string]interface{}
52+
assert.NilError(t, json.Unmarshal([]byte(stdout), &arr))
53+
assert.Assert(t, len(arr) > 0)
54+
index, ok := arr[0]["Index"].(map[string]interface{})
55+
assert.Assert(t, ok)
56+
manifests, ok := index["manifests"].([]interface{})
57+
assert.Assert(t, ok)
58+
assert.Assert(t, len(manifests) > 0)
59+
}),
60+
},
61+
{
62+
Description: "tag-verbose",
63+
Command: test.Command("manifest", "inspect", testutil.AlpineImage, "--verbose"),
64+
Expected: test.Expects(0, nil, func(stdout string, t tig.T) {
65+
var arr []map[string]interface{}
66+
assert.NilError(t, json.Unmarshal([]byte(stdout), &arr))
67+
assert.Assert(t, len(arr) > 0)
68+
indexDesc := arr[0]["IndexDesc"].(map[string]interface{})
69+
assert.Equal(t, indexDesc["mediaType"], "application/vnd.docker.distribution.manifest.list.v2+json")
70+
assert.Equal(t, indexDesc["digest"], alpineDigest)
71+
manifests, ok := arr[0]["Manifests"].([]interface{})
72+
assert.Assert(t, ok, "should have Manifests field")
73+
assert.Assert(t, len(manifests) > 0)
74+
manifestObj, ok := manifests[0].(map[string]interface{})
75+
assert.Assert(t, ok, "Manifests[0] should be object")
76+
manifestArr := []map[string]interface{}{manifestObj}
77+
assertManifestConfigDigest(t, manifestArr, alpineAmd64ConfigDigest)
78+
assertManifestDescDigest(t, manifestArr, alpineAmd64Digest)
79+
}),
80+
},
81+
{
82+
Description: "digest-non-verbose",
83+
Command: test.Command("manifest", "inspect", "alpine@"+alpineAmd64Digest),
84+
Expected: test.Expects(0, nil, func(stdout string, t tig.T) {
85+
var arr []map[string]interface{}
86+
assert.NilError(t, json.Unmarshal([]byte(stdout), &arr))
87+
assert.Assert(t, len(arr) > 0)
88+
assertManifestConfigDigest(t, arr, alpineAmd64ConfigDigest)
89+
}),
90+
},
91+
{
92+
Description: "digest-verbose",
93+
Command: test.Command("manifest", "inspect", "alpine@"+alpineAmd64Digest, "--verbose"),
94+
Expected: test.Expects(0, nil, func(stdout string, t tig.T) {
95+
var arr []map[string]interface{}
96+
assert.NilError(t, json.Unmarshal([]byte(stdout), &arr))
97+
assert.Assert(t, len(arr) > 0)
98+
assertManifestConfigDigest(t, arr, alpineAmd64ConfigDigest)
99+
assertManifestDescDigest(t, arr, alpineAmd64Digest)
100+
}),
101+
},
102+
{
103+
Description: "sha256-digest-non-verbose",
104+
Command: test.Command("manifest", "inspect", alpineAmd64Digest),
105+
Expected: test.Expects(0, nil, func(stdout string, t tig.T) {
106+
var arr []map[string]interface{}
107+
assert.NilError(t, json.Unmarshal([]byte(stdout), &arr))
108+
assert.Assert(t, len(arr) > 0)
109+
assertManifestConfigDigest(t, arr, alpineAmd64ConfigDigest)
110+
}),
111+
},
112+
{
113+
Description: "sha256-digest-verbose",
114+
Command: test.Command("manifest", "inspect", alpineAmd64Digest, "--verbose"),
115+
Expected: test.Expects(0, nil, func(stdout string, t tig.T) {
116+
var arr []map[string]interface{}
117+
assert.NilError(t, json.Unmarshal([]byte(stdout), &arr))
118+
assert.Assert(t, len(arr) > 0)
119+
assertManifestConfigDigest(t, arr, alpineAmd64ConfigDigest)
120+
assertManifestDescDigest(t, arr, alpineAmd64Digest)
121+
}),
122+
},
123+
}
124+
125+
testCase.Run(t)
126+
}
127+
128+
func assertManifestConfigDigest(t tig.T, arr []map[string]interface{}, wantDigest string) {
129+
manifest, ok := arr[0]["Manifest"].(map[string]interface{})
130+
assert.Assert(t, ok)
131+
config, ok := manifest["config"].(map[string]interface{})
132+
assert.Assert(t, ok, "should have config field")
133+
assert.Equal(t, config["digest"], wantDigest)
134+
}
135+
136+
func assertManifestDescDigest(t tig.T, arr []map[string]interface{}, wantDigest string) {
137+
manifestDesc, ok := arr[0]["ManifestDesc"].(map[string]interface{})
138+
assert.Assert(t, ok, "should have ManifestDesc field")
139+
assert.Equal(t, manifestDesc["digest"], wantDigest)
140+
}

cmd/nerdctl/manifest/manifest_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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 manifest
18+
19+
import (
20+
"testing"
21+
22+
"github.com/containerd/nerdctl/v2/pkg/testutil"
23+
)
24+
25+
func TestMain(m *testing.M) {
26+
testutil.M(m)
27+
}

pkg/testutil/images.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ alpine:
77
tag: "3.13-org"
88
digest: "sha256:ec14c7992a97fc11425907e908340c6c3d6ff602f5f13d899e6b7027c9b4133a"
99
variants: ["linux/amd64", "linux/arm64"]
10+
platformDigests:
11+
linux/amd64:
12+
configDigest: "sha256:49f356fa4513676c5e22e3a8404aad6c7262cc7aaed15341458265320786c58c"
13+
manifestDigest: "sha256:e103c1b4bf019dc290bcc7aca538dc2bf7a9d0fc836e186f5fa34945c5168310"
1014

1115
busybox:
1216
ref: "ghcr.io/containerd/busybox"

pkg/testutil/images_linux.go

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,30 +29,61 @@ var rawImagesList string
2929

3030
var testImagesOnce sync.Once
3131

32+
type PlatformDigest struct {
33+
Config string `yaml:"config,omitempty"`
34+
Manifest string `yaml:"manifest,omitempty"`
35+
}
36+
3237
type TestImage struct {
33-
Ref string `yaml:"ref"`
34-
Tag string `yaml:"tag,omitempty"`
35-
Digest string `yaml:"digest,omitempty"`
36-
Variants []string `yaml:"variants,omitempty"`
38+
Ref string `yaml:"ref"`
39+
Tag string `yaml:"tag,omitempty"`
40+
Digest string `yaml:"digest,omitempty"`
41+
Variants []string `yaml:"variants,omitempty"`
42+
PlatformDigests map[string]PlatformDigest `yaml:"platformDigests,omitempty"`
3743
}
3844

3945
var testImages map[string]TestImage
4046

41-
func getImage(key string) string {
47+
// internal helper to lookup TestImage by key, panics if not found
48+
func lookup(key string) TestImage {
4249
testImagesOnce.Do(func() {
4350
if err := yaml.Unmarshal([]byte(rawImagesList), &testImages); err != nil {
4451
fmt.Printf("Error unmarshaling test images YAML file: %v\n", err)
4552
panic("testing is broken")
4653
}
4754
})
48-
49-
var im TestImage
50-
var ok bool
51-
52-
if im, ok = testImages[key]; !ok {
55+
im, ok := testImages[key]
56+
if !ok {
5357
fmt.Printf("Image %s was not found in images list\n", key)
5458
panic("testing is broken")
5559
}
60+
return im
61+
}
5662

63+
func getImage(key string) string {
64+
im := lookup(key)
5765
return im.Ref + ":" + im.Tag
5866
}
67+
68+
func GetTestImageConfigDigest(key, platform string) string {
69+
im := lookup(key)
70+
pd, ok := im.PlatformDigests[platform]
71+
if !ok {
72+
panic(fmt.Sprintf("platform %s not found for image %s", platform, key))
73+
}
74+
return pd.Config
75+
}
76+
77+
func GetTestImageManifestDigest(key, platform string) string {
78+
im := lookup(key)
79+
pd, ok := im.PlatformDigests[platform]
80+
if !ok {
81+
panic(fmt.Sprintf("platform %s not found for image %s", platform, key))
82+
}
83+
return pd.Manifest
84+
}
85+
86+
func GetTestImageDigest(key string) string {
87+
im := lookup(key)
88+
return im.Digest
89+
}

0 commit comments

Comments
 (0)