github.com/thanos-io/thanos@v0.32.5/pkg/shipper/shipper_test.go (about)

     1  // Copyright (c) The Thanos Authors.
     2  // Licensed under the Apache License 2.0.
     3  
     4  package shipper
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"math"
    10  	"math/rand"
    11  	"os"
    12  	"path"
    13  	"path/filepath"
    14  	"sort"
    15  	"testing"
    16  
    17  	"github.com/go-kit/log"
    18  	"github.com/oklog/ulid"
    19  	"github.com/prometheus/prometheus/model/labels"
    20  	"github.com/prometheus/prometheus/tsdb"
    21  
    22  	"github.com/thanos-io/objstore"
    23  
    24  	"github.com/efficientgo/core/testutil"
    25  	"github.com/thanos-io/thanos/pkg/block"
    26  	"github.com/thanos-io/thanos/pkg/block/metadata"
    27  )
    28  
    29  func TestShipperTimestamps(t *testing.T) {
    30  	dir := t.TempDir()
    31  
    32  	s := New(nil, nil, dir, nil, nil, metadata.TestSource, nil, false, metadata.NoneFunc)
    33  
    34  	// Missing thanos meta file.
    35  	_, _, err := s.Timestamps()
    36  	testutil.NotOk(t, err)
    37  
    38  	meta := &Meta{Version: MetaVersion1}
    39  	testutil.Ok(t, WriteMetaFile(log.NewNopLogger(), dir, meta))
    40  
    41  	// Nothing uploaded, nothing in the filesystem. We assume that
    42  	// we are still waiting for TSDB to dump first TSDB block.
    43  	mint, maxt, err := s.Timestamps()
    44  	testutil.Ok(t, err)
    45  	testutil.Equals(t, int64(0), mint)
    46  	testutil.Equals(t, int64(math.MinInt64), maxt)
    47  
    48  	id1 := ulid.MustNew(1, nil)
    49  	testutil.Ok(t, os.Mkdir(path.Join(dir, id1.String()), os.ModePerm))
    50  	testutil.Ok(t, metadata.Meta{
    51  		BlockMeta: tsdb.BlockMeta{
    52  			ULID:    id1,
    53  			MaxTime: 2000,
    54  			MinTime: 1000,
    55  			Version: 1,
    56  		},
    57  	}.WriteToDir(log.NewNopLogger(), path.Join(dir, id1.String())))
    58  	mint, maxt, err = s.Timestamps()
    59  	testutil.Ok(t, err)
    60  	testutil.Equals(t, int64(1000), mint)
    61  	testutil.Equals(t, int64(math.MinInt64), maxt)
    62  
    63  	id2 := ulid.MustNew(2, nil)
    64  	testutil.Ok(t, os.Mkdir(path.Join(dir, id2.String()), os.ModePerm))
    65  	testutil.Ok(t, metadata.Meta{
    66  		BlockMeta: tsdb.BlockMeta{
    67  			ULID:    id2,
    68  			MaxTime: 4000,
    69  			MinTime: 2000,
    70  			Version: 1,
    71  		},
    72  	}.WriteToDir(log.NewNopLogger(), path.Join(dir, id2.String())))
    73  	mint, maxt, err = s.Timestamps()
    74  	testutil.Ok(t, err)
    75  	testutil.Equals(t, int64(1000), mint)
    76  	testutil.Equals(t, int64(math.MinInt64), maxt)
    77  
    78  	meta = &Meta{
    79  		Version:  MetaVersion1,
    80  		Uploaded: []ulid.ULID{id1},
    81  	}
    82  	testutil.Ok(t, WriteMetaFile(log.NewNopLogger(), dir, meta))
    83  	mint, maxt, err = s.Timestamps()
    84  	testutil.Ok(t, err)
    85  	testutil.Equals(t, int64(1000), mint)
    86  	testutil.Equals(t, int64(2000), maxt)
    87  }
    88  
    89  func TestIterBlockMetas(t *testing.T) {
    90  	dir := t.TempDir()
    91  
    92  	id1 := ulid.MustNew(1, nil)
    93  	testutil.Ok(t, os.Mkdir(path.Join(dir, id1.String()), os.ModePerm))
    94  	testutil.Ok(t, metadata.Meta{
    95  		BlockMeta: tsdb.BlockMeta{
    96  			ULID:    id1,
    97  			MaxTime: 2000,
    98  			MinTime: 1000,
    99  			Version: 1,
   100  		},
   101  	}.WriteToDir(log.NewNopLogger(), path.Join(dir, id1.String())))
   102  
   103  	id2 := ulid.MustNew(2, nil)
   104  	testutil.Ok(t, os.Mkdir(path.Join(dir, id2.String()), os.ModePerm))
   105  	testutil.Ok(t, metadata.Meta{
   106  		BlockMeta: tsdb.BlockMeta{
   107  			ULID:    id2,
   108  			MaxTime: 5000,
   109  			MinTime: 4000,
   110  			Version: 1,
   111  		},
   112  	}.WriteToDir(log.NewNopLogger(), path.Join(dir, id2.String())))
   113  
   114  	id3 := ulid.MustNew(3, nil)
   115  	testutil.Ok(t, os.Mkdir(path.Join(dir, id3.String()), os.ModePerm))
   116  	testutil.Ok(t, metadata.Meta{
   117  		BlockMeta: tsdb.BlockMeta{
   118  			ULID:    id3,
   119  			MaxTime: 3000,
   120  			MinTime: 2000,
   121  			Version: 1,
   122  		},
   123  	}.WriteToDir(log.NewNopLogger(), path.Join(dir, id3.String())))
   124  
   125  	shipper := New(nil, nil, dir, nil, nil, metadata.TestSource, nil, false, metadata.NoneFunc)
   126  	metas, err := shipper.blockMetasFromOldest()
   127  	testutil.Ok(t, err)
   128  	testutil.Equals(t, sort.SliceIsSorted(metas, func(i, j int) bool {
   129  		return metas[i].BlockMeta.MinTime < metas[j].BlockMeta.MinTime
   130  	}), true)
   131  }
   132  
   133  func BenchmarkIterBlockMetas(b *testing.B) {
   134  	var metas []*metadata.Meta
   135  	dir := b.TempDir()
   136  
   137  	for i := 0; i < 100; i++ {
   138  		id := ulid.MustNew(uint64(i), nil)
   139  		testutil.Ok(b, os.Mkdir(path.Join(dir, id.String()), os.ModePerm))
   140  		testutil.Ok(b,
   141  			metadata.Meta{
   142  				BlockMeta: tsdb.BlockMeta{
   143  					ULID:    id,
   144  					MaxTime: int64((i + 1) * 1000),
   145  					MinTime: int64(i * 1000),
   146  					Version: 1,
   147  				},
   148  			}.WriteToDir(log.NewNopLogger(), path.Join(dir, id.String())),
   149  		)
   150  	}
   151  	rand.Shuffle(len(metas), func(i, j int) {
   152  		metas[i], metas[j] = metas[j], metas[i]
   153  	})
   154  	b.ResetTimer()
   155  
   156  	shipper := New(nil, nil, dir, nil, nil, metadata.TestSource, nil, false, metadata.NoneFunc)
   157  
   158  	_, err := shipper.blockMetasFromOldest()
   159  	testutil.Ok(b, err)
   160  }
   161  
   162  func TestShipperAddsSegmentFiles(t *testing.T) {
   163  	dir := t.TempDir()
   164  
   165  	inmemory := objstore.NewInMemBucket()
   166  
   167  	lbls := []labels.Label{{Name: "test", Value: "test"}}
   168  	s := New(nil, nil, dir, inmemory, func() labels.Labels { return lbls }, metadata.TestSource, nil, false, metadata.NoneFunc)
   169  
   170  	id := ulid.MustNew(1, nil)
   171  	blockDir := path.Join(dir, id.String())
   172  	chunksDir := path.Join(blockDir, block.ChunksDirname)
   173  	testutil.Ok(t, os.MkdirAll(chunksDir, os.ModePerm))
   174  
   175  	// Prepare minimal "block" for shipper (meta.json, index, one segment file).
   176  	testutil.Ok(t, metadata.Meta{
   177  		BlockMeta: tsdb.BlockMeta{
   178  			ULID:    id,
   179  			MaxTime: 2000,
   180  			MinTime: 1000,
   181  			Version: 1,
   182  			Stats: tsdb.BlockStats{
   183  				NumSamples: 1000, // Not really, but shipper needs nonzero value.
   184  			},
   185  		},
   186  	}.WriteToDir(log.NewNopLogger(), path.Join(dir, id.String())))
   187  	testutil.Ok(t, os.WriteFile(filepath.Join(blockDir, "index"), []byte("index file"), 0666))
   188  	segmentFile := "00001"
   189  	testutil.Ok(t, os.WriteFile(filepath.Join(chunksDir, segmentFile), []byte("hello world"), 0666))
   190  
   191  	uploaded, err := s.Sync(context.Background())
   192  	testutil.Ok(t, err)
   193  	testutil.Equals(t, 1, uploaded)
   194  
   195  	meta, err := block.DownloadMeta(context.Background(), log.NewNopLogger(), inmemory, id)
   196  	testutil.Ok(t, err)
   197  
   198  	testutil.Equals(t, []string{segmentFile}, meta.Thanos.SegmentFiles)
   199  }
   200  
   201  func TestReadMetaFile(t *testing.T) {
   202  	t.Run("Missing meta file", func(t *testing.T) {
   203  		// Create TSDB directory without meta file
   204  		dpath := t.TempDir()
   205  
   206  		_, err := ReadMetaFile(dpath)
   207  		fpath := filepath.Join(dpath, MetaFilename)
   208  		testutil.Equals(t, fmt.Sprintf(`failed to read %s: open %s: no such file or directory`, fpath, fpath), err.Error())
   209  	})
   210  
   211  	t.Run("Non-JSON meta file", func(t *testing.T) {
   212  		dpath := t.TempDir()
   213  		fpath := filepath.Join(dpath, MetaFilename)
   214  		// Make an invalid JSON file
   215  		testutil.Ok(t, os.WriteFile(fpath, []byte("{"), 0600))
   216  
   217  		_, err := ReadMetaFile(dpath)
   218  		testutil.Equals(t, fmt.Sprintf(`failed to parse %s as JSON: "{": unexpected end of JSON input`, fpath), err.Error())
   219  	})
   220  
   221  	t.Run("Wrongly versioned meta file", func(t *testing.T) {
   222  		dpath := t.TempDir()
   223  		fpath := filepath.Join(dpath, MetaFilename)
   224  		testutil.Ok(t, os.WriteFile(fpath, []byte(`{"version": 2}`), 0600))
   225  
   226  		_, err := ReadMetaFile(dpath)
   227  		testutil.Equals(t, "unexpected meta file version 2", err.Error())
   228  	})
   229  }