github.com/opcr-io/oras-go/v2@v2.0.0-20231122155130-eb4260d8a0ae/content/oci/readonlystorage_test.go (about)

     1  /*
     2  Copyright The ORAS Authors.
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6  
     7  http://www.apache.org/licenses/LICENSE-2.0
     8  
     9  Unless required by applicable law or agreed to in writing, software
    10  distributed under the License is distributed on an "AS IS" BASIS,
    11  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  See the License for the specific language governing permissions and
    13  limitations under the License.
    14  */
    15  
    16  package oci
    17  
    18  import (
    19  	"bytes"
    20  	"context"
    21  	"errors"
    22  	"io"
    23  	"os"
    24  	"path/filepath"
    25  	"strings"
    26  	"testing"
    27  	"testing/fstest"
    28  
    29  	"github.com/opcr-io/oras-go/v2/content"
    30  	"github.com/opcr-io/oras-go/v2/errdef"
    31  	"github.com/opcr-io/oras-go/v2/internal/docker"
    32  	"github.com/opencontainers/go-digest"
    33  	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
    34  )
    35  
    36  func TestReadOnlyStorage_Exists(t *testing.T) {
    37  	blob := []byte("test")
    38  	dgst := digest.FromBytes(blob)
    39  	desc := content.NewDescriptorFromBytes("", blob)
    40  	fsys := fstest.MapFS{
    41  		strings.Join([]string{"blobs", dgst.Algorithm().String(), dgst.Encoded()}, "/"): {},
    42  	}
    43  	s := NewStorageFromFS(fsys)
    44  	ctx := context.Background()
    45  
    46  	// test sha256
    47  	got, err := s.Exists(ctx, desc)
    48  	if err != nil {
    49  		t.Fatal("ReadOnlyStorage.Exists() error =", err)
    50  	}
    51  	if want := true; got != want {
    52  		t.Errorf("ReadOnlyStorage.Exists() = %v, want %v", got, want)
    53  	}
    54  
    55  	// test not found
    56  	blob = []byte("whaterver")
    57  	desc = content.NewDescriptorFromBytes("", blob)
    58  	got, err = s.Exists(ctx, desc)
    59  	if err != nil {
    60  		t.Fatal("ReadOnlyStorage.Exists() error =", err)
    61  	}
    62  	if want := false; got != want {
    63  		t.Errorf("ReadOnlyStorage.Exists() = %v, want %v", got, want)
    64  	}
    65  
    66  	// test invalid digest
    67  	desc = ocispec.Descriptor{Digest: "not a digest"}
    68  	_, err = s.Exists(ctx, desc)
    69  	if err == nil {
    70  		t.Fatalf("ReadOnlyStorage.Exists() error = %v, wantErr %v", err, true)
    71  	}
    72  }
    73  
    74  func TestReadOnlyStorage_Fetch(t *testing.T) {
    75  	blob := []byte("test")
    76  	dgst := digest.FromBytes(blob)
    77  	desc := content.NewDescriptorFromBytes("", blob)
    78  	fsys := fstest.MapFS{
    79  		strings.Join([]string{"blobs", dgst.Algorithm().String(), dgst.Encoded()}, "/"): {
    80  			Data: blob,
    81  		},
    82  	}
    83  
    84  	s := NewStorageFromFS(fsys)
    85  	ctx := context.Background()
    86  
    87  	// test fetch
    88  	rc, err := s.Fetch(ctx, desc)
    89  	if err != nil {
    90  		t.Fatal("ReadOnlyStorage.Fetch() error =", err)
    91  	}
    92  	got, err := io.ReadAll(rc)
    93  	if err != nil {
    94  		t.Fatal("ReadOnlyStorage.Fetch().Read() error =", err)
    95  	}
    96  	err = rc.Close()
    97  	if err != nil {
    98  		t.Error("ReadOnlyStorage.Fetch().Close() error =", err)
    99  	}
   100  	if !bytes.Equal(got, blob) {
   101  		t.Errorf("ReadOnlyStorage.Fetch() = %v, want %v", got, blob)
   102  	}
   103  
   104  	// test not found
   105  	anotherBlob := []byte("whatever")
   106  	desc = content.NewDescriptorFromBytes("", anotherBlob)
   107  	_, err = s.Fetch(ctx, desc)
   108  	if !errors.Is(err, errdef.ErrNotFound) {
   109  		t.Fatalf("ReadOnlyStorage.Fetch() error = %v, wantErr %v", err, errdef.ErrNotFound)
   110  	}
   111  
   112  	// test invalid digest
   113  	desc = ocispec.Descriptor{Digest: "not a digest"}
   114  	_, err = s.Fetch(ctx, desc)
   115  	if err == nil {
   116  		t.Fatalf("ReadOnlyStorage.Fetch() error = %v, wantErr %v", err, true)
   117  	}
   118  }
   119  
   120  func TestReadOnlyStorage_DirFS(t *testing.T) {
   121  	tempDir := t.TempDir()
   122  	blob := []byte("test")
   123  	dgst := digest.FromBytes(blob)
   124  	desc := content.NewDescriptorFromBytes("test", blob)
   125  	// write blob to disk
   126  	path := filepath.Join(tempDir, "blobs", dgst.Algorithm().String(), dgst.Encoded())
   127  	if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil {
   128  		t.Fatal("error calling Mkdir(), error =", err)
   129  	}
   130  	if err := os.WriteFile(path, blob, 0444); err != nil {
   131  		t.Fatal("error calling WriteFile(), error =", err)
   132  	}
   133  
   134  	s := NewStorageFromFS(os.DirFS(tempDir))
   135  	ctx := context.Background()
   136  
   137  	// test Exists
   138  	exists, err := s.Exists(ctx, desc)
   139  	if err != nil {
   140  		t.Fatal("ReadOnlyStorage.Exists() error =", err)
   141  	}
   142  	if !exists {
   143  		t.Errorf("ReadOnlyStorage.Exists() = %v, want %v", exists, true)
   144  	}
   145  
   146  	// test Fetch
   147  	rc, err := s.Fetch(ctx, desc)
   148  	if err != nil {
   149  		t.Fatal("ReadOnlyStorage.Fetch() error =", err)
   150  	}
   151  	got, err := io.ReadAll(rc)
   152  	if err != nil {
   153  		t.Fatal("ReadOnlyStorage.Fetch().Read() error =", err)
   154  	}
   155  	err = rc.Close()
   156  	if err != nil {
   157  		t.Error("ReadOnlyStorage.Fetch().Close() error =", err)
   158  	}
   159  	if !bytes.Equal(got, blob) {
   160  		t.Errorf("ReadOnlyStorage.Fetch() = %v, want %v", got, blob)
   161  	}
   162  }
   163  
   164  func TestReadOnlyStorage_TarFS(t *testing.T) {
   165  	s, err := NewStorageFromTar("testdata/hello-world.tar")
   166  	if err != nil {
   167  		t.Fatal("NewStorageFromTar() error =", err)
   168  	}
   169  	ctx := context.Background()
   170  
   171  	// test data in testdata/hello-world.tar
   172  	blob := []byte(`{"architecture":"amd64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:b9935d4e8431fb1a7f0989304ec86b3329a99a25f5efdc7f09f3f8c41434ca6d","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"8746661ca3c2f215da94e6d3f7dfdcafaff5ec0b21c9aff6af3dc379a82fbc72","container_config":{"Hostname":"8746661ca3c2","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:b9935d4e8431fb1a7f0989304ec86b3329a99a25f5efdc7f09f3f8c41434ca6d","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2021-09-23T23:47:57.442225064Z","docker_version":"20.10.7","history":[{"created":"2021-09-23T23:47:57.098990892Z","created_by":"/bin/sh -c #(nop) COPY file:50563a97010fd7ce1ceebd1fa4f4891ac3decdf428333fb2683696f4358af6c2 in / "},{"created":"2021-09-23T23:47:57.442225064Z","created_by":"/bin/sh -c #(nop)  CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:e07ee1baac5fae6a26f30cabfe54a36d3402f96afda318fe0a96cec4ca393359"]}}`)
   173  	desc := content.NewDescriptorFromBytes(docker.MediaTypeManifest, blob)
   174  
   175  	// test Exists
   176  	exists, err := s.Exists(ctx, desc)
   177  	if err != nil {
   178  		t.Fatal("ReadOnlyStorage.Exists() error =", err)
   179  	}
   180  	if want := true; exists != want {
   181  		t.Errorf("ReadOnlyStorage.Exists() = %v, want %v", exists, want)
   182  	}
   183  
   184  	// test Fetch
   185  	rc, err := s.Fetch(ctx, desc)
   186  	if err != nil {
   187  		t.Fatal("ReadOnlyStorage.Fetch() error =", err)
   188  	}
   189  	got, err := io.ReadAll(rc)
   190  	if err != nil {
   191  		t.Fatal("ReadOnlyStorage.Fetch().Read() error =", err)
   192  	}
   193  	err = rc.Close()
   194  	if err != nil {
   195  		t.Error("ReadOnlyStorage.Fetch().Close() error =", err)
   196  	}
   197  	if !bytes.Equal(got, blob) {
   198  		t.Errorf("ReadOnlyStorage.Fetch() = %v, want %v", got, blob)
   199  	}
   200  
   201  	// test Exists against a non-existing content
   202  	blob = []byte("whatever")
   203  	desc = content.NewDescriptorFromBytes("", blob)
   204  	exists, err = s.Exists(ctx, desc)
   205  	if err != nil {
   206  		t.Fatal("ReadOnlyStorage.Exists() error =", err)
   207  	}
   208  	if want := false; exists != want {
   209  		t.Errorf("ReadOnlyStorage.Exists() = %v, want %v", exists, want)
   210  	}
   211  
   212  	// test Fetch against a non-existing content
   213  	_, err = s.Fetch(ctx, desc)
   214  	if want := errdef.ErrNotFound; !errors.Is(err, want) {
   215  		t.Errorf("ReadOnlyStorage.Fetch() error = %v, wantErr %v", err, want)
   216  	}
   217  }