c8d/list: Add a test case for images sharing a top layer
Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This commit is contained in:
parent
ad8a5a5732
commit
3312b82515
2 changed files with 64 additions and 16 deletions
|
@ -10,10 +10,14 @@ import (
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/image"
|
"github.com/docker/docker/api/types/image"
|
||||||
"github.com/docker/docker/integration/internal/container"
|
"github.com/docker/docker/integration/internal/container"
|
||||||
|
"github.com/docker/docker/internal/testutils/specialimage"
|
||||||
"github.com/docker/docker/testutil"
|
"github.com/docker/docker/testutil"
|
||||||
|
"github.com/docker/docker/testutil/daemon"
|
||||||
"github.com/google/go-cmp/cmp/cmpopts"
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
is "gotest.tools/v3/assert/cmp"
|
is "gotest.tools/v3/assert/cmp"
|
||||||
|
"gotest.tools/v3/skip"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Regression : #38171
|
// Regression : #38171
|
||||||
|
@ -192,3 +196,34 @@ func TestAPIImagesFilters(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify that the size calculation operates on ChainIDs and not DiffIDs.
|
||||||
|
// This test calls an image list with two images that share one, top layer.
|
||||||
|
func TestAPIImagesListSizeShared(t *testing.T) {
|
||||||
|
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
||||||
|
|
||||||
|
ctx := setupTest(t)
|
||||||
|
|
||||||
|
daemon := daemon.New(t)
|
||||||
|
daemon.Start(t)
|
||||||
|
defer daemon.Stop(t)
|
||||||
|
|
||||||
|
client := daemon.NewClientT(t)
|
||||||
|
|
||||||
|
specialimage.Load(ctx, t, client, func(dir string) (*ocispec.Index, error) {
|
||||||
|
return specialimage.MultiLayerCustom(dir, "multilayer:latest", []specialimage.SingleFileLayer{
|
||||||
|
{Name: "bar", Content: []byte("2")},
|
||||||
|
{Name: "foo", Content: []byte("1")},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
specialimage.Load(ctx, t, client, func(dir string) (*ocispec.Index, error) {
|
||||||
|
return specialimage.MultiLayerCustom(dir, "multilayer2:latest", []specialimage.SingleFileLayer{
|
||||||
|
{Name: "asdf", Content: []byte("3")},
|
||||||
|
{Name: "foo", Content: []byte("1")},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err := client.ImageList(ctx, image.ListOptions{SharedSize: true})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
}
|
||||||
|
|
|
@ -16,20 +16,32 @@ import (
|
||||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func MultiLayer(dir string) (*ocispec.Index, error) {
|
type SingleFileLayer struct {
|
||||||
const imageRef = "multilayer:latest"
|
Name string
|
||||||
|
Content []byte
|
||||||
|
}
|
||||||
|
|
||||||
layer1Desc, err := writeLayerWithOneFile(dir, "foo", []byte("1"))
|
func MultiLayer(dir string) (*ocispec.Index, error) {
|
||||||
|
return MultiLayerCustom(dir, "multilayer:latest", []SingleFileLayer{
|
||||||
|
{Name: "foo", Content: []byte("1")},
|
||||||
|
{Name: "bar", Content: []byte("2")},
|
||||||
|
{Name: "hello", Content: []byte("world")},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func MultiLayerCustom(dir string, imageRef string, layers []SingleFileLayer) (*ocispec.Index, error) {
|
||||||
|
var layerDescs []ocispec.Descriptor
|
||||||
|
var layerDgsts []digest.Digest
|
||||||
|
var layerBlobs []string
|
||||||
|
for _, layer := range layers {
|
||||||
|
layerDesc, err := writeLayerWithOneFile(dir, layer.Name, layer.Content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
layer2Desc, err := writeLayerWithOneFile(dir, "bar", []byte("2"))
|
|
||||||
if err != nil {
|
layerDescs = append(layerDescs, layerDesc)
|
||||||
return nil, err
|
layerDgsts = append(layerDgsts, layerDesc.Digest)
|
||||||
}
|
layerBlobs = append(layerBlobs, blobPath(layerDesc))
|
||||||
layer3Desc, err := writeLayerWithOneFile(dir, "hello", []byte("world"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configDesc, err := writeJsonBlob(dir, ocispec.MediaTypeImageConfig, ocispec.Image{
|
configDesc, err := writeJsonBlob(dir, ocispec.MediaTypeImageConfig, ocispec.Image{
|
||||||
|
@ -39,7 +51,7 @@ func MultiLayer(dir string) (*ocispec.Index, error) {
|
||||||
},
|
},
|
||||||
RootFS: ocispec.RootFS{
|
RootFS: ocispec.RootFS{
|
||||||
Type: "layers",
|
Type: "layers",
|
||||||
DiffIDs: []digest.Digest{layer1Desc.Digest, layer2Desc.Digest, layer3Desc.Digest},
|
DiffIDs: layerDgsts,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -49,14 +61,14 @@ func MultiLayer(dir string) (*ocispec.Index, error) {
|
||||||
manifest := ocispec.Manifest{
|
manifest := ocispec.Manifest{
|
||||||
MediaType: ocispec.MediaTypeImageManifest,
|
MediaType: ocispec.MediaTypeImageManifest,
|
||||||
Config: configDesc,
|
Config: configDesc,
|
||||||
Layers: []ocispec.Descriptor{layer1Desc, layer2Desc, layer3Desc},
|
Layers: layerDescs,
|
||||||
}
|
}
|
||||||
|
|
||||||
legacyManifests := []manifestItem{
|
legacyManifests := []manifestItem{
|
||||||
{
|
{
|
||||||
Config: blobPath(configDesc),
|
Config: blobPath(configDesc),
|
||||||
RepoTags: []string{imageRef},
|
RepoTags: []string{imageRef},
|
||||||
Layers: []string{blobPath(layer1Desc), blobPath(layer2Desc), blobPath(layer3Desc)},
|
Layers: layerBlobs,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,6 +140,7 @@ func writeLayerWithOneFile(dir string, filename string, content []byte) (ocispec
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ocispec.Descriptor{}, err
|
return ocispec.Descriptor{}, err
|
||||||
}
|
}
|
||||||
|
defer rd.Close()
|
||||||
|
|
||||||
return writeBlob(dir, ocispec.MediaTypeImageLayer, rd)
|
return writeBlob(dir, ocispec.MediaTypeImageLayer, rd)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue