github.com/dtroyer-salad/og2/v2@v2.0.0-20240412154159-c47231610877/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/opencontainers/go-digest" 30 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 31 "oras.land/oras-go/v2/content" 32 "oras.land/oras-go/v2/errdef" 33 "oras.land/oras-go/v2/internal/docker" 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 }