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  }