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