github.com/cockroachdb/pebble@v1.1.5/tool/data_test.go (about) 1 // Copyright 2019 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 tool 6 7 import ( 8 "bytes" 9 "fmt" 10 "os" 11 "path/filepath" 12 "strings" 13 "testing" 14 "time" 15 16 "github.com/cockroachdb/datadriven" 17 "github.com/cockroachdb/errors" 18 "github.com/cockroachdb/pebble" 19 "github.com/cockroachdb/pebble/internal/base" 20 "github.com/cockroachdb/pebble/internal/testkeys" 21 "github.com/cockroachdb/pebble/vfs" 22 "github.com/spf13/cobra" 23 "github.com/stretchr/testify/require" 24 ) 25 26 func runTests(t *testing.T, path string) { 27 paths, err := filepath.Glob(path) 28 require.NoError(t, err) 29 30 root := filepath.Dir(path) 31 for { 32 next := filepath.Dir(root) 33 if next == "." { 34 break 35 } 36 root = next 37 } 38 39 normalize := func(name string) string { 40 if os.PathSeparator == '/' { 41 return name 42 } 43 return strings.Replace(name, "/", string(os.PathSeparator), -1) 44 } 45 46 for _, path := range paths { 47 name, err := filepath.Rel(root, path) 48 require.NoError(t, err) 49 50 fs := vfs.NewMem() 51 t.Run(name, func(t *testing.T) { 52 datadriven.RunTest(t, path, func(t *testing.T, d *datadriven.TestData) string { 53 // Register a test comparer and merger so that we can check the 54 // behavior of tools when the comparer and merger do not match. 55 comparer := func() *Comparer { 56 c := *base.DefaultComparer 57 c.Name = "test-comparer" 58 c.FormatKey = func(key []byte) fmt.Formatter { 59 return fmtFormatter{ 60 fmt: "test formatter: %s", 61 v: key, 62 } 63 } 64 c.FormatValue = func(_, value []byte) fmt.Formatter { 65 return fmtFormatter{ 66 fmt: "test value formatter: %s", 67 v: value, 68 } 69 } 70 return &c 71 }() 72 altComparer := func() *Comparer { 73 c := *base.DefaultComparer 74 c.Name = "alt-comparer" 75 return &c 76 }() 77 merger := func() *Merger { 78 m := *base.DefaultMerger 79 m.Name = "test-merger" 80 return &m 81 }() 82 83 if d.Cmd == "create" { 84 dbDir := d.CmdArgs[0].String() 85 opts := &pebble.Options{ 86 Comparer: comparer, 87 Merger: merger, 88 FS: fs, 89 FormatMajorVersion: pebble.FormatMostCompatible, 90 } 91 db, err := pebble.Open(dbDir, opts) 92 if err != nil { 93 d.Fatalf(t, "%v", err) 94 } 95 db.Close() 96 return "" 97 } 98 99 args := []string{d.Cmd} 100 for _, arg := range d.CmdArgs { 101 args = append(args, arg.String()) 102 } 103 args = append(args, strings.Fields(d.Input)...) 104 105 // The testdata files contain paths with "/" path separators, but we 106 // might be running on a system with a different path separator 107 // (e.g. Windows). Copy the input data into a mem filesystem which 108 // always uses "/" for the path separator. 109 for i := range args { 110 src := normalize(args[i]) 111 dest := vfs.Default.PathBase(src) 112 if ok, err := vfs.Clone(vfs.Default, fs, src, dest); err != nil { 113 return err.Error() 114 } else if ok { 115 args[i] = fs.PathBase(args[i]) 116 } 117 } 118 119 var buf bytes.Buffer 120 var secs int64 121 timeNow = func() time.Time { secs++; return time.Unix(secs, 0) } 122 123 defer func() { 124 timeNow = time.Now 125 }() 126 127 openErrEnhancer := func(err error) error { 128 if errors.Is(err, base.ErrCorruption) { 129 return base.CorruptionErrorf("%v\nCustom message in case of corruption error.", err) 130 } 131 return err 132 } 133 134 tool := New( 135 DefaultComparer(comparer), 136 Comparers(altComparer, testkeys.Comparer), 137 Mergers(merger), 138 FS(fs), 139 OpenErrEnhancer(openErrEnhancer), 140 ) 141 142 c := &cobra.Command{} 143 c.AddCommand(tool.Commands...) 144 c.SetArgs(args) 145 c.SetOut(&buf) 146 c.SetErr(&buf) 147 if err := c.Execute(); err != nil { 148 return err.Error() 149 } 150 return buf.String() 151 }) 152 }) 153 } 154 }