github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/store/nbs/reflog_ring_buffer_test.go (about) 1 // Copyright 2023 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package nbs 16 17 import ( 18 "fmt" 19 "testing" 20 "time" 21 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 ) 25 26 // TestIteration asserts that we can iterate over the contents of a reflog ring buffer as the ring buffer grows. 27 func TestIteration(t *testing.T) { 28 buffer := newReflogRingBuffer(5) 29 30 // Assert that Iterate returns the correct items in the correct order when the buffer 31 // contains fewer items than the requested buffer size. 32 insertTestRecord(buffer, "aaaa") 33 insertTestRecord(buffer, "bbbb") 34 insertTestRecord(buffer, "cccc") 35 assertExpectedIterationOrder(t, buffer, []string{"aaaa", "bbbb", "cccc"}) 36 37 // Assert that Iterate returns the correct items in the correct order when the buffer 38 // contains the same number of items as the requested buffer size. 39 insertTestRecord(buffer, "dddd") 40 insertTestRecord(buffer, "eeee") 41 assertExpectedIterationOrder(t, buffer, []string{"aaaa", "bbbb", "cccc", "dddd", "eeee"}) 42 43 // Insert two new records that cause the buffer to exclude the first two records 44 insertTestRecord(buffer, "ffff") 45 insertTestRecord(buffer, "gggg") 46 assertExpectedIterationOrder(t, buffer, []string{"cccc", "dddd", "eeee", "ffff", "gggg"}) 47 48 // Insert three records to fill up the buffer's internal capacity 49 insertTestRecord(buffer, "hhhh") 50 insertTestRecord(buffer, "iiii") 51 insertTestRecord(buffer, "jjjj") 52 assertExpectedIterationOrder(t, buffer, []string{"ffff", "gggg", "hhhh", "iiii", "jjjj"}) 53 54 // Insert four records to test the buffer wrapping around for the first time 55 insertTestRecord(buffer, "kkkk") 56 insertTestRecord(buffer, "llll") 57 insertTestRecord(buffer, "mmmm") 58 insertTestRecord(buffer, "nnnn") 59 assertExpectedIterationOrder(t, buffer, []string{"jjjj", "kkkk", "llll", "mmmm", "nnnn"}) 60 61 // Insert 10 records to test the buffer wrapping around a second time 62 insertTestRecord(buffer, "oooo") 63 insertTestRecord(buffer, "pppp") 64 insertTestRecord(buffer, "qqqq") 65 insertTestRecord(buffer, "rrrr") 66 insertTestRecord(buffer, "ssss") 67 insertTestRecord(buffer, "tttt") 68 insertTestRecord(buffer, "uuuu") 69 insertTestRecord(buffer, "vvvv") 70 insertTestRecord(buffer, "wwww") 71 insertTestRecord(buffer, "xxxx") 72 assertExpectedIterationOrder(t, buffer, []string{"tttt", "uuuu", "vvvv", "wwww", "xxxx"}) 73 } 74 75 // TestTruncate asserts that the Truncate works correctly regardless of how much data 76 // is currently stored in the buffer. 77 func TestTruncate(t *testing.T) { 78 buffer := newReflogRingBuffer(5) 79 80 // When the buffer is empty, Truncate is a no-op 81 buffer.Truncate() 82 assertExpectedIterationOrder(t, buffer, []string{}) 83 buffer.Truncate() 84 assertExpectedIterationOrder(t, buffer, []string{}) 85 86 // When the buffer contains a single item 87 insertTestRecord(buffer, "aaaa") 88 buffer.Truncate() 89 assertExpectedIterationOrder(t, buffer, []string{}) 90 buffer.Truncate() 91 assertExpectedIterationOrder(t, buffer, []string{}) 92 93 // When the buffer is not full, Truncate empties the buffer 94 insertTestRecord(buffer, "bbbb") 95 insertTestRecord(buffer, "cccc") 96 insertTestRecord(buffer, "dddd") 97 buffer.Truncate() 98 assertExpectedIterationOrder(t, buffer, []string{}) 99 100 // When the buffer is full, Truncate empties the buffer 101 insertTestRecord(buffer, "aaaa") 102 insertTestRecord(buffer, "bbbb") 103 insertTestRecord(buffer, "cccc") 104 insertTestRecord(buffer, "dddd") 105 insertTestRecord(buffer, "eeee") 106 insertTestRecord(buffer, "ffff") 107 insertTestRecord(buffer, "gggg") 108 insertTestRecord(buffer, "hhhh") 109 insertTestRecord(buffer, "iiii") 110 insertTestRecord(buffer, "jjjj") 111 insertTestRecord(buffer, "kkkk") 112 insertTestRecord(buffer, "llll") 113 insertTestRecord(buffer, "mmmm") 114 buffer.Truncate() 115 assertExpectedIterationOrder(t, buffer, []string{}) 116 } 117 118 // TestIterationConflict asserts that when iterating through a reflog ring buffer and new items are written to the 119 // buffer and wrap around into the iteration range, that iteration stops early and an error is returned. 120 func TestIterationConflict(t *testing.T) { 121 buffer := newReflogRingBuffer(5) 122 buffer.Push(reflogRootHashEntry{"aaaa", time.Now()}) 123 buffer.Push(reflogRootHashEntry{"bbbb", time.Now()}) 124 buffer.Push(reflogRootHashEntry{"cccc", time.Now()}) 125 buffer.Push(reflogRootHashEntry{"dddd", time.Now()}) 126 buffer.Push(reflogRootHashEntry{"eeee", time.Now()}) 127 128 iterationCount := 0 129 err := buffer.Iterate(func(item reflogRootHashEntry) error { 130 for i := 0; i < 100; i++ { 131 buffer.Push(reflogRootHashEntry{fmt.Sprintf("i-%d", i), time.Now()}) 132 } 133 iterationCount++ 134 return nil 135 }) 136 require.Error(t, err) 137 require.Equal(t, errUnsafeIteration, err) 138 require.True(t, iterationCount < 5) 139 } 140 141 func insertTestRecord(buffer *reflogRingBuffer, root string) { 142 buffer.Push(reflogRootHashEntry{ 143 root: root, 144 timestamp: time.Now(), 145 }) 146 } 147 148 func assertExpectedIterationOrder(t *testing.T, buffer *reflogRingBuffer, expectedRoots []string) { 149 i := 0 150 err := buffer.Iterate(func(item reflogRootHashEntry) error { 151 assert.Equal(t, expectedRoots[i], item.root) 152 assert.False(t, time.Time.IsZero(item.timestamp)) 153 i++ 154 return nil 155 }) 156 assert.NoError(t, err) 157 assert.Equal(t, len(expectedRoots), i) 158 }