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