github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/metacache-stream_test.go (about) 1 // Copyright (c) 2015-2021 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package cmd 19 20 import ( 21 "bytes" 22 "context" 23 "io" 24 "os" 25 "reflect" 26 "sync" 27 "testing" 28 ) 29 30 var loadMetacacheSampleNames = []string{"src/compress/bzip2/", "src/compress/bzip2/bit_reader.go", "src/compress/bzip2/bzip2.go", "src/compress/bzip2/bzip2_test.go", "src/compress/bzip2/huffman.go", "src/compress/bzip2/move_to_front.go", "src/compress/bzip2/testdata/", "src/compress/bzip2/testdata/Isaac.Newton-Opticks.txt.bz2", "src/compress/bzip2/testdata/e.txt.bz2", "src/compress/bzip2/testdata/fail-issue5747.bz2", "src/compress/bzip2/testdata/pass-random1.bin", "src/compress/bzip2/testdata/pass-random1.bz2", "src/compress/bzip2/testdata/pass-random2.bin", "src/compress/bzip2/testdata/pass-random2.bz2", "src/compress/bzip2/testdata/pass-sawtooth.bz2", "src/compress/bzip2/testdata/random.data.bz2", "src/compress/flate/", "src/compress/flate/deflate.go", "src/compress/flate/deflate_test.go", "src/compress/flate/deflatefast.go", "src/compress/flate/dict_decoder.go", "src/compress/flate/dict_decoder_test.go", "src/compress/flate/example_test.go", "src/compress/flate/flate_test.go", "src/compress/flate/huffman_bit_writer.go", "src/compress/flate/huffman_bit_writer_test.go", "src/compress/flate/huffman_code.go", "src/compress/flate/inflate.go", "src/compress/flate/inflate_test.go", "src/compress/flate/reader_test.go", "src/compress/flate/testdata/", "src/compress/flate/testdata/huffman-null-max.dyn.expect", "src/compress/flate/testdata/huffman-null-max.dyn.expect-noinput", "src/compress/flate/testdata/huffman-null-max.golden", "src/compress/flate/testdata/huffman-null-max.in", "src/compress/flate/testdata/huffman-null-max.wb.expect", "src/compress/flate/testdata/huffman-null-max.wb.expect-noinput", "src/compress/flate/testdata/huffman-pi.dyn.expect", "src/compress/flate/testdata/huffman-pi.dyn.expect-noinput", "src/compress/flate/testdata/huffman-pi.golden", "src/compress/flate/testdata/huffman-pi.in", "src/compress/flate/testdata/huffman-pi.wb.expect", "src/compress/flate/testdata/huffman-pi.wb.expect-noinput", "src/compress/flate/testdata/huffman-rand-1k.dyn.expect", "src/compress/flate/testdata/huffman-rand-1k.dyn.expect-noinput", "src/compress/flate/testdata/huffman-rand-1k.golden", "src/compress/flate/testdata/huffman-rand-1k.in", "src/compress/flate/testdata/huffman-rand-1k.wb.expect", "src/compress/flate/testdata/huffman-rand-1k.wb.expect-noinput", "src/compress/flate/testdata/huffman-rand-limit.dyn.expect", "src/compress/flate/testdata/huffman-rand-limit.dyn.expect-noinput", "src/compress/flate/testdata/huffman-rand-limit.golden", "src/compress/flate/testdata/huffman-rand-limit.in", "src/compress/flate/testdata/huffman-rand-limit.wb.expect", "src/compress/flate/testdata/huffman-rand-limit.wb.expect-noinput", "src/compress/flate/testdata/huffman-rand-max.golden", "src/compress/flate/testdata/huffman-rand-max.in", "src/compress/flate/testdata/huffman-shifts.dyn.expect", "src/compress/flate/testdata/huffman-shifts.dyn.expect-noinput", "src/compress/flate/testdata/huffman-shifts.golden", "src/compress/flate/testdata/huffman-shifts.in", "src/compress/flate/testdata/huffman-shifts.wb.expect", "src/compress/flate/testdata/huffman-shifts.wb.expect-noinput", "src/compress/flate/testdata/huffman-text-shift.dyn.expect", "src/compress/flate/testdata/huffman-text-shift.dyn.expect-noinput", "src/compress/flate/testdata/huffman-text-shift.golden", "src/compress/flate/testdata/huffman-text-shift.in", "src/compress/flate/testdata/huffman-text-shift.wb.expect", "src/compress/flate/testdata/huffman-text-shift.wb.expect-noinput", "src/compress/flate/testdata/huffman-text.dyn.expect", "src/compress/flate/testdata/huffman-text.dyn.expect-noinput", "src/compress/flate/testdata/huffman-text.golden", "src/compress/flate/testdata/huffman-text.in", "src/compress/flate/testdata/huffman-text.wb.expect", "src/compress/flate/testdata/huffman-text.wb.expect-noinput", "src/compress/flate/testdata/huffman-zero.dyn.expect", "src/compress/flate/testdata/huffman-zero.dyn.expect-noinput", "src/compress/flate/testdata/huffman-zero.golden", "src/compress/flate/testdata/huffman-zero.in", "src/compress/flate/testdata/huffman-zero.wb.expect", "src/compress/flate/testdata/huffman-zero.wb.expect-noinput", "src/compress/flate/testdata/null-long-match.dyn.expect-noinput", "src/compress/flate/testdata/null-long-match.wb.expect-noinput", "src/compress/flate/token.go", "src/compress/flate/writer_test.go", "src/compress/gzip/", "src/compress/gzip/example_test.go", "src/compress/gzip/gunzip.go", "src/compress/gzip/gunzip_test.go", "src/compress/gzip/gzip.go", "src/compress/gzip/gzip_test.go", "src/compress/gzip/issue14937_test.go", "src/compress/gzip/testdata/", "src/compress/gzip/testdata/issue6550.gz.base64", "src/compress/lzw/", "src/compress/lzw/reader.go", "src/compress/lzw/reader_test.go", "src/compress/lzw/writer.go", "src/compress/lzw/writer_test.go", "src/compress/testdata/", "src/compress/testdata/e.txt", "src/compress/testdata/gettysburg.txt", "src/compress/testdata/pi.txt", "src/compress/zlib/", "src/compress/zlib/example_test.go", "src/compress/zlib/reader.go", "src/compress/zlib/reader_test.go", "src/compress/zlib/writer.go", "src/compress/zlib/writer_test.go"} 31 32 func loadMetacacheSample(t testing.TB) *metacacheReader { 33 b, err := os.ReadFile("testdata/metacache.s2") 34 if err != nil { 35 t.Fatal(err) 36 } 37 return newMetacacheReader(bytes.NewReader(b)) 38 } 39 40 func loadMetacacheSampleEntries(t testing.TB) metaCacheEntriesSorted { 41 r := loadMetacacheSample(t) 42 defer r.Close() 43 entries, err := r.readN(-1, false, true, false, "") 44 if err != io.EOF { 45 t.Fatal(err) 46 } 47 48 return entries 49 } 50 51 func Test_metacacheReader_readNames(t *testing.T) { 52 r := loadMetacacheSample(t) 53 defer r.Close() 54 names, err := r.readNames(-1) 55 if err != io.EOF { 56 t.Fatal(err) 57 } 58 want := loadMetacacheSampleNames 59 if !reflect.DeepEqual(names, want) { 60 t.Errorf("got unexpected result: %#v", names) 61 } 62 } 63 64 func Test_metacacheReader_readN(t *testing.T) { 65 r := loadMetacacheSample(t) 66 defer r.Close() 67 entries, err := r.readN(-1, false, true, false, "") 68 if err != io.EOF { 69 t.Fatal(err, entries.len()) 70 } 71 want := loadMetacacheSampleNames 72 for i, entry := range entries.entries() { 73 if entry.name != want[i] { 74 t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name) 75 } 76 } 77 if entries.len() != len(want) { 78 t.Fatal("unexpected length:", entries.len(), "want:", len(want)) 79 } 80 81 want = want[:0] 82 entries, err = r.readN(0, false, true, false, "") 83 if err != nil { 84 t.Fatal(err, entries.len()) 85 } 86 if entries.len() != len(want) { 87 t.Fatal("unexpected length:", entries.len(), "want:", len(want)) 88 } 89 90 // Reload. 91 r = loadMetacacheSample(t) 92 defer r.Close() 93 entries, err = r.readN(0, false, true, false, "") 94 if err != nil { 95 t.Fatal(err, entries.len()) 96 } 97 if entries.len() != len(want) { 98 t.Fatal("unexpected length:", entries.len(), "want:", len(want)) 99 } 100 101 entries, err = r.readN(5, false, true, false, "") 102 if err != nil { 103 t.Fatal(err, entries.len()) 104 } 105 want = loadMetacacheSampleNames[:5] 106 if entries.len() != len(want) { 107 t.Fatal("unexpected length:", entries.len(), "want:", len(want)) 108 } 109 110 for i, entry := range entries.entries() { 111 if entry.name != want[i] { 112 t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name) 113 } 114 } 115 } 116 117 func Test_metacacheReader_readNDirs(t *testing.T) { 118 r := loadMetacacheSample(t) 119 defer r.Close() 120 entries, err := r.readN(-1, false, true, false, "") 121 if err != io.EOF { 122 t.Fatal(err, entries.len()) 123 } 124 want := loadMetacacheSampleNames 125 var noDirs []string 126 for i, entry := range entries.entries() { 127 if entry.name != want[i] { 128 t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name) 129 } 130 if !entry.isDir() { 131 noDirs = append(noDirs, entry.name) 132 } 133 } 134 if entries.len() != len(want) { 135 t.Fatal("unexpected length:", entries.len(), "want:", len(want)) 136 } 137 138 want = noDirs 139 r = loadMetacacheSample(t) 140 defer r.Close() 141 entries, err = r.readN(-1, false, false, false, "") 142 if err != io.EOF { 143 t.Fatal(err, entries.len()) 144 } 145 for i, entry := range entries.entries() { 146 if entry.name != want[i] { 147 t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name) 148 } 149 } 150 if entries.len() != len(want) { 151 t.Fatal("unexpected length:", entries.len(), "want:", len(want)) 152 } 153 154 want = want[:0] 155 entries, err = r.readN(0, false, false, false, "") 156 if err != nil { 157 t.Fatal(err, entries.len()) 158 } 159 if entries.len() != len(want) { 160 t.Fatal("unexpected length:", entries.len(), "want:", len(want)) 161 } 162 163 // Reload. 164 r = loadMetacacheSample(t) 165 defer r.Close() 166 entries, err = r.readN(0, false, false, false, "") 167 if err != nil { 168 t.Fatal(err, entries.len()) 169 } 170 if entries.len() != len(want) { 171 t.Fatal("unexpected length:", entries.len(), "want:", len(want)) 172 } 173 174 entries, err = r.readN(5, false, false, false, "") 175 if err != nil { 176 t.Fatal(err, entries.len()) 177 } 178 want = noDirs[:5] 179 if entries.len() != len(want) { 180 t.Fatal("unexpected length:", entries.len(), "want:", len(want)) 181 } 182 183 for i, entry := range entries.entries() { 184 if entry.name != want[i] { 185 t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name) 186 } 187 } 188 } 189 190 func Test_metacacheReader_readNPrefix(t *testing.T) { 191 r := loadMetacacheSample(t) 192 defer r.Close() 193 entries, err := r.readN(-1, false, true, false, "src/compress/bzip2/") 194 if err != io.EOF { 195 t.Fatal(err, entries.len()) 196 } 197 want := loadMetacacheSampleNames[:16] 198 for i, entry := range entries.entries() { 199 if entry.name != want[i] { 200 t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name) 201 } 202 } 203 if entries.len() != len(want) { 204 t.Fatal("unexpected length:", entries.len(), "want:", len(want)) 205 } 206 207 r = loadMetacacheSample(t) 208 defer r.Close() 209 entries, err = r.readN(-1, false, true, false, "src/nonexist") 210 if err != io.EOF { 211 t.Fatal(err, entries.len()) 212 } 213 want = loadMetacacheSampleNames[:0] 214 if entries.len() != len(want) { 215 t.Fatal("unexpected length:", entries.len(), "want:", len(want)) 216 } 217 for i, entry := range entries.entries() { 218 if entry.name != want[i] { 219 t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name) 220 } 221 } 222 223 r = loadMetacacheSample(t) 224 defer r.Close() 225 entries, err = r.readN(-1, false, true, false, "src/a") 226 if err != io.EOF { 227 t.Fatal(err, entries.len()) 228 } 229 want = loadMetacacheSampleNames[:0] 230 if entries.len() != len(want) { 231 t.Fatal("unexpected length:", entries.len(), "want:", len(want)) 232 } 233 for i, entry := range entries.entries() { 234 if entry.name != want[i] { 235 t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name) 236 } 237 } 238 239 r = loadMetacacheSample(t) 240 defer r.Close() 241 entries, err = r.readN(-1, false, true, false, "src/compress/zlib/e") 242 if err != io.EOF { 243 t.Fatal(err, entries.len()) 244 } 245 want = []string{"src/compress/zlib/example_test.go"} 246 if entries.len() != len(want) { 247 t.Fatal("unexpected length:", entries.len(), "want:", len(want)) 248 } 249 for i, entry := range entries.entries() { 250 if entry.name != want[i] { 251 t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name) 252 } 253 } 254 } 255 256 func Test_metacacheReader_readFn(t *testing.T) { 257 r := loadMetacacheSample(t) 258 defer r.Close() 259 i := 0 260 err := r.readFn(func(entry metaCacheEntry) bool { 261 want := loadMetacacheSampleNames[i] 262 if entry.name != want { 263 t.Errorf("entry %d, want %q, got %q", i, want, entry.name) 264 } 265 i++ 266 return true 267 }) 268 if err != io.EOF { 269 t.Fatal(err) 270 } 271 } 272 273 func Test_metacacheReader_readAll(t *testing.T) { 274 r := loadMetacacheSample(t) 275 defer r.Close() 276 var readErr error 277 objs := make(chan metaCacheEntry, 1) 278 var wg sync.WaitGroup 279 wg.Add(1) 280 go func() { 281 readErr = r.readAll(context.Background(), objs) 282 wg.Done() 283 }() 284 want := loadMetacacheSampleNames 285 i := 0 286 for entry := range objs { 287 if entry.name != want[i] { 288 t.Errorf("entry %d, want %q, got %q", i, want[i], entry.name) 289 } 290 i++ 291 } 292 wg.Wait() 293 if readErr != nil { 294 t.Fatal(readErr) 295 } 296 } 297 298 func Test_metacacheReader_forwardTo(t *testing.T) { 299 r := loadMetacacheSample(t) 300 defer r.Close() 301 err := r.forwardTo("src/compress/zlib/reader_test.go") 302 if err != nil { 303 t.Fatal(err) 304 } 305 names, err := r.readNames(-1) 306 if err != io.EOF { 307 t.Fatal(err) 308 } 309 want := []string{"src/compress/zlib/reader_test.go", "src/compress/zlib/writer.go", "src/compress/zlib/writer_test.go"} 310 if !reflect.DeepEqual(names, want) { 311 t.Errorf("got unexpected result: %#v", names) 312 } 313 314 // Try with prefix 315 r = loadMetacacheSample(t) 316 err = r.forwardTo("src/compress/zlib/reader_t") 317 if err != nil { 318 t.Fatal(err) 319 } 320 names, err = r.readNames(-1) 321 if err != io.EOF { 322 t.Fatal(err) 323 } 324 if !reflect.DeepEqual(names, want) { 325 t.Errorf("got unexpected result: %#v", names) 326 } 327 } 328 329 func Test_metacacheReader_next(t *testing.T) { 330 r := loadMetacacheSample(t) 331 defer r.Close() 332 for i, want := range loadMetacacheSampleNames { 333 gotObj, err := r.next() 334 if err != nil { 335 t.Fatal(err) 336 } 337 if gotObj.name != want { 338 t.Errorf("entry %d, want %q, got %q", i, want, gotObj.name) 339 } 340 } 341 } 342 343 func Test_metacacheReader_peek(t *testing.T) { 344 r := loadMetacacheSample(t) 345 defer r.Close() 346 for i, want := range loadMetacacheSampleNames { 347 got, err := r.peek() 348 if err == io.EOF { 349 break 350 } 351 if err != nil { 352 t.Fatal(err) 353 } 354 if got.name != want { 355 t.Errorf("entry %d, want %q, got %q", i, want, got.name) 356 } 357 gotObj, err := r.next() 358 if err != nil { 359 t.Fatal(err) 360 } 361 if gotObj.name != want { 362 t.Errorf("entry %d, want %q, got %q", i, want, gotObj.name) 363 } 364 } 365 } 366 367 func Test_newMetacacheStream(t *testing.T) { 368 r := loadMetacacheSample(t) 369 var buf bytes.Buffer 370 w := newMetacacheWriter(&buf, 1<<20) 371 defer w.Close() 372 err := r.readFn(func(object metaCacheEntry) bool { 373 err := w.write(object) 374 if err != nil { 375 t.Fatal(err) 376 } 377 return true 378 }) 379 r.Close() 380 if err != io.EOF { 381 t.Fatal(err) 382 } 383 err = w.Close() 384 if err != nil { 385 t.Fatal(err) 386 } 387 388 r = newMetacacheReader(&buf) 389 defer r.Close() 390 names, err := r.readNames(-1) 391 if err != io.EOF { 392 t.Fatal(err) 393 } 394 want := loadMetacacheSampleNames 395 if !reflect.DeepEqual(names, want) { 396 t.Errorf("got unexpected result: %#v", names) 397 } 398 } 399 400 func Test_metacacheReader_skip(t *testing.T) { 401 r := loadMetacacheSample(t) 402 defer r.Close() 403 names, err := r.readNames(5) 404 if err != nil { 405 t.Fatal(err) 406 } 407 want := loadMetacacheSampleNames[:5] 408 if !reflect.DeepEqual(names, want) { 409 t.Errorf("got unexpected result: %#v", names) 410 } 411 err = r.skip(5) 412 if err != nil { 413 t.Fatal(err) 414 } 415 names, err = r.readNames(5) 416 if err != nil { 417 t.Fatal(err) 418 } 419 want = loadMetacacheSampleNames[10:15] 420 if !reflect.DeepEqual(names, want) { 421 t.Errorf("got unexpected result: %#v", names) 422 } 423 424 err = r.skip(len(loadMetacacheSampleNames)) 425 if err != io.EOF { 426 t.Fatal(err) 427 } 428 }