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 }