driver_test.go raw
1 package ffldb_test
2
3 import (
4 "fmt"
5 "github.com/p9c/p9/pkg/block"
6 "os"
7 "path/filepath"
8 "reflect"
9 "testing"
10
11 "github.com/p9c/p9/pkg/chaincfg"
12 "github.com/p9c/p9/pkg/database"
13 "github.com/p9c/p9/pkg/database/ffldb"
14 )
15
16 // dbType is the database type name for this driver.
17 const dbType = "ffldb"
18
19 // TestCreateOpenFail ensures that errors related to creating and opening a database are handled properly.
20 func TestCreateOpenFail(t *testing.T) {
21 t.Parallel()
22 // Ensure that attempting to open a database that doesn't exist returns the expected error.
23 wantErrCode := database.ErrDbDoesNotExist
24 _, e := database.Open(dbType, "noexist", blockDataNet)
25 if !checkDbError(t, "Open", e, wantErrCode) {
26 return
27 }
28 // Ensure that attempting to open a database with the wrong number of parameters returns the expected error.
29 wantErr := fmt.Errorf(
30 "invalid arguments to %s.Open -- expected "+
31 "database path and block network", dbType,
32 )
33 _, e = database.Open(dbType, 1, 2, 3)
34 if e != nil && e.Error() != wantErr.Error() {
35 t.Errorf(
36 "Open: did not receive expected error - got %v, "+
37 "want %v", e, wantErr,
38 )
39 return
40 }
41 // Ensure that attempting to open a database with an invalid type for the first parameter returns the expected
42 // error.
43 wantErr = fmt.Errorf(
44 "first argument to %s.Open is invalid -- "+
45 "expected database path string", dbType,
46 )
47 _, e = database.Open(dbType, 1, blockDataNet)
48 if e != nil && e.Error() != wantErr.Error() {
49 t.Errorf(
50 "Open: did not receive expected error - got %v, "+
51 "want %v", e, wantErr,
52 )
53 return
54 }
55 // Ensure that attempting to open a database with an invalid type for the second parameter returns the expected
56 // error.
57 wantErr = fmt.Errorf(
58 "second argument to %s.Open is invalid -- "+
59 "expected block network", dbType,
60 )
61 _, e = database.Open(dbType, "noexist", "invalid")
62 if e != nil && e.Error() != wantErr.Error() {
63 t.Errorf(
64 "Open: did not receive expected error - got %v, "+
65 "want %v", e, wantErr,
66 )
67 return
68 }
69 // Ensure that attempting to create a database with the wrong number of parameters returns the expected error.
70 wantErr = fmt.Errorf(
71 "invalid arguments to %s.Create -- expected "+
72 "database path and block network", dbType,
73 )
74 _, e = database.Create(dbType, 1, 2, 3)
75 if e != nil && e.Error() != wantErr.Error() {
76 t.Errorf(
77 "Create: did not receive expected error - got %v, "+
78 "want %v", e, wantErr,
79 )
80 return
81 }
82 // Ensure that attempting to create a database with an invalid type for the first parameter returns the expected
83 // error.
84 wantErr = fmt.Errorf(
85 "first argument to %s.Create is invalid -- "+
86 "expected database path string", dbType,
87 )
88 _, e = database.Create(dbType, 1, blockDataNet)
89 if e != nil && e.Error() != wantErr.Error() {
90 t.Errorf(
91 "Create: did not receive expected error - got %v, "+
92 "want %v", e, wantErr,
93 )
94 return
95 }
96 // Ensure that attempting to create a database with an invalid type for the second parameter returns the expected
97 // error.
98 wantErr = fmt.Errorf(
99 "second argument to %s.Create is invalid -- "+
100 "expected block network", dbType,
101 )
102 _, e = database.Create(dbType, "noexist", "invalid")
103 if e != nil && e.Error() != wantErr.Error() {
104 t.Errorf(
105 "Create: did not receive expected error - got %v, "+
106 "want %v", e, wantErr,
107 )
108 return
109 }
110 // Ensure operations against a closed database return the expected error.
111 dbPath := filepath.Join(os.TempDir(), "ffldb-createfail")
112 _ = os.RemoveAll(dbPath)
113 db, e := database.Create(dbType, dbPath, blockDataNet)
114 if e != nil {
115 t.Errorf("Create: unexpected error: %v", e)
116 return
117 }
118 defer func() {
119 if e = os.RemoveAll(dbPath); ffldb.E.Chk(e) {
120 }
121 }()
122 func() {
123 if e = db.Close(); ffldb.E.Chk(e) {
124 }
125 }()
126 wantErrCode = database.ErrDbNotOpen
127 e = db.View(
128 func(tx database.Tx) (e error) {
129 return nil
130 },
131 )
132 if !checkDbError(t, "View", e, wantErrCode) {
133 return
134 }
135 wantErrCode = database.ErrDbNotOpen
136 e = db.Update(
137 func(tx database.Tx) (e error) {
138 return nil
139 },
140 )
141 if !checkDbError(t, "Update", e, wantErrCode) {
142 return
143 }
144 wantErrCode = database.ErrDbNotOpen
145 _, e = db.Begin(false)
146 if !checkDbError(t, "Begin(false)", e, wantErrCode) {
147 return
148 }
149 wantErrCode = database.ErrDbNotOpen
150 _, e = db.Begin(true)
151 if !checkDbError(t, "Begin(true)", e, wantErrCode) {
152 return
153 }
154 wantErrCode = database.ErrDbNotOpen
155 e = db.Close()
156 if !checkDbError(t, "Close", e, wantErrCode) {
157 return
158 }
159 }
160
161 // TestPersistence ensures that values stored are still valid after closing and reopening the database.
162 func TestPersistence(t *testing.T) {
163 t.Parallel()
164 // Create a new database to run tests against.
165 dbPath := filepath.Join(os.TempDir(), "ffldb-persistencetest")
166 _ = os.RemoveAll(dbPath)
167 db, e := database.Create(dbType, dbPath, blockDataNet)
168 if e != nil {
169 t.Errorf("Failed to create test database (%s) %v", dbType, e)
170 return
171 }
172 defer func() {
173 if e = os.RemoveAll(dbPath); ffldb.E.Chk(e) {
174 }
175 }()
176 defer func() {
177 if e = db.Close(); ffldb.E.Chk(e) {
178 }
179 }()
180 // Create a bucket, put some values into it, and store a block so they can be tested for existence on re-open.
181 bucket1Key := []byte("bucket1")
182 storeValues := map[string]string{
183 "b1key1": "foo1",
184 "b1key2": "foo2",
185 "b1key3": "foo3",
186 }
187 genesisBlock := block.NewBlock(chaincfg.MainNetParams.GenesisBlock)
188 genesisHash := chaincfg.MainNetParams.GenesisHash
189 e = db.Update(
190 func(tx database.Tx) (e error) {
191 metadataBucket := tx.Metadata()
192 if metadataBucket == nil {
193 return fmt.Errorf("metadata: unexpected nil bucket")
194 }
195 bucket1, e := metadataBucket.CreateBucket(bucket1Key)
196 if e != nil {
197 return fmt.Errorf(
198 "createBucket: unexpected error: %v",
199 e,
200 )
201 }
202 for k, v := range storeValues {
203 e := bucket1.Put([]byte(k), []byte(v))
204 if e != nil {
205 return fmt.Errorf(
206 "put: unexpected error: %v",
207 e,
208 )
209 }
210 }
211 if e := tx.StoreBlock(genesisBlock); E.Chk(e) {
212 return fmt.Errorf(
213 "StoreBlock: unexpected error: %v",
214 e,
215 )
216 }
217 return nil
218 },
219 )
220 if e != nil {
221 t.Errorf("Update: unexpected error: %v", e)
222 return
223 }
224 // Close and reopen the database to ensure the values persist.
225 if e = db.Close(); ffldb.E.Chk(e) {
226 }
227 db, e = database.Open(dbType, dbPath, blockDataNet)
228 if e != nil {
229 t.Errorf("Failed to open test database (%s) %v", dbType, e)
230 return
231 }
232 defer func() {
233 if e = db.Close(); ffldb.E.Chk(e) {
234 }
235 }()
236 // Ensure the values previously stored in the 3rd namespace still exist and are correct.
237 e = db.View(
238 func(tx database.Tx) (e error) {
239 metadataBucket := tx.Metadata()
240 if metadataBucket == nil {
241 return fmt.Errorf("metadata: unexpected nil bucket")
242 }
243 bucket1 := metadataBucket.Bucket(bucket1Key)
244 if bucket1 == nil {
245 return fmt.Errorf("bucket1: unexpected nil bucket")
246 }
247 for k, v := range storeValues {
248 gotVal := bucket1.Get([]byte(k))
249 if !reflect.DeepEqual(gotVal, []byte(v)) {
250 return fmt.Errorf(
251 "get: key '%s' does not match expected value - got %s, want %s",
252 k, gotVal, v,
253 )
254 }
255 }
256 genesisBlockBytes, _ := genesisBlock.Bytes()
257 gotBytes, e := tx.FetchBlock(genesisHash)
258 if e != nil {
259 return fmt.Errorf(
260 "fetchBlock: unexpected error: %v",
261 e,
262 )
263 }
264 if !reflect.DeepEqual(gotBytes, genesisBlockBytes) {
265 return fmt.Errorf("fetchBlock: stored block mismatch")
266 }
267 return nil
268 },
269 )
270 if e != nil {
271 t.Errorf("view: unexpected error: %v", e)
272 return
273 }
274 }
275
276 // // TestInterface performs all interfaces tests for this database driver.
277 // func TestInterface(// t *testing.T) {
278 // t.Parallel()
279 // // Create a new database to run tests against.
280 // dbPath := filepath.Join(os.TempDir(), "ffldb-interfacetest")
281 // _ = os.RemoveAll(dbPath)
282 // db, e := database.Create(dbType, dbPath, blockDataNet)
283 // if e != nil {
284 // t.Errorf("Failed to create test database (%s) %v", dbType, err)
285 // return
286 // }
287 // defer os.RemoveAll(dbPath)
288 // defer db.Close()
289 // // Ensure the driver type is the expected value.
290 // gotDbType := db.Type()
291 // if gotDbType != dbType {
292 // t.Errorf("Type: unepxected driver type - got %v, want %v",
293 // gotDbType, dbType)
294 // return
295 // }
296 // // Run all of the interface tests against the database.
297 // runtime.GOMAXPROCS(runtime.NumCPU())
298 // // Change the maximum file size to a small value to force multiple flat files with the test data set.
299 // ffldb.TstRunWithMaxBlockFileSize(db, 2048, func() {
300 // testInterface(t, db)
301 // })
302 // }
303