Skip to content

Commit 044c1c1

Browse files
committed
loopdb/test: add database dump and restore tools
1 parent bd6e3f4 commit 044c1c1

File tree

1 file changed

+147
-0
lines changed

1 file changed

+147
-0
lines changed

loopdb/raw_db_test.go

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package loopdb
2+
3+
import (
4+
"encoding/hex"
5+
"errors"
6+
"fmt"
7+
"strings"
8+
9+
"github.com/coreos/bbolt"
10+
)
11+
12+
// DumpDB dumps go code describing the contents of the database to stdout. This
13+
// function is only intended for use during development. Therefore also the
14+
// linter unused warnings are suppressed.
15+
//
16+
// Example output:
17+
//
18+
// map[string]interface{}{
19+
// Hex("1234"): map[string]interface{}{
20+
// "human-readable": Hex("102030"),
21+
// Hex("1111"): Hex("5783492373"),
22+
// },
23+
// }
24+
func DumpDB(tx *bbolt.Tx) error { // nolint: unused
25+
return tx.ForEach(func(k []byte, bucket *bbolt.Bucket) error {
26+
key := toString(k)
27+
fmt.Printf("%v: ", key)
28+
29+
err := dumpBucket(bucket)
30+
if err != nil {
31+
return err
32+
}
33+
fmt.Printf(",\n")
34+
35+
return nil
36+
})
37+
}
38+
39+
func dumpBucket(bucket *bbolt.Bucket) error { // nolint: unused
40+
fmt.Printf("map[string]interface{} {\n")
41+
err := bucket.ForEach(func(k, v []byte) error {
42+
key := toString(k)
43+
fmt.Printf("%v: ", key)
44+
45+
subBucket := bucket.Bucket(k)
46+
if subBucket != nil {
47+
err := dumpBucket(subBucket)
48+
if err != nil {
49+
return err
50+
}
51+
} else {
52+
fmt.Print(toHex(v))
53+
}
54+
fmt.Printf(",\n")
55+
56+
return nil
57+
})
58+
if err != nil {
59+
return err
60+
}
61+
fmt.Printf("}")
62+
63+
return nil
64+
}
65+
66+
// RestoreDB primes the database with the given data set.
67+
func RestoreDB(tx *bbolt.Tx, data map[string]interface{}) error {
68+
for k, v := range data {
69+
key := []byte(k)
70+
71+
value := v.(map[string]interface{})
72+
73+
subBucket, err := tx.CreateBucket(key)
74+
if err != nil {
75+
return fmt.Errorf("create bucket %v: %v",
76+
string(key), err)
77+
}
78+
79+
if err := restoreDB(subBucket, value); err != nil {
80+
return err
81+
}
82+
}
83+
84+
return nil
85+
}
86+
87+
func restoreDB(bucket *bbolt.Bucket, data map[string]interface{}) error {
88+
for k, v := range data {
89+
key := []byte(k)
90+
91+
switch value := v.(type) {
92+
93+
// Key contains value.
94+
case string:
95+
err := bucket.Put(key, []byte(value))
96+
if err != nil {
97+
return err
98+
}
99+
100+
// Key contains a sub-bucket.
101+
case map[string]interface{}:
102+
subBucket, err := bucket.CreateBucket(key)
103+
if err != nil {
104+
return err
105+
}
106+
107+
if err := restoreDB(subBucket, value); err != nil {
108+
return err
109+
}
110+
111+
default:
112+
return errors.New("invalid type")
113+
}
114+
}
115+
116+
return nil
117+
}
118+
119+
func toHex(v []byte) string { // nolint: unused
120+
if len(v) == 0 {
121+
return "nil"
122+
}
123+
124+
return "Hex(\"" + hex.EncodeToString(v) + "\")"
125+
}
126+
127+
func toString(v []byte) string { // nolint: unused
128+
readableChars := "abcdefghijklmnopqrstuvwxyz0123456789-"
129+
130+
for _, c := range v {
131+
if !strings.Contains(readableChars, string(c)) {
132+
return toHex(v)
133+
}
134+
}
135+
136+
return "\"" + string(v) + "\""
137+
}
138+
139+
// Hex is a test helper function to convert readable hex arrays to raw byte
140+
// strings.
141+
func Hex(value string) string {
142+
b, err := hex.DecodeString(value)
143+
if err != nil {
144+
panic(err)
145+
}
146+
return string(b)
147+
}

0 commit comments

Comments
 (0)