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  }