1 package tests_test
2
3 import (
4 "fmt"
5 "testing"
6
7 "github.com/stretchr/testify/require"
8
9 bolt "go.etcd.io/bbolt"
10 "go.etcd.io/bbolt/internal/btesting"
11 "go.etcd.io/bbolt/internal/guts_cli"
12 "go.etcd.io/bbolt/internal/surgeon"
13 )
14
15 func TestTx_RecursivelyCheckPages_MisplacedPage(t *testing.T) {
16 db := btesting.MustCreateDB(t)
17 require.NoError(t,
18 db.Fill([]byte("data"), 1, 10000,
19 func(tx int, k int) []byte { return []byte(fmt.Sprintf("%04d", k)) },
20 func(tx int, k int) []byte { return make([]byte, 100) },
21 ))
22 require.NoError(t, db.Close())
23
24 xRay := surgeon.NewXRay(db.Path())
25
26 path1, err := xRay.FindPathsToKey([]byte("0451"))
27 require.NoError(t, err, "cannot find page that contains key:'0451'")
28 require.Len(t, path1, 1, "Expected only one page that contains key:'0451'")
29
30 path2, err := xRay.FindPathsToKey([]byte("7563"))
31 require.NoError(t, err, "cannot find page that contains key:'7563'")
32 require.Len(t, path2, 1, "Expected only one page that contains key:'7563'")
33
34 srcPage := path1[0][len(path1[0])-1]
35 targetPage := path2[0][len(path2[0])-1]
36 require.NoError(t, surgeon.CopyPage(db.Path(), srcPage, targetPage))
37
38 db.MustReopen()
39 require.NoError(t, db.Update(func(tx *bolt.Tx) error {
40
41 var errors []error
42 for err := range tx.Check() {
43 errors = append(errors, err)
44 }
45 require.Len(t, errors, 1)
46 require.ErrorContains(t, errors[0], fmt.Sprintf("leaf page(%v) needs to be >= the key in the ancestor", targetPage))
47 return nil
48 }))
49 require.NoError(t, db.Close())
50 }
51
52 func TestTx_RecursivelyCheckPages_CorruptedLeaf(t *testing.T) {
53 db := btesting.MustCreateDB(t)
54 require.NoError(t,
55 db.Fill([]byte("data"), 1, 10000,
56 func(tx int, k int) []byte { return []byte(fmt.Sprintf("%04d", k)) },
57 func(tx int, k int) []byte { return make([]byte, 100) },
58 ))
59 require.NoError(t, db.Close())
60
61 xray := surgeon.NewXRay(db.Path())
62
63 path1, err := xray.FindPathsToKey([]byte("0451"))
64 require.NoError(t, err, "cannot find page that contains key:'0451'")
65 require.Len(t, path1, 1, "Expected only one page that contains key:'0451'")
66
67 srcPage := path1[0][len(path1[0])-1]
68 p, pbuf, err := guts_cli.ReadPage(db.Path(), uint64(srcPage))
69 require.NoError(t, err)
70 require.Positive(t, p.Count(), "page must be not empty")
71 p.LeafPageElement(p.Count() / 2).Key()[0] = 'z'
72 require.NoError(t, guts_cli.WritePage(db.Path(), pbuf))
73
74 db.MustReopen()
75 require.NoError(t, db.Update(func(tx *bolt.Tx) error {
76
77 var errors []error
78 for err := range tx.Check() {
79 errors = append(errors, err)
80 }
81 require.Len(t, errors, 2)
82 require.ErrorContains(t, errors[0], fmt.Sprintf("leaf page(%v) needs to be < than key of the next element in ancestor", srcPage))
83 require.ErrorContains(t, errors[1], fmt.Sprintf("leaf page(%v) needs to be > (found <) than previous element", srcPage))
84 return nil
85 }))
86 require.NoError(t, db.Close())
87 }
88
View as plain text