@@ -19,12 +19,18 @@ package client
1919import (
2020 "archive/tar"
2121 "bytes"
22+ "context"
23+ "encoding/json"
2224 "io"
25+ "os"
2326 "testing"
2427
2528 . "github.com/containerd/containerd"
29+ "github.com/containerd/containerd/content"
30+ "github.com/containerd/containerd/images"
2631 "github.com/containerd/containerd/images/archive"
2732 "github.com/containerd/containerd/platforms"
33+ ocispec "github.com/opencontainers/image-spec/specs-go/v1"
2834)
2935
3036// TestExport exports testImage as a tar stream
@@ -50,14 +56,103 @@ func TestExport(t *testing.T) {
5056 if err != nil {
5157 t .Fatal (err )
5258 }
53- assertOCITar (t , bytes .NewReader (wb .Bytes ()))
59+ assertOCITar (t , bytes .NewReader (wb .Bytes ()), true )
5460}
5561
56- func assertOCITar (t * testing.T , r io.Reader ) {
62+ // TestExportDockerManifest exports testImage as a tar stream, using the
63+ // WithSkipDockerManifest option
64+ func TestExportDockerManifest (t * testing.T ) {
65+ if testing .Short () {
66+ t .Skip ()
67+ }
68+ ctx , cancel := testContext (t )
69+ defer cancel ()
70+
71+ client , err := New (address )
72+ if err != nil {
73+ t .Fatal (err )
74+ }
75+ defer client .Close ()
76+
77+ _ , err = client .Fetch (ctx , testImage )
78+ if err != nil {
79+ t .Fatal (err )
80+ }
81+ dstFile , err := os .CreateTemp ("" , "export-import-test" )
82+ if err != nil {
83+ t .Fatal (err )
84+ }
85+ defer func () {
86+ dstFile .Close ()
87+ os .Remove (dstFile .Name ())
88+ }()
89+
90+ img , err := client .ImageService ().Get (ctx , testImage )
91+ if err != nil {
92+ t .Fatal (err )
93+ }
94+
95+ // test multi-platform export
96+ err = client .Export (ctx , dstFile , archive .WithManifest (img .Target ), archive .WithSkipDockerManifest ())
97+ if err != nil {
98+ t .Fatal (err )
99+ }
100+ dstFile .Seek (0 , 0 )
101+ assertOCITar (t , dstFile , false )
102+
103+ // reset to beginning
104+ dstFile .Seek (0 , 0 )
105+
106+ // test single-platform export
107+ var result ocispec.Descriptor
108+ err = images .Walk (ctx , images .HandlerFunc (func (ctx context.Context , desc ocispec.Descriptor ) ([]ocispec.Descriptor , error ) {
109+ switch desc .MediaType {
110+ case images .MediaTypeDockerSchema2Manifest , ocispec .MediaTypeImageManifest :
111+ p , err := content .ReadBlob (ctx , client .ContentStore (), desc )
112+ if err != nil {
113+ return nil , err
114+ }
115+
116+ var manifest ocispec.Manifest
117+ if err := json .Unmarshal (p , & manifest ); err != nil {
118+ return nil , err
119+ }
120+
121+ if desc .Platform == nil || platforms .Default ().Match (platforms .Normalize (* desc .Platform )) {
122+ result = desc
123+ }
124+ return nil , nil
125+ case images .MediaTypeDockerSchema2ManifestList , ocispec .MediaTypeImageIndex :
126+ p , err := content .ReadBlob (ctx , client .ContentStore (), desc )
127+ if err != nil {
128+ return nil , err
129+ }
130+
131+ var idx ocispec.Index
132+ if err := json .Unmarshal (p , & idx ); err != nil {
133+ return nil , err
134+ }
135+ return idx .Manifests , nil
136+ }
137+ return nil , nil
138+ }), img .Target )
139+ if err != nil {
140+ t .Fatal (err )
141+ }
142+ err = client .Export (ctx , dstFile , archive .WithManifest (result ), archive .WithSkipDockerManifest ())
143+ if err != nil {
144+ t .Fatal (err )
145+ }
146+ dstFile .Seek (0 , 0 )
147+ assertOCITar (t , dstFile , false )
148+ }
149+
150+ func assertOCITar (t * testing.T , r io.Reader , docker bool ) {
57151 // TODO: add more assertion
58152 tr := tar .NewReader (r )
59153 foundOCILayout := false
60154 foundIndexJSON := false
155+ foundManifestJSON := false
61156 for {
62157 h , err := tr .Next ()
63158 if err == io .EOF {
@@ -73,11 +168,19 @@ func assertOCITar(t *testing.T, r io.Reader) {
73168 if h .Name == "index.json" {
74169 foundIndexJSON = true
75170 }
171+ if h .Name == "manifest.json" {
172+ foundManifestJSON = true
173+ }
76174 }
77175 if ! foundOCILayout {
78176 t .Error ("oci-layout not found" )
79177 }
80178 if ! foundIndexJSON {
81179 t .Error ("index.json not found" )
82180 }
181+ if docker && ! foundManifestJSON {
182+ t .Error ("manifest.json not found" )
183+ } else if ! docker && foundManifestJSON {
184+ t .Error ("manifest.json found" )
185+ }
83186}
0 commit comments