File: storage_transport_test.go

package info (click to toggle)
golang-github-containers-image 5.28.0-4
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 5,104 kB
  • sloc: sh: 194; makefile: 73
file content (187 lines) | stat: -rw-r--r-- 11,095 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
//go:build !containers_image_storage_stub
// +build !containers_image_storage_stub

package storage

import (
	"fmt"
	"testing"

	"github.com/containers/image/v5/docker/reference"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

const (
	sha256digestHex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
	sha256Digest2   = "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
)

func TestTransportName(t *testing.T) {
	assert.Equal(t, "containers-storage", Transport.Name())
}

func TestTransportSetGetStore(t *testing.T) {
	Transport.SetStore(nil)
	res := Transport.GetStoreIfSet()
	assert.Nil(t, res)
	store := newStore(t) // Calls SetStore
	res = Transport.GetStoreIfSet()
	assert.Equal(t, store, res)
	Transport.SetStore(nil)
}

func TestTransportParseStoreReference(t *testing.T) {
	const digest3 = "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"

	store := newStore(t)

	Transport.SetStore(nil)
	for _, c := range []struct{ input, expectedRef, expectedID string }{
		{"", "", ""}, // Empty input
		// Handling of the store prefix
		// FIXME? Should we be silently discarding input like this?
		{"[unterminated", "", ""},                                    // Unterminated store specifier
		{"[garbage]busybox", "docker.io/library/busybox:latest", ""}, // Store specifier is overridden by the store we pass to ParseStoreReference

		{"UPPERCASEISINVALID", "", ""}, // Invalid single-component name
		{"sha256:" + sha256digestHex, "docker.io/library/sha256:" + sha256digestHex, ""}, // Valid single-component name; the hex part is not an ID unless it has a "@" prefix, so it looks like a tag
		// FIXME: This test is now incorrect, this should not fail _if the image ID matches_
		{sha256digestHex, "", ""},                    // Invalid single-component ID; not an ID without a "@" prefix, so it's parsed as a name, but names aren't allowed to look like IDs
		{"@" + sha256digestHex, "", sha256digestHex}, // Valid single-component ID
		{"@sha256:" + sha256digestHex, "", ""},       // Invalid un-named @digest
		// "aaaa", either a valid image ID prefix, or a short form of docker.io/library/aaaa, untested
		{"sha256:ab", "docker.io/library/sha256:ab", ""},                                   // Valid single-component name, explicit tag
		{"busybox", "docker.io/library/busybox:latest", ""},                                // Valid single-component name, implicit tag
		{"busybox:notlatest", "docker.io/library/busybox:notlatest", ""},                   // Valid single-component name, explicit tag
		{"docker.io/library/busybox:notlatest", "docker.io/library/busybox:notlatest", ""}, // Valid single-component name, everything explicit

		{"UPPERCASEISINVALID@" + sha256digestHex, "", ""}, // Invalid name in name@digestOrID
		{"busybox@ab", "", ""},                            // Invalid ID in name@digestOrID
		{"busybox@", "", ""},                              // Empty ID in name@digestOrID
		{"busybox@sha256:ab", "", ""},                     // Invalid digest in name@digestOrID
		{"busybox@sha256:" + sha256digestHex, "docker.io/library/busybox@sha256:" + sha256digestHex, ""}, // Valid name@digest, no tag
		{"busybox@" + sha256digestHex, "docker.io/library/busybox:latest", sha256digestHex},              // Valid name@ID, implicit tag
		// "busybox@aaaa", a valid image ID prefix, untested
		{"busybox:notlatest@" + sha256digestHex, "docker.io/library/busybox:notlatest", sha256digestHex},                     // Valid name@ID, explicit tag
		{"docker.io/library/busybox:notlatest@" + sha256digestHex, "docker.io/library/busybox:notlatest", sha256digestHex},   // Valid name@ID, everything explicit
		{"docker.io/library/busybox:notlatest@" + sha256Digest2, "docker.io/library/busybox:notlatest@" + sha256Digest2, ""}, // Valid name:tag@digest, everything explicit

		{"busybox@sha256:" + sha256digestHex + "@ab", "", ""}, // Invalid ID in name@digest@ID
		{"busybox@ab@" + sha256digestHex, "", ""},             // Invalid digest in name@digest@ID
		{"busybox@@" + sha256digestHex, "", ""},               // Invalid digest in name@digest@ID
		{"busybox@" + sha256Digest2 + "@" + sha256digestHex, "docker.io/library/busybox@" + sha256Digest2, sha256digestHex},                                                         // name@digest@ID
		{"docker.io/library/busybox@" + sha256Digest2 + "@" + sha256digestHex, "docker.io/library/busybox@" + sha256Digest2, sha256digestHex},                                       // name@digest@ID, everything explicit
		{"docker.io/library/busybox:notlatest@sha256:" + sha256digestHex + "@" + sha256digestHex, "docker.io/library/busybox:notlatest@sha256:" + sha256digestHex, sha256digestHex}, // name:tag@digest@ID, everything explicit
		// "busybox@sha256:"+sha256digestHex+"@aaaa", a valid image ID prefix, untested
		{"busybox:notlatest@" + sha256Digest2 + "@" + digest3 + "@" + sha256digestHex, "", ""}, // name@digest@ID, with name containing another digest
	} {
		storageRef, err := Transport.ParseStoreReference(store, c.input)
		if c.expectedRef == "" && c.expectedID == "" {
			assert.Error(t, err, c.input)
		} else {
			require.NoError(t, err, c.input)
			assert.Equal(t, store, storageRef.transport.store, c.input)
			if c.expectedRef == "" {
				assert.Nil(t, storageRef.named, c.input)
			} else {
				dockerRef, err := reference.ParseNormalizedNamed(c.expectedRef)
				require.NoError(t, err)
				require.NotNil(t, storageRef.named, c.input)
				assert.Equal(t, dockerRef.String(), storageRef.named.String())
			}
			assert.Equal(t, c.expectedID, storageRef.id, c.input)
		}
	}
}

func TestTransportParseReference(t *testing.T) {
	store := newStore(t)
	driver := store.GraphDriverName()
	root := store.GraphRoot()

	for _, c := range []struct{ prefix, expectedDriver, expectedRoot, expectedRunRoot string }{
		{"", driver, root, ""},                                             // Implicit store location prefix
		{"[unterminated", "", "", ""},                                      // Unterminated store specifier
		{"[]", "", "", ""},                                                 // Empty store specifier
		{"[relative/path]", "", "", ""},                                    // Non-absolute graph root path
		{"[" + driver + "@relative/path]", "", "", ""},                     // Non-absolute graph root path
		{"[@" + root + "suffix2]", "", "", ""},                             // Empty graph driver
		{"[" + driver + "@]", "", "", ""},                                  // Empty root path
		{"[thisisunknown@" + root + "suffix2]", "", "", ""},                // Unknown graph driver
		{"[" + root + "suffix1]", "", "", ""},                              // A valid root path, but no run dir
		{"[" + driver + "@" + root + "suffix3+relative/path]", "", "", ""}, // Non-absolute run dir
		{"[" + driver + "@" + root + "suffix3+" + root + "suffix4]",
			driver,
			root + "suffix3",
			root + "suffix4"}, // A valid root@graph+run set
		{"[" + driver + "@" + root + "suffix3+" + root + "suffix4:options,options,options]",
			driver,
			root + "suffix3",
			root + "suffix4"}, // A valid root@graph+run+options set
	} {
		t.Logf("parsing %q", c.prefix+"busybox")
		ref, err := Transport.ParseReference(c.prefix + "busybox")
		if c.expectedDriver == "" {
			assert.Error(t, err, c.prefix)
		} else {
			require.NoError(t, err, c.prefix)
			storageRef, ok := ref.(*storageReference)
			require.True(t, ok, c.prefix)
			assert.Equal(t, c.expectedDriver, storageRef.transport.store.GraphDriverName(), c.prefix)
			assert.Equal(t, c.expectedRoot, storageRef.transport.store.GraphRoot(), c.prefix)
			if c.expectedRunRoot != "" {
				assert.Equal(t, c.expectedRunRoot, storageRef.transport.store.RunRoot(), c.prefix)
			}
		}
	}
}

func TestTransportValidatePolicyConfigurationScope(t *testing.T) {
	store := newStore(t)
	driver := store.GraphDriverName()
	root := store.GraphRoot()
	storeSpec := fmt.Sprintf("[%s@%s]", driver, root) // As computed in PolicyConfigurationNamespaces

	// Valid inputs
	for _, scope := range []string{
		"[" + root + "suffix1]",                                                                    // driverlessStoreSpec in PolicyConfigurationNamespaces
		"[" + driver + "@" + root + "suffix3]",                                                     // storeSpec in PolicyConfigurationNamespaces
		storeSpec + "@" + sha256digestHex,                                                          // ID only
		storeSpec + "docker.io",                                                                    // Host name only
		storeSpec + "docker.io/library",                                                            // A repository namespace
		storeSpec + "docker.io/library/busybox",                                                    // A repository name
		storeSpec + "docker.io/library/busybox:notlatest",                                          // name:tag
		storeSpec + "docker.io/library/busybox:notlatest@" + sha256digestHex,                       // name@ID
		storeSpec + "docker.io/library/busybox@" + sha256Digest2,                                   // name@digest
		storeSpec + "docker.io/library/busybox@" + sha256Digest2 + "@" + sha256digestHex,           // name@digest@ID
		storeSpec + "docker.io/library/busybox:notlatest@" + sha256Digest2,                         // name:tag@digest
		storeSpec + "docker.io/library/busybox:notlatest@" + sha256Digest2 + "@" + sha256digestHex, // name:tag@digest@ID
	} {
		err := Transport.ValidatePolicyConfigurationScope(scope)
		assert.NoError(t, err, scope)
	}

	// Invalid inputs
	for _, scope := range []string{
		"busybox",                        // Unprefixed reference
		"[unterminated",                  // Unterminated store specifier
		"[]",                             // Empty store specifier
		"[relative/path]",                // Non-absolute graph root path
		"[" + driver + "@relative/path]", // Non-absolute graph root path
		// "[thisisunknown@" + root + "suffix2]", // Unknown graph driver FIXME: validate against storage.ListGraphDrivers() once that's available
		storeSpec + "@", // An incomplete two-component name

		storeSpec + "docker.io/library/busybox@sha256:ab",                    // Invalid digest in name@digest
		storeSpec + "docker.io/library/busybox@ab",                           // Invalid ID in name@ID
		storeSpec + "docker.io/library/busybox@",                             // Empty ID/digest in name@ID
		storeSpec + "docker.io/library/busybox@@" + sha256digestHex,          // Empty digest in name@digest@ID
		storeSpec + "docker.io/library/busybox@ab@" + sha256digestHex,        // Invalid digest in name@digest@ID
		storeSpec + "docker.io/library/busybox@sha256:ab@" + sha256digestHex, // Invalid digest in name@digest@ID
		storeSpec + "docker.io/library/busybox@" + sha256Digest2 + "@",       // Empty ID in name@digest@ID
		storeSpec + "docker.io/library/busybox@" + sha256Digest2 + "@ab",     // Invalid ID in name@digest@ID
	} {
		err := Transport.ValidatePolicyConfigurationScope(scope)
		assert.Error(t, err, scope)
	}
}