image/directory/directory_test.go

211 lines
6.7 KiB
Go
Raw Permalink 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 directory
import (
"bytes"
"context"
"errors"
"io"
"os"
"testing"
"github.com/containers/image/v5/internal/private"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/pkg/blobinfocache/memory"
"github.com/containers/image/v5/types"
"github.com/opencontainers/go-digest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var _ private.ImageSource = (*dirImageSource)(nil)
var _ private.ImageDestination = (*dirImageDestination)(nil)
func TestDestinationReference(t *testing.T) {
ref, tmpDir := refToTempDir(t)
dest, err := ref.NewImageDestination(context.Background(), nil)
require.NoError(t, err)
defer dest.Close()
ref2 := dest.Reference()
assert.Equal(t, tmpDir, ref2.StringWithinTransport())
}
func TestGetPutManifest(t *testing.T) {
ref, _ := refToTempDir(t)
man := []byte("test-manifest")
list := []byte("test-manifest-list")
md, err := manifest.Digest(man)
require.NoError(t, err)
dest, err := ref.NewImageDestination(context.Background(), nil)
require.NoError(t, err)
defer dest.Close()
err = dest.PutManifest(context.Background(), man, &md)
assert.NoError(t, err)
err = dest.PutManifest(context.Background(), list, nil)
assert.NoError(t, err)
err = dest.Commit(context.Background(), nil) // nil unparsedToplevel is invalid, we dont currently use the value
assert.NoError(t, err)
src, err := ref.NewImageSource(context.Background(), nil)
require.NoError(t, err)
defer src.Close()
m, mt, err := src.GetManifest(context.Background(), nil)
assert.NoError(t, err)
assert.Equal(t, list, m)
assert.Equal(t, "", mt)
m, mt, err = src.GetManifest(context.Background(), &md)
assert.NoError(t, err)
assert.Equal(t, man, m)
assert.Equal(t, "", mt)
}
func TestGetPutBlob(t *testing.T) {
computedBlob := []byte("test-blob")
providedBlob := []byte("provided-blob")
providedDigest := digest.Digest("sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
ref, _ := refToTempDir(t)
cache := memory.New()
dest, err := ref.NewImageDestination(context.Background(), nil)
require.NoError(t, err)
defer dest.Close()
assert.Equal(t, types.PreserveOriginal, dest.DesiredLayerCompression())
// PutBlob with caller-provided data
providedInfo, err := dest.PutBlob(context.Background(), bytes.NewReader(providedBlob), types.BlobInfo{Digest: providedDigest, Size: int64(len(providedBlob))}, cache, false)
assert.NoError(t, err)
assert.Equal(t, int64(len(providedBlob)), providedInfo.Size)
assert.Equal(t, providedDigest, providedInfo.Digest)
// PutBlob with unknown data
computedInfo, err := dest.PutBlob(context.Background(), bytes.NewReader(computedBlob), types.BlobInfo{Digest: "", Size: int64(-1)}, cache, false)
assert.NoError(t, err)
assert.Equal(t, int64(len(computedBlob)), computedInfo.Size)
assert.Equal(t, digest.FromBytes(computedBlob), computedInfo.Digest)
err = dest.Commit(context.Background(), nil) // nil unparsedToplevel is invalid, we dont currently use the value
assert.NoError(t, err)
src, err := ref.NewImageSource(context.Background(), nil)
require.NoError(t, err)
defer src.Close()
for digest, expectedBlob := range map[digest.Digest][]byte{
providedInfo.Digest: providedBlob,
computedInfo.Digest: computedBlob,
} {
rc, size, err := src.GetBlob(context.Background(), types.BlobInfo{Digest: digest, Size: int64(len(expectedBlob))}, cache)
assert.NoError(t, err)
defer rc.Close()
b, err := io.ReadAll(rc)
assert.NoError(t, err)
assert.Equal(t, expectedBlob, b)
assert.Equal(t, int64(len(expectedBlob)), size)
}
}
// readerFromFunc allows implementing Reader by any function, e.g. a closure.
type readerFromFunc func([]byte) (int, error)
func (fn readerFromFunc) Read(p []byte) (int, error) {
return fn(p)
}
// TestPutBlobDigestFailure simulates behavior on digest verification failure.
func TestPutBlobDigestFailure(t *testing.T) {
const digestErrorString = "Simulated digest error"
const blobDigest = digest.Digest("sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
ref, _ := refToTempDir(t)
dirRef, ok := ref.(dirReference)
require.True(t, ok)
blobPath, err := dirRef.layerPath(blobDigest)
require.NoError(t, err)
cache := memory.New()
firstRead := true
reader := readerFromFunc(func(p []byte) (int, error) {
_, err := os.Lstat(blobPath)
require.Error(t, err)
require.True(t, os.IsNotExist(err))
if firstRead {
if len(p) > 0 {
firstRead = false
}
for i := 0; i < len(p); i++ {
p[i] = 0xAA
}
return len(p), nil
}
return 0, errors.New(digestErrorString)
})
dest, err := ref.NewImageDestination(context.Background(), nil)
require.NoError(t, err)
defer dest.Close()
_, err = dest.PutBlob(context.Background(), reader, types.BlobInfo{Digest: blobDigest, Size: -1}, cache, false)
assert.ErrorContains(t, err, digestErrorString)
err = dest.Commit(context.Background(), nil) // nil unparsedToplevel is invalid, we dont currently use the value
assert.NoError(t, err)
_, err = os.Lstat(blobPath)
require.Error(t, err)
require.True(t, os.IsNotExist(err))
}
func TestGetPutSignatures(t *testing.T) {
ref, _ := refToTempDir(t)
man := []byte("test-manifest")
list := []byte("test-manifest-list")
md, err := manifest.Digest(man)
require.NoError(t, err)
// These signatures are completely invalid; start with 0xA3 just to be minimally plausible to signature.FromBlob.
signatures := [][]byte{
[]byte("\xA3sig1"),
[]byte("\xA3sig2"),
}
listSignatures := [][]byte{
[]byte("\xA3sig3"),
[]byte("\xA3sig4"),
}
dest, err := ref.NewImageDestination(context.Background(), nil)
require.NoError(t, err)
defer dest.Close()
err = dest.SupportsSignatures(context.Background())
assert.NoError(t, err)
err = dest.PutManifest(context.Background(), man, &md)
require.NoError(t, err)
err = dest.PutManifest(context.Background(), list, nil)
require.NoError(t, err)
err = dest.PutSignatures(context.Background(), signatures, &md)
assert.NoError(t, err)
err = dest.PutSignatures(context.Background(), listSignatures, nil)
assert.NoError(t, err)
err = dest.Commit(context.Background(), nil) // nil unparsedToplevel is invalid, we dont currently use the value
assert.NoError(t, err)
src, err := ref.NewImageSource(context.Background(), nil)
require.NoError(t, err)
defer src.Close()
sigs, err := src.GetSignatures(context.Background(), nil)
assert.NoError(t, err)
assert.Equal(t, listSignatures, sigs)
sigs, err = src.GetSignatures(context.Background(), &md)
assert.NoError(t, err)
assert.Equal(t, signatures, sigs)
}
func TestSourceReference(t *testing.T) {
ref, tmpDir := refToTempDir(t)
src, err := ref.NewImageSource(context.Background(), nil)
require.NoError(t, err)
defer src.Close()
ref2 := src.Reference()
assert.Equal(t, tmpDir, ref2.StringWithinTransport())
}