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 }