image/docker/archive/transport_test.go

290 lines
9.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package archive
import (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/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
expectedSourceIndex int
}{
{"", "", "", -1}, // Empty input is explicitly rejected
{"/path", "/path", "", -1},
{"/path:busybox:notlatest", "/path", "docker.io/library/busybox:notlatest", -1}, // Explicit tag
{"/path:busybox" + sha256digest, "", "", -1}, // Digest references are forbidden
{"/path:busybox", "/path", "docker.io/library/busybox:latest", -1}, // Default tag
// A github.com/distribution/reference value can have a tag and a digest at the same time!
{"/path:busybox:latest" + sha256digest, "", "", -1}, // Both tag and digest is rejected
{"/path:docker.io/library/busybox:latest", "/path", "docker.io/library/busybox:latest", -1}, // All implied reference parts explicitly specified
{"/path:UPPERCASEISINVALID", "", "", -1}, // Invalid reference format
{"/path:@", "", "", -1}, // Missing source index
{"/path:@0", "/path", "", 0}, // Valid source index
{"/path:@999999", "/path", "", 999999}, // Valid source index
{"/path:@-2", "", "", -1}, // Negative source index
{"/path:@-1", "", "", -1}, // Negative source index, using the placeholder value
{"/path:busybox@0", "", "", -1}, // References and source indices cant be combined.
{"/path:@0:busybox", "", "", -1}, // References and source indices cant be combined.
} {
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.ref, c.input)
} else {
require.NotNil(t, archiveRef.ref, c.input)
assert.Equal(t, c.expectedRef, archiveRef.ref.String(), c.input)
}
assert.Equal(t, c.expectedSourceIndex, archiveRef.sourceIndex, c.input)
}
}
}
// namedTaggedRef returns a reference.NamedTagged for input
func namedTaggedRef(t *testing.T, input string) reference.NamedTagged {
named, err := reference.ParseNormalizedNamed(input)
require.NoError(t, err, input)
nt, ok := named.(reference.NamedTagged)
require.True(t, ok, input)
return nt
}
func TestNewReference(t *testing.T) {
for _, path := range []string{"relative", "/absolute"} {
for _, c := range []struct {
ref string
ok bool
}{
{"busybox:notlatest", true},
{"busybox:notlatest" + sha256digest, false},
{"", true},
} {
var ntRef reference.NamedTagged = nil
if c.ref != "" {
ntRef = namedTaggedRef(t, c.ref)
}
res, err := NewReference(path, ntRef)
if !c.ok {
assert.Error(t, err, c.ref)
} else {
require.NoError(t, err, c.ref)
archiveRef, ok := res.(archiveReference)
require.True(t, ok, c.ref)
assert.Equal(t, path, archiveRef.path)
if c.ref == "" {
assert.Nil(t, archiveRef.ref, c.ref)
} else {
require.NotNil(t, archiveRef.ref, c.ref)
assert.Equal(t, ntRef.String(), archiveRef.ref.String(), c.ref)
}
assert.Equal(t, -1, archiveRef.sourceIndex, c.ref)
}
}
}
_, err := NewReference("with:colon", nil)
assert.Error(t, err)
// Complete coverage testing of the private newReference here as well
ntRef := namedTaggedRef(t, "busybox:latest")
_, err = newReference("path", ntRef, 0, nil, nil)
assert.Error(t, err)
}
func TestNewIndexReference(t *testing.T) {
for _, path := range []string{"relative", "/absolute"} {
for _, c := range []struct {
index int
ok bool
}{
{0, true},
{9999990, true},
{-1, true},
{-2, false},
} {
res, err := NewIndexReference(path, c.index)
if !c.ok {
assert.Error(t, err, c.index)
} else {
require.NoError(t, err, c.index)
archiveRef, ok := res.(archiveReference)
require.True(t, ok, c.index)
assert.Equal(t, path, archiveRef.path)
assert.Nil(t, archiveRef.ref, c.index)
assert.Equal(t, c.index, archiveRef.sourceIndex)
}
}
}
_, err := NewReference("with:colon", nil)
assert.Error(t, err)
}
// A common list of reference formats to test for the various ImageReference methods.
var validReferenceTestCases = []struct {
input, dockerRef string
sourceIndex int
stringWithinTransport string
}{
{"/pathonly", "", -1, "/pathonly"},
{"/path:busybox:notlatest", "docker.io/library/busybox:notlatest", -1, "/path:docker.io/library/busybox:notlatest"}, // Explicit tag
{"/path:docker.io/library/busybox:latest", "docker.io/library/busybox:latest", -1, "/path:docker.io/library/busybox:latest"}, // All implied reference part explicitly specified
{"/path:example.com/ns/foo:bar", "example.com/ns/foo:bar", -1, "/path:example.com/ns/foo:bar"}, // All values explicitly specified
{"/path:@0", "", 0, "/path:@0"},
{"/path:@999999", "", 999999, "/path:@999999"},
}
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{"", ":emptyimage:latest", ":@0"} {
ref, err := ParseReference(tarFixture + suffix)
require.NoError(t, err, suffix)
img, err := ref.NewImage(context.Background(), nil)
require.NoError(t, err, suffix)
defer img.Close()
}
}
func TestReferenceNewImageSource(t *testing.T) {
for _, suffix := range []string{"", ":emptyimage:latest", ":@0"} {
ref, err := ParseReference(tarFixture + suffix)
require.NoError(t, err, suffix)
src, err := ref.NewImageSource(context.Background(), nil)
require.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(context.Background(), nil)
assert.NoError(t, err)
dest.Close()
ref, err = ParseReference(filepath.Join(tmpDir, "with-reference") + "busybox:latest")
require.NoError(t, err)
dest, err = ref.NewImageDestination(context.Background(), 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{"", ":some-reference", ":@0"} {
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(context.Background(), nil)
assert.Error(t, err, suffix)
_, err = os.Lstat(testFile)
assert.NoError(t, err, suffix)
}
}