Skip to content

Commit fdd0d1b

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

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

tx_test.go

+102
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,105 @@ 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+
buf := []byte("this is to corrupt the page")
89+
copy(victimBuf[17:], buf)
90+
// write page back to file
91+
err = guts_cli.WritePage(dbPath, victimBuf)
92+
if err != nil {
93+
t.Errorf("error writing victim page %v back to dbpath %v: %v", victimPage.Id(), dbPath, err)
94+
}
95+
}
96+
97+
// generateSampleDataInBucket fill in sample data into given bucket to create the given
98+
// number of leafPages. To control the number of leafPages, sample data are generated in order.
99+
func generateSampleDataInBucket(t testing.TB, bk *bolt.Bucket, lPages int) {
100+
currentKey := 1
101+
currentVal := 100
102+
for i := 0; i < lPages; i++ {
103+
104+
currentSize := pageHeaderSize
105+
for currentSize < pageSize {
106+
err := bk.Put(convertIntIntoBytes(t, currentKey), convertIntIntoBytes(t, currentVal))
107+
require.NoError(t, err)
108+
currentSize += 16 + 4 + 4
109+
}
110+
111+
currentKey++
112+
currentVal++
113+
}
114+
}
115+
116+
func convertIntIntoBytes(t testing.TB, i int) []byte {
117+
t.Helper()
118+
buf := make([]byte, 4)
119+
binary.BigEndian.PutUint32(buf, uint32(i))
120+
return buf
121+
}
122+
21123
// TestTx_Check_ReadOnly tests consistency checking on a ReadOnly database.
22124
func TestTx_Check_ReadOnly(t *testing.T) {
23125
db := btesting.MustCreateDB(t)

0 commit comments

Comments
 (0)