github.com/thanos-io/thanos@v0.32.5/pkg/store/io_test.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package store 5 6 import ( 7 "bytes" 8 "io" 9 "testing" 10 11 "github.com/pkg/errors" 12 13 "github.com/efficientgo/core/testutil" 14 ) 15 16 func TestByteRanges_contiguous(t *testing.T) { 17 tests := []struct { 18 ranges byteRanges 19 expected bool 20 }{ 21 { 22 ranges: nil, 23 expected: true, 24 }, { 25 ranges: byteRanges{{offset: 10, length: 5}}, 26 expected: true, 27 }, { 28 ranges: byteRanges{{offset: 10, length: 5}, {offset: 15, length: 3}, {offset: 18, length: 2}}, 29 expected: true, 30 }, { 31 ranges: byteRanges{{offset: 10, length: 3}, {offset: 15, length: 3}, {offset: 18, length: 2}}, 32 expected: false, 33 }, { 34 ranges: byteRanges{{offset: 10, length: 5}, {offset: 15, length: 3}, {offset: 19, length: 2}}, 35 expected: false, 36 }, 37 } 38 39 for _, tc := range tests { 40 testutil.Equals(t, tc.expected, tc.ranges.areContiguous()) 41 } 42 } 43 44 func TestReadByteRanges(t *testing.T) { 45 tests := map[string]struct { 46 src []byte 47 ranges byteRanges 48 expectedRead []byte 49 expectedErr error 50 }{ 51 "no ranges": { 52 src: []byte(""), 53 ranges: nil, 54 expectedRead: nil, 55 }, 56 "single range with offset == 0": { 57 src: []byte("ABCDEFGHILMNOPQRSTUVZ"), 58 ranges: []byteRange{{offset: 0, length: 21}}, 59 expectedRead: []byte("ABCDEFGHILMNOPQRSTUVZ"), 60 }, 61 "single range with offset > 0": { 62 src: []byte("ABCDEFGHILMNOPQRSTUVZ"), 63 ranges: []byteRange{{offset: 10, length: 11}}, 64 expectedRead: []byte("MNOPQRSTUVZ"), 65 }, 66 "multiple contiguous ranges with first offset == 0": { 67 src: []byte("ABCDEFGHILMNOPQRSTUVZ"), 68 ranges: []byteRange{ 69 {offset: 0, length: 10}, 70 {offset: 10, length: 10}, 71 {offset: 20, length: 1}, 72 }, 73 expectedRead: []byte("ABCDEFGHILMNOPQRSTUVZ"), 74 }, 75 "multiple contiguous ranges with first offset > 0": { 76 src: []byte("ABCDEFGHILMNOPQRSTUVZ"), 77 ranges: []byteRange{ 78 {offset: 5, length: 5}, 79 {offset: 10, length: 10}, 80 {offset: 20, length: 1}, 81 }, 82 expectedRead: []byte("FGHILMNOPQRSTUVZ"), 83 }, 84 "multiple non-contiguous ranges": { 85 src: []byte("ABCDEFGHILMNOPQRSTUVZ"), 86 ranges: []byteRange{ 87 {offset: 0, length: 3}, 88 {offset: 10, length: 5}, 89 {offset: 16, length: 1}, 90 {offset: 20, length: 1}, 91 }, 92 expectedRead: []byte("ABCMNOPQSZ"), 93 }, 94 "discard bytes before the first range": { 95 src: []byte("ABCDEFGHILMNOPQRSTUVZ"), 96 ranges: []byteRange{ 97 {offset: 5, length: 16}, 98 }, 99 expectedRead: []byte("FGHILMNOPQRSTUVZ"), 100 }, 101 "discard bytes after the last range": { 102 src: []byte("ABCDEFGHILMNOPQRSTUVZ"), 103 ranges: []byteRange{ 104 {offset: 0, length: 16}, 105 }, 106 expectedRead: []byte("ABCDEFGHILMNOPQR"), 107 }, 108 "unexpected EOF while discarding bytes": { 109 src: []byte("ABCDEFGHILMNOPQRSTUVZ"), 110 ranges: []byteRange{ 111 {offset: 0, length: 16}, 112 {offset: 25, length: 5}, 113 }, 114 expectedErr: io.ErrUnexpectedEOF, 115 }, 116 "unexpected EOF while reading byte range": { 117 src: []byte("ABCDEFGHILMNOPQRSTUVZ"), 118 ranges: []byteRange{ 119 {offset: 20, length: 10}, 120 {offset: 40, length: 10}, 121 }, 122 expectedErr: io.ErrUnexpectedEOF, 123 }, 124 "unexpected EOF at the beginning of a byte range": { 125 src: []byte("ABCDEFGHILMNOPQRSTUVZ"), 126 ranges: []byteRange{ 127 {offset: 0, length: 10}, 128 {offset: 20, length: 1}, 129 {offset: 21, length: 10}, 130 }, 131 expectedErr: io.ErrUnexpectedEOF, 132 }, 133 } 134 135 for testName, testData := range tests { 136 t.Run(testName, func(t *testing.T) { 137 actual := make([]byte, 0, 1024) 138 actual, err := readByteRanges(bytes.NewReader(testData.src), actual, testData.ranges) 139 140 if testData.expectedErr != nil { 141 testutil.NotOk(t, err) 142 testutil.Equals(t, true, errors.Is(err, testData.expectedErr)) 143 } else { 144 testutil.Ok(t, err) 145 testutil.Equals(t, testData.expectedRead, actual) 146 } 147 }) 148 } 149 }