github.com/cockroachdb/pebble@v0.0.0-20231214172447-ab4952c5f87b/metamorphic/generator_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 metamorphic
     6  
     7  import (
     8  	"fmt"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/cockroachdb/pebble"
    13  	"github.com/cockroachdb/pebble/internal/randvar"
    14  	"github.com/pmezard/go-difflib/difflib"
    15  	"github.com/stretchr/testify/require"
    16  	"golang.org/x/exp/rand"
    17  )
    18  
    19  func TestGenerator(t *testing.T) {
    20  	rng := randvar.NewRand()
    21  	g := newGenerator(rng, defaultConfig(), newKeyManager(1 /* numInstances */))
    22  
    23  	g.newBatch()
    24  	g.newBatch()
    25  	g.newBatch()
    26  	require.EqualValues(t, 3, len(g.liveBatches))
    27  	require.EqualValues(t, 0, len(g.batches))
    28  
    29  	g.newIndexedBatch()
    30  	g.newIndexedBatch()
    31  	g.newIndexedBatch()
    32  	require.EqualValues(t, 6, len(g.liveBatches))
    33  	require.EqualValues(t, 3, len(g.batches))
    34  	require.EqualValues(t, 3, len(g.readers))
    35  
    36  	g.newIter()
    37  	g.newIter()
    38  	g.newIter()
    39  	require.EqualValues(t, 3, len(g.liveIters))
    40  
    41  	g.batchAbort()
    42  	g.batchAbort()
    43  	g.batchAbort()
    44  	g.batchAbort()
    45  	g.batchAbort()
    46  	g.batchAbort()
    47  
    48  	require.EqualValues(t, 0, len(g.liveBatches))
    49  	require.EqualValues(t, 0, len(g.batches))
    50  	require.EqualValues(t, 0, len(g.iters))
    51  	require.EqualValues(t, 1, len(g.liveReaders))
    52  	require.EqualValues(t, 0, len(g.readers))
    53  	require.EqualValues(t, 0, len(g.liveSnapshots))
    54  	require.EqualValues(t, 0, len(g.snapshots))
    55  	require.EqualValues(t, 1, len(g.liveWriters))
    56  
    57  	g.randIter(g.iterClose)()
    58  	g.randIter(g.iterClose)()
    59  	g.randIter(g.iterClose)()
    60  	require.EqualValues(t, 0, len(g.liveIters))
    61  
    62  	if testing.Verbose() {
    63  		t.Logf("\n%s", g)
    64  	}
    65  
    66  	g = newGenerator(rng, defaultConfig(), newKeyManager(1 /* numInstances */))
    67  
    68  	g.newSnapshot()
    69  	g.newSnapshot()
    70  	g.newSnapshot()
    71  	require.EqualValues(t, 3, len(g.liveSnapshots))
    72  	require.EqualValues(t, 3, len(g.snapshots))
    73  
    74  	g.newIter()
    75  	g.newIter()
    76  	g.newIter()
    77  	g.snapshotClose()
    78  	g.snapshotClose()
    79  	g.snapshotClose()
    80  
    81  	require.EqualValues(t, 0, len(g.liveBatches))
    82  	require.EqualValues(t, 0, len(g.batches))
    83  	require.EqualValues(t, 0, len(g.iters))
    84  	require.EqualValues(t, 1, len(g.liveReaders))
    85  	require.EqualValues(t, 0, len(g.readers))
    86  	require.EqualValues(t, 0, len(g.liveSnapshots))
    87  	require.EqualValues(t, 0, len(g.snapshots))
    88  	require.EqualValues(t, 1, len(g.liveWriters))
    89  
    90  	g.randIter(g.iterClose)()
    91  	g.randIter(g.iterClose)()
    92  	g.randIter(g.iterClose)()
    93  	require.EqualValues(t, 0, len(g.liveIters))
    94  
    95  	if testing.Verbose() {
    96  		t.Logf("\n%s", g)
    97  	}
    98  
    99  	g = newGenerator(rng, defaultConfig(), newKeyManager(1 /* numInstances */))
   100  
   101  	g.newIndexedBatch()
   102  	g.newIndexedBatch()
   103  	g.newIndexedBatch()
   104  	g.newIter()
   105  	g.newIter()
   106  	g.newIter()
   107  	g.writerApply()
   108  	g.writerApply()
   109  	g.writerApply()
   110  	g.randIter(g.iterClose)()
   111  	g.randIter(g.iterClose)()
   112  	g.randIter(g.iterClose)()
   113  
   114  	require.EqualValues(t, 0, len(g.liveBatches))
   115  	require.EqualValues(t, 0, len(g.batches))
   116  	require.EqualValues(t, 0, len(g.liveIters))
   117  	require.EqualValues(t, 0, len(g.iters))
   118  	require.EqualValues(t, 1, len(g.liveReaders))
   119  	require.EqualValues(t, 0, len(g.readers))
   120  	require.EqualValues(t, 0, len(g.liveSnapshots))
   121  	require.EqualValues(t, 0, len(g.snapshots))
   122  	require.EqualValues(t, 1, len(g.liveWriters))
   123  
   124  	if testing.Verbose() {
   125  		t.Logf("\n%s", g)
   126  	}
   127  }
   128  
   129  func TestGeneratorRandom(t *testing.T) {
   130  	seed := uint64(time.Now().UnixNano())
   131  	ops := randvar.NewUniform(1000, 10000)
   132  	cfgs := []string{"default", "multiInstance"}
   133  	generateFromSeed := func(cfg config) string {
   134  		rng := rand.New(rand.NewSource(seed))
   135  		count := ops.Uint64(rng)
   136  		return formatOps(generate(rng, count, cfg, newKeyManager(cfg.numInstances)))
   137  	}
   138  
   139  	for i := range cfgs {
   140  		t.Run(fmt.Sprintf("config=%s", cfgs[i]), func(t *testing.T) {
   141  			cfg := defaultConfig
   142  			if cfgs[i] == "multiInstance" {
   143  				cfg = func() config {
   144  					cfg := multiInstanceConfig()
   145  					cfg.numInstances = 2
   146  					return cfg
   147  				}
   148  			}
   149  			// Ensure that generate doesn't use any other source of randomness other
   150  			// than rng.
   151  			referenceOps := generateFromSeed(cfg())
   152  			for i := 0; i < 10; i++ {
   153  				regeneratedOps := generateFromSeed(cfg())
   154  				diff, err := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
   155  					A:       difflib.SplitLines(referenceOps),
   156  					B:       difflib.SplitLines(regeneratedOps),
   157  					Context: 1,
   158  				})
   159  				require.NoError(t, err)
   160  				if len(diff) > 0 {
   161  					t.Fatalf("Diff:\n%s", diff)
   162  				}
   163  			}
   164  			if testing.Verbose() {
   165  				t.Logf("\nOps:\n%s", referenceOps)
   166  			}
   167  		})
   168  	}
   169  }
   170  
   171  func TestGenerateRandKeyToReadInRange(t *testing.T) {
   172  	rng := randvar.NewRand()
   173  	g := newGenerator(rng, defaultConfig(), newKeyManager(1 /* numInstances */))
   174  	// Seed 100 initial keys.
   175  	for i := 0; i < 100; i++ {
   176  		_ = g.randKeyToWrite(1.0)
   177  	}
   178  	for i := 0; i < 100; i++ {
   179  		a := g.randKeyToRead(0.01)
   180  		b := g.randKeyToRead(0.01)
   181  		// Ensure unique prefixes; required by randKeyToReadInRange.
   182  		for g.equal(g.prefix(a), g.prefix(b)) {
   183  			b = g.randKeyToRead(0.01)
   184  		}
   185  		if v := g.cmp(a, b); v > 0 {
   186  			a, b = b, a
   187  		}
   188  		kr := pebble.KeyRange{Start: a, End: b}
   189  		for j := 0; j < 10; j++ {
   190  			k := g.randKeyToReadInRange(0.05, kr)
   191  			if g.cmp(k, a) < 0 {
   192  				t.Errorf("generated random key %q outside range %s", k, kr)
   193  			} else if g.cmp(k, b) >= 0 {
   194  				t.Errorf("generated random key %q outside range %s", k, kr)
   195  			}
   196  		}
   197  	}
   198  }
   199  
   200  func TestGenerateDisjointKeyRanges(t *testing.T) {
   201  	rng := randvar.NewRand()
   202  	g := newGenerator(rng, defaultConfig(), newKeyManager(1 /* numInstances */))
   203  
   204  	for i := 0; i < 10; i++ {
   205  		keyRanges := g.generateDisjointKeyRanges(5)
   206  		for j := range keyRanges {
   207  			t.Logf("%d: %d: %s", i, j, keyRanges[j])
   208  			for k := range keyRanges {
   209  				if j == k {
   210  					continue
   211  				}
   212  				if g.cmp(keyRanges[j].End, keyRanges[k].Start) <= 0 {
   213  					require.Less(t, j, k)
   214  					continue
   215  				}
   216  				if g.cmp(keyRanges[j].Start, keyRanges[k].End) >= 0 {
   217  					require.Greater(t, j, k)
   218  					continue
   219  				}
   220  				t.Fatalf("generated key ranges %q and %q overlap", keyRanges[j], keyRanges[k])
   221  			}
   222  		}
   223  	}
   224  }