Compare commits

...

1 Commits

Author SHA1 Message Date
Philip Laine
4694b53177
Rename mock client to memory client and add tests 2024-05-23 10:22:23 +02:00
6 changed files with 142 additions and 118 deletions

View File

@ -5,10 +5,19 @@ import (
"fmt" "fmt"
iofs "io/fs" iofs "io/fs"
"net/url" "net/url"
"path"
"testing" "testing"
"github.com/containerd/containerd"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/content/local"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/metadata"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/spf13/afero" "github.com/spf13/afero"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
bolt "go.etcd.io/bbolt"
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1" runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
) )
@ -384,3 +393,47 @@ func stringListToUrlList(t *testing.T, list []string) []url.URL {
} }
return urls return urls
} }
func createTestContainerd(t *testing.T, ctx context.Context, imgs []map[string]string, blobs map[digest.Digest][]byte, enableLocalStore bool) *Containerd {
t.Helper()
contentPath := t.TempDir()
contentStore, err := local.NewStore(contentPath)
require.NoError(t, err)
boltDB, err := bolt.Open(path.Join(t.TempDir(), "bolt.db"), 0o644, nil)
require.NoError(t, err)
db := metadata.NewDB(boltDB, contentStore, nil)
imageStore := metadata.NewImageStore(db)
for _, img := range imgs {
dgst, err := digest.Parse(img["digest"])
require.NoError(t, err)
cImg := images.Image{
Name: img["name"],
Target: ocispec.Descriptor{
MediaType: img["mediaType"],
Digest: dgst,
Size: int64(len(blobs[dgst])),
},
}
_, err = imageStore.Create(ctx, cImg)
require.NoError(t, err)
}
for k, v := range blobs {
writer, err := contentStore.Writer(ctx, content.WithRef(k.String()))
require.NoError(t, err)
_, err = writer.Write(v)
require.NoError(t, err)
err = writer.Commit(ctx, int64(len(v)), k)
require.NoError(t, err)
writer.Close()
}
containerdClient, err := containerd.New("", containerd.WithServices(containerd.WithImageStore(imageStore), containerd.WithContentStore(contentStore)))
require.NoError(t, err)
if !enableLocalStore {
contentPath = ""
}
return &Containerd{
contentPath: contentPath,
client: containerdClient,
}
}

60
pkg/oci/memory.go Normal file
View File

@ -0,0 +1,60 @@
package oci
import (
"context"
"io"
"github.com/opencontainers/go-digest"
)
var _ Client = &MemoryClient{}
type MemoryClient struct {
images []Image
}
func NewMemoryClient(images []Image) *MemoryClient {
return &MemoryClient{
images: images,
}
}
func (m *MemoryClient) Name() string {
return "memory"
}
func (m *MemoryClient) Verify(ctx context.Context) error {
return nil
}
func (m *MemoryClient) Subscribe(ctx context.Context) (<-chan ImageEvent, <-chan error, error) {
return nil, nil, nil
}
func (m *MemoryClient) ListImages(ctx context.Context) ([]Image, error) {
return m.images, nil
}
func (m *MemoryClient) AllIdentifiers(ctx context.Context, img Image) ([]string, error) {
return []string{img.Digest.String()}, nil
}
func (m *MemoryClient) Resolve(ctx context.Context, ref string) (digest.Digest, error) {
return "", nil
}
func (m *MemoryClient) Size(ctx context.Context, dgst digest.Digest) (int64, error) {
return 0, nil
}
func (m *MemoryClient) GetManifest(ctx context.Context, dgst digest.Digest) ([]byte, string, error) {
return nil, "", nil
}
func (m *MemoryClient) GetBlob(ctx context.Context, dgst digest.Digest) (io.ReadCloser, error) {
return nil, nil
}
func (m *MemoryClient) CopyLayer(ctx context.Context, dgst digest.Digest, dst io.Writer) error {
return nil
}

12
pkg/oci/memory_test.go Normal file
View File

@ -0,0 +1,12 @@
package oci
import (
"testing"
"github.com/opencontainers/go-digest"
)
func createTestMemory(t *testing.T, imgs []map[string]string, blobs map[digest.Digest][]byte) *MemoryClient {
images := []Images{}
return NewMemoryClient(images)
}

View File

@ -1,60 +0,0 @@
package oci
import (
"context"
"io"
"github.com/opencontainers/go-digest"
)
var _ Client = &MockClient{}
type MockClient struct {
images []Image
}
func NewMockClient(images []Image) *MockClient {
return &MockClient{
images: images,
}
}
func (m *MockClient) Name() string {
return "mock"
}
func (m *MockClient) Verify(ctx context.Context) error {
return nil
}
func (m *MockClient) Subscribe(ctx context.Context) (<-chan ImageEvent, <-chan error, error) {
return nil, nil, nil
}
func (m *MockClient) ListImages(ctx context.Context) ([]Image, error) {
return m.images, nil
}
func (m *MockClient) AllIdentifiers(ctx context.Context, img Image) ([]string, error) {
return []string{img.Digest.String()}, nil
}
func (m *MockClient) Resolve(ctx context.Context, ref string) (digest.Digest, error) {
return "", nil
}
func (m *MockClient) Size(ctx context.Context, dgst digest.Digest) (int64, error) {
return 0, nil
}
func (m *MockClient) GetManifest(ctx context.Context, dgst digest.Digest) ([]byte, string, error) {
return nil, "", nil
}
func (m *MockClient) GetBlob(ctx context.Context, dgst digest.Digest) (io.ReadCloser, error) {
return nil, nil
}
func (m *MockClient) CopyLayer(ctx context.Context, dgst digest.Digest, dst io.Writer) error {
return nil
}

View File

@ -9,21 +9,16 @@ import (
"path" "path"
"testing" "testing"
"github.com/containerd/containerd"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/content/local"
"github.com/containerd/containerd/images"
"github.com/containerd/containerd/metadata"
"github.com/containerd/containerd/namespaces" "github.com/containerd/containerd/namespaces"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
bolt "go.etcd.io/bbolt"
) )
func TestOCIClient(t *testing.T) { func TestOCIClient(t *testing.T) {
t.Parallel() t.Parallel()
// Load the test images
b, err := os.ReadFile("./testdata/images.json") b, err := os.ReadFile("./testdata/images.json")
require.NoError(t, err) require.NoError(t, err)
imgs := []map[string]string{} imgs := []map[string]string{}
@ -43,67 +38,31 @@ func TestOCIClient(t *testing.T) {
blobs[dgst] = b blobs[dgst] = b
} }
contentPath := t.TempDir() ctx := namespaces.WithNamespace(context.Background(), "k8s.io")
contentStore, err := local.NewStore(contentPath) clients := []Client{}
require.NoError(t, err) clients = append(clients, createTestMemory(t, imgs, blobs))
boltDB, err := bolt.Open(path.Join(t.TempDir(), "bolt.db"), 0o644, nil) clients = append(clients, createTestContainerd(t, ctx, imgs, blobs, false))
require.NoError(t, err) clients = append(clients, createTestContainerd(t, ctx, imgs, blobs, true))
db := metadata.NewDB(boltDB, contentStore, nil) for _, client := range clients {
imageStore := metadata.NewImageStore(db) t.Run(client.Name(), func(t *testing.T) {
ctx := namespaces.WithNamespace(context.TODO(), "k8s.io")
for _, img := range imgs {
dgst, err := digest.Parse(img["digest"])
require.NoError(t, err)
cImg := images.Image{
Name: img["name"],
Target: ocispec.Descriptor{
MediaType: img["mediaType"],
Digest: dgst,
Size: int64(len(blobs[dgst])),
},
}
_, err = imageStore.Create(ctx, cImg)
require.NoError(t, err)
}
for k, v := range blobs {
writer, err := contentStore.Writer(ctx, content.WithRef(k.String()))
require.NoError(t, err)
_, err = writer.Write(v)
require.NoError(t, err)
err = writer.Commit(ctx, int64(len(v)), k)
require.NoError(t, err)
writer.Close()
}
containerdClient, err := containerd.New("", containerd.WithServices(containerd.WithImageStore(imageStore), containerd.WithContentStore(contentStore)))
require.NoError(t, err)
remoteContainerd := &Containerd{
client: containerdClient,
}
localContainerd := &Containerd{
contentPath: contentPath,
client: containerdClient,
}
for _, ociClient := range []Client{remoteContainerd, localContainerd} {
t.Run(ociClient.Name(), func(t *testing.T) {
t.Parallel() t.Parallel()
imgs, err := ociClient.ListImages(ctx) imgs, err := client.ListImages(ctx)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, imgs, 5) require.Len(t, imgs, 5)
for _, img := range imgs { for _, img := range imgs {
_, err := ociClient.Resolve(ctx, img.Name) _, err := client.Resolve(ctx, img.Name)
require.NoError(t, err) require.NoError(t, err)
} }
noPlatformName := "example.com/org/no-platform:test" noPlatformName := "example.com/org/no-platform:test"
dgst, err := ociClient.Resolve(ctx, noPlatformName) dgst, err := client.Resolve(ctx, noPlatformName)
require.NoError(t, err) require.NoError(t, err)
img := Image{ img := Image{
Name: noPlatformName, Name: noPlatformName,
Digest: dgst, Digest: dgst,
} }
_, err = ociClient.AllIdentifiers(ctx, img) _, err = client.AllIdentifiers(ctx, img)
require.EqualError(t, err, "failed to walk image manifests: could not find any platforms with local content in manifest list: sha256:addc990c58744bdf96364fe89bd4aab38b1e824d51c688edb36c75247cd45fa9") require.EqualError(t, err, "failed to walk image manifests: could not find any platforms with local content in manifest list: sha256:addc990c58744bdf96364fe89bd4aab38b1e824d51c688edb36c75247cd45fa9")
contentTests := []struct { contentTests := []struct {
@ -136,16 +95,16 @@ func TestOCIClient(t *testing.T) {
t.Run(tt.mediaType, func(t *testing.T) { t.Run(tt.mediaType, func(t *testing.T) {
t.Parallel() t.Parallel()
size, err := ociClient.Size(ctx, tt.dgst) size, err := client.Size(ctx, tt.dgst)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tt.size, size) require.Equal(t, tt.size, size)
if tt.mediaType != ocispec.MediaTypeImageLayer { if tt.mediaType != ocispec.MediaTypeImageLayer {
b, mediaType, err := ociClient.GetManifest(ctx, tt.dgst) b, mediaType, err := client.GetManifest(ctx, tt.dgst)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tt.mediaType, mediaType) require.Equal(t, tt.mediaType, mediaType)
require.Equal(t, blobs[tt.dgst], b) require.Equal(t, blobs[tt.dgst], b)
} else { } else {
rc, err := ociClient.GetBlob(ctx, tt.dgst) rc, err := client.GetBlob(ctx, tt.dgst)
require.NoError(t, err) require.NoError(t, err)
defer rc.Close() defer rc.Close()
b, err := io.ReadAll(rc) b, err := io.ReadAll(rc)
@ -259,7 +218,7 @@ func TestOCIClient(t *testing.T) {
img, err := Parse(tt.imageName, digest.Digest(tt.imageDigest)) img, err := Parse(tt.imageName, digest.Digest(tt.imageDigest))
require.NoError(t, err) require.NoError(t, err)
keys, err := ociClient.AllIdentifiers(ctx, img) keys, err := client.AllIdentifiers(ctx, img)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, tt.expectedKeys, keys) require.Equal(t, tt.expectedKeys, keys)
}) })

View File

@ -45,7 +45,7 @@ func TestBasic(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
imgs = append(imgs, img) imgs = append(imgs, img)
} }
ociClient := oci.NewMockClient(imgs) ociClient := oci.NewMemoryClient(imgs)
router := routing.NewMemoryRouter(map[string][]netip.AddrPort{}, netip.MustParseAddrPort("127.0.0.1:5000")) router := routing.NewMemoryRouter(map[string][]netip.AddrPort{}, netip.MustParseAddrPort("127.0.0.1:5000"))
ctx, cancel := context.WithCancel(context.TODO()) ctx, cancel := context.WithCancel(context.TODO())