github.com/dtroyer-salad/og2/v2@v2.0.0-20240412154159-c47231610877/content/reader_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 content 17 18 import ( 19 "bytes" 20 _ "crypto/sha256" 21 "errors" 22 "io" 23 "reflect" 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/internal/spec" 29 ) 30 31 func TestVerifyReader_NewVerifyReader(t *testing.T) { 32 content := []byte("example content") 33 34 // Default no-resume path 35 r := bytes.NewReader(content) 36 desc := ocispec.Descriptor{ 37 MediaType: ocispec.MediaTypeImageLayer, 38 Digest: digest.FromBytes(content), 39 Size: int64(len(content) + 1), 40 } 41 vr := NewVerifyReader(r, desc) 42 if vr.resume { 43 t.Fatalf("resume is set: %s", desc.Annotations) 44 } 45 46 // Resume is enabled and we expect to read something 47 r = bytes.NewReader(content) 48 desc = ocispec.Descriptor{ 49 MediaType: ocispec.MediaTypeImageLayer, 50 Digest: digest.FromBytes(content), 51 Size: int64(len(content) + 1), 52 Annotations: map[string]string{ 53 spec.AnnotationResumeDownload: "true", 54 spec.AnnotationResumeOffset: "3", 55 }, 56 } 57 vr = NewVerifyReader(r, desc) 58 if !vr.resume { 59 t.Fatalf("resume is not set: %+v", desc.Annotations) 60 } 61 62 // Resume is enabled and we expect to read something with hash 63 d := digest.FromBytes(content) 64 h, _ := EncodeHash(d.Algorithm().Hash()) 65 r = bytes.NewReader(content) 66 desc = ocispec.Descriptor{ 67 MediaType: ocispec.MediaTypeImageLayer, 68 Digest: d, 69 Size: int64(len(content) + 1), 70 Annotations: map[string]string{ 71 spec.AnnotationResumeDownload: "true", 72 spec.AnnotationResumeOffset: "3", 73 spec.AnnotationResumeHash: h, 74 }, 75 } 76 vr = NewVerifyReader(r, desc) 77 if !vr.resume { 78 t.Fatalf("resume is not set: %+v", desc.Annotations) 79 } 80 } 81 82 func TestVerifyReader_Read(t *testing.T) { 83 // matched content and descriptor with small buffer 84 content := []byte("example content") 85 desc := NewDescriptorFromBytes("test", content) 86 r := bytes.NewReader(content) 87 vr := NewVerifyReader(r, desc) 88 buf := make([]byte, 5) 89 n, err := vr.Read(buf) 90 if err != nil { 91 t.Fatal("Read() error = ", err) 92 } 93 if !bytes.Equal(buf, []byte("examp")) { 94 t.Fatalf("incorrect read content: %s", buf) 95 } 96 if n != 5 { 97 t.Fatalf("incorrect number of bytes read: %d", n) 98 } 99 100 // matched content and descriptor with sufficient buffer 101 content = []byte("foo foo") 102 desc = NewDescriptorFromBytes("test", content) 103 r = bytes.NewReader(content) 104 vr = NewVerifyReader(r, desc) 105 buf = make([]byte, len(content)) 106 n, err = vr.Read(buf) 107 if err != nil { 108 t.Fatal("Read() error = ", err) 109 } 110 if n != len(content) { 111 t.Fatalf("incorrect number of bytes read: %d", n) 112 } 113 if !bytes.Equal(buf, content) { 114 t.Fatalf("incorrect read content: %s", buf) 115 } 116 117 // mismatched content and descriptor with sufficient buffer 118 r = bytes.NewReader([]byte("bar")) 119 vr = NewVerifyReader(r, desc) 120 buf = make([]byte, 5) 121 n, err = vr.Read(buf) 122 if err != nil { 123 t.Fatal("Read() error = ", err) 124 } 125 if n != 3 { 126 t.Fatalf("incorrect number of bytes read: %d", n) 127 } 128 } 129 130 func TestVerifyReader_Read_Resume(t *testing.T) { 131 // matched content and descriptor with small buffer 132 content := []byte("example content") 133 desc := NewDescriptorFromBytes("test", content) 134 r := bytes.NewReader(content) 135 vr := NewVerifyReader(r, desc) 136 vr.resume = true 137 buf := make([]byte, 5) 138 n, err := vr.Read(buf) 139 if err != nil { 140 t.Fatal("Read() error = ", err) 141 } 142 if !bytes.Equal(buf, []byte("examp")) { 143 t.Fatalf("incorrect read content: %s", buf) 144 } 145 if n != 5 { 146 t.Fatalf("incorrect number of bytes read: %d", n) 147 } 148 149 // matched content and descriptor with sufficient buffer 150 content = []byte("foo foo") 151 desc = NewDescriptorFromBytes("test", content) 152 r = bytes.NewReader(content) 153 vr = NewVerifyReader(r, desc) 154 vr.resume = true 155 buf = make([]byte, len(content)) 156 n, err = vr.Read(buf) 157 if err != nil { 158 t.Fatal("Read() error = ", err) 159 } 160 if n != len(content) { 161 t.Fatalf("incorrect number of bytes read: %d", n) 162 } 163 if !bytes.Equal(buf, content) { 164 t.Fatalf("incorrect read content: %s", buf) 165 } 166 167 // mismatched content and descriptor with sufficient buffer 168 r = bytes.NewReader([]byte("bar")) 169 vr = NewVerifyReader(r, desc) 170 vr.resume = true 171 buf = make([]byte, 5) 172 n, err = vr.Read(buf) 173 if err != nil { 174 t.Fatal("Read() error = ", err) 175 } 176 if n != 3 { 177 t.Fatalf("incorrect number of bytes read: %d", n) 178 } 179 } 180 181 func TestVerifyReader_Verify(t *testing.T) { 182 // matched content and descriptor 183 content := []byte("example content") 184 desc := NewDescriptorFromBytes("test", content) 185 r := bytes.NewReader(content) 186 vr := NewVerifyReader(r, desc) 187 buf := make([]byte, len(content)) 188 if _, err := vr.Read(buf); err != nil { 189 t.Fatal("Read() error = ", err) 190 } 191 if err := vr.Verify(); err != nil { 192 t.Fatal("Verify() error = ", err) 193 } 194 if !bytes.Equal(buf, content) { 195 t.Fatalf("incorrect read content: %s", buf) 196 } 197 198 // mismatched content and descriptor, read size larger than descriptor size 199 content = []byte("foo") 200 r = bytes.NewReader(content) 201 desc = ocispec.Descriptor{ 202 MediaType: ocispec.MediaTypeImageLayer, 203 Digest: digest.FromBytes(content), 204 Size: int64(len(content)) - 1} 205 vr = NewVerifyReader(r, desc) 206 buf = make([]byte, len(content)) 207 if _, err := vr.Read(buf); err != nil { 208 t.Fatal("Read() error = ", err) 209 } 210 if err := vr.Verify(); !errors.Is(err, ErrTrailingData) { 211 t.Fatalf("Verify() error = %v, want %v", err, ErrTrailingData) 212 } 213 // call vr.Verify again, the result should be the same 214 if err := vr.Verify(); !errors.Is(err, ErrTrailingData) { 215 t.Fatalf("2nd Verify() error = %v, want %v", err, ErrTrailingData) 216 } 217 218 // mismatched content and descriptor, read size smaller than descriptor size 219 content = []byte("foo") 220 r = bytes.NewReader(content) 221 desc = ocispec.Descriptor{ 222 MediaType: ocispec.MediaTypeImageLayer, 223 Digest: digest.FromBytes(content), 224 Size: int64(len(content)) + 1} 225 vr = NewVerifyReader(r, desc) 226 buf = make([]byte, len(content)) 227 if _, err := vr.Read(buf); err != nil { 228 t.Fatal("Read() error = ", err) 229 } 230 if err := vr.Verify(); !errors.Is(err, errEarlyVerify) { 231 t.Fatalf("Verify() error = %v, want %v", err, errEarlyVerify) 232 } 233 // call vr.Verify again, the result should be the same 234 if err := vr.Verify(); !errors.Is(err, errEarlyVerify) { 235 t.Fatalf("Verify() error = %v, want %v", err, errEarlyVerify) 236 } 237 238 // mismatched content and descriptor, wrong digest 239 content = []byte("bar") 240 r = bytes.NewReader(content) 241 desc = NewDescriptorFromBytes("test", []byte("foo")) 242 vr = NewVerifyReader(r, desc) 243 buf = make([]byte, len(content)) 244 if _, err := vr.Read(buf); err != nil { 245 t.Fatal("Read() error = ", err) 246 } 247 if err := vr.Verify(); !errors.Is(err, ErrMismatchedDigest) { 248 t.Fatalf("Verify() error = %v, want %v", err, ErrMismatchedDigest) 249 } 250 // call vr.Verify again, the result should be the same 251 if err := vr.Verify(); !errors.Is(err, ErrMismatchedDigest) { 252 t.Fatalf("2nd Verify() error = %v, want %v", err, ErrMismatchedDigest) 253 } 254 } 255 256 func TestVerifyReader_Verify_Resume(t *testing.T) { 257 // matched content and descriptor 258 content := []byte("example content") 259 desc := ocispec.Descriptor{ 260 MediaType: "test", 261 Digest: digest.FromBytes(content), 262 Size: int64(len(content)), 263 Annotations: map[string]string{ 264 spec.AnnotationResumeDownload: "true", 265 spec.AnnotationResumeOffset: "3", 266 }, 267 } 268 r := bytes.NewReader(content) 269 vr := NewVerifyReader(r, desc) 270 buf := make([]byte, len(content)) 271 if _, err := vr.Read(buf); err != nil { 272 t.Fatal("Read() error = ", err) 273 } 274 if err := vr.Verify(); err != nil { 275 t.Fatal("Verify() error = ", err) 276 } 277 if !bytes.Equal(buf, content) { 278 t.Fatalf("incorrect read content: %s", buf) 279 } 280 281 // mismatched content and descriptor, read size larger than descriptor size 282 content = []byte("foo") 283 r = bytes.NewReader(content) 284 desc = ocispec.Descriptor{ 285 MediaType: "test", 286 Digest: digest.FromBytes(content), 287 Size: int64(len(content) - 1), 288 Annotations: map[string]string{ 289 spec.AnnotationResumeDownload: "true", 290 spec.AnnotationResumeOffset: "3", 291 }, 292 } 293 vr = NewVerifyReader(r, desc) 294 buf = make([]byte, len(content)) 295 if _, err := vr.Read(buf); err != nil { 296 t.Fatal("Read() error = ", err) 297 } 298 if err := vr.Verify(); !errors.Is(err, ErrTrailingData) { 299 t.Fatalf("Verify() error = %v, want %v", err, ErrTrailingData) 300 } 301 // call vr.Verify again, the result should be the same 302 if err := vr.Verify(); !errors.Is(err, ErrTrailingData) { 303 t.Fatalf("2nd Verify() error = %v, want %v", err, ErrTrailingData) 304 } 305 306 // mismatched content and descriptor, read size smaller than descriptor size 307 content = []byte("foo") 308 r = bytes.NewReader(content) 309 desc = ocispec.Descriptor{ 310 MediaType: "test", 311 Digest: digest.FromBytes(content), 312 Size: int64(len(content) + 1), 313 Annotations: map[string]string{ 314 spec.AnnotationResumeDownload: "true", 315 spec.AnnotationResumeOffset: "3", 316 }, 317 } 318 vr = NewVerifyReader(r, desc) 319 buf = make([]byte, len(content)) 320 if _, err := vr.Read(buf); err != nil { 321 t.Fatal("Read() error = ", err) 322 } 323 if err := vr.Verify(); !errors.Is(err, errEarlyVerify) { 324 t.Fatalf("Verify() error = %v, want %v", err, errEarlyVerify) 325 } 326 // call vr.Verify again, the result should be the same 327 if err := vr.Verify(); !errors.Is(err, errEarlyVerify) { 328 t.Fatalf("Verify() error = %v, want %v", err, errEarlyVerify) 329 } 330 331 // mismatched content and descriptor, wrong digest 332 content = []byte("bar") 333 r = bytes.NewReader(content) 334 desc = ocispec.Descriptor{ 335 MediaType: "test", 336 Digest: digest.FromBytes([]byte("foo")), 337 Size: int64(len(content)), 338 Annotations: map[string]string{ 339 spec.AnnotationResumeDownload: "true", 340 spec.AnnotationResumeOffset: "3", 341 }, 342 } 343 vr = NewVerifyReader(r, desc) 344 buf = make([]byte, len(content)) 345 if _, err := vr.Read(buf); err != nil { 346 t.Fatal("Read() error = ", err) 347 } 348 if err := vr.Verify(); !errors.Is(err, ErrMismatchedDigest) { 349 t.Fatalf("Verify() error = %v, want %v", err, ErrMismatchedDigest) 350 } 351 // call vr.Verify again, the result should be the same 352 if err := vr.Verify(); !errors.Is(err, ErrMismatchedDigest) { 353 t.Fatalf("2nd Verify() error = %v, want %v", err, ErrMismatchedDigest) 354 } 355 } 356 357 func TestReadAll_CorrectDescriptor(t *testing.T) { 358 content := []byte("example content") 359 desc := NewDescriptorFromBytes("test", content) 360 r := bytes.NewReader([]byte(content)) 361 got, err := ReadAll(r, desc) 362 if err != nil { 363 t.Fatal("ReadAll() error = ", err) 364 } 365 if !bytes.Equal(got, content) { 366 t.Errorf("ReadAll() = %v, want %v", got, content) 367 } 368 } 369 370 func TestReadAll_CorrectDescriptor_Resume(t *testing.T) { 371 content := []byte("example content") 372 desc := ocispec.Descriptor{ 373 MediaType: "test", 374 Digest: digest.FromBytes(content), 375 Size: int64(len(content)), 376 Annotations: map[string]string{ 377 spec.AnnotationResumeDownload: "true", 378 spec.AnnotationResumeOffset: "3", 379 }, 380 } 381 r := bytes.NewReader([]byte(content)) 382 got, err := ReadAll(r, desc) 383 if err != nil { 384 t.Fatal("ReadAll() error = ", err) 385 } 386 if !bytes.Equal(got, content) { 387 t.Errorf("ReadAll() = %v, want %v", got, content) 388 } 389 } 390 391 func TestReadAll_ReadSizeSmallerThanDescriptorSize(t *testing.T) { 392 content := []byte("example content") 393 desc := ocispec.Descriptor{ 394 MediaType: ocispec.MediaTypeImageLayer, 395 Digest: digest.FromBytes(content), 396 Size: int64(len(content) + 1)} 397 r := bytes.NewReader([]byte(content)) 398 _, err := ReadAll(r, desc) 399 if err == nil || !errors.Is(err, io.ErrUnexpectedEOF) { 400 t.Errorf("ReadAll() error = %v, want %v", err, io.ErrUnexpectedEOF) 401 } 402 } 403 404 func TestReadAll_ReadSizeSmallerThanDescriptorSize_Resume(t *testing.T) { 405 content := []byte("example content") 406 desc := ocispec.Descriptor{ 407 MediaType: ocispec.MediaTypeImageLayer, 408 Digest: digest.FromBytes(content), 409 Size: int64(len(content) + 1), 410 Annotations: map[string]string{ 411 spec.AnnotationResumeDownload: "true", 412 spec.AnnotationResumeOffset: "3", 413 }, 414 } 415 r := bytes.NewReader([]byte(content)) 416 _, err := ReadAll(r, desc) 417 if err == nil || !errors.Is(err, io.EOF) { 418 t.Errorf("ReadAll() error = %v, want %v", err, io.EOF) 419 } 420 } 421 422 func TestReadAll_ReadSizeLargerThanDescriptorSize(t *testing.T) { 423 content := []byte("example content") 424 desc := ocispec.Descriptor{ 425 MediaType: ocispec.MediaTypeImageLayer, 426 Digest: digest.FromBytes(content), 427 Size: int64(len(content) - 1)} 428 r := bytes.NewReader([]byte(content)) 429 _, err := ReadAll(r, desc) 430 if err == nil || !errors.Is(err, ErrTrailingData) { 431 t.Errorf("ReadAll() error = %v, want %v", err, ErrTrailingData) 432 } 433 } 434 435 func TestReadAll_ReadSizeLargerThanDescriptorSize_Resume(t *testing.T) { 436 content := []byte("example content") 437 desc := ocispec.Descriptor{ 438 MediaType: ocispec.MediaTypeImageLayer, 439 Digest: digest.FromBytes(content), 440 Size: int64(len(content) - 1), 441 Annotations: map[string]string{ 442 spec.AnnotationResumeDownload: "true", 443 spec.AnnotationResumeOffset: "3", 444 }, 445 } 446 r := bytes.NewReader([]byte(content)) 447 _, err := ReadAll(r, desc) 448 if err == nil || !errors.Is(err, ErrTrailingData) { 449 t.Errorf("ReadAll() error = %v, want %v", err, ErrTrailingData) 450 } 451 } 452 453 func TestReadAll_InvalidDigest(t *testing.T) { 454 content := []byte("example content") 455 desc := NewDescriptorFromBytes("test", []byte("another content")) 456 r := bytes.NewReader([]byte(content)) 457 _, err := ReadAll(r, desc) 458 if err == nil || !errors.Is(err, ErrMismatchedDigest) { 459 t.Errorf("ReadAll() error = %v, want %v", err, ErrMismatchedDigest) 460 } 461 } 462 463 func TestReadAll_InvalidDigest_Resume(t *testing.T) { 464 content := []byte("example content") 465 desc := ocispec.Descriptor{ 466 MediaType: "test", 467 Digest: digest.FromBytes([]byte("another content")), 468 Size: int64(len(content)), 469 Annotations: map[string]string{ 470 spec.AnnotationResumeDownload: "true", 471 spec.AnnotationResumeOffset: "3", 472 }, 473 } 474 r := bytes.NewReader([]byte(content)) 475 _, err := ReadAll(r, desc) 476 if err == nil || !errors.Is(err, ErrMismatchedDigest) { 477 t.Errorf("ReadAll() error = %v, want %v", err, ErrMismatchedDigest) 478 } 479 } 480 481 func TestReadAll_EmptyContent(t *testing.T) { 482 content := []byte("") 483 desc := NewDescriptorFromBytes("test", content) 484 r := bytes.NewReader([]byte(content)) 485 got, err := ReadAll(r, desc) 486 if err != nil { 487 t.Fatal("ReadAll() error = ", err) 488 } 489 if !bytes.Equal(got, content) { 490 t.Errorf("ReadAll() = %v, want %v", got, content) 491 } 492 } 493 494 func TestReadAll_EmptyContent_Resume(t *testing.T) { 495 content := []byte("") 496 desc := ocispec.Descriptor{ 497 MediaType: "test", 498 Digest: digest.FromBytes(content), 499 Size: int64(len(content)), 500 Annotations: map[string]string{ 501 spec.AnnotationResumeDownload: "true", 502 spec.AnnotationResumeOffset: "3", 503 }, 504 } 505 r := bytes.NewReader([]byte(content)) 506 got, err := ReadAll(r, desc) 507 if err != nil { 508 t.Fatal("ReadAll() error = ", err) 509 } 510 if !bytes.Equal(got, content) { 511 t.Errorf("ReadAll() = %v, want %v", got, content) 512 } 513 } 514 515 func TestReadAll_InvalidDescriptorSize(t *testing.T) { 516 content := []byte("example content") 517 desc := ocispec.Descriptor{ 518 MediaType: ocispec.MediaTypeImageLayer, 519 Digest: digest.FromBytes(content), 520 Size: -1, 521 } 522 r := bytes.NewReader([]byte(content)) 523 _, err := ReadAll(r, desc) 524 if err == nil || !errors.Is(err, ErrInvalidDescriptorSize) { 525 t.Errorf("ReadAll() error = %v, want %v", err, ErrInvalidDescriptorSize) 526 } 527 } 528 529 func TestReadAll_InvalidDescriptorSize_Resume(t *testing.T) { 530 content := []byte("example content") 531 desc := ocispec.Descriptor{ 532 MediaType: ocispec.MediaTypeImageLayer, 533 Digest: digest.FromBytes(content), 534 Size: -1, 535 Annotations: map[string]string{ 536 spec.AnnotationResumeDownload: "true", 537 spec.AnnotationResumeOffset: "3", 538 }, 539 } 540 r := bytes.NewReader([]byte(content)) 541 _, err := ReadAll(r, desc) 542 if err == nil || !errors.Is(err, ErrInvalidDescriptorSize) { 543 t.Errorf("ReadAll() error = %v, want %v", err, ErrInvalidDescriptorSize) 544 } 545 } 546 547 func TestEncodeDecodeHash(t *testing.T) { 548 content := []byte("example content") 549 550 d := digest.FromBytes(content) 551 eh, err := EncodeHash(d.Algorithm().Hash()) 552 if err != nil { 553 t.Fatal("EncodeHash failed =", err) 554 } 555 if eh == "" { 556 t.Fatal("EncodeHash returned empty") 557 } 558 559 dh, err := DecodeHash(eh, d) 560 if err != nil { 561 t.Fatal("DecodeHash failed =", err) 562 } 563 if !reflect.DeepEqual(dh, d.Algorithm().Hash()) { 564 t.Fatalf("EncodeHash/DecodeHash error = %v, want %v", dh, d.Algorithm().Hash()) 565 } 566 }