0c6e9121b2
When repo and digest is provided, remove all references within a repository for the given digest. Signed-off-by: Derek McGowan <derek@mcg.dev>
286 lines
6.4 KiB
Go
286 lines
6.4 KiB
Go
package containerd
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/containerd/containerd/images"
|
|
"github.com/containerd/containerd/metadata"
|
|
"github.com/containerd/containerd/namespaces"
|
|
"github.com/containerd/log/logtest"
|
|
"github.com/docker/docker/container"
|
|
daemonevents "github.com/docker/docker/daemon/events"
|
|
dimages "github.com/docker/docker/daemon/images"
|
|
"gotest.tools/v3/assert"
|
|
is "gotest.tools/v3/assert/cmp"
|
|
)
|
|
|
|
func TestImageDelete(t *testing.T) {
|
|
ctx := namespaces.WithNamespace(context.TODO(), "testing")
|
|
|
|
for _, tc := range []struct {
|
|
ref string
|
|
starting []images.Image
|
|
remaining []images.Image
|
|
err error
|
|
// TODO: Records
|
|
// TODO: Containers
|
|
// TODO: Events
|
|
}{
|
|
{
|
|
ref: "nothingthere",
|
|
err: dimages.ErrImageDoesNotExist{Ref: nameTag("nothingthere", "latest")},
|
|
},
|
|
{
|
|
ref: "justoneimage",
|
|
starting: []images.Image{
|
|
{
|
|
Name: "docker.io/library/justoneimage:latest",
|
|
Target: desc(10),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ref: "justoneref",
|
|
starting: []images.Image{
|
|
{
|
|
Name: "docker.io/library/justoneref:latest",
|
|
Target: desc(10),
|
|
},
|
|
{
|
|
Name: "docker.io/library/differentrepo:latest",
|
|
Target: desc(10),
|
|
},
|
|
},
|
|
remaining: []images.Image{
|
|
{
|
|
Name: "docker.io/library/differentrepo:latest",
|
|
Target: desc(10),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ref: "hasdigest",
|
|
starting: []images.Image{
|
|
{
|
|
Name: "docker.io/library/hasdigest:latest",
|
|
Target: desc(10),
|
|
},
|
|
{
|
|
Name: "docker.io/library/hasdigest@" + digestFor(10).String(),
|
|
Target: desc(10),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ref: digestFor(11).String(),
|
|
starting: []images.Image{
|
|
{
|
|
Name: "docker.io/library/byid:latest",
|
|
Target: desc(11),
|
|
},
|
|
{
|
|
Name: "docker.io/library/byid@" + digestFor(11).String(),
|
|
Target: desc(11),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ref: "bydigest@" + digestFor(12).String(),
|
|
starting: []images.Image{
|
|
{
|
|
Name: "docker.io/library/bydigest:latest",
|
|
Target: desc(12),
|
|
},
|
|
{
|
|
Name: "docker.io/library/bydigest@" + digestFor(12).String(),
|
|
Target: desc(12),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ref: "onerefoftwo",
|
|
starting: []images.Image{
|
|
{
|
|
Name: "docker.io/library/onerefoftwo:latest",
|
|
Target: desc(12),
|
|
},
|
|
{
|
|
Name: "docker.io/library/onerefoftwo:other",
|
|
Target: desc(12),
|
|
},
|
|
{
|
|
Name: "docker.io/library/onerefoftwo@" + digestFor(12).String(),
|
|
Target: desc(12),
|
|
},
|
|
},
|
|
remaining: []images.Image{
|
|
{
|
|
Name: "docker.io/library/onerefoftwo:other",
|
|
Target: desc(12),
|
|
},
|
|
{
|
|
Name: "docker.io/library/onerefoftwo@" + digestFor(12).String(),
|
|
Target: desc(12),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ref: "otherreporemaining",
|
|
starting: []images.Image{
|
|
{
|
|
Name: "docker.io/library/otherreporemaining:latest",
|
|
Target: desc(12),
|
|
},
|
|
{
|
|
Name: "docker.io/library/otherreporemaining@" + digestFor(12).String(),
|
|
Target: desc(12),
|
|
},
|
|
{
|
|
Name: "docker.io/library/someotherrepo:latest",
|
|
Target: desc(12),
|
|
},
|
|
},
|
|
remaining: []images.Image{
|
|
{
|
|
Name: "docker.io/library/someotherrepo:latest",
|
|
Target: desc(12),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ref: "repoanddigest@" + digestFor(15).String(),
|
|
starting: []images.Image{
|
|
{
|
|
Name: "docker.io/library/repoanddigest:latest",
|
|
Target: desc(15),
|
|
},
|
|
{
|
|
Name: "docker.io/library/repoanddigest:latest@" + digestFor(15).String(),
|
|
Target: desc(15),
|
|
},
|
|
{
|
|
Name: "docker.io/library/someotherrepo:latest",
|
|
Target: desc(15),
|
|
},
|
|
},
|
|
remaining: []images.Image{
|
|
{
|
|
Name: "docker.io/library/someotherrepo:latest",
|
|
Target: desc(15),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ref: "repoanddigestothertags@" + digestFor(15).String(),
|
|
starting: []images.Image{
|
|
{
|
|
Name: "docker.io/library/repoanddigestothertags:v1",
|
|
Target: desc(15),
|
|
},
|
|
{
|
|
Name: "docker.io/library/repoanddigestothertags:v1@" + digestFor(15).String(),
|
|
Target: desc(15),
|
|
},
|
|
{
|
|
Name: "docker.io/library/repoanddigestothertags:v2",
|
|
Target: desc(15),
|
|
},
|
|
{
|
|
Name: "docker.io/library/repoanddigestothertags:v2@" + digestFor(15).String(),
|
|
Target: desc(15),
|
|
},
|
|
{
|
|
Name: "docker.io/library/someotherrepo:latest",
|
|
Target: desc(15),
|
|
},
|
|
},
|
|
remaining: []images.Image{
|
|
{
|
|
Name: "docker.io/library/someotherrepo:latest",
|
|
Target: desc(15),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
ref: "repoanddigestzerocase@" + digestFor(16).String(),
|
|
starting: []images.Image{
|
|
{
|
|
Name: "docker.io/library/someotherrepo:latest",
|
|
Target: desc(16),
|
|
},
|
|
},
|
|
remaining: []images.Image{
|
|
{
|
|
Name: "docker.io/library/someotherrepo:latest",
|
|
Target: desc(16),
|
|
},
|
|
},
|
|
err: dimages.ErrImageDoesNotExist{Ref: nameDigest("repoanddigestzerocase", digestFor(16))},
|
|
},
|
|
} {
|
|
tc := tc
|
|
t.Run(tc.ref, func(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := logtest.WithT(ctx, t)
|
|
mdb := newTestDB(ctx, t)
|
|
service := &ImageService{
|
|
images: metadata.NewImageStore(mdb),
|
|
containers: emptyTestContainerStore(),
|
|
eventsService: daemonevents.New(),
|
|
}
|
|
for _, img := range tc.starting {
|
|
if _, err := service.images.Create(ctx, img); err != nil {
|
|
t.Fatalf("failed to create image %q: %v", img.Name, err)
|
|
}
|
|
}
|
|
|
|
_, err := service.ImageDelete(ctx, tc.ref, false, false)
|
|
if tc.err == nil {
|
|
assert.NilError(t, err)
|
|
} else {
|
|
assert.Error(t, err, tc.err.Error())
|
|
}
|
|
|
|
all, err := service.images.List(ctx)
|
|
assert.NilError(t, err)
|
|
assert.Assert(t, is.Len(tc.remaining, len(all)))
|
|
|
|
// Order should match
|
|
for i := range all {
|
|
assert.Check(t, is.Equal(all[i].Name, tc.remaining[i].Name), "image[%d]", i)
|
|
assert.Check(t, is.Equal(all[i].Target.Digest, tc.remaining[i].Target.Digest), "image[%d]", i)
|
|
// TODO: Check labels too
|
|
}
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
type testContainerStore struct{}
|
|
|
|
func emptyTestContainerStore() container.Store {
|
|
return &testContainerStore{}
|
|
}
|
|
|
|
func (*testContainerStore) Add(string, *container.Container) {}
|
|
|
|
func (*testContainerStore) Get(string) *container.Container {
|
|
return nil
|
|
}
|
|
|
|
func (*testContainerStore) Delete(string) {}
|
|
|
|
func (*testContainerStore) List() []*container.Container {
|
|
return []*container.Container{}
|
|
}
|
|
|
|
func (*testContainerStore) Size() int {
|
|
return 0
|
|
}
|
|
|
|
func (*testContainerStore) First(container.StoreFilter) *container.Container {
|
|
return nil
|
|
}
|
|
|
|
func (*testContainerStore) ApplyAll(container.StoreReducer) {}
|