|
|
|
@ -15,6 +15,8 @@ package tsdb
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"encoding/binary"
|
|
|
|
|
"errors"
|
|
|
|
|
"io/ioutil"
|
|
|
|
|
"math/rand"
|
|
|
|
|
"os"
|
|
|
|
@ -22,6 +24,7 @@ import (
|
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
"github.com/go-kit/kit/log"
|
|
|
|
|
"github.com/prometheus/tsdb/chunks"
|
|
|
|
|
"github.com/prometheus/tsdb/testutil"
|
|
|
|
|
"github.com/prometheus/tsdb/tsdbutil"
|
|
|
|
|
)
|
|
|
|
@ -77,6 +80,74 @@ func TestCreateBlock(t *testing.T) {
|
|
|
|
|
testutil.Ok(t, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestCorruptedChunk(t *testing.T) {
|
|
|
|
|
for name, test := range map[string]struct {
|
|
|
|
|
corrFunc func(f *os.File) // Func that applies the corruption.
|
|
|
|
|
expErr error
|
|
|
|
|
}{
|
|
|
|
|
"invalid header size": {
|
|
|
|
|
func(f *os.File) {
|
|
|
|
|
err := f.Truncate(1)
|
|
|
|
|
testutil.Ok(t, err)
|
|
|
|
|
},
|
|
|
|
|
errors.New("invalid chunk header in segment 0: invalid size"),
|
|
|
|
|
},
|
|
|
|
|
"invalid magic number": {
|
|
|
|
|
func(f *os.File) {
|
|
|
|
|
magicChunksOffset := int64(0)
|
|
|
|
|
_, err := f.Seek(magicChunksOffset, 0)
|
|
|
|
|
testutil.Ok(t, err)
|
|
|
|
|
|
|
|
|
|
// Set invalid magic number.
|
|
|
|
|
b := make([]byte, chunks.MagicChunksSize)
|
|
|
|
|
binary.BigEndian.PutUint32(b[:chunks.MagicChunksSize], 0x00000000)
|
|
|
|
|
n, err := f.Write(b)
|
|
|
|
|
testutil.Ok(t, err)
|
|
|
|
|
testutil.Equals(t, chunks.MagicChunksSize, n)
|
|
|
|
|
},
|
|
|
|
|
errors.New("invalid magic number 0"),
|
|
|
|
|
},
|
|
|
|
|
"invalid chunk format version": {
|
|
|
|
|
func(f *os.File) {
|
|
|
|
|
chunksFormatVersionOffset := int64(4)
|
|
|
|
|
_, err := f.Seek(chunksFormatVersionOffset, 0)
|
|
|
|
|
testutil.Ok(t, err)
|
|
|
|
|
|
|
|
|
|
// Set invalid chunk format version.
|
|
|
|
|
b := make([]byte, chunks.ChunksFormatVersionSize)
|
|
|
|
|
b[0] = 0
|
|
|
|
|
n, err := f.Write(b)
|
|
|
|
|
testutil.Ok(t, err)
|
|
|
|
|
testutil.Equals(t, chunks.ChunksFormatVersionSize, n)
|
|
|
|
|
},
|
|
|
|
|
errors.New("invalid chunk format version 0"),
|
|
|
|
|
},
|
|
|
|
|
} {
|
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
|
tmpdir, err := ioutil.TempDir("", "test_open_block_chunk_corrupted")
|
|
|
|
|
testutil.Ok(t, err)
|
|
|
|
|
defer func() {
|
|
|
|
|
testutil.Ok(t, os.RemoveAll(tmpdir))
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
blockDir := createBlock(t, tmpdir, genSeries(1, 1, 0, 0))
|
|
|
|
|
files, err := sequenceFiles(chunkDir(blockDir))
|
|
|
|
|
testutil.Ok(t, err)
|
|
|
|
|
testutil.Assert(t, len(files) > 0, "No chunk created.")
|
|
|
|
|
|
|
|
|
|
f, err := os.OpenFile(files[0], os.O_RDWR, 0666)
|
|
|
|
|
testutil.Ok(t, err)
|
|
|
|
|
|
|
|
|
|
// Apply corruption function.
|
|
|
|
|
test.corrFunc(f)
|
|
|
|
|
testutil.Ok(t, f.Close())
|
|
|
|
|
|
|
|
|
|
_, err = OpenBlock(nil, blockDir, nil)
|
|
|
|
|
testutil.Equals(t, test.expErr.Error(), err.Error())
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// createBlock creates a block with given set of series and returns its dir.
|
|
|
|
|
func createBlock(tb testing.TB, dir string, series []Series) string {
|
|
|
|
|
head, err := NewHead(nil, nil, nil, 2*60*60*1000)
|
|
|
|
|