1 package failpoint
2
3 import (
4 "fmt"
5 "path/filepath"
6 "testing"
7 "time"
8
9 "github.com/stretchr/testify/require"
10
11 bolt "go.etcd.io/bbolt"
12 "go.etcd.io/bbolt/internal/btesting"
13 gofail "go.etcd.io/gofail/runtime"
14 )
15
16 func TestFailpoint_MapFail(t *testing.T) {
17 err := gofail.Enable("mapError", `return("map somehow failed")`)
18 require.NoError(t, err)
19 defer func() {
20 err = gofail.Disable("mapError")
21 require.NoError(t, err)
22 }()
23
24 f := filepath.Join(t.TempDir(), "db")
25 _, err = bolt.Open(f, 0666, nil)
26 require.Error(t, err)
27 require.ErrorContains(t, err, "map somehow failed")
28 }
29
30
31 func TestFailpoint_UnmapFail_DbClose(t *testing.T) {
32
33
34
35 f := filepath.Join(t.TempDir(), "db")
36
37 err := gofail.Enable("unmapError", `return("unmap somehow failed")`)
38 require.NoError(t, err)
39 _, err = bolt.Open(f, 0666, nil)
40 require.Error(t, err)
41 require.ErrorContains(t, err, "unmap somehow failed")
42
43 err = gofail.Disable("unmapError")
44 require.NoError(t, err)
45
46 db, err := bolt.Open(f, 0666, &bolt.Options{Timeout: 30 * time.Second})
47 require.NoError(t, err)
48 err = db.Close()
49 require.NoError(t, err)
50 }
51
52 func TestFailpoint_mLockFail(t *testing.T) {
53 err := gofail.Enable("mlockError", `return("mlock somehow failed")`)
54 require.NoError(t, err)
55
56 f := filepath.Join(t.TempDir(), "db")
57 _, err = bolt.Open(f, 0666, &bolt.Options{Mlock: true})
58 require.Error(t, err)
59 require.ErrorContains(t, err, "mlock somehow failed")
60
61
62 err = gofail.Disable("mlockError")
63 require.NoError(t, err)
64
65 _, err = bolt.Open(f, 0666, &bolt.Options{Mlock: true})
66 require.NoError(t, err)
67 }
68
69 func TestFailpoint_mLockFail_When_remap(t *testing.T) {
70 db := btesting.MustCreateDB(t)
71 db.Mlock = true
72
73 err := gofail.Enable("mlockError", `return("mlock somehow failed in allocate")`)
74 require.NoError(t, err)
75
76 err = db.Fill([]byte("data"), 1, 10000,
77 func(tx int, k int) []byte { return []byte(fmt.Sprintf("%04d", k)) },
78 func(tx int, k int) []byte { return make([]byte, 100) },
79 )
80
81 require.Error(t, err)
82 require.ErrorContains(t, err, "mlock somehow failed in allocate")
83
84
85 err = gofail.Disable("mlockError")
86 require.NoError(t, err)
87 db.MustClose()
88 db.MustReopen()
89
90 err = db.Fill([]byte("data"), 1, 10000,
91 func(tx int, k int) []byte { return []byte(fmt.Sprintf("%04d", k)) },
92 func(tx int, k int) []byte { return make([]byte, 100) },
93 )
94
95 require.NoError(t, err)
96 }
97
98
99
100
101
102
103
104
105
106
107
108 func TestIssue72(t *testing.T) {
109 db := btesting.MustCreateDBWithOption(t, &bolt.Options{PageSize: 4096})
110
111 bucketName := []byte(t.Name())
112 err := db.Update(func(tx *bolt.Tx) error {
113 _, txerr := tx.CreateBucket(bucketName)
114 return txerr
115 })
116 require.NoError(t, err)
117
118
119
120
121
122
123
124
125
126
127
128
129 err = db.Update(func(tx *bolt.Tx) error {
130 bk := tx.Bucket(bucketName)
131
132 for _, id := range []int{1, 2, 3, 4, 10, 11, 12} {
133 if txerr := bk.Put(idToBytes(id), make([]byte, 1000)); txerr != nil {
134 return txerr
135 }
136 }
137 return nil
138 })
139 require.NoError(t, err)
140
141 require.NoError(t, gofail.Enable("beforeBucketPut", `sleep(5000)`))
142
143
144
145
146
147
148
149
150
151
152 key := idToBytes(13)
153 updatedKey := idToBytes(1)
154 err = db.Update(func(tx *bolt.Tx) error {
155 bk := tx.Bucket(bucketName)
156
157 go func() {
158 time.Sleep(3 * time.Second)
159 copy(key, updatedKey)
160 }()
161 return bk.Put(key, make([]byte, 100))
162 })
163 require.NoError(t, err)
164
165 require.NoError(t, gofail.Disable("beforeBucketPut"))
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184 err = db.Update(func(tx *bolt.Tx) error {
185 return tx.Bucket(bucketName).Put(idToBytes(100), make([]byte, 100))
186 })
187 require.NoError(t, err)
188
189 defer func() {
190 if r := recover(); r != nil {
191 t.Logf("panic info:\n %v", r)
192 }
193 }()
194
195
196 err = db.Update(func(tx *bolt.Tx) error {
197 bk := tx.Bucket(bucketName)
198
199 for _, id := range []int{101, 102, 103, 104, 105} {
200 if txerr := bk.Put(idToBytes(id), make([]byte, 1000)); txerr != nil {
201 return txerr
202 }
203 }
204 return nil
205 })
206 require.NoError(t, err)
207 }
208
209 func idToBytes(id int) []byte {
210 return []byte(fmt.Sprintf("%010d", id))
211 }
212
View as plain text