Skip to content

Commit 6209500

Browse files
committed
add test check page
Signed-off-by: Mustafa Elbehery <melbeher@redhat.com>
1 parent 288e823 commit 6209500

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

tx_test.go

+104
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ package bbolt_test
22

33
import (
44
"bytes"
5+
"encoding/binary"
56
"errors"
67
"fmt"
8+
"go.etcd.io/bbolt/internal/common"
9+
"go.etcd.io/bbolt/internal/guts_cli"
710
"log"
811
"os"
912
"runtime"
@@ -18,6 +21,107 @@ import (
1821
"go.etcd.io/bbolt/internal/btesting"
1922
)
2023

24+
func TestTx_Check_Page(t *testing.T) {
25+
bucketKey := "testBucket"
26+
db := btesting.MustCreateDBWithOption(t, &bolt.Options{PageSize: pageSize})
27+
defer db.MustDeleteFile()
28+
29+
// arrange
30+
if err := db.Update(func(tx *bolt.Tx) error {
31+
b, err := tx.CreateBucketIfNotExists([]byte(bucketKey))
32+
if err != nil {
33+
t.Fatal(err)
34+
}
35+
// insert random data
36+
for i := 0; i < 10; i++ {
37+
generateSampleDataInBucket(t, b, 3)
38+
}
39+
return nil
40+
}); err != nil {
41+
t.Fatal(err)
42+
}
43+
db.MustCheck()
44+
45+
// act : corrupt a leaf page
46+
corruptLeafPageFromDB(t, db.Path())
47+
48+
// assert: expected an error after check
49+
if err := db.View(func(tx *bolt.Tx) error {
50+
for err := range tx.Check() {
51+
fmt.Println(err)
52+
}
53+
return nil
54+
}); err != nil {
55+
t.Fatal(err)
56+
}
57+
db.MustClose()
58+
}
59+
60+
func corruptLeafPageFromDB(t testing.TB, dbPath string) {
61+
_, hwm, err := guts_cli.ReadPageAndHWMSize(dbPath)
62+
if err != nil {
63+
t.Fatalf("error reading HWM from dbPath %v: %v", dbPath, err)
64+
}
65+
66+
var victimPage *common.Page
67+
var victimBuf []byte
68+
69+
// find first leaf page starting page after root bucket's page
70+
for pageID := uint64(4); pageID < uint64(hwm); {
71+
p, buf, err := guts_cli.ReadPage(dbPath, pageID)
72+
if err != nil {
73+
t.Fatalf("error reading page %v from dbPath %v: %v", pageID, dbPath, err)
74+
}
75+
76+
if p.IsLeafPage() {
77+
victimPage = p
78+
victimBuf = buf
79+
break
80+
}
81+
}
82+
83+
if victimPage == nil || victimBuf == nil {
84+
t.Fatalf("no leaf page is found in dbPath %v", dbPath)
85+
}
86+
87+
// corrupt page's type
88+
invalidLPE := common.NewLeafPageElement(0, 0, 0, 0)
89+
var buf bytes.Buffer
90+
binary.Write(&buf, binary.BigEndian, invalidLPE)
91+
copy(victimBuf[17:], buf.Bytes())
92+
// write page back to file
93+
err = guts_cli.WritePage(dbPath, victimBuf)
94+
if err != nil {
95+
t.Errorf("error writing victim page %v back to dbpath %v: %v", victimPage.Id(), dbPath, err)
96+
}
97+
}
98+
99+
// generateSampleDataInBucket fill in sample data into given bucket to create the given
100+
// number of leafPages. To control the number of leafPages, sample data are generated in order.
101+
func generateSampleDataInBucket(t testing.TB, bk *bolt.Bucket, lPages int) {
102+
currentKey := 1
103+
currentVal := 100
104+
for i := 0; i < lPages; i++ {
105+
106+
currentSize := pageHeaderSize
107+
for currentSize < pageSize {
108+
err := bk.Put(convertIntIntoBytes(t, currentKey), convertIntIntoBytes(t, currentVal))
109+
require.NoError(t, err)
110+
currentSize += 16 + 4 + 4
111+
}
112+
113+
currentKey++
114+
currentVal++
115+
}
116+
}
117+
118+
func convertIntIntoBytes(t testing.TB, i int) []byte {
119+
t.Helper()
120+
buf := make([]byte, 4)
121+
binary.BigEndian.PutUint32(buf, uint32(i))
122+
return buf
123+
}
124+
21125
// TestTx_Check_ReadOnly tests consistency checking on a ReadOnly database.
22126
func TestTx_Check_ReadOnly(t *testing.T) {
23127
db := btesting.MustCreateDB(t)

0 commit comments

Comments
 (0)