vendor: remove dep and use vndr
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
parent
16f44674a4
commit
148e72d81e
16131 changed files with 73815 additions and 4235138 deletions
BIN
vendor/github.com/containers/image/docker/archive/fixtures/almostempty.tar
generated
vendored
BIN
vendor/github.com/containers/image/docker/archive/fixtures/almostempty.tar
generated
vendored
Binary file not shown.
198
vendor/github.com/containers/image/docker/archive/transport_test.go
generated
vendored
198
vendor/github.com/containers/image/docker/archive/transport_test.go
generated
vendored
|
@ -1,198 +0,0 @@
|
|||
package archive
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/containers/image/docker/reference"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
sha256digestHex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
sha256digest = "@sha256:" + sha256digestHex
|
||||
tarFixture = "fixtures/almostempty.tar"
|
||||
)
|
||||
|
||||
func TestTransportName(t *testing.T) {
|
||||
assert.Equal(t, "docker-archive", Transport.Name())
|
||||
}
|
||||
|
||||
func TestTransportParseReference(t *testing.T) {
|
||||
testParseReference(t, Transport.ParseReference)
|
||||
}
|
||||
|
||||
func TestTransportValidatePolicyConfigurationScope(t *testing.T) {
|
||||
for _, scope := range []string{ // A semi-representative assortment of values; everything is rejected.
|
||||
"docker.io/library/busybox:notlatest",
|
||||
"docker.io/library/busybox",
|
||||
"docker.io/library",
|
||||
"docker.io",
|
||||
"",
|
||||
} {
|
||||
err := Transport.ValidatePolicyConfigurationScope(scope)
|
||||
assert.Error(t, err, scope)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseReference(t *testing.T) {
|
||||
testParseReference(t, ParseReference)
|
||||
}
|
||||
|
||||
// testParseReference is a test shared for Transport.ParseReference and ParseReference.
|
||||
func testParseReference(t *testing.T, fn func(string) (types.ImageReference, error)) {
|
||||
for _, c := range []struct{ input, expectedPath, expectedRef string }{
|
||||
{"", "", ""}, // Empty input is explicitly rejected
|
||||
{"/path", "/path", ""},
|
||||
{"/path:busybox:notlatest", "/path", "docker.io/library/busybox:notlatest"}, // Explicit tag
|
||||
{"/path:busybox" + sha256digest, "", ""}, // Digest references are forbidden
|
||||
{"/path:busybox", "/path", "docker.io/library/busybox:latest"}, // Default tag
|
||||
// A github.com/distribution/reference value can have a tag and a digest at the same time!
|
||||
{"/path:busybox:latest" + sha256digest, "", ""}, // Both tag and digest is rejected
|
||||
{"/path:docker.io/library/busybox:latest", "/path", "docker.io/library/busybox:latest"}, // All implied values explicitly specified
|
||||
{"/path:UPPERCASEISINVALID", "", ""}, // Invalid input
|
||||
} {
|
||||
ref, err := fn(c.input)
|
||||
if c.expectedPath == "" {
|
||||
assert.Error(t, err, c.input)
|
||||
} else {
|
||||
require.NoError(t, err, c.input)
|
||||
archiveRef, ok := ref.(archiveReference)
|
||||
require.True(t, ok, c.input)
|
||||
assert.Equal(t, c.expectedPath, archiveRef.path, c.input)
|
||||
if c.expectedRef == "" {
|
||||
assert.Nil(t, archiveRef.destinationRef, c.input)
|
||||
} else {
|
||||
require.NotNil(t, archiveRef.destinationRef, c.input)
|
||||
assert.Equal(t, c.expectedRef, archiveRef.destinationRef.String(), c.input)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// refWithTagAndDigest is a reference.NamedTagged and reference.Canonical at the same time.
|
||||
type refWithTagAndDigest struct{ reference.Canonical }
|
||||
|
||||
func (ref refWithTagAndDigest) Tag() string {
|
||||
return "notLatest"
|
||||
}
|
||||
|
||||
// A common list of reference formats to test for the various ImageReference methods.
|
||||
var validReferenceTestCases = []struct{ input, dockerRef, stringWithinTransport string }{
|
||||
{"/pathonly", "", "/pathonly"},
|
||||
{"/path:busybox:notlatest", "docker.io/library/busybox:notlatest", "/path:docker.io/library/busybox:notlatest"}, // Explicit tag
|
||||
{"/path:docker.io/library/busybox:latest", "docker.io/library/busybox:latest", "/path:docker.io/library/busybox:latest"}, // All implied values explicitly specified
|
||||
{"/path:example.com/ns/foo:bar", "example.com/ns/foo:bar", "/path:example.com/ns/foo:bar"}, // All values explicitly specified
|
||||
}
|
||||
|
||||
func TestReferenceTransport(t *testing.T) {
|
||||
ref, err := ParseReference("/tmp/archive.tar")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, Transport, ref.Transport())
|
||||
}
|
||||
|
||||
func TestReferenceStringWithinTransport(t *testing.T) {
|
||||
for _, c := range validReferenceTestCases {
|
||||
ref, err := ParseReference(c.input)
|
||||
require.NoError(t, err, c.input)
|
||||
stringRef := ref.StringWithinTransport()
|
||||
assert.Equal(t, c.stringWithinTransport, stringRef, c.input)
|
||||
// Do one more round to verify that the output can be parsed, to an equal value.
|
||||
ref2, err := Transport.ParseReference(stringRef)
|
||||
require.NoError(t, err, c.input)
|
||||
stringRef2 := ref2.StringWithinTransport()
|
||||
assert.Equal(t, stringRef, stringRef2, c.input)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReferenceDockerReference(t *testing.T) {
|
||||
for _, c := range validReferenceTestCases {
|
||||
ref, err := ParseReference(c.input)
|
||||
require.NoError(t, err, c.input)
|
||||
dockerRef := ref.DockerReference()
|
||||
if c.dockerRef != "" {
|
||||
require.NotNil(t, dockerRef, c.input)
|
||||
assert.Equal(t, c.dockerRef, dockerRef.String(), c.input)
|
||||
} else {
|
||||
require.Nil(t, dockerRef, c.input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReferencePolicyConfigurationIdentity(t *testing.T) {
|
||||
for _, c := range validReferenceTestCases {
|
||||
ref, err := ParseReference(c.input)
|
||||
require.NoError(t, err, c.input)
|
||||
assert.Equal(t, "", ref.PolicyConfigurationIdentity(), c.input)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReferencePolicyConfigurationNamespaces(t *testing.T) {
|
||||
for _, c := range validReferenceTestCases {
|
||||
ref, err := ParseReference(c.input)
|
||||
require.NoError(t, err, c.input)
|
||||
assert.Empty(t, "", ref.PolicyConfigurationNamespaces(), c.input)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReferenceNewImage(t *testing.T) {
|
||||
for _, suffix := range []string{"", ":thisisignoredbutaccepted"} {
|
||||
ref, err := ParseReference(tarFixture + suffix)
|
||||
require.NoError(t, err, suffix)
|
||||
img, err := ref.NewImage(nil)
|
||||
assert.NoError(t, err, suffix)
|
||||
defer img.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestReferenceNewImageSource(t *testing.T) {
|
||||
for _, suffix := range []string{"", ":thisisignoredbutaccepted"} {
|
||||
ref, err := ParseReference(tarFixture + suffix)
|
||||
require.NoError(t, err, suffix)
|
||||
src, err := ref.NewImageSource(nil, nil)
|
||||
assert.NoError(t, err, suffix)
|
||||
defer src.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestReferenceNewImageDestination(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir("", "docker-archive-test")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
ref, err := ParseReference(filepath.Join(tmpDir, "no-reference"))
|
||||
require.NoError(t, err)
|
||||
dest, err := ref.NewImageDestination(nil)
|
||||
assert.Error(t, err)
|
||||
|
||||
ref, err = ParseReference(filepath.Join(tmpDir, "with-reference") + "busybox:latest")
|
||||
require.NoError(t, err)
|
||||
dest, err = ref.NewImageDestination(nil)
|
||||
assert.NoError(t, err)
|
||||
defer dest.Close()
|
||||
}
|
||||
|
||||
func TestReferenceDeleteImage(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir("", "docker-archive-test")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
for i, suffix := range []string{"", ":thisisignoredbutaccepted"} {
|
||||
testFile := filepath.Join(tmpDir, fmt.Sprintf("file%d.tar", i))
|
||||
err := ioutil.WriteFile(testFile, []byte("nonempty"), 0644)
|
||||
require.NoError(t, err, suffix)
|
||||
|
||||
ref, err := ParseReference(testFile + suffix)
|
||||
require.NoError(t, err, suffix)
|
||||
err = ref.DeleteImage(nil)
|
||||
assert.Error(t, err, suffix)
|
||||
|
||||
_, err = os.Lstat(testFile)
|
||||
assert.NoError(t, err, suffix)
|
||||
}
|
||||
}
|
228
vendor/github.com/containers/image/docker/daemon/daemon_transport_test.go
generated
vendored
228
vendor/github.com/containers/image/docker/daemon/daemon_transport_test.go
generated
vendored
|
@ -1,228 +0,0 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/containers/image/docker/reference"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
sha256digestHex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
sha256digest = "sha256:" + sha256digestHex
|
||||
)
|
||||
|
||||
func TestTransportName(t *testing.T) {
|
||||
assert.Equal(t, "docker-daemon", Transport.Name())
|
||||
}
|
||||
|
||||
func TestTransportParseReference(t *testing.T) {
|
||||
testParseReference(t, Transport.ParseReference)
|
||||
}
|
||||
|
||||
func TestTransportValidatePolicyConfigurationScope(t *testing.T) {
|
||||
for _, scope := range []string{ // A semi-representative assortment of values; everything is rejected.
|
||||
sha256digestHex,
|
||||
sha256digest,
|
||||
"docker.io/library/busybox:latest",
|
||||
"docker.io",
|
||||
"",
|
||||
} {
|
||||
err := Transport.ValidatePolicyConfigurationScope(scope)
|
||||
assert.Error(t, err, scope)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseReference(t *testing.T) {
|
||||
testParseReference(t, ParseReference)
|
||||
}
|
||||
|
||||
// testParseReference is a test shared for Transport.ParseReference and ParseReference.
|
||||
func testParseReference(t *testing.T, fn func(string) (types.ImageReference, error)) {
|
||||
for _, c := range []struct{ input, expectedID, expectedRef string }{
|
||||
{sha256digest, sha256digest, ""}, // Valid digest format
|
||||
{"sha512:" + sha256digestHex + sha256digestHex, "", ""}, // Non-digest.Canonical digest
|
||||
{"sha256:ab", "", ""}, // Invalid digest value (too short)
|
||||
{sha256digest + "ab", "", ""}, // Invalid digest value (too long)
|
||||
{"sha256:XX23456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "", ""}, // Invalid digest value
|
||||
{"UPPERCASEISINVALID", "", ""}, // Invalid reference input
|
||||
{"busybox", "", ""}, // Missing tag or digest
|
||||
{"busybox:latest", "", "docker.io/library/busybox:latest"}, // Explicit tag
|
||||
{"busybox@" + sha256digest, "", "docker.io/library/busybox@" + sha256digest}, // Explicit digest
|
||||
// A github.com/distribution/reference value can have a tag and a digest at the same time!
|
||||
// Most versions of docker/reference do not handle that (ignoring the tag), so we reject such input.
|
||||
{"busybox:latest@" + sha256digest, "", ""}, // Both tag and digest
|
||||
{"docker.io/library/busybox:latest", "", "docker.io/library/busybox:latest"}, // All implied values explicitly specified
|
||||
} {
|
||||
ref, err := fn(c.input)
|
||||
if c.expectedID == "" && c.expectedRef == "" {
|
||||
assert.Error(t, err, c.input)
|
||||
} else {
|
||||
require.NoError(t, err, c.input)
|
||||
daemonRef, ok := ref.(daemonReference)
|
||||
require.True(t, ok, c.input)
|
||||
// If we don't reject the input, the interpretation must be consistent with reference.ParseAnyReference
|
||||
dockerRef, err := reference.ParseAnyReference(c.input)
|
||||
require.NoError(t, err, c.input)
|
||||
|
||||
if c.expectedRef == "" {
|
||||
assert.Equal(t, c.expectedID, daemonRef.id.String(), c.input)
|
||||
assert.Nil(t, daemonRef.ref, c.input)
|
||||
|
||||
_, ok := dockerRef.(reference.Digested)
|
||||
require.True(t, ok, c.input)
|
||||
assert.Equal(t, c.expectedID, dockerRef.String(), c.input)
|
||||
} else {
|
||||
assert.Equal(t, "", daemonRef.id.String(), c.input)
|
||||
require.NotNil(t, daemonRef.ref, c.input)
|
||||
assert.Equal(t, c.expectedRef, daemonRef.ref.String(), c.input)
|
||||
|
||||
_, ok := dockerRef.(reference.Named)
|
||||
require.True(t, ok, c.input)
|
||||
assert.Equal(t, c.expectedRef, dockerRef.String(), c.input)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A common list of reference formats to test for the various ImageReference methods.
|
||||
// (For IDs it is much simpler, we simply use them unmodified)
|
||||
var validNamedReferenceTestCases = []struct{ input, dockerRef, stringWithinTransport string }{
|
||||
{"busybox:notlatest", "docker.io/library/busybox:notlatest", "busybox:notlatest"}, // Explicit tag
|
||||
{"busybox" + sha256digest, "docker.io/library/busybox" + sha256digest, "busybox" + sha256digest}, // Explicit digest
|
||||
{"docker.io/library/busybox:latest", "docker.io/library/busybox:latest", "busybox:latest"}, // All implied values explicitly specified
|
||||
{"example.com/ns/foo:bar", "example.com/ns/foo:bar", "example.com/ns/foo:bar"}, // All values explicitly specified
|
||||
}
|
||||
|
||||
func TestNewReference(t *testing.T) {
|
||||
// An ID reference.
|
||||
id, err := digest.Parse(sha256digest)
|
||||
require.NoError(t, err)
|
||||
ref, err := NewReference(id, nil)
|
||||
require.NoError(t, err)
|
||||
daemonRef, ok := ref.(daemonReference)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, id, daemonRef.id)
|
||||
assert.Nil(t, daemonRef.ref)
|
||||
|
||||
// Named references
|
||||
for _, c := range validNamedReferenceTestCases {
|
||||
parsed, err := reference.ParseNormalizedNamed(c.input)
|
||||
require.NoError(t, err)
|
||||
ref, err := NewReference("", parsed)
|
||||
require.NoError(t, err, c.input)
|
||||
daemonRef, ok := ref.(daemonReference)
|
||||
require.True(t, ok, c.input)
|
||||
assert.Equal(t, "", daemonRef.id.String())
|
||||
require.NotNil(t, daemonRef.ref)
|
||||
assert.Equal(t, c.dockerRef, daemonRef.ref.String(), c.input)
|
||||
}
|
||||
|
||||
// Both an ID and a named reference provided
|
||||
parsed, err := reference.ParseNormalizedNamed("busybox:latest")
|
||||
require.NoError(t, err)
|
||||
_, err = NewReference(id, parsed)
|
||||
assert.Error(t, err)
|
||||
|
||||
// A reference with neither a tag nor digest
|
||||
parsed, err = reference.ParseNormalizedNamed("busybox")
|
||||
require.NoError(t, err)
|
||||
_, err = NewReference("", parsed)
|
||||
assert.Error(t, err)
|
||||
|
||||
// A github.com/distribution/reference value can have a tag and a digest at the same time!
|
||||
parsed, err = reference.ParseNormalizedNamed("busybox:notlatest@" + sha256digest)
|
||||
require.NoError(t, err)
|
||||
_, ok = parsed.(reference.Canonical)
|
||||
require.True(t, ok)
|
||||
_, ok = parsed.(reference.NamedTagged)
|
||||
require.True(t, ok)
|
||||
_, err = NewReference("", parsed)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestReferenceTransport(t *testing.T) {
|
||||
ref, err := ParseReference(sha256digest)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, Transport, ref.Transport())
|
||||
|
||||
ref, err = ParseReference("busybox:latest")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, Transport, ref.Transport())
|
||||
}
|
||||
|
||||
func TestReferenceStringWithinTransport(t *testing.T) {
|
||||
ref, err := ParseReference(sha256digest)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, sha256digest, ref.StringWithinTransport())
|
||||
|
||||
for _, c := range validNamedReferenceTestCases {
|
||||
ref, err := ParseReference(c.input)
|
||||
require.NoError(t, err, c.input)
|
||||
stringRef := ref.StringWithinTransport()
|
||||
assert.Equal(t, c.stringWithinTransport, stringRef, c.input)
|
||||
// Do one more round to verify that the output can be parsed, to an equal value.
|
||||
ref2, err := Transport.ParseReference(stringRef)
|
||||
require.NoError(t, err, c.input)
|
||||
stringRef2 := ref2.StringWithinTransport()
|
||||
assert.Equal(t, stringRef, stringRef2, c.input)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReferenceDockerReference(t *testing.T) {
|
||||
ref, err := ParseReference(sha256digest)
|
||||
require.NoError(t, err)
|
||||
assert.Nil(t, ref.DockerReference())
|
||||
|
||||
for _, c := range validNamedReferenceTestCases {
|
||||
ref, err := ParseReference(c.input)
|
||||
require.NoError(t, err, c.input)
|
||||
dockerRef := ref.DockerReference()
|
||||
require.NotNil(t, dockerRef, c.input)
|
||||
assert.Equal(t, c.dockerRef, dockerRef.String(), c.input)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReferencePolicyConfigurationIdentity(t *testing.T) {
|
||||
ref, err := ParseReference(sha256digest)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "", ref.PolicyConfigurationIdentity())
|
||||
|
||||
for _, c := range validNamedReferenceTestCases {
|
||||
ref, err := ParseReference(c.input)
|
||||
require.NoError(t, err, c.input)
|
||||
assert.Equal(t, "", ref.PolicyConfigurationIdentity(), c.input)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReferencePolicyConfigurationNamespaces(t *testing.T) {
|
||||
ref, err := ParseReference(sha256digest)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, ref.PolicyConfigurationNamespaces())
|
||||
|
||||
for _, c := range validNamedReferenceTestCases {
|
||||
ref, err := ParseReference(c.input)
|
||||
require.NoError(t, err, c.input)
|
||||
assert.Empty(t, ref.PolicyConfigurationNamespaces(), c.input)
|
||||
}
|
||||
}
|
||||
|
||||
// daemonReference.NewImage, daemonReference.NewImageSource, openshiftReference.NewImageDestination
|
||||
// untested because just creating the objects immediately connects to the daemon.
|
||||
|
||||
func TestReferenceDeleteImage(t *testing.T) {
|
||||
ref, err := ParseReference(sha256digest)
|
||||
require.NoError(t, err)
|
||||
err = ref.DeleteImage(nil)
|
||||
assert.Error(t, err)
|
||||
|
||||
for _, c := range validNamedReferenceTestCases {
|
||||
ref, err := ParseReference(c.input)
|
||||
require.NoError(t, err, c.input)
|
||||
err = ref.DeleteImage(nil)
|
||||
assert.Error(t, err, c.input)
|
||||
}
|
||||
}
|
55
vendor/github.com/containers/image/docker/docker_client.go
generated
vendored
55
vendor/github.com/containers/image/docker/docker_client.go
generated
vendored
|
@ -34,6 +34,8 @@ const (
|
|||
dockerCfgFileName = "config.json"
|
||||
dockerCfgObsolete = ".dockercfg"
|
||||
|
||||
systemPerHostCertDirPath = "/etc/docker/certs.d"
|
||||
|
||||
resolvedPingV2URL = "%s://%s/v2/"
|
||||
resolvedPingV1URL = "%s://%s/v1/_ping"
|
||||
tagsPath = "/v2/%s/tags/list"
|
||||
|
@ -129,12 +131,29 @@ func newTransport() *http.Transport {
|
|||
return tr
|
||||
}
|
||||
|
||||
func setupCertificates(dir string, tlsc *tls.Config) error {
|
||||
if dir == "" {
|
||||
return nil
|
||||
// dockerCertDir returns a path to a directory to be consumed by setupCertificates() depending on ctx and hostPort.
|
||||
func dockerCertDir(ctx *types.SystemContext, hostPort string) string {
|
||||
if ctx != nil && ctx.DockerCertPath != "" {
|
||||
return ctx.DockerCertPath
|
||||
}
|
||||
var hostCertDir string
|
||||
if ctx != nil && ctx.DockerPerHostCertDirPath != "" {
|
||||
hostCertDir = ctx.DockerPerHostCertDirPath
|
||||
} else if ctx != nil && ctx.RootForImplicitAbsolutePaths != "" {
|
||||
hostCertDir = filepath.Join(ctx.RootForImplicitAbsolutePaths, systemPerHostCertDirPath)
|
||||
} else {
|
||||
hostCertDir = systemPerHostCertDirPath
|
||||
}
|
||||
return filepath.Join(hostCertDir, hostPort)
|
||||
}
|
||||
|
||||
func setupCertificates(dir string, tlsc *tls.Config) error {
|
||||
logrus.Debugf("Looking for TLS certificates and private keys in %s", dir)
|
||||
fs, err := ioutil.ReadDir(dir)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -146,7 +165,7 @@ func setupCertificates(dir string, tlsc *tls.Config) error {
|
|||
return errors.Wrap(err, "unable to get system cert pool")
|
||||
}
|
||||
tlsc.RootCAs = systemPool
|
||||
logrus.Debugf("crt: %s", fullPath)
|
||||
logrus.Debugf(" crt: %s", fullPath)
|
||||
data, err := ioutil.ReadFile(fullPath)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -156,7 +175,7 @@ func setupCertificates(dir string, tlsc *tls.Config) error {
|
|||
if strings.HasSuffix(f.Name(), ".cert") {
|
||||
certName := f.Name()
|
||||
keyName := certName[:len(certName)-5] + ".key"
|
||||
logrus.Debugf("cert: %s", fullPath)
|
||||
logrus.Debugf(" cert: %s", fullPath)
|
||||
if !hasFile(fs, keyName) {
|
||||
return errors.Errorf("missing key %s for client certificate %s. Note that CA certificates should use the extension .crt", keyName, certName)
|
||||
}
|
||||
|
@ -169,7 +188,7 @@ func setupCertificates(dir string, tlsc *tls.Config) error {
|
|||
if strings.HasSuffix(f.Name(), ".key") {
|
||||
keyName := f.Name()
|
||||
certName := keyName[:len(keyName)-4] + ".cert"
|
||||
logrus.Debugf("key: %s", fullPath)
|
||||
logrus.Debugf(" key: %s", fullPath)
|
||||
if !hasFile(fs, certName) {
|
||||
return errors.Errorf("missing client certificate %s for key %s", certName, keyName)
|
||||
}
|
||||
|
@ -199,18 +218,18 @@ func newDockerClient(ctx *types.SystemContext, ref dockerReference, write bool,
|
|||
return nil, err
|
||||
}
|
||||
tr := newTransport()
|
||||
if ctx != nil && (ctx.DockerCertPath != "" || ctx.DockerInsecureSkipTLSVerify) {
|
||||
tlsc := &tls.Config{}
|
||||
|
||||
if err := setupCertificates(ctx.DockerCertPath, tlsc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tlsc.InsecureSkipVerify = ctx.DockerInsecureSkipTLSVerify
|
||||
tr.TLSClientConfig = tlsc
|
||||
tr.TLSClientConfig = serverDefault()
|
||||
// It is undefined whether the host[:port] string for dockerHostname should be dockerHostname or dockerRegistry,
|
||||
// because docker/docker does not read the certs.d subdirectory at all in that case. We use the user-visible
|
||||
// dockerHostname here, because it is more symmetrical to read the configuration in that case as well, and because
|
||||
// generally the UI hides the existence of the different dockerRegistry. But note that this behavior is
|
||||
// undocumented and may change if docker/docker changes.
|
||||
certDir := dockerCertDir(ctx, reference.Domain(ref.ref))
|
||||
if err := setupCertificates(certDir, tr.TLSClientConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tr.TLSClientConfig == nil {
|
||||
tr.TLSClientConfig = serverDefault()
|
||||
if ctx != nil && ctx.DockerInsecureSkipTLSVerify {
|
||||
tr.TLSClientConfig.InsecureSkipVerify = true
|
||||
}
|
||||
client := &http.Client{Transport: tr}
|
||||
|
||||
|
|
432
vendor/github.com/containers/image/docker/docker_client_test.go
generated
vendored
432
vendor/github.com/containers/image/docker/docker_client_test.go
generated
vendored
|
@ -1,432 +0,0 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
//"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/containers/image/types"
|
||||
"github.com/containers/storage/pkg/homedir"
|
||||
)
|
||||
|
||||
func TestGetAuth(t *testing.T) {
|
||||
origHomeDir := homedir.Get()
|
||||
tmpDir, err := ioutil.TempDir("", "test_docker_client_get_auth")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("using temporary home directory: %q", tmpDir)
|
||||
// override homedir
|
||||
os.Setenv(homedir.Key(), tmpDir)
|
||||
defer func() {
|
||||
err := os.RemoveAll(tmpDir)
|
||||
if err != nil {
|
||||
t.Logf("failed to cleanup temporary home directory %q: %v", tmpDir, err)
|
||||
}
|
||||
os.Setenv(homedir.Key(), origHomeDir)
|
||||
}()
|
||||
|
||||
configDir := filepath.Join(tmpDir, ".docker")
|
||||
if err := os.Mkdir(configDir, 0750); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
configPath := filepath.Join(configDir, "config.json")
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
hostname string
|
||||
authConfig testAuthConfig
|
||||
expectedUsername string
|
||||
expectedPassword string
|
||||
expectedError error
|
||||
ctx *types.SystemContext
|
||||
}{
|
||||
{
|
||||
name: "empty hostname",
|
||||
authConfig: makeTestAuthConfig(testAuthConfigDataMap{"localhost:5000": testAuthConfigData{"bob", "password"}}),
|
||||
},
|
||||
{
|
||||
name: "no auth config",
|
||||
hostname: "index.docker.io",
|
||||
},
|
||||
{
|
||||
name: "match one",
|
||||
hostname: "example.org",
|
||||
authConfig: makeTestAuthConfig(testAuthConfigDataMap{"example.org": testAuthConfigData{"joe", "mypass"}}),
|
||||
expectedUsername: "joe",
|
||||
expectedPassword: "mypass",
|
||||
},
|
||||
{
|
||||
name: "match none",
|
||||
hostname: "registry.example.org",
|
||||
authConfig: makeTestAuthConfig(testAuthConfigDataMap{"example.org": testAuthConfigData{"joe", "mypass"}}),
|
||||
},
|
||||
{
|
||||
name: "match docker.io",
|
||||
hostname: "docker.io",
|
||||
authConfig: makeTestAuthConfig(testAuthConfigDataMap{
|
||||
"example.org": testAuthConfigData{"example", "org"},
|
||||
"index.docker.io": testAuthConfigData{"index", "docker.io"},
|
||||
"docker.io": testAuthConfigData{"docker", "io"},
|
||||
}),
|
||||
expectedUsername: "docker",
|
||||
expectedPassword: "io",
|
||||
},
|
||||
{
|
||||
name: "match docker.io normalized",
|
||||
hostname: "docker.io",
|
||||
authConfig: makeTestAuthConfig(testAuthConfigDataMap{
|
||||
"example.org": testAuthConfigData{"bob", "pw"},
|
||||
"https://index.docker.io/v1": testAuthConfigData{"alice", "wp"},
|
||||
}),
|
||||
expectedUsername: "alice",
|
||||
expectedPassword: "wp",
|
||||
},
|
||||
{
|
||||
name: "normalize registry",
|
||||
hostname: "https://docker.io/v1",
|
||||
authConfig: makeTestAuthConfig(testAuthConfigDataMap{
|
||||
"docker.io": testAuthConfigData{"user", "pw"},
|
||||
"localhost:5000": testAuthConfigData{"joe", "pass"},
|
||||
}),
|
||||
expectedUsername: "user",
|
||||
expectedPassword: "pw",
|
||||
},
|
||||
{
|
||||
name: "match localhost",
|
||||
hostname: "http://localhost",
|
||||
authConfig: makeTestAuthConfig(testAuthConfigDataMap{
|
||||
"docker.io": testAuthConfigData{"user", "pw"},
|
||||
"localhost": testAuthConfigData{"joe", "pass"},
|
||||
"example.com": testAuthConfigData{"alice", "pwd"},
|
||||
}),
|
||||
expectedUsername: "joe",
|
||||
expectedPassword: "pass",
|
||||
},
|
||||
{
|
||||
name: "match ip",
|
||||
hostname: "10.10.3.56:5000",
|
||||
authConfig: makeTestAuthConfig(testAuthConfigDataMap{
|
||||
"10.10.30.45": testAuthConfigData{"user", "pw"},
|
||||
"localhost": testAuthConfigData{"joe", "pass"},
|
||||
"10.10.3.56": testAuthConfigData{"alice", "pwd"},
|
||||
"10.10.3.56:5000": testAuthConfigData{"me", "mine"},
|
||||
}),
|
||||
expectedUsername: "me",
|
||||
expectedPassword: "mine",
|
||||
},
|
||||
{
|
||||
name: "match port",
|
||||
hostname: "https://localhost:5000",
|
||||
authConfig: makeTestAuthConfig(testAuthConfigDataMap{
|
||||
"https://127.0.0.1:5000": testAuthConfigData{"user", "pw"},
|
||||
"http://localhost": testAuthConfigData{"joe", "pass"},
|
||||
"https://localhost:5001": testAuthConfigData{"alice", "pwd"},
|
||||
"localhost:5000": testAuthConfigData{"me", "mine"},
|
||||
}),
|
||||
expectedUsername: "me",
|
||||
expectedPassword: "mine",
|
||||
},
|
||||
{
|
||||
name: "use system context",
|
||||
hostname: "example.org",
|
||||
authConfig: makeTestAuthConfig(testAuthConfigDataMap{
|
||||
"example.org": testAuthConfigData{"user", "pw"},
|
||||
}),
|
||||
expectedUsername: "foo",
|
||||
expectedPassword: "bar",
|
||||
ctx: &types.SystemContext{
|
||||
DockerAuthConfig: &types.DockerAuthConfig{
|
||||
Username: "foo",
|
||||
Password: "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
contents, err := json.MarshalIndent(&tc.authConfig, "", " ")
|
||||
if err != nil {
|
||||
t.Errorf("[%s] failed to marshal authConfig: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
if err := ioutil.WriteFile(configPath, contents, 0640); err != nil {
|
||||
t.Errorf("[%s] failed to write file %q: %v", tc.name, configPath, err)
|
||||
continue
|
||||
}
|
||||
|
||||
var ctx *types.SystemContext
|
||||
if tc.ctx != nil {
|
||||
ctx = tc.ctx
|
||||
}
|
||||
username, password, err := getAuth(ctx, tc.hostname)
|
||||
if err == nil && tc.expectedError != nil {
|
||||
t.Errorf("[%s] got unexpected non error and username=%q, password=%q", tc.name, username, password)
|
||||
continue
|
||||
}
|
||||
if err != nil && tc.expectedError == nil {
|
||||
t.Errorf("[%s] got unexpected error: %#+v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(err, tc.expectedError) {
|
||||
t.Errorf("[%s] got unexpected error: %#+v != %#+v", tc.name, err, tc.expectedError)
|
||||
continue
|
||||
}
|
||||
|
||||
if username != tc.expectedUsername {
|
||||
t.Errorf("[%s] got unexpected user name: %q != %q", tc.name, username, tc.expectedUsername)
|
||||
}
|
||||
if password != tc.expectedPassword {
|
||||
t.Errorf("[%s] got unexpected user name: %q != %q", tc.name, password, tc.expectedPassword)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAuthFromLegacyFile(t *testing.T) {
|
||||
origHomeDir := homedir.Get()
|
||||
tmpDir, err := ioutil.TempDir("", "test_docker_client_get_auth")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("using temporary home directory: %q", tmpDir)
|
||||
// override homedir
|
||||
os.Setenv(homedir.Key(), tmpDir)
|
||||
defer func() {
|
||||
err := os.RemoveAll(tmpDir)
|
||||
if err != nil {
|
||||
t.Logf("failed to cleanup temporary home directory %q: %v", tmpDir, err)
|
||||
}
|
||||
os.Setenv(homedir.Key(), origHomeDir)
|
||||
}()
|
||||
|
||||
configPath := filepath.Join(tmpDir, ".dockercfg")
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
hostname string
|
||||
authConfig testAuthConfig
|
||||
expectedUsername string
|
||||
expectedPassword string
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "normalize registry",
|
||||
hostname: "https://docker.io/v1",
|
||||
authConfig: makeTestAuthConfig(testAuthConfigDataMap{
|
||||
"docker.io": testAuthConfigData{"user", "pw"},
|
||||
"localhost:5000": testAuthConfigData{"joe", "pass"},
|
||||
}),
|
||||
expectedUsername: "user",
|
||||
expectedPassword: "pw",
|
||||
},
|
||||
{
|
||||
name: "ignore schema and path",
|
||||
hostname: "http://index.docker.io/v1",
|
||||
authConfig: makeTestAuthConfig(testAuthConfigDataMap{
|
||||
"docker.io/v2": testAuthConfigData{"user", "pw"},
|
||||
"https://localhost/v1": testAuthConfigData{"joe", "pwd"},
|
||||
}),
|
||||
expectedUsername: "user",
|
||||
expectedPassword: "pw",
|
||||
},
|
||||
} {
|
||||
contents, err := json.MarshalIndent(&tc.authConfig.Auths, "", " ")
|
||||
if err != nil {
|
||||
t.Errorf("[%s] failed to marshal authConfig: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
if err := ioutil.WriteFile(configPath, contents, 0640); err != nil {
|
||||
t.Errorf("[%s] failed to write file %q: %v", tc.name, configPath, err)
|
||||
continue
|
||||
}
|
||||
|
||||
username, password, err := getAuth(nil, tc.hostname)
|
||||
if err == nil && tc.expectedError != nil {
|
||||
t.Errorf("[%s] got unexpected non error and username=%q, password=%q", tc.name, username, password)
|
||||
continue
|
||||
}
|
||||
if err != nil && tc.expectedError == nil {
|
||||
t.Errorf("[%s] got unexpected error: %#+v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(err, tc.expectedError) {
|
||||
t.Errorf("[%s] got unexpected error: %#+v != %#+v", tc.name, err, tc.expectedError)
|
||||
continue
|
||||
}
|
||||
|
||||
if username != tc.expectedUsername {
|
||||
t.Errorf("[%s] got unexpected user name: %q != %q", tc.name, username, tc.expectedUsername)
|
||||
}
|
||||
if password != tc.expectedPassword {
|
||||
t.Errorf("[%s] got unexpected user name: %q != %q", tc.name, password, tc.expectedPassword)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAuthPreferNewConfig(t *testing.T) {
|
||||
origHomeDir := homedir.Get()
|
||||
tmpDir, err := ioutil.TempDir("", "test_docker_client_get_auth")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("using temporary home directory: %q", tmpDir)
|
||||
// override homedir
|
||||
os.Setenv(homedir.Key(), tmpDir)
|
||||
defer func() {
|
||||
err := os.RemoveAll(tmpDir)
|
||||
if err != nil {
|
||||
t.Logf("failed to cleanup temporary home directory %q: %v", tmpDir, err)
|
||||
}
|
||||
os.Setenv(homedir.Key(), origHomeDir)
|
||||
}()
|
||||
|
||||
configDir := filepath.Join(tmpDir, ".docker")
|
||||
if err := os.Mkdir(configDir, 0750); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, data := range []struct {
|
||||
path string
|
||||
ac interface{}
|
||||
}{
|
||||
{
|
||||
filepath.Join(configDir, "config.json"),
|
||||
makeTestAuthConfig(testAuthConfigDataMap{
|
||||
"https://index.docker.io/v1/": testAuthConfigData{"alice", "pass"},
|
||||
}),
|
||||
},
|
||||
{
|
||||
filepath.Join(tmpDir, ".dockercfg"),
|
||||
makeTestAuthConfig(testAuthConfigDataMap{
|
||||
"https://index.docker.io/v1/": testAuthConfigData{"bob", "pw"},
|
||||
}).Auths,
|
||||
},
|
||||
} {
|
||||
contents, err := json.MarshalIndent(&data.ac, "", " ")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal authConfig: %v", err)
|
||||
}
|
||||
if err := ioutil.WriteFile(data.path, contents, 0640); err != nil {
|
||||
t.Fatalf("failed to write file %q: %v", data.path, err)
|
||||
}
|
||||
}
|
||||
|
||||
username, password, err := getAuth(nil, "index.docker.io")
|
||||
if err != nil {
|
||||
t.Fatalf("got unexpected error: %#+v", err)
|
||||
}
|
||||
|
||||
if username != "alice" {
|
||||
t.Fatalf("got unexpected user name: %q != %q", username, "alice")
|
||||
}
|
||||
if password != "pass" {
|
||||
t.Fatalf("got unexpected user name: %q != %q", password, "pass")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAuthFailsOnBadInput(t *testing.T) {
|
||||
origHomeDir := homedir.Get()
|
||||
tmpDir, err := ioutil.TempDir("", "test_docker_client_get_auth")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("using temporary home directory: %q", tmpDir)
|
||||
// override homedir
|
||||
os.Setenv(homedir.Key(), tmpDir)
|
||||
defer func() {
|
||||
err := os.RemoveAll(tmpDir)
|
||||
if err != nil {
|
||||
t.Logf("failed to cleanup temporary home directory %q: %v", tmpDir, err)
|
||||
}
|
||||
os.Setenv(homedir.Key(), origHomeDir)
|
||||
}()
|
||||
|
||||
configDir := filepath.Join(tmpDir, ".docker")
|
||||
if err := os.Mkdir(configDir, 0750); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
configPath := filepath.Join(configDir, "config.json")
|
||||
|
||||
// no config file present
|
||||
username, password, err := getAuth(nil, "index.docker.io")
|
||||
if err != nil {
|
||||
t.Fatalf("got unexpected error: %#+v", err)
|
||||
}
|
||||
if len(username) > 0 || len(password) > 0 {
|
||||
t.Fatalf("got unexpected not empty username/password: %q/%q", username, password)
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(configPath, []byte("Json rocks! Unless it doesn't."), 0640); err != nil {
|
||||
t.Fatalf("failed to write file %q: %v", configPath, err)
|
||||
}
|
||||
username, password, err = getAuth(nil, "index.docker.io")
|
||||
if err == nil {
|
||||
t.Fatalf("got unexpected non-error: username=%q, password=%q", username, password)
|
||||
}
|
||||
if _, ok := err.(*json.SyntaxError); !ok {
|
||||
t.Fatalf("expected os.PathError, not: %#+v", err)
|
||||
}
|
||||
|
||||
// remove the invalid config file
|
||||
os.RemoveAll(configPath)
|
||||
// no config file present
|
||||
username, password, err = getAuth(nil, "index.docker.io")
|
||||
if err != nil {
|
||||
t.Fatalf("got unexpected error: %#+v", err)
|
||||
}
|
||||
if len(username) > 0 || len(password) > 0 {
|
||||
t.Fatalf("got unexpected not empty username/password: %q/%q", username, password)
|
||||
}
|
||||
|
||||
configPath = filepath.Join(tmpDir, ".dockercfg")
|
||||
if err := ioutil.WriteFile(configPath, []byte("I'm certainly not a json string."), 0640); err != nil {
|
||||
t.Fatalf("failed to write file %q: %v", configPath, err)
|
||||
}
|
||||
username, password, err = getAuth(nil, "index.docker.io")
|
||||
if err == nil {
|
||||
t.Fatalf("got unexpected non-error: username=%q, password=%q", username, password)
|
||||
}
|
||||
if _, ok := err.(*json.SyntaxError); !ok {
|
||||
t.Fatalf("expected os.PathError, not: %#+v", err)
|
||||
}
|
||||
}
|
||||
|
||||
type testAuthConfigData struct {
|
||||
username string
|
||||
password string
|
||||
}
|
||||
|
||||
type testAuthConfigDataMap map[string]testAuthConfigData
|
||||
|
||||
type testAuthConfigEntry struct {
|
||||
Auth string `json:"auth,omitempty"`
|
||||
}
|
||||
|
||||
type testAuthConfig struct {
|
||||
Auths map[string]testAuthConfigEntry `json:"auths"`
|
||||
}
|
||||
|
||||
// encodeAuth creates an auth value from given authConfig data to be stored in auth config file.
|
||||
// Inspired by github.com/docker/docker/cliconfig/config.go v1.10.3.
|
||||
func encodeAuth(authConfig *testAuthConfigData) string {
|
||||
authStr := authConfig.username + ":" + authConfig.password
|
||||
msg := []byte(authStr)
|
||||
encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg)))
|
||||
base64.StdEncoding.Encode(encoded, msg)
|
||||
return string(encoded)
|
||||
}
|
||||
|
||||
func makeTestAuthConfig(authConfigData map[string]testAuthConfigData) testAuthConfig {
|
||||
ac := testAuthConfig{
|
||||
Auths: make(map[string]testAuthConfigEntry),
|
||||
}
|
||||
for host, data := range authConfigData {
|
||||
ac.Auths[host] = testAuthConfigEntry{
|
||||
Auth: encodeAuth(&data),
|
||||
}
|
||||
}
|
||||
return ac
|
||||
}
|
24
vendor/github.com/containers/image/docker/docker_image_src_test.go
generated
vendored
24
vendor/github.com/containers/image/docker/docker_image_src_test.go
generated
vendored
|
@ -1,24 +0,0 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSimplifyContentType(t *testing.T) {
|
||||
for _, c := range []struct{ input, expected string }{
|
||||
{"", ""},
|
||||
{"application/json", "application/json"},
|
||||
{"application/json;charset=utf-8", "application/json"},
|
||||
{"application/json; charset=utf-8", "application/json"},
|
||||
{"application/json ; charset=utf-8", "application/json"},
|
||||
{"application/json\t;\tcharset=utf-8", "application/json"},
|
||||
{"application/json ;charset=utf-8", "application/json"},
|
||||
{`application/json; charset="utf-8"`, "application/json"},
|
||||
{"completely invalid", ""},
|
||||
} {
|
||||
out := simplifyContentType(c.input)
|
||||
assert.Equal(t, c.expected, out, c.input)
|
||||
}
|
||||
}
|
196
vendor/github.com/containers/image/docker/docker_transport_test.go
generated
vendored
196
vendor/github.com/containers/image/docker/docker_transport_test.go
generated
vendored
|
@ -1,196 +0,0 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/containers/image/docker/reference"
|
||||
"github.com/containers/image/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
const (
|
||||
sha256digestHex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
sha256digest = "@sha256:" + sha256digestHex
|
||||
)
|
||||
|
||||
func TestTransportName(t *testing.T) {
|
||||
assert.Equal(t, "docker", Transport.Name())
|
||||
}
|
||||
|
||||
func TestTransportParseReference(t *testing.T) {
|
||||
testParseReference(t, Transport.ParseReference)
|
||||
}
|
||||
|
||||
func TestTransportValidatePolicyConfigurationScope(t *testing.T) {
|
||||
for _, scope := range []string{
|
||||
"docker.io/library/busybox" + sha256digest,
|
||||
"docker.io/library/busybox:notlatest",
|
||||
"docker.io/library/busybox",
|
||||
"docker.io/library",
|
||||
"docker.io",
|
||||
} {
|
||||
err := Transport.ValidatePolicyConfigurationScope(scope)
|
||||
assert.NoError(t, err, scope)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseReference(t *testing.T) {
|
||||
testParseReference(t, ParseReference)
|
||||
}
|
||||
|
||||
// testParseReference is a test shared for Transport.ParseReference and ParseReference.
|
||||
func testParseReference(t *testing.T, fn func(string) (types.ImageReference, error)) {
|
||||
for _, c := range []struct{ input, expected string }{
|
||||
{"busybox", ""}, // Missing // prefix
|
||||
{"//busybox:notlatest", "docker.io/library/busybox:notlatest"}, // Explicit tag
|
||||
{"//busybox" + sha256digest, "docker.io/library/busybox" + sha256digest}, // Explicit digest
|
||||
{"//busybox", "docker.io/library/busybox:latest"}, // Default tag
|
||||
// A github.com/distribution/reference value can have a tag and a digest at the same time!
|
||||
// The docker/distribution API does not really support that (we can’t ask for an image with a specific
|
||||
// tag and digest), so fail. This MAY be accepted in the future.
|
||||
{"//busybox:latest" + sha256digest, ""}, // Both tag and digest
|
||||
{"//docker.io/library/busybox:latest", "docker.io/library/busybox:latest"}, // All implied values explicitly specified
|
||||
{"//UPPERCASEISINVALID", ""}, // Invalid input
|
||||
} {
|
||||
ref, err := fn(c.input)
|
||||
if c.expected == "" {
|
||||
assert.Error(t, err, c.input)
|
||||
} else {
|
||||
require.NoError(t, err, c.input)
|
||||
dockerRef, ok := ref.(dockerReference)
|
||||
require.True(t, ok, c.input)
|
||||
assert.Equal(t, c.expected, dockerRef.ref.String(), c.input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A common list of reference formats to test for the various ImageReference methods.
|
||||
var validReferenceTestCases = []struct{ input, dockerRef, stringWithinTransport string }{
|
||||
{"busybox:notlatest", "docker.io/library/busybox:notlatest", "//busybox:notlatest"}, // Explicit tag
|
||||
{"busybox" + sha256digest, "docker.io/library/busybox" + sha256digest, "//busybox" + sha256digest}, // Explicit digest
|
||||
{"docker.io/library/busybox:latest", "docker.io/library/busybox:latest", "//busybox:latest"}, // All implied values explicitly specified
|
||||
{"example.com/ns/foo:bar", "example.com/ns/foo:bar", "//example.com/ns/foo:bar"}, // All values explicitly specified
|
||||
}
|
||||
|
||||
func TestNewReference(t *testing.T) {
|
||||
for _, c := range validReferenceTestCases {
|
||||
parsed, err := reference.ParseNormalizedNamed(c.input)
|
||||
require.NoError(t, err)
|
||||
ref, err := NewReference(parsed)
|
||||
require.NoError(t, err, c.input)
|
||||
dockerRef, ok := ref.(dockerReference)
|
||||
require.True(t, ok, c.input)
|
||||
assert.Equal(t, c.dockerRef, dockerRef.ref.String(), c.input)
|
||||
}
|
||||
|
||||
// Neither a tag nor digest
|
||||
parsed, err := reference.ParseNormalizedNamed("busybox")
|
||||
require.NoError(t, err)
|
||||
_, err = NewReference(parsed)
|
||||
assert.Error(t, err)
|
||||
|
||||
// A github.com/distribution/reference value can have a tag and a digest at the same time!
|
||||
parsed, err = reference.ParseNormalizedNamed("busybox:notlatest" + sha256digest)
|
||||
require.NoError(t, err)
|
||||
_, ok := parsed.(reference.Canonical)
|
||||
require.True(t, ok)
|
||||
_, ok = parsed.(reference.NamedTagged)
|
||||
require.True(t, ok)
|
||||
_, err = NewReference(parsed)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestReferenceTransport(t *testing.T) {
|
||||
ref, err := ParseReference("//busybox")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, Transport, ref.Transport())
|
||||
}
|
||||
|
||||
func TestReferenceStringWithinTransport(t *testing.T) {
|
||||
for _, c := range validReferenceTestCases {
|
||||
ref, err := ParseReference("//" + c.input)
|
||||
require.NoError(t, err, c.input)
|
||||
stringRef := ref.StringWithinTransport()
|
||||
assert.Equal(t, c.stringWithinTransport, stringRef, c.input)
|
||||
// Do one more round to verify that the output can be parsed, to an equal value.
|
||||
ref2, err := Transport.ParseReference(stringRef)
|
||||
require.NoError(t, err, c.input)
|
||||
stringRef2 := ref2.StringWithinTransport()
|
||||
assert.Equal(t, stringRef, stringRef2, c.input)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReferenceDockerReference(t *testing.T) {
|
||||
for _, c := range validReferenceTestCases {
|
||||
ref, err := ParseReference("//" + c.input)
|
||||
require.NoError(t, err, c.input)
|
||||
dockerRef := ref.DockerReference()
|
||||
require.NotNil(t, dockerRef, c.input)
|
||||
assert.Equal(t, c.dockerRef, dockerRef.String(), c.input)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReferencePolicyConfigurationIdentity(t *testing.T) {
|
||||
// Just a smoke test, the substance is tested in policyconfiguration.TestDockerReference.
|
||||
ref, err := ParseReference("//busybox")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "docker.io/library/busybox:latest", ref.PolicyConfigurationIdentity())
|
||||
}
|
||||
|
||||
func TestReferencePolicyConfigurationNamespaces(t *testing.T) {
|
||||
// Just a smoke test, the substance is tested in policyconfiguration.TestDockerReference.
|
||||
ref, err := ParseReference("//busybox")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{
|
||||
"docker.io/library/busybox",
|
||||
"docker.io/library",
|
||||
"docker.io",
|
||||
}, ref.PolicyConfigurationNamespaces())
|
||||
}
|
||||
|
||||
func TestReferenceNewImage(t *testing.T) {
|
||||
ref, err := ParseReference("//busybox")
|
||||
require.NoError(t, err)
|
||||
img, err := ref.NewImage(&types.SystemContext{RegistriesDirPath: "/this/doesnt/exist"})
|
||||
assert.NoError(t, err)
|
||||
defer img.Close()
|
||||
}
|
||||
|
||||
func TestReferenceNewImageSource(t *testing.T) {
|
||||
ref, err := ParseReference("//busybox")
|
||||
require.NoError(t, err)
|
||||
src, err := ref.NewImageSource(&types.SystemContext{RegistriesDirPath: "/this/doesnt/exist"}, nil)
|
||||
assert.NoError(t, err)
|
||||
defer src.Close()
|
||||
}
|
||||
|
||||
func TestReferenceNewImageDestination(t *testing.T) {
|
||||
ref, err := ParseReference("//busybox")
|
||||
require.NoError(t, err)
|
||||
dest, err := ref.NewImageDestination(&types.SystemContext{RegistriesDirPath: "/this/doesnt/exist"})
|
||||
assert.NoError(t, err)
|
||||
defer dest.Close()
|
||||
}
|
||||
|
||||
func TestReferenceTagOrDigest(t *testing.T) {
|
||||
for input, expected := range map[string]string{
|
||||
"//busybox:notlatest": "notlatest",
|
||||
"//busybox" + sha256digest: "sha256:" + sha256digestHex,
|
||||
} {
|
||||
ref, err := ParseReference(input)
|
||||
require.NoError(t, err, input)
|
||||
dockerRef, ok := ref.(dockerReference)
|
||||
require.True(t, ok, input)
|
||||
tod, err := dockerRef.tagOrDigest()
|
||||
require.NoError(t, err, input)
|
||||
assert.Equal(t, expected, tod, input)
|
||||
}
|
||||
|
||||
// Invalid input
|
||||
ref, err := reference.ParseNormalizedNamed("busybox")
|
||||
require.NoError(t, err)
|
||||
dockerRef := dockerReference{ref: ref}
|
||||
_, err = dockerRef.tagOrDigest()
|
||||
assert.Error(t, err)
|
||||
}
|
1
vendor/github.com/containers/image/docker/fixtures/registries.d/emptyConfig.yaml
generated
vendored
1
vendor/github.com/containers/image/docker/fixtures/registries.d/emptyConfig.yaml
generated
vendored
|
@ -1 +0,0 @@
|
|||
{}
|
|
@ -1,14 +0,0 @@
|
|||
docker:
|
||||
example.com:
|
||||
sigstore: https://sigstore.example.com
|
||||
registry.test.example.com:
|
||||
sigstore: http://registry.test.example.com/sigstore
|
||||
registry.test.example.com:8888:
|
||||
sigstore: http://registry.test.example.com:8889/sigstore
|
||||
sigstore-staging: https://registry.test.example.com:8889/sigstore/specialAPIserverWhichDoesntExist
|
||||
localhost:
|
||||
sigstore: file:///home/mitr/mydevelopment1
|
||||
localhost:8080:
|
||||
sigstore: file:///home/mitr/mydevelopment2
|
||||
localhost/invalid/url/test:
|
||||
sigstore: ":emptyscheme"
|
12
vendor/github.com/containers/image/docker/fixtures/registries.d/internet-user.yaml
generated
vendored
12
vendor/github.com/containers/image/docker/fixtures/registries.d/internet-user.yaml
generated
vendored
|
@ -1,12 +0,0 @@
|
|||
default-docker:
|
||||
sigstore: file:///mnt/companywide/signatures/for/other/repositories
|
||||
docker:
|
||||
docker.io/contoso:
|
||||
sigstore: https://sigstore.contoso.com/fordocker
|
||||
docker.io/centos:
|
||||
sigstore: https://sigstore.centos.org/
|
||||
docker.io/centos/mybetaprooduct:
|
||||
sigstore: http://localhost:9999/mybetaWIP/sigstore
|
||||
sigstore-staging: file:///srv/mybetaWIP/sigstore
|
||||
docker.io/centos/mybetaproduct:latest:
|
||||
sigstore: https://sigstore.centos.org/
|
1
vendor/github.com/containers/image/docker/fixtures/registries.d/invalid-but.notyaml
generated
vendored
1
vendor/github.com/containers/image/docker/fixtures/registries.d/invalid-but.notyaml
generated
vendored
|
@ -1 +0,0 @@
|
|||
}
|
278
vendor/github.com/containers/image/docker/lookaside_test.go
generated
vendored
278
vendor/github.com/containers/image/docker/lookaside_test.go
generated
vendored
|
@ -1,278 +0,0 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/containers/image/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func dockerRefFromString(t *testing.T, s string) dockerReference {
|
||||
ref, err := ParseReference(s)
|
||||
require.NoError(t, err, s)
|
||||
dockerRef, ok := ref.(dockerReference)
|
||||
require.True(t, ok, s)
|
||||
return dockerRef
|
||||
}
|
||||
|
||||
func TestConfiguredSignatureStorageBase(t *testing.T) {
|
||||
// Error reading configuration directory (/dev/null is not a directory)
|
||||
_, err := configuredSignatureStorageBase(&types.SystemContext{RegistriesDirPath: "/dev/null"},
|
||||
dockerRefFromString(t, "//busybox"), false)
|
||||
assert.Error(t, err)
|
||||
|
||||
// No match found
|
||||
emptyDir, err := ioutil.TempDir("", "empty-dir")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(emptyDir)
|
||||
base, err := configuredSignatureStorageBase(&types.SystemContext{RegistriesDirPath: emptyDir},
|
||||
dockerRefFromString(t, "//this/is/not/in/the:configuration"), false)
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, base)
|
||||
|
||||
// Invalid URL
|
||||
_, err = configuredSignatureStorageBase(&types.SystemContext{RegistriesDirPath: "fixtures/registries.d"},
|
||||
dockerRefFromString(t, "//localhost/invalid/url/test"), false)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Success
|
||||
base, err = configuredSignatureStorageBase(&types.SystemContext{RegistriesDirPath: "fixtures/registries.d"},
|
||||
dockerRefFromString(t, "//example.com/my/project"), false)
|
||||
assert.NoError(t, err)
|
||||
require.NotNil(t, base)
|
||||
assert.Equal(t, "https://sigstore.example.com/my/project", (*url.URL)(base).String())
|
||||
}
|
||||
|
||||
func TestRegistriesDirPath(t *testing.T) {
|
||||
const nondefaultPath = "/this/is/not/the/default/registries.d"
|
||||
const variableReference = "$HOME"
|
||||
const rootPrefix = "/root/prefix"
|
||||
|
||||
for _, c := range []struct {
|
||||
ctx *types.SystemContext
|
||||
expected string
|
||||
}{
|
||||
// The common case
|
||||
{nil, systemRegistriesDirPath},
|
||||
// There is a context, but it does not override the path.
|
||||
{&types.SystemContext{}, systemRegistriesDirPath},
|
||||
// Path overridden
|
||||
{&types.SystemContext{RegistriesDirPath: nondefaultPath}, nondefaultPath},
|
||||
// Root overridden
|
||||
{
|
||||
&types.SystemContext{RootForImplicitAbsolutePaths: rootPrefix},
|
||||
filepath.Join(rootPrefix, systemRegistriesDirPath),
|
||||
},
|
||||
// Root and path overrides present simultaneously,
|
||||
{
|
||||
&types.SystemContext{
|
||||
RootForImplicitAbsolutePaths: rootPrefix,
|
||||
RegistriesDirPath: nondefaultPath,
|
||||
},
|
||||
nondefaultPath,
|
||||
},
|
||||
// No environment expansion happens in the overridden paths
|
||||
{&types.SystemContext{RegistriesDirPath: variableReference}, variableReference},
|
||||
} {
|
||||
path := registriesDirPath(c.ctx)
|
||||
assert.Equal(t, c.expected, path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadAndMergeConfig(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir("", "merge-config")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
// No registries.d exists
|
||||
config, err := loadAndMergeConfig(filepath.Join(tmpDir, "thisdoesnotexist"))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, ®istryConfiguration{Docker: map[string]registryNamespace{}}, config)
|
||||
|
||||
// Empty registries.d directory
|
||||
emptyDir := filepath.Join(tmpDir, "empty")
|
||||
err = os.Mkdir(emptyDir, 0755)
|
||||
require.NoError(t, err)
|
||||
config, err = loadAndMergeConfig(emptyDir)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, ®istryConfiguration{Docker: map[string]registryNamespace{}}, config)
|
||||
|
||||
// Unreadable registries.d directory
|
||||
unreadableDir := filepath.Join(tmpDir, "unreadable")
|
||||
err = os.Mkdir(unreadableDir, 0000)
|
||||
require.NoError(t, err)
|
||||
config, err = loadAndMergeConfig(unreadableDir)
|
||||
assert.Error(t, err)
|
||||
|
||||
// An unreadable file in a registries.d directory
|
||||
unreadableFileDir := filepath.Join(tmpDir, "unreadableFile")
|
||||
err = os.Mkdir(unreadableFileDir, 0755)
|
||||
require.NoError(t, err)
|
||||
err = ioutil.WriteFile(filepath.Join(unreadableFileDir, "0.yaml"), []byte("{}"), 0644)
|
||||
require.NoError(t, err)
|
||||
err = ioutil.WriteFile(filepath.Join(unreadableFileDir, "1.yaml"), nil, 0000)
|
||||
require.NoError(t, err)
|
||||
config, err = loadAndMergeConfig(unreadableFileDir)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Invalid YAML
|
||||
invalidYAMLDir := filepath.Join(tmpDir, "invalidYAML")
|
||||
err = os.Mkdir(invalidYAMLDir, 0755)
|
||||
require.NoError(t, err)
|
||||
err = ioutil.WriteFile(filepath.Join(invalidYAMLDir, "0.yaml"), []byte("}"), 0644)
|
||||
require.NoError(t, err)
|
||||
config, err = loadAndMergeConfig(invalidYAMLDir)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Duplicate DefaultDocker
|
||||
duplicateDefault := filepath.Join(tmpDir, "duplicateDefault")
|
||||
err = os.Mkdir(duplicateDefault, 0755)
|
||||
require.NoError(t, err)
|
||||
err = ioutil.WriteFile(filepath.Join(duplicateDefault, "0.yaml"),
|
||||
[]byte("default-docker:\n sigstore: file:////tmp/something"), 0644)
|
||||
require.NoError(t, err)
|
||||
err = ioutil.WriteFile(filepath.Join(duplicateDefault, "1.yaml"),
|
||||
[]byte("default-docker:\n sigstore: file:////tmp/different"), 0644)
|
||||
require.NoError(t, err)
|
||||
config, err = loadAndMergeConfig(duplicateDefault)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "0.yaml")
|
||||
assert.Contains(t, err.Error(), "1.yaml")
|
||||
|
||||
// Duplicate DefaultDocker
|
||||
duplicateNS := filepath.Join(tmpDir, "duplicateNS")
|
||||
err = os.Mkdir(duplicateNS, 0755)
|
||||
require.NoError(t, err)
|
||||
err = ioutil.WriteFile(filepath.Join(duplicateNS, "0.yaml"),
|
||||
[]byte("docker:\n example.com:\n sigstore: file:////tmp/something"), 0644)
|
||||
require.NoError(t, err)
|
||||
err = ioutil.WriteFile(filepath.Join(duplicateNS, "1.yaml"),
|
||||
[]byte("docker:\n example.com:\n sigstore: file:////tmp/different"), 0644)
|
||||
require.NoError(t, err)
|
||||
config, err = loadAndMergeConfig(duplicateNS)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "0.yaml")
|
||||
assert.Contains(t, err.Error(), "1.yaml")
|
||||
|
||||
// A fully worked example, including an empty-dictionary file and a non-.yaml file
|
||||
config, err = loadAndMergeConfig("fixtures/registries.d")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, ®istryConfiguration{
|
||||
DefaultDocker: ®istryNamespace{SigStore: "file:///mnt/companywide/signatures/for/other/repositories"},
|
||||
Docker: map[string]registryNamespace{
|
||||
"example.com": {SigStore: "https://sigstore.example.com"},
|
||||
"registry.test.example.com": {SigStore: "http://registry.test.example.com/sigstore"},
|
||||
"registry.test.example.com:8888": {SigStore: "http://registry.test.example.com:8889/sigstore", SigStoreStaging: "https://registry.test.example.com:8889/sigstore/specialAPIserverWhichDoesntExist"},
|
||||
"localhost": {SigStore: "file:///home/mitr/mydevelopment1"},
|
||||
"localhost:8080": {SigStore: "file:///home/mitr/mydevelopment2"},
|
||||
"localhost/invalid/url/test": {SigStore: ":emptyscheme"},
|
||||
"docker.io/contoso": {SigStore: "https://sigstore.contoso.com/fordocker"},
|
||||
"docker.io/centos": {SigStore: "https://sigstore.centos.org/"},
|
||||
"docker.io/centos/mybetaprooduct": {
|
||||
SigStore: "http://localhost:9999/mybetaWIP/sigstore",
|
||||
SigStoreStaging: "file:///srv/mybetaWIP/sigstore",
|
||||
},
|
||||
"docker.io/centos/mybetaproduct:latest": {SigStore: "https://sigstore.centos.org/"},
|
||||
},
|
||||
}, config)
|
||||
}
|
||||
|
||||
func TestRegistryConfigurationSignaureTopLevel(t *testing.T) {
|
||||
config := registryConfiguration{
|
||||
DefaultDocker: ®istryNamespace{SigStore: "=default", SigStoreStaging: "=default+w"},
|
||||
Docker: map[string]registryNamespace{},
|
||||
}
|
||||
for _, ns := range []string{
|
||||
"localhost",
|
||||
"localhost:5000",
|
||||
"example.com",
|
||||
"example.com/ns1",
|
||||
"example.com/ns1/ns2",
|
||||
"example.com/ns1/ns2/repo",
|
||||
"example.com/ns1/ns2/repo:notlatest",
|
||||
} {
|
||||
config.Docker[ns] = registryNamespace{SigStore: ns, SigStoreStaging: ns + "+w"}
|
||||
}
|
||||
|
||||
for _, c := range []struct{ input, expected string }{
|
||||
{"example.com/ns1/ns2/repo:notlatest", "example.com/ns1/ns2/repo:notlatest"},
|
||||
{"example.com/ns1/ns2/repo:unmatched", "example.com/ns1/ns2/repo"},
|
||||
{"example.com/ns1/ns2/notrepo:notlatest", "example.com/ns1/ns2"},
|
||||
{"example.com/ns1/notns2/repo:notlatest", "example.com/ns1"},
|
||||
{"example.com/notns1/ns2/repo:notlatest", "example.com"},
|
||||
{"unknown.example.com/busybox", "=default"},
|
||||
{"localhost:5000/busybox", "localhost:5000"},
|
||||
{"localhost/busybox", "localhost"},
|
||||
{"localhost:9999/busybox", "=default"},
|
||||
} {
|
||||
dr := dockerRefFromString(t, "//"+c.input)
|
||||
|
||||
res := config.signatureTopLevel(dr, false)
|
||||
assert.Equal(t, c.expected, res, c.input)
|
||||
res = config.signatureTopLevel(dr, true) // test that forWriting is correctly propagated
|
||||
assert.Equal(t, c.expected+"+w", res, c.input)
|
||||
}
|
||||
|
||||
config = registryConfiguration{
|
||||
Docker: map[string]registryNamespace{
|
||||
"unmatched": {SigStore: "a", SigStoreStaging: "b"},
|
||||
},
|
||||
}
|
||||
dr := dockerRefFromString(t, "//thisisnotmatched")
|
||||
res := config.signatureTopLevel(dr, false)
|
||||
assert.Equal(t, "", res)
|
||||
res = config.signatureTopLevel(dr, true)
|
||||
assert.Equal(t, "", res)
|
||||
}
|
||||
|
||||
func TestRegistryNamespaceSignatureTopLevel(t *testing.T) {
|
||||
for _, c := range []struct {
|
||||
ns registryNamespace
|
||||
forWriting bool
|
||||
expected string
|
||||
}{
|
||||
{registryNamespace{SigStoreStaging: "a", SigStore: "b"}, true, "a"},
|
||||
{registryNamespace{SigStoreStaging: "a", SigStore: "b"}, false, "b"},
|
||||
{registryNamespace{SigStore: "b"}, true, "b"},
|
||||
{registryNamespace{SigStore: "b"}, false, "b"},
|
||||
{registryNamespace{SigStoreStaging: "a"}, true, "a"},
|
||||
{registryNamespace{SigStoreStaging: "a"}, false, ""},
|
||||
{registryNamespace{}, true, ""},
|
||||
{registryNamespace{}, false, ""},
|
||||
} {
|
||||
res := c.ns.signatureTopLevel(c.forWriting)
|
||||
assert.Equal(t, c.expected, res, fmt.Sprintf("%#v %v", c.ns, c.forWriting))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignatureStorageBaseSignatureStorageURL(t *testing.T) {
|
||||
const mdInput = "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
const mdMapped = "sha256=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
|
||||
assert.True(t, signatureStorageURL(nil, mdInput, 0) == nil)
|
||||
for _, c := range []struct {
|
||||
base string
|
||||
index int
|
||||
expected string
|
||||
}{
|
||||
{"file:///tmp", 0, "file:///tmp@" + mdMapped + "/signature-1"},
|
||||
{"file:///tmp", 1, "file:///tmp@" + mdMapped + "/signature-2"},
|
||||
{"https://localhost:5555/root", 0, "https://localhost:5555/root@" + mdMapped + "/signature-1"},
|
||||
{"https://localhost:5555/root", 1, "https://localhost:5555/root@" + mdMapped + "/signature-2"},
|
||||
{"http://localhost:5555/root", 0, "http://localhost:5555/root@" + mdMapped + "/signature-1"},
|
||||
{"http://localhost:5555/root", 1, "http://localhost:5555/root@" + mdMapped + "/signature-2"},
|
||||
} {
|
||||
url, err := url.Parse(c.base)
|
||||
require.NoError(t, err)
|
||||
expectedURL, err := url.Parse(c.expected)
|
||||
require.NoError(t, err)
|
||||
res := signatureStorageURL(url, mdInput, c.index)
|
||||
assert.Equal(t, expectedURL, res, c.expected)
|
||||
}
|
||||
}
|
79
vendor/github.com/containers/image/docker/policyconfiguration/naming_test.go
generated
vendored
79
vendor/github.com/containers/image/docker/policyconfiguration/naming_test.go
generated
vendored
|
@ -1,79 +0,0 @@
|
|||
package policyconfiguration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/containers/image/docker/reference"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestDockerReference tests DockerReferenceIdentity and DockerReferenceNamespaces simulatenously
|
||||
// to ensure they are consistent.
|
||||
func TestDockerReference(t *testing.T) {
|
||||
sha256Digest := "@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
// Test both that DockerReferenceIdentity returns the expected value (fullName+suffix),
|
||||
// and that DockerReferenceNamespaces starts with the expected value (fullName), i.e. that the two functions are
|
||||
// consistent.
|
||||
for inputName, expectedNS := range map[string][]string{
|
||||
"example.com/ns/repo": {"example.com/ns/repo", "example.com/ns", "example.com"},
|
||||
"example.com/repo": {"example.com/repo", "example.com"},
|
||||
"localhost/ns/repo": {"localhost/ns/repo", "localhost/ns", "localhost"},
|
||||
// Note that "localhost" is special here: notlocalhost/repo is parsed as docker.io/notlocalhost.repo:
|
||||
"localhost/repo": {"localhost/repo", "localhost"},
|
||||
"notlocalhost/repo": {"docker.io/notlocalhost/repo", "docker.io/notlocalhost", "docker.io"},
|
||||
"docker.io/ns/repo": {"docker.io/ns/repo", "docker.io/ns", "docker.io"},
|
||||
"docker.io/library/repo": {"docker.io/library/repo", "docker.io/library", "docker.io"},
|
||||
"docker.io/repo": {"docker.io/library/repo", "docker.io/library", "docker.io"},
|
||||
"ns/repo": {"docker.io/ns/repo", "docker.io/ns", "docker.io"},
|
||||
"library/repo": {"docker.io/library/repo", "docker.io/library", "docker.io"},
|
||||
"repo": {"docker.io/library/repo", "docker.io/library", "docker.io"},
|
||||
} {
|
||||
for inputSuffix, mappedSuffix := range map[string]string{
|
||||
":tag": ":tag",
|
||||
sha256Digest: sha256Digest,
|
||||
} {
|
||||
fullInput := inputName + inputSuffix
|
||||
ref, err := reference.ParseNormalizedNamed(fullInput)
|
||||
require.NoError(t, err, fullInput)
|
||||
|
||||
identity, err := DockerReferenceIdentity(ref)
|
||||
require.NoError(t, err, fullInput)
|
||||
assert.Equal(t, expectedNS[0]+mappedSuffix, identity, fullInput)
|
||||
|
||||
ns := DockerReferenceNamespaces(ref)
|
||||
require.NotNil(t, ns, fullInput)
|
||||
require.Len(t, ns, len(expectedNS), fullInput)
|
||||
moreSpecific := identity
|
||||
for i := range expectedNS {
|
||||
assert.Equal(t, ns[i], expectedNS[i], fmt.Sprintf("%s item %d", fullInput, i))
|
||||
assert.True(t, strings.HasPrefix(moreSpecific, ns[i]))
|
||||
moreSpecific = ns[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDockerReferenceIdentity(t *testing.T) {
|
||||
// TestDockerReference above has tested the core of the functionality, this tests only the failure cases.
|
||||
|
||||
// Neither a tag nor digest
|
||||
parsed, err := reference.ParseNormalizedNamed("busybox")
|
||||
require.NoError(t, err)
|
||||
id, err := DockerReferenceIdentity(parsed)
|
||||
assert.Equal(t, "", id)
|
||||
assert.Error(t, err)
|
||||
|
||||
// A github.com/distribution/reference value can have a tag and a digest at the same time!
|
||||
parsed, err = reference.ParseNormalizedNamed("busybox:notlatest@sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
|
||||
require.NoError(t, err)
|
||||
_, ok := parsed.(reference.Canonical)
|
||||
require.True(t, ok)
|
||||
_, ok = parsed.(reference.NamedTagged)
|
||||
require.True(t, ok)
|
||||
id, err = DockerReferenceIdentity(parsed)
|
||||
assert.Equal(t, "", id)
|
||||
assert.Error(t, err)
|
||||
}
|
573
vendor/github.com/containers/image/docker/reference/normalize_test.go
generated
vendored
573
vendor/github.com/containers/image/docker/reference/normalize_test.go
generated
vendored
|
@ -1,573 +0,0 @@
|
|||
package reference
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
func TestValidateReferenceName(t *testing.T) {
|
||||
validRepoNames := []string{
|
||||
"docker/docker",
|
||||
"library/debian",
|
||||
"debian",
|
||||
"docker.io/docker/docker",
|
||||
"docker.io/library/debian",
|
||||
"docker.io/debian",
|
||||
"index.docker.io/docker/docker",
|
||||
"index.docker.io/library/debian",
|
||||
"index.docker.io/debian",
|
||||
"127.0.0.1:5000/docker/docker",
|
||||
"127.0.0.1:5000/library/debian",
|
||||
"127.0.0.1:5000/debian",
|
||||
"thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev",
|
||||
|
||||
// This test case was moved from invalid to valid since it is valid input
|
||||
// when specified with a hostname, it removes the ambiguity from about
|
||||
// whether the value is an identifier or repository name
|
||||
"docker.io/1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
|
||||
}
|
||||
invalidRepoNames := []string{
|
||||
"https://github.com/docker/docker",
|
||||
"docker/Docker",
|
||||
"-docker",
|
||||
"-docker/docker",
|
||||
"-docker.io/docker/docker",
|
||||
"docker///docker",
|
||||
"docker.io/docker/Docker",
|
||||
"docker.io/docker///docker",
|
||||
"1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
|
||||
}
|
||||
|
||||
for _, name := range invalidRepoNames {
|
||||
_, err := ParseNormalizedNamed(name)
|
||||
if err == nil {
|
||||
t.Fatalf("Expected invalid repo name for %q", name)
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range validRepoNames {
|
||||
_, err := ParseNormalizedNamed(name)
|
||||
if err != nil {
|
||||
t.Fatalf("Error parsing repo name %s, got: %q", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRemoteName(t *testing.T) {
|
||||
validRepositoryNames := []string{
|
||||
// Sanity check.
|
||||
"docker/docker",
|
||||
|
||||
// Allow 64-character non-hexadecimal names (hexadecimal names are forbidden).
|
||||
"thisisthesongthatneverendsitgoesonandonandonthisisthesongthatnev",
|
||||
|
||||
// Allow embedded hyphens.
|
||||
"docker-rules/docker",
|
||||
|
||||
// Allow multiple hyphens as well.
|
||||
"docker---rules/docker",
|
||||
|
||||
//Username doc and image name docker being tested.
|
||||
"doc/docker",
|
||||
|
||||
// single character names are now allowed.
|
||||
"d/docker",
|
||||
"jess/t",
|
||||
|
||||
// Consecutive underscores.
|
||||
"dock__er/docker",
|
||||
}
|
||||
for _, repositoryName := range validRepositoryNames {
|
||||
_, err := ParseNormalizedNamed(repositoryName)
|
||||
if err != nil {
|
||||
t.Errorf("Repository name should be valid: %v. Error: %v", repositoryName, err)
|
||||
}
|
||||
}
|
||||
|
||||
invalidRepositoryNames := []string{
|
||||
// Disallow capital letters.
|
||||
"docker/Docker",
|
||||
|
||||
// Only allow one slash.
|
||||
"docker///docker",
|
||||
|
||||
// Disallow 64-character hexadecimal.
|
||||
"1a3f5e7d9c1b3a5f7e9d1c3b5a7f9e1d3c5b7a9f1e3d5d7c9b1a3f5e7d9c1b3a",
|
||||
|
||||
// Disallow leading and trailing hyphens in namespace.
|
||||
"-docker/docker",
|
||||
"docker-/docker",
|
||||
"-docker-/docker",
|
||||
|
||||
// Don't allow underscores everywhere (as opposed to hyphens).
|
||||
"____/____",
|
||||
|
||||
"_docker/_docker",
|
||||
|
||||
// Disallow consecutive periods.
|
||||
"dock..er/docker",
|
||||
"dock_.er/docker",
|
||||
"dock-.er/docker",
|
||||
|
||||
// No repository.
|
||||
"docker/",
|
||||
|
||||
//namespace too long
|
||||
"this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255_this_is_not_a_valid_namespace_because_its_lenth_is_greater_than_255/docker",
|
||||
}
|
||||
for _, repositoryName := range invalidRepositoryNames {
|
||||
if _, err := ParseNormalizedNamed(repositoryName); err == nil {
|
||||
t.Errorf("Repository name should be invalid: %v", repositoryName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRepositoryInfo(t *testing.T) {
|
||||
type tcase struct {
|
||||
RemoteName, FamiliarName, FullName, AmbiguousName, Domain string
|
||||
}
|
||||
|
||||
tcases := []tcase{
|
||||
{
|
||||
RemoteName: "fooo/bar",
|
||||
FamiliarName: "fooo/bar",
|
||||
FullName: "docker.io/fooo/bar",
|
||||
AmbiguousName: "index.docker.io/fooo/bar",
|
||||
Domain: "docker.io",
|
||||
},
|
||||
{
|
||||
RemoteName: "library/ubuntu",
|
||||
FamiliarName: "ubuntu",
|
||||
FullName: "docker.io/library/ubuntu",
|
||||
AmbiguousName: "library/ubuntu",
|
||||
Domain: "docker.io",
|
||||
},
|
||||
{
|
||||
RemoteName: "nonlibrary/ubuntu",
|
||||
FamiliarName: "nonlibrary/ubuntu",
|
||||
FullName: "docker.io/nonlibrary/ubuntu",
|
||||
AmbiguousName: "",
|
||||
Domain: "docker.io",
|
||||
},
|
||||
{
|
||||
RemoteName: "other/library",
|
||||
FamiliarName: "other/library",
|
||||
FullName: "docker.io/other/library",
|
||||
AmbiguousName: "",
|
||||
Domain: "docker.io",
|
||||
},
|
||||
{
|
||||
RemoteName: "private/moonbase",
|
||||
FamiliarName: "127.0.0.1:8000/private/moonbase",
|
||||
FullName: "127.0.0.1:8000/private/moonbase",
|
||||
AmbiguousName: "",
|
||||
Domain: "127.0.0.1:8000",
|
||||
},
|
||||
{
|
||||
RemoteName: "privatebase",
|
||||
FamiliarName: "127.0.0.1:8000/privatebase",
|
||||
FullName: "127.0.0.1:8000/privatebase",
|
||||
AmbiguousName: "",
|
||||
Domain: "127.0.0.1:8000",
|
||||
},
|
||||
{
|
||||
RemoteName: "private/moonbase",
|
||||
FamiliarName: "example.com/private/moonbase",
|
||||
FullName: "example.com/private/moonbase",
|
||||
AmbiguousName: "",
|
||||
Domain: "example.com",
|
||||
},
|
||||
{
|
||||
RemoteName: "privatebase",
|
||||
FamiliarName: "example.com/privatebase",
|
||||
FullName: "example.com/privatebase",
|
||||
AmbiguousName: "",
|
||||
Domain: "example.com",
|
||||
},
|
||||
{
|
||||
RemoteName: "private/moonbase",
|
||||
FamiliarName: "example.com:8000/private/moonbase",
|
||||
FullName: "example.com:8000/private/moonbase",
|
||||
AmbiguousName: "",
|
||||
Domain: "example.com:8000",
|
||||
},
|
||||
{
|
||||
RemoteName: "privatebasee",
|
||||
FamiliarName: "example.com:8000/privatebasee",
|
||||
FullName: "example.com:8000/privatebasee",
|
||||
AmbiguousName: "",
|
||||
Domain: "example.com:8000",
|
||||
},
|
||||
{
|
||||
RemoteName: "library/ubuntu-12.04-base",
|
||||
FamiliarName: "ubuntu-12.04-base",
|
||||
FullName: "docker.io/library/ubuntu-12.04-base",
|
||||
AmbiguousName: "index.docker.io/library/ubuntu-12.04-base",
|
||||
Domain: "docker.io",
|
||||
},
|
||||
{
|
||||
RemoteName: "library/foo",
|
||||
FamiliarName: "foo",
|
||||
FullName: "docker.io/library/foo",
|
||||
AmbiguousName: "docker.io/foo",
|
||||
Domain: "docker.io",
|
||||
},
|
||||
{
|
||||
RemoteName: "library/foo/bar",
|
||||
FamiliarName: "library/foo/bar",
|
||||
FullName: "docker.io/library/foo/bar",
|
||||
AmbiguousName: "",
|
||||
Domain: "docker.io",
|
||||
},
|
||||
{
|
||||
RemoteName: "store/foo/bar",
|
||||
FamiliarName: "store/foo/bar",
|
||||
FullName: "docker.io/store/foo/bar",
|
||||
AmbiguousName: "",
|
||||
Domain: "docker.io",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tcase := range tcases {
|
||||
refStrings := []string{tcase.FamiliarName, tcase.FullName}
|
||||
if tcase.AmbiguousName != "" {
|
||||
refStrings = append(refStrings, tcase.AmbiguousName)
|
||||
}
|
||||
|
||||
var refs []Named
|
||||
for _, r := range refStrings {
|
||||
named, err := ParseNormalizedNamed(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
refs = append(refs, named)
|
||||
}
|
||||
|
||||
for _, r := range refs {
|
||||
if expected, actual := tcase.FamiliarName, FamiliarName(r); expected != actual {
|
||||
t.Fatalf("Invalid normalized reference for %q. Expected %q, got %q", r, expected, actual)
|
||||
}
|
||||
if expected, actual := tcase.FullName, r.String(); expected != actual {
|
||||
t.Fatalf("Invalid canonical reference for %q. Expected %q, got %q", r, expected, actual)
|
||||
}
|
||||
if expected, actual := tcase.Domain, Domain(r); expected != actual {
|
||||
t.Fatalf("Invalid domain for %q. Expected %q, got %q", r, expected, actual)
|
||||
}
|
||||
if expected, actual := tcase.RemoteName, Path(r); expected != actual {
|
||||
t.Fatalf("Invalid remoteName for %q. Expected %q, got %q", r, expected, actual)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseReferenceWithTagAndDigest(t *testing.T) {
|
||||
shortRef := "busybox:latest@sha256:86e0e091d0da6bde2456dbb48306f3956bbeb2eae1b5b9a43045843f69fe4aaa"
|
||||
ref, err := ParseNormalizedNamed(shortRef)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if expected, actual := "docker.io/library/"+shortRef, ref.String(); actual != expected {
|
||||
t.Fatalf("Invalid parsed reference for %q: expected %q, got %q", ref, expected, actual)
|
||||
}
|
||||
|
||||
if _, isTagged := ref.(NamedTagged); !isTagged {
|
||||
t.Fatalf("Reference from %q should support tag", ref)
|
||||
}
|
||||
if _, isCanonical := ref.(Canonical); !isCanonical {
|
||||
t.Fatalf("Reference from %q should support digest", ref)
|
||||
}
|
||||
if expected, actual := shortRef, FamiliarString(ref); actual != expected {
|
||||
t.Fatalf("Invalid parsed reference for %q: expected %q, got %q", ref, expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInvalidReferenceComponents(t *testing.T) {
|
||||
if _, err := ParseNormalizedNamed("-foo"); err == nil {
|
||||
t.Fatal("Expected WithName to detect invalid name")
|
||||
}
|
||||
ref, err := ParseNormalizedNamed("busybox")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := WithTag(ref, "-foo"); err == nil {
|
||||
t.Fatal("Expected WithName to detect invalid tag")
|
||||
}
|
||||
if _, err := WithDigest(ref, digest.Digest("foo")); err == nil {
|
||||
t.Fatal("Expected WithDigest to detect invalid digest")
|
||||
}
|
||||
}
|
||||
|
||||
func equalReference(r1, r2 Reference) bool {
|
||||
switch v1 := r1.(type) {
|
||||
case digestReference:
|
||||
if v2, ok := r2.(digestReference); ok {
|
||||
return v1 == v2
|
||||
}
|
||||
case repository:
|
||||
if v2, ok := r2.(repository); ok {
|
||||
return v1 == v2
|
||||
}
|
||||
case taggedReference:
|
||||
if v2, ok := r2.(taggedReference); ok {
|
||||
return v1 == v2
|
||||
}
|
||||
case canonicalReference:
|
||||
if v2, ok := r2.(canonicalReference); ok {
|
||||
return v1 == v2
|
||||
}
|
||||
case reference:
|
||||
if v2, ok := r2.(reference); ok {
|
||||
return v1 == v2
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func TestParseAnyReference(t *testing.T) {
|
||||
tcases := []struct {
|
||||
Reference string
|
||||
Equivalent string
|
||||
Expected Reference
|
||||
}{
|
||||
{
|
||||
Reference: "redis",
|
||||
Equivalent: "docker.io/library/redis",
|
||||
},
|
||||
{
|
||||
Reference: "redis:latest",
|
||||
Equivalent: "docker.io/library/redis:latest",
|
||||
},
|
||||
{
|
||||
Reference: "docker.io/library/redis:latest",
|
||||
Equivalent: "docker.io/library/redis:latest",
|
||||
},
|
||||
{
|
||||
Reference: "redis@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||
Equivalent: "docker.io/library/redis@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||
},
|
||||
{
|
||||
Reference: "docker.io/library/redis@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||
Equivalent: "docker.io/library/redis@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||
},
|
||||
{
|
||||
Reference: "dmcgowan/myapp",
|
||||
Equivalent: "docker.io/dmcgowan/myapp",
|
||||
},
|
||||
{
|
||||
Reference: "dmcgowan/myapp:latest",
|
||||
Equivalent: "docker.io/dmcgowan/myapp:latest",
|
||||
},
|
||||
{
|
||||
Reference: "docker.io/mcgowan/myapp:latest",
|
||||
Equivalent: "docker.io/mcgowan/myapp:latest",
|
||||
},
|
||||
{
|
||||
Reference: "dmcgowan/myapp@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||
Equivalent: "docker.io/dmcgowan/myapp@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||
},
|
||||
{
|
||||
Reference: "docker.io/dmcgowan/myapp@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||
Equivalent: "docker.io/dmcgowan/myapp@sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||
},
|
||||
{
|
||||
Reference: "dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||
Expected: digestReference("sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c"),
|
||||
Equivalent: "sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||
},
|
||||
{
|
||||
Reference: "sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||
Expected: digestReference("sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c"),
|
||||
Equivalent: "sha256:dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9c",
|
||||
},
|
||||
{
|
||||
Reference: "dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9",
|
||||
Equivalent: "docker.io/library/dbcc1c35ac38df41fd2f5e4130b32ffdb93ebae8b3dbe638c23575912276fc9",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tcase := range tcases {
|
||||
var ref Reference
|
||||
var err error
|
||||
ref, err = ParseAnyReference(tcase.Reference)
|
||||
if err != nil {
|
||||
t.Fatalf("Error parsing reference %s: %v", tcase.Reference, err)
|
||||
}
|
||||
if ref.String() != tcase.Equivalent {
|
||||
t.Fatalf("Unexpected string: %s, expected %s", ref.String(), tcase.Equivalent)
|
||||
}
|
||||
|
||||
expected := tcase.Expected
|
||||
if expected == nil {
|
||||
expected, err = Parse(tcase.Equivalent)
|
||||
if err != nil {
|
||||
t.Fatalf("Error parsing reference %s: %v", tcase.Equivalent, err)
|
||||
}
|
||||
}
|
||||
if !equalReference(ref, expected) {
|
||||
t.Errorf("Unexpected reference %#v, expected %#v", ref, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizedSplitHostname(t *testing.T) {
|
||||
testcases := []struct {
|
||||
input string
|
||||
domain string
|
||||
name string
|
||||
}{
|
||||
{
|
||||
input: "test.com/foo",
|
||||
domain: "test.com",
|
||||
name: "foo",
|
||||
},
|
||||
{
|
||||
input: "test_com/foo",
|
||||
domain: "docker.io",
|
||||
name: "test_com/foo",
|
||||
},
|
||||
{
|
||||
input: "docker/migrator",
|
||||
domain: "docker.io",
|
||||
name: "docker/migrator",
|
||||
},
|
||||
{
|
||||
input: "test.com:8080/foo",
|
||||
domain: "test.com:8080",
|
||||
name: "foo",
|
||||
},
|
||||
{
|
||||
input: "test-com:8080/foo",
|
||||
domain: "test-com:8080",
|
||||
name: "foo",
|
||||
},
|
||||
{
|
||||
input: "foo",
|
||||
domain: "docker.io",
|
||||
name: "library/foo",
|
||||
},
|
||||
{
|
||||
input: "xn--n3h.com/foo",
|
||||
domain: "xn--n3h.com",
|
||||
name: "foo",
|
||||
},
|
||||
{
|
||||
input: "xn--n3h.com:18080/foo",
|
||||
domain: "xn--n3h.com:18080",
|
||||
name: "foo",
|
||||
},
|
||||
{
|
||||
input: "docker.io/foo",
|
||||
domain: "docker.io",
|
||||
name: "library/foo",
|
||||
},
|
||||
{
|
||||
input: "docker.io/library/foo",
|
||||
domain: "docker.io",
|
||||
name: "library/foo",
|
||||
},
|
||||
{
|
||||
input: "docker.io/library/foo/bar",
|
||||
domain: "docker.io",
|
||||
name: "library/foo/bar",
|
||||
},
|
||||
}
|
||||
for _, testcase := range testcases {
|
||||
failf := func(format string, v ...interface{}) {
|
||||
t.Logf(strconv.Quote(testcase.input)+": "+format, v...)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
named, err := ParseNormalizedNamed(testcase.input)
|
||||
if err != nil {
|
||||
failf("error parsing name: %s", err)
|
||||
}
|
||||
domain, name := SplitHostname(named)
|
||||
if domain != testcase.domain {
|
||||
failf("unexpected domain: got %q, expected %q", domain, testcase.domain)
|
||||
}
|
||||
if name != testcase.name {
|
||||
failf("unexpected name: got %q, expected %q", name, testcase.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchError(t *testing.T) {
|
||||
named, err := ParseAnyReference("foo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = FamiliarMatch("[-x]", named)
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error, got nothing")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatch(t *testing.T) {
|
||||
matchCases := []struct {
|
||||
reference string
|
||||
pattern string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
reference: "foo",
|
||||
pattern: "foo/**/ba[rz]",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
reference: "foo/any/bat",
|
||||
pattern: "foo/**/ba[rz]",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
reference: "foo/a/bar",
|
||||
pattern: "foo/**/ba[rz]",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
reference: "foo/b/baz",
|
||||
pattern: "foo/**/ba[rz]",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
reference: "foo/c/baz:tag",
|
||||
pattern: "foo/**/ba[rz]",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
reference: "foo/c/baz:tag",
|
||||
pattern: "foo/*/baz:tag",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
reference: "foo/c/baz:tag",
|
||||
pattern: "foo/c/baz:tag",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
reference: "example.com/foo/c/baz:tag",
|
||||
pattern: "*/foo/c/baz",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
reference: "example.com/foo/c/baz:tag",
|
||||
pattern: "example.com/foo/c/baz",
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
for _, c := range matchCases {
|
||||
named, err := ParseAnyReference(c.reference)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actual, err := FamiliarMatch(c.pattern, named)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if actual != c.expected {
|
||||
t.Fatalf("expected %s match %s to be %v, was %v", c.reference, c.pattern, c.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
659
vendor/github.com/containers/image/docker/reference/reference_test.go
generated
vendored
659
vendor/github.com/containers/image/docker/reference/reference_test.go
generated
vendored
|
@ -1,659 +0,0 @@
|
|||
package reference
|
||||
|
||||
import (
|
||||
_ "crypto/sha256"
|
||||
_ "crypto/sha512"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
func TestReferenceParse(t *testing.T) {
|
||||
// referenceTestcases is a unified set of testcases for
|
||||
// testing the parsing of references
|
||||
referenceTestcases := []struct {
|
||||
// input is the repository name or name component testcase
|
||||
input string
|
||||
// err is the error expected from Parse, or nil
|
||||
err error
|
||||
// repository is the string representation for the reference
|
||||
repository string
|
||||
// domain is the domain expected in the reference
|
||||
domain string
|
||||
// tag is the tag for the reference
|
||||
tag string
|
||||
// digest is the digest for the reference (enforces digest reference)
|
||||
digest string
|
||||
}{
|
||||
{
|
||||
input: "test_com",
|
||||
repository: "test_com",
|
||||
},
|
||||
{
|
||||
input: "test.com:tag",
|
||||
repository: "test.com",
|
||||
tag: "tag",
|
||||
},
|
||||
{
|
||||
input: "test.com:5000",
|
||||
repository: "test.com",
|
||||
tag: "5000",
|
||||
},
|
||||
{
|
||||
input: "test.com/repo:tag",
|
||||
domain: "test.com",
|
||||
repository: "test.com/repo",
|
||||
tag: "tag",
|
||||
},
|
||||
{
|
||||
input: "test:5000/repo",
|
||||
domain: "test:5000",
|
||||
repository: "test:5000/repo",
|
||||
},
|
||||
{
|
||||
input: "test:5000/repo:tag",
|
||||
domain: "test:5000",
|
||||
repository: "test:5000/repo",
|
||||
tag: "tag",
|
||||
},
|
||||
{
|
||||
input: "test:5000/repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
domain: "test:5000",
|
||||
repository: "test:5000/repo",
|
||||
digest: "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
},
|
||||
{
|
||||
input: "test:5000/repo:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
domain: "test:5000",
|
||||
repository: "test:5000/repo",
|
||||
tag: "tag",
|
||||
digest: "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
},
|
||||
{
|
||||
input: "test:5000/repo",
|
||||
domain: "test:5000",
|
||||
repository: "test:5000/repo",
|
||||
},
|
||||
{
|
||||
input: "",
|
||||
err: ErrNameEmpty,
|
||||
},
|
||||
{
|
||||
input: ":justtag",
|
||||
err: ErrReferenceInvalidFormat,
|
||||
},
|
||||
{
|
||||
input: "@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
err: ErrReferenceInvalidFormat,
|
||||
},
|
||||
{
|
||||
input: "repo@sha256:ffffffffffffffffffffffffffffffffff",
|
||||
err: digest.ErrDigestInvalidLength,
|
||||
},
|
||||
{
|
||||
input: "validname@invaliddigest:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
err: digest.ErrDigestUnsupported,
|
||||
},
|
||||
{
|
||||
input: "Uppercase:tag",
|
||||
err: ErrNameContainsUppercase,
|
||||
},
|
||||
// FIXME "Uppercase" is incorrectly handled as a domain-name here, therefore passes.
|
||||
// See https://github.com/docker/distribution/pull/1778, and https://github.com/docker/docker/pull/20175
|
||||
//{
|
||||
// input: "Uppercase/lowercase:tag",
|
||||
// err: ErrNameContainsUppercase,
|
||||
//},
|
||||
{
|
||||
input: "test:5000/Uppercase/lowercase:tag",
|
||||
err: ErrNameContainsUppercase,
|
||||
},
|
||||
{
|
||||
input: "lowercase:Uppercase",
|
||||
repository: "lowercase",
|
||||
tag: "Uppercase",
|
||||
},
|
||||
{
|
||||
input: strings.Repeat("a/", 128) + "a:tag",
|
||||
err: ErrNameTooLong,
|
||||
},
|
||||
{
|
||||
input: strings.Repeat("a/", 127) + "a:tag-puts-this-over-max",
|
||||
domain: "a",
|
||||
repository: strings.Repeat("a/", 127) + "a",
|
||||
tag: "tag-puts-this-over-max",
|
||||
},
|
||||
{
|
||||
input: "aa/asdf$$^/aa",
|
||||
err: ErrReferenceInvalidFormat,
|
||||
},
|
||||
{
|
||||
input: "sub-dom1.foo.com/bar/baz/quux",
|
||||
domain: "sub-dom1.foo.com",
|
||||
repository: "sub-dom1.foo.com/bar/baz/quux",
|
||||
},
|
||||
{
|
||||
input: "sub-dom1.foo.com/bar/baz/quux:some-long-tag",
|
||||
domain: "sub-dom1.foo.com",
|
||||
repository: "sub-dom1.foo.com/bar/baz/quux",
|
||||
tag: "some-long-tag",
|
||||
},
|
||||
{
|
||||
input: "b.gcr.io/test.example.com/my-app:test.example.com",
|
||||
domain: "b.gcr.io",
|
||||
repository: "b.gcr.io/test.example.com/my-app",
|
||||
tag: "test.example.com",
|
||||
},
|
||||
{
|
||||
input: "xn--n3h.com/myimage:xn--n3h.com", // ☃.com in punycode
|
||||
domain: "xn--n3h.com",
|
||||
repository: "xn--n3h.com/myimage",
|
||||
tag: "xn--n3h.com",
|
||||
},
|
||||
{
|
||||
input: "xn--7o8h.com/myimage:xn--7o8h.com@sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // 🐳.com in punycode
|
||||
domain: "xn--7o8h.com",
|
||||
repository: "xn--7o8h.com/myimage",
|
||||
tag: "xn--7o8h.com",
|
||||
digest: "sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
},
|
||||
{
|
||||
input: "foo_bar.com:8080",
|
||||
repository: "foo_bar.com",
|
||||
tag: "8080",
|
||||
},
|
||||
{
|
||||
input: "foo/foo_bar.com:8080",
|
||||
domain: "foo",
|
||||
repository: "foo/foo_bar.com",
|
||||
tag: "8080",
|
||||
},
|
||||
}
|
||||
for _, testcase := range referenceTestcases {
|
||||
failf := func(format string, v ...interface{}) {
|
||||
t.Logf(strconv.Quote(testcase.input)+": "+format, v...)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
repo, err := Parse(testcase.input)
|
||||
if testcase.err != nil {
|
||||
if err == nil {
|
||||
failf("missing expected error: %v", testcase.err)
|
||||
} else if testcase.err != err {
|
||||
failf("mismatched error: got %v, expected %v", err, testcase.err)
|
||||
}
|
||||
continue
|
||||
} else if err != nil {
|
||||
failf("unexpected parse error: %v", err)
|
||||
continue
|
||||
}
|
||||
if repo.String() != testcase.input {
|
||||
failf("mismatched repo: got %q, expected %q", repo.String(), testcase.input)
|
||||
}
|
||||
|
||||
if named, ok := repo.(Named); ok {
|
||||
if named.Name() != testcase.repository {
|
||||
failf("unexpected repository: got %q, expected %q", named.Name(), testcase.repository)
|
||||
}
|
||||
domain, _ := SplitHostname(named)
|
||||
if domain != testcase.domain {
|
||||
failf("unexpected domain: got %q, expected %q", domain, testcase.domain)
|
||||
}
|
||||
} else if testcase.repository != "" || testcase.domain != "" {
|
||||
failf("expected named type, got %T", repo)
|
||||
}
|
||||
|
||||
tagged, ok := repo.(Tagged)
|
||||
if testcase.tag != "" {
|
||||
if ok {
|
||||
if tagged.Tag() != testcase.tag {
|
||||
failf("unexpected tag: got %q, expected %q", tagged.Tag(), testcase.tag)
|
||||
}
|
||||
} else {
|
||||
failf("expected tagged type, got %T", repo)
|
||||
}
|
||||
} else if ok {
|
||||
failf("unexpected tagged type")
|
||||
}
|
||||
|
||||
digested, ok := repo.(Digested)
|
||||
if testcase.digest != "" {
|
||||
if ok {
|
||||
if digested.Digest().String() != testcase.digest {
|
||||
failf("unexpected digest: got %q, expected %q", digested.Digest().String(), testcase.digest)
|
||||
}
|
||||
} else {
|
||||
failf("expected digested type, got %T", repo)
|
||||
}
|
||||
} else if ok {
|
||||
failf("unexpected digested type")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// TestWithNameFailure tests cases where WithName should fail. Cases where it
|
||||
// should succeed are covered by TestSplitHostname, below.
|
||||
func TestWithNameFailure(t *testing.T) {
|
||||
testcases := []struct {
|
||||
input string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
input: "",
|
||||
err: ErrNameEmpty,
|
||||
},
|
||||
{
|
||||
input: ":justtag",
|
||||
err: ErrReferenceInvalidFormat,
|
||||
},
|
||||
{
|
||||
input: "@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
err: ErrReferenceInvalidFormat,
|
||||
},
|
||||
{
|
||||
input: "validname@invaliddigest:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
err: ErrReferenceInvalidFormat,
|
||||
},
|
||||
{
|
||||
input: strings.Repeat("a/", 128) + "a:tag",
|
||||
err: ErrNameTooLong,
|
||||
},
|
||||
{
|
||||
input: "aa/asdf$$^/aa",
|
||||
err: ErrReferenceInvalidFormat,
|
||||
},
|
||||
}
|
||||
for _, testcase := range testcases {
|
||||
failf := func(format string, v ...interface{}) {
|
||||
t.Logf(strconv.Quote(testcase.input)+": "+format, v...)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
_, err := WithName(testcase.input)
|
||||
if err == nil {
|
||||
failf("no error parsing name. expected: %s", testcase.err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitHostname(t *testing.T) {
|
||||
testcases := []struct {
|
||||
input string
|
||||
domain string
|
||||
name string
|
||||
}{
|
||||
{
|
||||
input: "test.com/foo",
|
||||
domain: "test.com",
|
||||
name: "foo",
|
||||
},
|
||||
{
|
||||
input: "test_com/foo",
|
||||
domain: "",
|
||||
name: "test_com/foo",
|
||||
},
|
||||
{
|
||||
input: "test:8080/foo",
|
||||
domain: "test:8080",
|
||||
name: "foo",
|
||||
},
|
||||
{
|
||||
input: "test.com:8080/foo",
|
||||
domain: "test.com:8080",
|
||||
name: "foo",
|
||||
},
|
||||
{
|
||||
input: "test-com:8080/foo",
|
||||
domain: "test-com:8080",
|
||||
name: "foo",
|
||||
},
|
||||
{
|
||||
input: "xn--n3h.com:18080/foo",
|
||||
domain: "xn--n3h.com:18080",
|
||||
name: "foo",
|
||||
},
|
||||
}
|
||||
for _, testcase := range testcases {
|
||||
failf := func(format string, v ...interface{}) {
|
||||
t.Logf(strconv.Quote(testcase.input)+": "+format, v...)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
named, err := WithName(testcase.input)
|
||||
if err != nil {
|
||||
failf("error parsing name: %s", err)
|
||||
}
|
||||
domain, name := SplitHostname(named)
|
||||
if domain != testcase.domain {
|
||||
failf("unexpected domain: got %q, expected %q", domain, testcase.domain)
|
||||
}
|
||||
if name != testcase.name {
|
||||
failf("unexpected name: got %q, expected %q", name, testcase.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type serializationType struct {
|
||||
Description string
|
||||
Field Field
|
||||
}
|
||||
|
||||
func TestSerialization(t *testing.T) {
|
||||
testcases := []struct {
|
||||
description string
|
||||
input string
|
||||
name string
|
||||
tag string
|
||||
digest string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
description: "empty value",
|
||||
err: ErrNameEmpty,
|
||||
},
|
||||
{
|
||||
description: "just a name",
|
||||
input: "example.com:8000/named",
|
||||
name: "example.com:8000/named",
|
||||
},
|
||||
{
|
||||
description: "name with a tag",
|
||||
input: "example.com:8000/named:tagged",
|
||||
name: "example.com:8000/named",
|
||||
tag: "tagged",
|
||||
},
|
||||
{
|
||||
description: "name with digest",
|
||||
input: "other.com/named@sha256:1234567890098765432112345667890098765432112345667890098765432112",
|
||||
name: "other.com/named",
|
||||
digest: "sha256:1234567890098765432112345667890098765432112345667890098765432112",
|
||||
},
|
||||
}
|
||||
for _, testcase := range testcases {
|
||||
failf := func(format string, v ...interface{}) {
|
||||
t.Logf(strconv.Quote(testcase.input)+": "+format, v...)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
m := map[string]string{
|
||||
"Description": testcase.description,
|
||||
"Field": testcase.input,
|
||||
}
|
||||
b, err := json.Marshal(m)
|
||||
if err != nil {
|
||||
failf("error marshalling: %v", err)
|
||||
}
|
||||
t := serializationType{}
|
||||
|
||||
if err := json.Unmarshal(b, &t); err != nil {
|
||||
if testcase.err == nil {
|
||||
failf("error unmarshalling: %v", err)
|
||||
}
|
||||
if err != testcase.err {
|
||||
failf("wrong error, expected %v, got %v", testcase.err, err)
|
||||
}
|
||||
|
||||
continue
|
||||
} else if testcase.err != nil {
|
||||
failf("expected error unmarshalling: %v", testcase.err)
|
||||
}
|
||||
|
||||
if t.Description != testcase.description {
|
||||
failf("wrong description, expected %q, got %q", testcase.description, t.Description)
|
||||
}
|
||||
|
||||
ref := t.Field.Reference()
|
||||
|
||||
if named, ok := ref.(Named); ok {
|
||||
if named.Name() != testcase.name {
|
||||
failf("unexpected repository: got %q, expected %q", named.Name(), testcase.name)
|
||||
}
|
||||
} else if testcase.name != "" {
|
||||
failf("expected named type, got %T", ref)
|
||||
}
|
||||
|
||||
tagged, ok := ref.(Tagged)
|
||||
if testcase.tag != "" {
|
||||
if ok {
|
||||
if tagged.Tag() != testcase.tag {
|
||||
failf("unexpected tag: got %q, expected %q", tagged.Tag(), testcase.tag)
|
||||
}
|
||||
} else {
|
||||
failf("expected tagged type, got %T", ref)
|
||||
}
|
||||
} else if ok {
|
||||
failf("unexpected tagged type")
|
||||
}
|
||||
|
||||
digested, ok := ref.(Digested)
|
||||
if testcase.digest != "" {
|
||||
if ok {
|
||||
if digested.Digest().String() != testcase.digest {
|
||||
failf("unexpected digest: got %q, expected %q", digested.Digest().String(), testcase.digest)
|
||||
}
|
||||
} else {
|
||||
failf("expected digested type, got %T", ref)
|
||||
}
|
||||
} else if ok {
|
||||
failf("unexpected digested type")
|
||||
}
|
||||
|
||||
t = serializationType{
|
||||
Description: testcase.description,
|
||||
Field: AsField(ref),
|
||||
}
|
||||
|
||||
b2, err := json.Marshal(t)
|
||||
if err != nil {
|
||||
failf("error marshing serialization type: %v", err)
|
||||
}
|
||||
|
||||
if string(b) != string(b2) {
|
||||
failf("unexpected serialized value: expected %q, got %q", string(b), string(b2))
|
||||
}
|
||||
|
||||
// Ensure t.Field is not implementing "Reference" directly, getting
|
||||
// around the Reference type system
|
||||
var fieldInterface interface{} = t.Field
|
||||
if _, ok := fieldInterface.(Reference); ok {
|
||||
failf("field should not implement Reference interface")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithTag(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
digest digest.Digest
|
||||
tag string
|
||||
combined string
|
||||
}{
|
||||
{
|
||||
name: "test.com/foo",
|
||||
tag: "tag",
|
||||
combined: "test.com/foo:tag",
|
||||
},
|
||||
{
|
||||
name: "foo",
|
||||
tag: "tag2",
|
||||
combined: "foo:tag2",
|
||||
},
|
||||
{
|
||||
name: "test.com:8000/foo",
|
||||
tag: "tag4",
|
||||
combined: "test.com:8000/foo:tag4",
|
||||
},
|
||||
{
|
||||
name: "test.com:8000/foo",
|
||||
tag: "TAG5",
|
||||
combined: "test.com:8000/foo:TAG5",
|
||||
},
|
||||
{
|
||||
name: "test.com:8000/foo",
|
||||
digest: "sha256:1234567890098765432112345667890098765",
|
||||
tag: "TAG5",
|
||||
combined: "test.com:8000/foo:TAG5@sha256:1234567890098765432112345667890098765",
|
||||
},
|
||||
}
|
||||
for _, testcase := range testcases {
|
||||
failf := func(format string, v ...interface{}) {
|
||||
t.Logf(strconv.Quote(testcase.name)+": "+format, v...)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
named, err := WithName(testcase.name)
|
||||
if err != nil {
|
||||
failf("error parsing name: %s", err)
|
||||
}
|
||||
if testcase.digest != "" {
|
||||
canonical, err := WithDigest(named, testcase.digest)
|
||||
if err != nil {
|
||||
failf("error adding digest")
|
||||
}
|
||||
named = canonical
|
||||
}
|
||||
|
||||
tagged, err := WithTag(named, testcase.tag)
|
||||
if err != nil {
|
||||
failf("WithTag failed: %s", err)
|
||||
}
|
||||
if tagged.String() != testcase.combined {
|
||||
failf("unexpected: got %q, expected %q", tagged.String(), testcase.combined)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithDigest(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
digest digest.Digest
|
||||
tag string
|
||||
combined string
|
||||
}{
|
||||
{
|
||||
name: "test.com/foo",
|
||||
digest: "sha256:1234567890098765432112345667890098765",
|
||||
combined: "test.com/foo@sha256:1234567890098765432112345667890098765",
|
||||
},
|
||||
{
|
||||
name: "foo",
|
||||
digest: "sha256:1234567890098765432112345667890098765",
|
||||
combined: "foo@sha256:1234567890098765432112345667890098765",
|
||||
},
|
||||
{
|
||||
name: "test.com:8000/foo",
|
||||
digest: "sha256:1234567890098765432112345667890098765",
|
||||
combined: "test.com:8000/foo@sha256:1234567890098765432112345667890098765",
|
||||
},
|
||||
{
|
||||
name: "test.com:8000/foo",
|
||||
digest: "sha256:1234567890098765432112345667890098765",
|
||||
tag: "latest",
|
||||
combined: "test.com:8000/foo:latest@sha256:1234567890098765432112345667890098765",
|
||||
},
|
||||
}
|
||||
for _, testcase := range testcases {
|
||||
failf := func(format string, v ...interface{}) {
|
||||
t.Logf(strconv.Quote(testcase.name)+": "+format, v...)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
named, err := WithName(testcase.name)
|
||||
if err != nil {
|
||||
failf("error parsing name: %s", err)
|
||||
}
|
||||
if testcase.tag != "" {
|
||||
tagged, err := WithTag(named, testcase.tag)
|
||||
if err != nil {
|
||||
failf("error adding tag")
|
||||
}
|
||||
named = tagged
|
||||
}
|
||||
digested, err := WithDigest(named, testcase.digest)
|
||||
if err != nil {
|
||||
failf("WithDigest failed: %s", err)
|
||||
}
|
||||
if digested.String() != testcase.combined {
|
||||
failf("unexpected: got %q, expected %q", digested.String(), testcase.combined)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseNamed(t *testing.T) {
|
||||
testcases := []struct {
|
||||
input string
|
||||
domain string
|
||||
name string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
input: "test.com/foo",
|
||||
domain: "test.com",
|
||||
name: "foo",
|
||||
},
|
||||
{
|
||||
input: "test:8080/foo",
|
||||
domain: "test:8080",
|
||||
name: "foo",
|
||||
},
|
||||
{
|
||||
input: "test_com/foo",
|
||||
err: ErrNameNotCanonical,
|
||||
},
|
||||
{
|
||||
input: "test.com",
|
||||
err: ErrNameNotCanonical,
|
||||
},
|
||||
{
|
||||
input: "foo",
|
||||
err: ErrNameNotCanonical,
|
||||
},
|
||||
{
|
||||
input: "library/foo",
|
||||
err: ErrNameNotCanonical,
|
||||
},
|
||||
{
|
||||
input: "docker.io/library/foo",
|
||||
domain: "docker.io",
|
||||
name: "library/foo",
|
||||
},
|
||||
// Ambiguous case, parser will add "library/" to foo
|
||||
{
|
||||
input: "docker.io/foo",
|
||||
err: ErrNameNotCanonical,
|
||||
},
|
||||
}
|
||||
for _, testcase := range testcases {
|
||||
failf := func(format string, v ...interface{}) {
|
||||
t.Logf(strconv.Quote(testcase.input)+": "+format, v...)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
named, err := ParseNamed(testcase.input)
|
||||
if err != nil && testcase.err == nil {
|
||||
failf("error parsing name: %s", err)
|
||||
continue
|
||||
} else if err == nil && testcase.err != nil {
|
||||
failf("parsing succeded: expected error %v", testcase.err)
|
||||
continue
|
||||
} else if err != testcase.err {
|
||||
failf("unexpected error %v, expected %v", err, testcase.err)
|
||||
continue
|
||||
} else if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
domain, name := SplitHostname(named)
|
||||
if domain != testcase.domain {
|
||||
failf("unexpected domain: got %q, expected %q", domain, testcase.domain)
|
||||
}
|
||||
if name != testcase.name {
|
||||
failf("unexpected name: got %q, expected %q", name, testcase.name)
|
||||
}
|
||||
}
|
||||
}
|
553
vendor/github.com/containers/image/docker/reference/regexp_test.go
generated
vendored
553
vendor/github.com/containers/image/docker/reference/regexp_test.go
generated
vendored
|
@ -1,553 +0,0 @@
|
|||
package reference
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type regexpMatch struct {
|
||||
input string
|
||||
match bool
|
||||
subs []string
|
||||
}
|
||||
|
||||
func checkRegexp(t *testing.T, r *regexp.Regexp, m regexpMatch) {
|
||||
matches := r.FindStringSubmatch(m.input)
|
||||
if m.match && matches != nil {
|
||||
if len(matches) != (r.NumSubexp()+1) || matches[0] != m.input {
|
||||
t.Fatalf("Bad match result %#v for %q", matches, m.input)
|
||||
}
|
||||
if len(matches) < (len(m.subs) + 1) {
|
||||
t.Errorf("Expected %d sub matches, only have %d for %q", len(m.subs), len(matches)-1, m.input)
|
||||
}
|
||||
for i := range m.subs {
|
||||
if m.subs[i] != matches[i+1] {
|
||||
t.Errorf("Unexpected submatch %d: %q, expected %q for %q", i+1, matches[i+1], m.subs[i], m.input)
|
||||
}
|
||||
}
|
||||
} else if m.match {
|
||||
t.Errorf("Expected match for %q", m.input)
|
||||
} else if matches != nil {
|
||||
t.Errorf("Unexpected match for %q", m.input)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDomainRegexp(t *testing.T) {
|
||||
hostcases := []regexpMatch{
|
||||
{
|
||||
input: "test.com",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "test.com:10304",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "test.com:http",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "localhost",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "localhost:8080",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "a",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "a.b",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "ab.cd.com",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "a-b.com",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "-ab.com",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "ab-.com",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "ab.c-om",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "ab.-com",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "ab.com-",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "0101.com",
|
||||
match: true, // TODO(dmcgowan): valid if this should be allowed
|
||||
},
|
||||
{
|
||||
input: "001a.com",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "b.gbc.io:443",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "b.gbc.io",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "xn--n3h.com", // ☃.com in punycode
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "Asdf.com", // uppercase character
|
||||
match: true,
|
||||
},
|
||||
}
|
||||
r := regexp.MustCompile(`^` + domainRegexp.String() + `$`)
|
||||
for i := range hostcases {
|
||||
checkRegexp(t, r, hostcases[i])
|
||||
}
|
||||
}
|
||||
|
||||
func TestFullNameRegexp(t *testing.T) {
|
||||
if anchoredNameRegexp.NumSubexp() != 2 {
|
||||
t.Fatalf("anchored name regexp should have two submatches: %v, %v != 2",
|
||||
anchoredNameRegexp, anchoredNameRegexp.NumSubexp())
|
||||
}
|
||||
|
||||
testcases := []regexpMatch{
|
||||
{
|
||||
input: "",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "short",
|
||||
match: true,
|
||||
subs: []string{"", "short"},
|
||||
},
|
||||
{
|
||||
input: "simple/name",
|
||||
match: true,
|
||||
subs: []string{"simple", "name"},
|
||||
},
|
||||
{
|
||||
input: "library/ubuntu",
|
||||
match: true,
|
||||
subs: []string{"library", "ubuntu"},
|
||||
},
|
||||
{
|
||||
input: "docker/stevvooe/app",
|
||||
match: true,
|
||||
subs: []string{"docker", "stevvooe/app"},
|
||||
},
|
||||
{
|
||||
input: "aa/aa/aa/aa/aa/aa/aa/aa/aa/bb/bb/bb/bb/bb/bb",
|
||||
match: true,
|
||||
subs: []string{"aa", "aa/aa/aa/aa/aa/aa/aa/aa/bb/bb/bb/bb/bb/bb"},
|
||||
},
|
||||
{
|
||||
input: "aa/aa/bb/bb/bb",
|
||||
match: true,
|
||||
subs: []string{"aa", "aa/bb/bb/bb"},
|
||||
},
|
||||
{
|
||||
input: "a/a/a/a",
|
||||
match: true,
|
||||
subs: []string{"a", "a/a/a"},
|
||||
},
|
||||
{
|
||||
input: "a/a/a/a/",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "a//a/a",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "a",
|
||||
match: true,
|
||||
subs: []string{"", "a"},
|
||||
},
|
||||
{
|
||||
input: "a/aa",
|
||||
match: true,
|
||||
subs: []string{"a", "aa"},
|
||||
},
|
||||
{
|
||||
input: "a/aa/a",
|
||||
match: true,
|
||||
subs: []string{"a", "aa/a"},
|
||||
},
|
||||
{
|
||||
input: "foo.com",
|
||||
match: true,
|
||||
subs: []string{"", "foo.com"},
|
||||
},
|
||||
{
|
||||
input: "foo.com/",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "foo.com:8080/bar",
|
||||
match: true,
|
||||
subs: []string{"foo.com:8080", "bar"},
|
||||
},
|
||||
{
|
||||
input: "foo.com:http/bar",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "foo.com/bar",
|
||||
match: true,
|
||||
subs: []string{"foo.com", "bar"},
|
||||
},
|
||||
{
|
||||
input: "foo.com/bar/baz",
|
||||
match: true,
|
||||
subs: []string{"foo.com", "bar/baz"},
|
||||
},
|
||||
{
|
||||
input: "localhost:8080/bar",
|
||||
match: true,
|
||||
subs: []string{"localhost:8080", "bar"},
|
||||
},
|
||||
{
|
||||
input: "sub-dom1.foo.com/bar/baz/quux",
|
||||
match: true,
|
||||
subs: []string{"sub-dom1.foo.com", "bar/baz/quux"},
|
||||
},
|
||||
{
|
||||
input: "blog.foo.com/bar/baz",
|
||||
match: true,
|
||||
subs: []string{"blog.foo.com", "bar/baz"},
|
||||
},
|
||||
{
|
||||
input: "a^a",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "aa/asdf$$^/aa",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "asdf$$^/aa",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "aa-a/a",
|
||||
match: true,
|
||||
subs: []string{"aa-a", "a"},
|
||||
},
|
||||
{
|
||||
input: strings.Repeat("a/", 128) + "a",
|
||||
match: true,
|
||||
subs: []string{"a", strings.Repeat("a/", 127) + "a"},
|
||||
},
|
||||
{
|
||||
input: "a-/a/a/a",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "foo.com/a-/a/a",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "-foo/bar",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "foo/bar-",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "foo-/bar",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "foo/-bar",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "_foo/bar",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "foo_bar",
|
||||
match: true,
|
||||
subs: []string{"", "foo_bar"},
|
||||
},
|
||||
{
|
||||
input: "foo_bar.com",
|
||||
match: true,
|
||||
subs: []string{"", "foo_bar.com"},
|
||||
},
|
||||
{
|
||||
input: "foo_bar.com:8080",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "foo_bar.com:8080/app",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "foo.com/foo_bar",
|
||||
match: true,
|
||||
subs: []string{"foo.com", "foo_bar"},
|
||||
},
|
||||
{
|
||||
input: "____/____",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "_docker/_docker",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "docker_/docker_",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "b.gcr.io/test.example.com/my-app",
|
||||
match: true,
|
||||
subs: []string{"b.gcr.io", "test.example.com/my-app"},
|
||||
},
|
||||
{
|
||||
input: "xn--n3h.com/myimage", // ☃.com in punycode
|
||||
match: true,
|
||||
subs: []string{"xn--n3h.com", "myimage"},
|
||||
},
|
||||
{
|
||||
input: "xn--7o8h.com/myimage", // 🐳.com in punycode
|
||||
match: true,
|
||||
subs: []string{"xn--7o8h.com", "myimage"},
|
||||
},
|
||||
{
|
||||
input: "example.com/xn--7o8h.com/myimage", // 🐳.com in punycode
|
||||
match: true,
|
||||
subs: []string{"example.com", "xn--7o8h.com/myimage"},
|
||||
},
|
||||
{
|
||||
input: "example.com/some_separator__underscore/myimage",
|
||||
match: true,
|
||||
subs: []string{"example.com", "some_separator__underscore/myimage"},
|
||||
},
|
||||
{
|
||||
input: "example.com/__underscore/myimage",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "example.com/..dots/myimage",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "example.com/.dots/myimage",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "example.com/nodouble..dots/myimage",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "example.com/nodouble..dots/myimage",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "docker./docker",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: ".docker/docker",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "docker-/docker",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "-docker/docker",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "do..cker/docker",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "do__cker:8080/docker",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "do__cker/docker",
|
||||
match: true,
|
||||
subs: []string{"", "do__cker/docker"},
|
||||
},
|
||||
{
|
||||
input: "b.gcr.io/test.example.com/my-app",
|
||||
match: true,
|
||||
subs: []string{"b.gcr.io", "test.example.com/my-app"},
|
||||
},
|
||||
{
|
||||
input: "registry.io/foo/project--id.module--name.ver---sion--name",
|
||||
match: true,
|
||||
subs: []string{"registry.io", "foo/project--id.module--name.ver---sion--name"},
|
||||
},
|
||||
{
|
||||
input: "Asdf.com/foo/bar", // uppercase character in hostname
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "Foo/FarB", // uppercase characters in remote name
|
||||
match: false,
|
||||
},
|
||||
}
|
||||
for i := range testcases {
|
||||
checkRegexp(t, anchoredNameRegexp, testcases[i])
|
||||
}
|
||||
}
|
||||
|
||||
func TestReferenceRegexp(t *testing.T) {
|
||||
if ReferenceRegexp.NumSubexp() != 3 {
|
||||
t.Fatalf("anchored name regexp should have three submatches: %v, %v != 3",
|
||||
ReferenceRegexp, ReferenceRegexp.NumSubexp())
|
||||
}
|
||||
|
||||
testcases := []regexpMatch{
|
||||
{
|
||||
input: "registry.com:8080/myapp:tag",
|
||||
match: true,
|
||||
subs: []string{"registry.com:8080/myapp", "tag", ""},
|
||||
},
|
||||
{
|
||||
input: "registry.com:8080/myapp@sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912",
|
||||
match: true,
|
||||
subs: []string{"registry.com:8080/myapp", "", "sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912"},
|
||||
},
|
||||
{
|
||||
input: "registry.com:8080/myapp:tag2@sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912",
|
||||
match: true,
|
||||
subs: []string{"registry.com:8080/myapp", "tag2", "sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912"},
|
||||
},
|
||||
{
|
||||
input: "registry.com:8080/myapp@sha256:badbadbadbad",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "registry.com:8080/myapp:invalid~tag",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "bad_hostname.com:8080/myapp:tag",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input:// localhost treated as name, missing tag with 8080 as tag
|
||||
"localhost:8080@sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912",
|
||||
match: true,
|
||||
subs: []string{"localhost", "8080", "sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912"},
|
||||
},
|
||||
{
|
||||
input: "localhost:8080/name@sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912",
|
||||
match: true,
|
||||
subs: []string{"localhost:8080/name", "", "sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912"},
|
||||
},
|
||||
{
|
||||
input: "localhost:http/name@sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
// localhost will be treated as an image name without a host
|
||||
input: "localhost@sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912",
|
||||
match: true,
|
||||
subs: []string{"localhost", "", "sha256:be178c0543eb17f5f3043021c9e5fcf30285e557a4fc309cce97ff9ca6182912"},
|
||||
},
|
||||
{
|
||||
input: "registry.com:8080/myapp@bad",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "registry.com:8080/myapp@2bad",
|
||||
match: false, // TODO(dmcgowan): Support this as valid
|
||||
},
|
||||
}
|
||||
|
||||
for i := range testcases {
|
||||
checkRegexp(t, ReferenceRegexp, testcases[i])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestIdentifierRegexp(t *testing.T) {
|
||||
fullCases := []regexpMatch{
|
||||
{
|
||||
input: "da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf9821",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "7EC43B381E5AEFE6E04EFB0B3F0693FF2A4A50652D64AEC573905F2DB5889A1C",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "sha256:da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf9821",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf98218482",
|
||||
match: false,
|
||||
},
|
||||
}
|
||||
|
||||
shortCases := []regexpMatch{
|
||||
{
|
||||
input: "da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf9821",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "7EC43B381E5AEFE6E04EFB0B3F0693FF2A4A50652D64AEC573905F2DB5889A1C",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf",
|
||||
match: true,
|
||||
},
|
||||
{
|
||||
input: "sha256:da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf9821",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "da304e823d8ca2b9d863a3c897baeb852ba21ea9a9f1414736394ae7fcaf98218482",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "da304",
|
||||
match: false,
|
||||
},
|
||||
{
|
||||
input: "da304e",
|
||||
match: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i := range fullCases {
|
||||
checkRegexp(t, anchoredIdentifierRegexp, fullCases[i])
|
||||
}
|
||||
|
||||
for i := range shortCases {
|
||||
checkRegexp(t, anchoredShortIdentifierRegexp, shortCases[i])
|
||||
}
|
||||
}
|
45
vendor/github.com/containers/image/docker/wwwauthenticate_test.go
generated
vendored
45
vendor/github.com/containers/image/docker/wwwauthenticate_test.go
generated
vendored
|
@ -1,45 +0,0 @@
|
|||
package docker
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// This is just a smoke test for the common expected header formats,
|
||||
// by no means comprehensive.
|
||||
func TestParseValueAndParams(t *testing.T) {
|
||||
for _, c := range []struct {
|
||||
input string
|
||||
scope string
|
||||
params map[string]string
|
||||
}{
|
||||
{
|
||||
`Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:library/busybox:pull"`,
|
||||
"bearer",
|
||||
map[string]string{
|
||||
"realm": "https://auth.docker.io/token",
|
||||
"service": "registry.docker.io",
|
||||
"scope": "repository:library/busybox:pull",
|
||||
},
|
||||
},
|
||||
{
|
||||
`Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:library/busybox:pull,push"`,
|
||||
"bearer",
|
||||
map[string]string{
|
||||
"realm": "https://auth.docker.io/token",
|
||||
"service": "registry.docker.io",
|
||||
"scope": "repository:library/busybox:pull,push",
|
||||
},
|
||||
},
|
||||
{
|
||||
`Bearer realm="http://127.0.0.1:5000/openshift/token"`,
|
||||
"bearer",
|
||||
map[string]string{"realm": "http://127.0.0.1:5000/openshift/token"},
|
||||
},
|
||||
} {
|
||||
scope, params := parseValueAndParams(c.input)
|
||||
assert.Equal(t, c.scope, scope, c.input)
|
||||
assert.Equal(t, c.params, params, c.input)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue