github.com/dtroyer-salad/og2/v2@v2.0.0-20240412154159-c47231610877/internal/cas/proxy_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 cas 17 18 import ( 19 "bytes" 20 "context" 21 _ "crypto/sha256" 22 "errors" 23 "io" 24 "testing" 25 26 "github.com/opencontainers/go-digest" 27 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 28 "oras.land/oras-go/v2/errdef" 29 ) 30 31 func TestProxyCache(t *testing.T) { 32 content := []byte("hello world") 33 desc := ocispec.Descriptor{ 34 MediaType: "test", 35 Digest: digest.FromBytes(content), 36 Size: int64(len(content)), 37 } 38 39 ctx := context.Background() 40 base := NewMemory() 41 err := base.Push(ctx, desc, bytes.NewReader(content)) 42 if err != nil { 43 t.Fatal("Memory.Push() error =", err) 44 } 45 s := NewProxy(base, NewMemory()) 46 47 // first fetch 48 exists, err := s.Exists(ctx, desc) 49 if err != nil { 50 t.Fatal("Proxy.Exists() error =", err) 51 } 52 if !exists { 53 t.Errorf("Proxy.Exists() = %v, want %v", exists, true) 54 } 55 rc, err := s.Fetch(ctx, desc) 56 if err != nil { 57 t.Fatal("Proxy.Fetch() error =", err) 58 } 59 got, err := io.ReadAll(rc) 60 if err != nil { 61 t.Fatal("Proxy.Fetch().Read() error =", err) 62 } 63 err = rc.Close() 64 if err != nil { 65 t.Error("Proxy.Fetch().Close() error =", err) 66 } 67 if !bytes.Equal(got, content) { 68 t.Errorf("Proxy.Fetch() = %v, want %v", got, content) 69 } 70 71 // repeated fetch should not touch base CAS 72 // nil base will generate panic if the base CAS is touched 73 s.ReadOnlyStorage = nil 74 75 exists, err = s.Exists(ctx, desc) 76 if err != nil { 77 t.Fatal("Proxy.Exists() error =", err) 78 } 79 if !exists { 80 t.Errorf("Proxy.Exists() = %v, want %v", exists, true) 81 } 82 rc, err = s.Fetch(ctx, desc) 83 if err != nil { 84 t.Fatal("Proxy.Fetch() error =", err) 85 } 86 got, err = io.ReadAll(rc) 87 if err != nil { 88 t.Fatal("Proxy.Fetch().Read() error =", err) 89 } 90 err = rc.Close() 91 if err != nil { 92 t.Error("Proxy.Fetch().Close() error =", err) 93 } 94 if !bytes.Equal(got, content) { 95 t.Errorf("Proxy.Fetch() = %v, want %v", got, content) 96 } 97 } 98 99 func TestProxy_FetchCached_NotCachedContent(t *testing.T) { 100 content := []byte("hello world") 101 desc := ocispec.Descriptor{ 102 MediaType: "test", 103 Digest: digest.FromBytes(content), 104 Size: int64(len(content)), 105 } 106 107 ctx := context.Background() 108 base := NewMemory() 109 err := base.Push(ctx, desc, bytes.NewReader(content)) 110 if err != nil { 111 t.Fatal("Memory.Push() error =", err) 112 } 113 s := NewProxy(base, NewMemory()) 114 115 // FetchCached should fetch from the base CAS 116 exists, err := s.Exists(ctx, desc) 117 if err != nil { 118 t.Fatal("Proxy.Exists() error =", err) 119 } 120 if !exists { 121 t.Errorf("Proxy.Exists() = %v, want %v", exists, true) 122 } 123 rc, err := s.FetchCached(ctx, desc) 124 if err != nil { 125 t.Fatal("Proxy.Fetch() error =", err) 126 } 127 got, err := io.ReadAll(rc) 128 if err != nil { 129 t.Fatal("Proxy.Fetch().Read() error =", err) 130 } 131 err = rc.Close() 132 if err != nil { 133 t.Error("Proxy.Fetch().Close() error =", err) 134 } 135 if !bytes.Equal(got, content) { 136 t.Errorf("Proxy.Fetch() = %v, want %v", got, content) 137 } 138 139 // the content should not exist in the cache 140 exists, err = s.Cache.Exists(ctx, desc) 141 if err != nil { 142 t.Fatal("Proxy.Cache.Exists() error =", err) 143 } 144 145 if exists { 146 t.Errorf("Proxy.Cache.Exists()() = %v, want %v", exists, false) 147 } 148 } 149 150 func TestProxy_FetchCached_CachedContent(t *testing.T) { 151 content := []byte("hello world") 152 desc := ocispec.Descriptor{ 153 MediaType: "test", 154 Digest: digest.FromBytes(content), 155 Size: int64(len(content)), 156 } 157 158 ctx := context.Background() 159 base := NewMemory() 160 err := base.Push(ctx, desc, bytes.NewReader(content)) 161 if err != nil { 162 t.Fatal("Memory.Push() error =", err) 163 } 164 s := NewProxy(base, NewMemory()) 165 166 // first fetch 167 exists, err := s.Exists(ctx, desc) 168 if err != nil { 169 t.Fatal("Proxy.Exists() error =", err) 170 } 171 if !exists { 172 t.Errorf("Proxy.Exists() = %v, want %v", exists, true) 173 } 174 rc, err := s.Fetch(ctx, desc) 175 if err != nil { 176 t.Fatal("Proxy.Fetch() error =", err) 177 } 178 got, err := io.ReadAll(rc) 179 if err != nil { 180 t.Fatal("Proxy.Fetch().Read() error =", err) 181 } 182 err = rc.Close() 183 if err != nil { 184 t.Error("Proxy.Fetch().Close() error =", err) 185 } 186 if !bytes.Equal(got, content) { 187 t.Errorf("Proxy.Fetch() = %v, want %v", got, content) 188 } 189 190 // the subsequent FetchCached should not touch base CAS 191 // nil base will generate panic if the base CAS is touched 192 s.ReadOnlyStorage = nil 193 194 exists, err = s.Exists(ctx, desc) 195 if err != nil { 196 t.Fatal("Proxy.Exists() error =", err) 197 } 198 if !exists { 199 t.Errorf("Proxy.Exists() = %v, want %v", exists, true) 200 } 201 rc, err = s.FetchCached(ctx, desc) 202 if err != nil { 203 t.Fatal("Proxy.Fetch() error =", err) 204 } 205 got, err = io.ReadAll(rc) 206 if err != nil { 207 t.Fatal("Proxy.Fetch().Read() error =", err) 208 } 209 err = rc.Close() 210 if err != nil { 211 t.Error("Proxy.Fetch().Close() error =", err) 212 } 213 if !bytes.Equal(got, content) { 214 t.Errorf("Proxy.Fetch() = %v, want %v", got, content) 215 } 216 } 217 218 func TestProxy_StopCaching(t *testing.T) { 219 content := []byte("hello world") 220 desc := ocispec.Descriptor{ 221 MediaType: "test", 222 Digest: digest.FromBytes(content), 223 Size: int64(len(content)), 224 } 225 226 ctx := context.Background() 227 base := NewMemory() 228 err := base.Push(ctx, desc, bytes.NewReader(content)) 229 if err != nil { 230 t.Fatal("Memory.Push() error =", err) 231 } 232 s := NewProxy(base, NewMemory()) 233 234 // FetchCached should fetch from the base CAS 235 exists, err := s.Exists(ctx, desc) 236 if err != nil { 237 t.Fatal("Proxy.Exists() error =", err) 238 } 239 if !exists { 240 t.Errorf("Proxy.Exists() = %v, want %v", exists, true) 241 } 242 243 // test StopCaching 244 s.StopCaching = true 245 rc, err := s.Fetch(ctx, desc) 246 if err != nil { 247 t.Fatal("Proxy.Fetch() error =", err) 248 } 249 got, err := io.ReadAll(rc) 250 if err != nil { 251 t.Fatal("Proxy.Fetch().Read() error =", err) 252 } 253 err = rc.Close() 254 if err != nil { 255 t.Error("Proxy.Fetch().Close() error =", err) 256 } 257 if !bytes.Equal(got, content) { 258 t.Errorf("Proxy.Fetch() = %v, want %v", got, content) 259 } 260 261 // the content should not exist in the cache 262 exists, err = s.Cache.Exists(ctx, desc) 263 if err != nil { 264 t.Fatal("Proxy.Cache.Exists() error =", err) 265 } 266 267 if exists { 268 t.Errorf("Proxy.Cache.Exists()() = %v, want %v", exists, false) 269 } 270 } 271 272 func TestProxyWithLimit_WithinLimit(t *testing.T) { 273 content := []byte("hello world") 274 desc := ocispec.Descriptor{ 275 MediaType: "test", 276 Digest: digest.FromBytes(content), 277 Size: int64(len(content)), 278 } 279 280 ctx := context.Background() 281 base := NewMemory() 282 err := base.Push(ctx, desc, bytes.NewReader(content)) 283 if err != nil { 284 t.Fatal("Memory.Push() error =", err) 285 } 286 s := NewProxyWithLimit(base, NewMemory(), 4*1024*1024) 287 288 // first fetch 289 exists, err := s.Exists(ctx, desc) 290 if err != nil { 291 t.Fatal("Proxy.Exists() error =", err) 292 } 293 if !exists { 294 t.Errorf("Proxy.Exists() = %v, want %v", exists, true) 295 } 296 rc, err := s.Fetch(ctx, desc) 297 if err != nil { 298 t.Fatal("Proxy.Fetch() error =", err) 299 } 300 got, err := io.ReadAll(rc) 301 if err != nil { 302 t.Fatal("Proxy.Fetch().Read() error =", err) 303 } 304 err = rc.Close() 305 if err != nil { 306 t.Error("Proxy.Fetch().Close() error =", err) 307 } 308 if !bytes.Equal(got, content) { 309 t.Errorf("Proxy.Fetch() = %v, want %v", got, content) 310 } 311 312 // repeated fetch should not touch base CAS 313 // nil base will generate panic if the base CAS is touched 314 s.ReadOnlyStorage = nil 315 316 exists, err = s.Exists(ctx, desc) 317 if err != nil { 318 t.Fatal("Proxy.Exists() error =", err) 319 } 320 if !exists { 321 t.Errorf("Proxy.Exists() = %v, want %v", exists, true) 322 } 323 rc, err = s.Fetch(ctx, desc) 324 if err != nil { 325 t.Fatal("Proxy.Fetch() error =", err) 326 } 327 got, err = io.ReadAll(rc) 328 if err != nil { 329 t.Fatal("Proxy.Fetch().Read() error =", err) 330 } 331 err = rc.Close() 332 if err != nil { 333 t.Error("Proxy.Fetch().Close() error =", err) 334 } 335 if !bytes.Equal(got, content) { 336 t.Errorf("Proxy.Fetch() = %v, want %v", got, content) 337 } 338 } 339 340 func TestProxyWithLimit_ExceedsLimit(t *testing.T) { 341 content := []byte("hello world") 342 desc := ocispec.Descriptor{ 343 MediaType: "test", 344 Digest: digest.FromBytes(content), 345 Size: int64(len(content)), 346 } 347 348 ctx := context.Background() 349 base := NewMemory() 350 err := base.Push(ctx, desc, bytes.NewReader(content)) 351 if err != nil { 352 t.Fatal("Memory.Push() error =", err) 353 } 354 s := NewProxyWithLimit(base, NewMemory(), 1) 355 356 // test fetch 357 exists, err := s.Exists(ctx, desc) 358 if err != nil { 359 t.Fatal("Proxy.Exists() error =", err) 360 } 361 if !exists { 362 t.Errorf("Proxy.Exists() = %v, want %v", exists, true) 363 } 364 rc, err := s.Fetch(ctx, desc) 365 if err != nil { 366 t.Fatal("Proxy.Fetch() error =", err) 367 } 368 _, err = io.ReadAll(rc) 369 if !errors.Is(err, errdef.ErrSizeExceedsLimit) { 370 t.Fatalf("Proxy.Fetch().Read() error = %v, wantErr %v", err, errdef.ErrSizeExceedsLimit) 371 } 372 }