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  }