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  }