libimage: add save tests
Add save tests. Also fix a bug when saving a single image but with multiple tags. Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
parent
73305281fd
commit
9c6c0eab43
|
|
@ -57,9 +57,13 @@ func (r *Runtime) Save(ctx context.Context, names []string, format, path string,
|
||||||
// Dispatch the save operations.
|
// Dispatch the save operations.
|
||||||
switch format {
|
switch format {
|
||||||
case "oci-archive", "oci-dir", "docker-dir":
|
case "oci-archive", "oci-dir", "docker-dir":
|
||||||
|
if len(names) > 1 {
|
||||||
|
return errors.Errorf("%q does not support saving multiple images (%v)", format, names)
|
||||||
|
}
|
||||||
return r.saveSingleImage(ctx, names[0], format, path, options)
|
return r.saveSingleImage(ctx, names[0], format, path, options)
|
||||||
|
|
||||||
case "docker-archive":
|
case "docker-archive":
|
||||||
|
options.ManifestMIMEType = manifest.DockerV2Schema2MediaType
|
||||||
return r.saveDockerArchive(ctx, names, path, options)
|
return r.saveDockerArchive(ctx, names, path, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -134,6 +138,18 @@ func (r *Runtime) saveDockerArchive(ctx context.Context, names []string, path st
|
||||||
tags []reference.NamedTagged
|
tags []reference.NamedTagged
|
||||||
}
|
}
|
||||||
|
|
||||||
|
additionalTags := []reference.NamedTagged{}
|
||||||
|
for _, tag := range options.AdditionalTags {
|
||||||
|
named, err := NormalizeName(tag)
|
||||||
|
if err == nil {
|
||||||
|
tagged, withTag := named.(reference.NamedTagged)
|
||||||
|
if !withTag {
|
||||||
|
return errors.Errorf("invalid additional tag %q: normalized to untagged %q", tag, named.String())
|
||||||
|
}
|
||||||
|
additionalTags = append(additionalTags, tagged)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
orderedIDs := []string{} // to preserve the relative order
|
orderedIDs := []string{} // to preserve the relative order
|
||||||
localImages := make(map[string]*localImage) // to assemble tags
|
localImages := make(map[string]*localImage) // to assemble tags
|
||||||
visitedNames := make(map[string]bool) // filters duplicate names
|
visitedNames := make(map[string]bool) // filters duplicate names
|
||||||
|
|
@ -153,6 +169,7 @@ func (r *Runtime) saveDockerArchive(ctx context.Context, names []string, path st
|
||||||
local, exists := localImages[image.ID()]
|
local, exists := localImages[image.ID()]
|
||||||
if !exists {
|
if !exists {
|
||||||
local = &localImage{image: image}
|
local = &localImage{image: image}
|
||||||
|
local.tags = additionalTags
|
||||||
orderedIDs = append(orderedIDs, image.ID())
|
orderedIDs = append(orderedIDs, image.ID())
|
||||||
}
|
}
|
||||||
// Add the tag if the locally resolved name is properly tagged
|
// Add the tag if the locally resolved name is properly tagged
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
package libimage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/containers/common/pkg/config"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSave(t *testing.T) {
|
||||||
|
runtime, cleanup := testNewRuntime(t)
|
||||||
|
defer cleanup()
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
// Prefetch alpine, busybox.
|
||||||
|
pullOptions := &PullOptions{}
|
||||||
|
pullOptions.Writer = os.Stdout
|
||||||
|
_, err := runtime.Pull(ctx, "docker.io/library/alpine:latest", config.PullPolicyAlways, pullOptions)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = runtime.Pull(ctx, "docker.io/library/busybox:latest", config.PullPolicyAlways, pullOptions)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Save the two images into a multi-image archive. This way, we can
|
||||||
|
// reload the images for each test.
|
||||||
|
saveOptions := &SaveOptions{}
|
||||||
|
saveOptions.Writer = os.Stdout
|
||||||
|
imageCache, err := ioutil.TempFile("", "saveimagecache")
|
||||||
|
require.NoError(t, err)
|
||||||
|
imageCache.Close()
|
||||||
|
defer os.Remove(imageCache.Name())
|
||||||
|
err = runtime.Save(ctx, []string{"alpine", "busybox"}, "docker-archive", imageCache.Name(), saveOptions)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
loadOptions := &LoadOptions{}
|
||||||
|
loadOptions.Writer = os.Stdout
|
||||||
|
|
||||||
|
// The table tests are smoke tests to exercise the different code
|
||||||
|
// paths. More detailed tests follow below.
|
||||||
|
for _, test := range []struct {
|
||||||
|
names []string
|
||||||
|
tags []string
|
||||||
|
format string
|
||||||
|
isDir bool
|
||||||
|
expectError bool
|
||||||
|
}{
|
||||||
|
// No `names`
|
||||||
|
{nil, nil, "", false, true},
|
||||||
|
{[]string{}, nil, "", false, true},
|
||||||
|
// Invalid/unsupported format
|
||||||
|
{[]string{"something"}, nil, "", false, true},
|
||||||
|
{[]string{"something"}, nil, "else", false, true},
|
||||||
|
// oci
|
||||||
|
{[]string{"busybox"}, nil, "oci-dir", true, false},
|
||||||
|
{[]string{"busybox"}, nil, "oci-archive", false, false},
|
||||||
|
// oci-archive doesn't support multi-image archives
|
||||||
|
{[]string{"busybox", "alpine"}, nil, "oci-archive", false, true},
|
||||||
|
// docker
|
||||||
|
{[]string{"busybox"}, nil, "docker-archive", false, false},
|
||||||
|
{[]string{"busybox"}, []string{"localhost/tag:1", "quay.io/repo/image:tag"}, "docker-archive", false, false},
|
||||||
|
{[]string{"busybox"}, nil, "docker-dir", true, false},
|
||||||
|
{[]string{"busybox", "alpine"}, nil, "docker-archive", false, false},
|
||||||
|
// additional tags and multi-images conflict
|
||||||
|
{[]string{"busybox", "alpine"}, []string{"tag"}, "docker-archive", false, true},
|
||||||
|
} {
|
||||||
|
// First clean up all images and load the cache.
|
||||||
|
_, rmErrors := runtime.RemoveImages(ctx, nil, nil)
|
||||||
|
require.Nil(t, rmErrors)
|
||||||
|
_, err = runtime.Load(ctx, imageCache.Name(), loadOptions)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tmp, err := ioutil.TempDir("", "libimagesavetest")
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer os.RemoveAll(tmp)
|
||||||
|
if !test.isDir {
|
||||||
|
tmp += "/archive.tar"
|
||||||
|
}
|
||||||
|
|
||||||
|
saveOptions.AdditionalTags = test.tags
|
||||||
|
err = runtime.Save(ctx, test.names, test.format, tmp, saveOptions)
|
||||||
|
if test.expectError {
|
||||||
|
require.Error(t, err, "%v", test)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
require.NoError(t, err, "%v", test)
|
||||||
|
|
||||||
|
// Now remove all images again and attempt to load the
|
||||||
|
// previously saved ones.
|
||||||
|
_, rmErrors = runtime.RemoveImages(ctx, nil, nil)
|
||||||
|
require.Nil(t, rmErrors)
|
||||||
|
|
||||||
|
namesAndTags := append(test.names, test.tags...)
|
||||||
|
loadedImages, err := runtime.Load(ctx, tmp, loadOptions)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, loadedImages, len(namesAndTags))
|
||||||
|
|
||||||
|
// Now make sure that all specified names (and tags) resolve to
|
||||||
|
// an image the local containers storage. Note that names are
|
||||||
|
// only preserved in archives.
|
||||||
|
if strings.HasSuffix(test.format, "-dir") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, err = runtime.ListImages(ctx, namesAndTags, nil)
|
||||||
|
require.NoError(t, err, "%v", test)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue