github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/snapshot_test.go (about) 1 // Copyright 2012 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package pebble 6 7 import ( 8 "bytes" 9 "fmt" 10 "reflect" 11 "strings" 12 "testing" 13 14 "github.com/petermattis/pebble/internal/datadriven" 15 "github.com/petermattis/pebble/vfs" 16 "github.com/stretchr/testify/require" 17 ) 18 19 func TestSnapshotListToSlice(t *testing.T) { 20 testCases := []struct { 21 vals []uint64 22 }{ 23 {nil}, 24 {[]uint64{1}}, 25 {[]uint64{1, 2, 3}}, 26 {[]uint64{3, 2, 1}}, 27 } 28 for _, c := range testCases { 29 t.Run("", func(t *testing.T) { 30 var l snapshotList 31 l.init() 32 for _, v := range c.vals { 33 l.pushBack(&Snapshot{seqNum: v}) 34 } 35 slice := l.toSlice() 36 if !reflect.DeepEqual(c.vals, slice) { 37 t.Fatalf("expected %d, but got %d", c.vals, slice) 38 } 39 }) 40 } 41 } 42 43 func TestSnapshot(t *testing.T) { 44 var d *DB 45 var snapshots map[string]*Snapshot 46 47 datadriven.RunTest(t, "testdata/snapshot", func(td *datadriven.TestData) string { 48 switch td.Cmd { 49 case "define": 50 var err error 51 d, err = Open("", &Options{ 52 FS: vfs.NewMem(), 53 }) 54 if err != nil { 55 return err.Error() 56 } 57 snapshots = make(map[string]*Snapshot) 58 59 for _, line := range strings.Split(td.Input, "\n") { 60 parts := strings.Fields(line) 61 if len(parts) == 0 { 62 continue 63 } 64 var err error 65 switch parts[0] { 66 case "set": 67 if len(parts) != 3 { 68 return fmt.Sprintf("%s expects 2 arguments", parts[0]) 69 } 70 err = d.Set([]byte(parts[1]), []byte(parts[2]), nil) 71 case "del": 72 if len(parts) != 2 { 73 return fmt.Sprintf("%s expects 1 argument", parts[0]) 74 } 75 err = d.Delete([]byte(parts[1]), nil) 76 case "merge": 77 if len(parts) != 3 { 78 return fmt.Sprintf("%s expects 2 arguments", parts[0]) 79 } 80 err = d.Merge([]byte(parts[1]), []byte(parts[2]), nil) 81 case "snapshot": 82 if len(parts) != 2 { 83 return fmt.Sprintf("%s expects 1 argument", parts[0]) 84 } 85 snapshots[parts[1]] = d.NewSnapshot() 86 case "compact": 87 if len(parts) != 2 { 88 return fmt.Sprintf("%s expects 1 argument", parts[0]) 89 } 90 keys := strings.Split(parts[1], "-") 91 if len(keys) != 2 { 92 return fmt.Sprintf("malformed key range: %s", parts[1]) 93 } 94 err = d.Compact([]byte(keys[0]), []byte(keys[1])) 95 default: 96 return fmt.Sprintf("unknown op: %s", parts[0]) 97 } 98 if err != nil { 99 return err.Error() 100 } 101 } 102 return "" 103 104 case "iter": 105 var iter *Iterator 106 if len(td.CmdArgs) == 1 { 107 if td.CmdArgs[0].Key != "snapshot" { 108 return fmt.Sprintf("unknown argument: %s", td.CmdArgs[0]) 109 } 110 if len(td.CmdArgs[0].Vals) != 1 { 111 return fmt.Sprintf("%s expects 1 value: %s", td.CmdArgs[0].Key, td.CmdArgs[0]) 112 } 113 name := td.CmdArgs[0].Vals[0] 114 snapshot := snapshots[name] 115 if snapshot == nil { 116 return fmt.Sprintf("unable to find snapshot \"%s\"", name) 117 } 118 iter = snapshot.NewIter(nil) 119 } else { 120 iter = d.NewIter(nil) 121 } 122 defer iter.Close() 123 124 var b bytes.Buffer 125 for _, line := range strings.Split(td.Input, "\n") { 126 parts := strings.Fields(line) 127 if len(parts) == 0 { 128 continue 129 } 130 switch parts[0] { 131 case "first": 132 iter.First() 133 case "last": 134 iter.Last() 135 case "seek-ge": 136 if len(parts) != 2 { 137 return fmt.Sprintf("seek-ge <key>\n") 138 } 139 iter.SeekGE([]byte(strings.TrimSpace(parts[1]))) 140 case "seek-lt": 141 if len(parts) != 2 { 142 return fmt.Sprintf("seek-lt <key>\n") 143 } 144 iter.SeekLT([]byte(strings.TrimSpace(parts[1]))) 145 case "next": 146 iter.Next() 147 case "prev": 148 iter.Prev() 149 default: 150 return fmt.Sprintf("unknown op: %s", parts[0]) 151 } 152 if iter.Valid() { 153 fmt.Fprintf(&b, "%s:%s\n", iter.Key(), iter.Value()) 154 } else if err := iter.Error(); err != nil { 155 fmt.Fprintf(&b, "err=%v\n", err) 156 } else { 157 fmt.Fprintf(&b, ".\n") 158 } 159 } 160 return b.String() 161 162 default: 163 return fmt.Sprintf("unknown command: %s", td.Cmd) 164 } 165 }) 166 } 167 168 func TestSnapshotClosed(t *testing.T) { 169 d, err := Open("", &Options{ 170 FS: vfs.NewMem(), 171 }) 172 if err != nil { 173 t.Fatal(err) 174 } 175 176 catch := func(f func()) (err error) { 177 defer func() { 178 if r := recover(); r != nil { 179 err = r.(error) 180 } 181 }() 182 f() 183 return nil 184 } 185 186 snap := d.NewSnapshot() 187 if err := snap.Close(); err != nil { 188 t.Fatal(err) 189 } 190 require.EqualValues(t, ErrClosed, catch(func() { _ = snap.Close() })) 191 require.EqualValues(t, ErrClosed, catch(func() { _, _ = snap.Get(nil) })) 192 require.EqualValues(t, ErrClosed, catch(func() { snap.NewIter(nil) })) 193 }