@@ -19,11 +19,14 @@ package fs
1919import (
2020 "bytes"
2121 "context"
22+ "errors"
2223 "fmt"
2324 "io"
2425 "net/http"
2526 "testing"
2627
28+ "github.com/awslabs/soci-snapshotter/soci"
29+ "github.com/awslabs/soci-snapshotter/soci/store"
2730 "github.com/containerd/containerd/reference"
2831 "github.com/google/go-cmp/cmp"
2932 "github.com/opencontainers/go-digest"
@@ -214,6 +217,49 @@ func TestArtifactFetcherFetchOnlyOnce(t *testing.T) {
214217 }
215218}
216219
220+ func TestArtifactFetcherStore (t * testing.T ) {
221+ testCases := []struct {
222+ name string
223+ contents []byte
224+ digest digest.Digest
225+ expectedError error
226+ }{
227+ {
228+ name : "correct digest succeeds on store" ,
229+ contents : []byte ("test" ),
230+ digest : digest .FromBytes ([]byte ("test" )),
231+ expectedError : nil ,
232+ },
233+ {
234+ name : "incorrect digest fails on store" ,
235+ contents : []byte ("test" ),
236+ digest : digest .FromBytes ([]byte ("different data" )),
237+ expectedError : content .ErrMismatchedDigest ,
238+ },
239+ }
240+
241+ for _ , tc := range testCases {
242+ t .Run (tc .name , func (t * testing.T ) {
243+ fetcher , err := newFakeArtifactFetcher (imageRef , tc .contents )
244+ if err != nil {
245+ t .Fatalf ("could not create artifact fetcher: %v" , err )
246+ }
247+ size := len (tc .contents )
248+ desc := ocispec.Descriptor {
249+ Digest : tc .digest ,
250+ Size : int64 (size ),
251+ }
252+ ctx := context .Background ()
253+
254+ err = fetcher .Store (ctx , desc , bytes .NewReader (tc .contents ))
255+ if ! errors .Is (err , tc .expectedError ) {
256+ t .Fatalf ("unexpected error, expected = %v, got = %v" , tc .expectedError , err )
257+ }
258+ })
259+ }
260+
261+ }
262+
217263func TestNewRemoteStore (t * testing.T ) {
218264 client := http.Client {}
219265 testCases := []struct {
@@ -255,6 +301,80 @@ func TestNewRemoteStore(t *testing.T) {
255301 }
256302}
257303
304+ func TestFetchSociArtifacts (t * testing.T ) {
305+ fakeZtoc := []byte ("test data" )
306+ fakeZtocDesc := ocispec.Descriptor {
307+ Size : int64 (len (fakeZtoc )),
308+ Digest : digest .FromBytes (fakeZtoc ),
309+ }
310+
311+ blobs := []ocispec.Descriptor {
312+ {
313+ MediaType : soci .SociLayerMediaType ,
314+ Digest : fakeZtocDesc .Digest ,
315+ Size : fakeZtocDesc .Size ,
316+ },
317+ }
318+ sociIndex := soci .NewIndex (soci .V2 , blobs , nil , nil )
319+ sociBytes , err := soci .MarshalIndex (sociIndex )
320+ if err != nil {
321+ t .Fatalf ("failed to serialize soci index: %v" , err )
322+ }
323+ sociIndexDesc := ocispec.Descriptor {
324+ MediaType : ocispec .MediaTypeImageManifest ,
325+ Size : int64 (len (sociBytes )),
326+ Digest : digest .FromBytes (sociBytes ),
327+ }
328+
329+ modifiedSociIndex := soci .NewIndex (soci .V2 , blobs , nil , map [string ]string {"a" : "b" })
330+ modifiedSociBytes , err := soci .MarshalIndex (modifiedSociIndex )
331+ if err != nil {
332+ t .Fatalf ("failed to serialize modified soci index: %v" , err )
333+ }
334+ modifiedZtocBytes := []byte ("modified test data" )
335+
336+ tests := []struct {
337+ name string
338+ remoteContents map [digest.Digest ][]byte
339+ expectedError error
340+ }{
341+ {
342+ name : "correct data succeeds" ,
343+ remoteContents : map [digest.Digest ][]byte {
344+ sociIndexDesc .Digest : sociBytes ,
345+ fakeZtocDesc .Digest : fakeZtoc ,
346+ },
347+ expectedError : nil ,
348+ },
349+ {
350+ name : "modified index data fails" ,
351+ remoteContents : map [digest.Digest ][]byte {
352+ sociIndexDesc .Digest : modifiedSociBytes ,
353+ fakeZtocDesc .Digest : fakeZtoc ,
354+ },
355+ expectedError : content .ErrMismatchedDigest ,
356+ },
357+ {
358+ name : "modified ztoc data fails" ,
359+ remoteContents : map [digest.Digest ][]byte {
360+ sociIndexDesc .Digest : sociBytes ,
361+ fakeZtocDesc .Digest : modifiedZtocBytes ,
362+ },
363+ expectedError : content .ErrTrailingData ,
364+ },
365+ }
366+
367+ for _ , test := range tests {
368+ t .Run (test .name , func (t * testing.T ) {
369+ ctx := context .Background ()
370+ _ , err = FetchSociArtifacts (ctx , reference.Spec {}, sociIndexDesc , newFakeLocalStore (), newFakeRemoteStoreWithContents (test .remoteContents ))
371+ if ! errors .Is (err , test .expectedError ) {
372+ t .Fatalf ("unexpected error, got: %v. expected: %v" , err , test .expectedError )
373+ }
374+ })
375+ }
376+ }
377+
258378func newFakeArtifactFetcher (ref string , contents []byte ) (* artifactFetcher , error ) {
259379 refspec , err := reference .Parse (ref )
260380 if err != nil {
@@ -263,20 +383,55 @@ func newFakeArtifactFetcher(ref string, contents []byte) (*artifactFetcher, erro
263383 return newArtifactFetcher (refspec , memory .New (), newFakeRemoteStore (contents ))
264384}
265385
386+ func newFakeLocalStore () store.Store {
387+ return & fakeLocalStore {
388+ Store : memory .New (),
389+ }
390+ }
391+
392+ type fakeLocalStore struct {
393+ * memory.Store
394+ }
395+
396+ func (s * fakeLocalStore ) BatchOpen (ctx context.Context ) (context.Context , store.CleanupFunc , error ) {
397+ return ctx , func (ctx context.Context ) error { return nil }, nil
398+ }
399+
400+ func (s * fakeLocalStore ) Delete (_ context.Context , _ digest.Digest ) error {
401+ return nil
402+ }
403+
404+ func (s * fakeLocalStore ) Label (_ context.Context , _ ocispec.Descriptor , _ , _ string ) error {
405+ return nil
406+ }
407+
266408func newFakeRemoteStore (contents []byte ) resolverStorage {
267409 return & fakeRemoteStore {
268- contents : contents ,
410+ defaultContents : contents ,
411+ contents : make (map [digest.Digest ][]byte ),
412+ }
413+ }
414+
415+ func newFakeRemoteStoreWithContents (contents map [digest.Digest ][]byte ) resolverStorage {
416+ return & fakeRemoteStore {
417+ defaultContents : []byte {},
418+ contents : contents ,
269419 }
270420}
271421
272422type fakeRemoteStore struct {
273- contents []byte
423+ defaultContents []byte
424+ contents map [digest.Digest ][]byte
274425}
275426
276427var _ content.Storage = & fakeRemoteStore {}
277428
278429func (f * fakeRemoteStore ) Fetch (_ context.Context , desc ocispec.Descriptor ) (io.ReadCloser , error ) {
279- return io .NopCloser (bytes .NewReader (f .contents )), nil
430+ if data , ok := f .contents [desc .Digest ]; ok {
431+ return io .NopCloser (bytes .NewReader (data )), nil
432+ }
433+
434+ return io .NopCloser (bytes .NewReader (f .defaultContents )), nil
280435}
281436
282437func (f * fakeRemoteStore ) Push (_ context.Context , desc ocispec.Descriptor , ra io.Reader ) error {
@@ -289,6 +444,6 @@ func (f *fakeRemoteStore) Exists(_ context.Context, desc ocispec.Descriptor) (bo
289444
290445func (f * fakeRemoteStore ) Resolve (_ context.Context , ref string ) (ocispec.Descriptor , error ) {
291446 return ocispec.Descriptor {
292- Size : int64 (len (f .contents )),
447+ Size : int64 (len (f .defaultContents )),
293448 }, nil
294449}
0 commit comments