github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/kbfssync/leveled_mutex_test.go (about) 1 // Copyright 2016 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 package kbfssync 6 7 import ( 8 "fmt" 9 "sync" 10 "testing" 11 12 "github.com/stretchr/testify/require" 13 ) 14 15 func TestExclusiveLock(t *testing.T) { 16 el := makeExclusiveLock() 17 el.lock() 18 defer el.unlock() 19 20 // This must leave el unlocked. 21 require.Panics(t, func() { 22 el.lock() 23 }) 24 } 25 26 type testMutexLevel MutexLevel 27 28 const ( 29 testFirst testMutexLevel = 1 30 testSecond testMutexLevel = 2 31 testThird testMutexLevel = 3 32 ) 33 34 func (o testMutexLevel) String() string { 35 return fmt.Sprintf("test-lock-%d", int(o)) 36 } 37 38 func testMutexLevelToString(o MutexLevel) string { 39 return (testMutexLevel(o)).String() 40 } 41 42 func TestLeveledMutexSingleFlow(t *testing.T) { 43 mu1 := MakeLeveledMutex(MutexLevel(testFirst), &sync.Mutex{}) 44 mu2 := MakeLeveledMutex(MutexLevel(testSecond), &sync.Mutex{}) 45 mu3 := MakeLeveledMutex(MutexLevel(testThird), &sync.Mutex{}) 46 47 state := MakeLevelState(testMutexLevelToString) 48 49 for _, mu := range []LeveledMutex{mu1, mu2, mu3} { 50 mu.AssertUnlocked(state) 51 mu.Lock(state) 52 mu.AssertLocked(state) 53 54 defer func(mu LeveledMutex) { 55 mu.AssertLocked(state) 56 mu.Unlock(state) 57 mu.AssertUnlocked(state) 58 }(mu) 59 } 60 } 61 62 func TestLeveledMutexIncorrect(t *testing.T) { 63 mu1 := MakeLeveledMutex(MutexLevel(testFirst), &sync.Mutex{}) 64 mu2 := MakeLeveledMutex(MutexLevel(testSecond), &sync.Mutex{}) 65 mu3 := MakeLeveledMutex(MutexLevel(testThird), &sync.Mutex{}) 66 67 state := MakeLevelState(testMutexLevelToString) 68 69 require.Panics(t, func() { 70 mu1.AssertLocked(state) 71 }) 72 73 mu2.Lock(state) 74 75 require.Panics(t, func() { 76 mu2.AssertUnlocked(state) 77 }) 78 79 defer func() { 80 mu2.Unlock(state) 81 82 require.Panics(t, func() { 83 mu2.AssertLocked(state) 84 }) 85 }() 86 87 // This must leave mu1 unlocked. 88 require.Panics(t, func() { 89 mu1.Lock(state) 90 }) 91 92 mu3.Lock(state) 93 defer mu3.Unlock(state) 94 95 // This must leave mu2 locked. 96 require.Panics(t, func() { 97 mu2.Unlock(state) 98 }) 99 } 100 101 // runLockSubsequences() runs all possible subsequences of {mu1, mu2, 102 // mu3}.Lock() under the given WaitGroup. 103 func runLockSubsequences(wg *sync.WaitGroup, mu1, mu2, mu3 LeveledLocker) { 104 wg.Add(1) 105 go func() { 106 defer wg.Done() 107 state := MakeLevelState(testMutexLevelToString) 108 mu1.Lock(state) 109 defer mu1.Unlock(state) 110 mu2.Lock(state) 111 defer mu2.Unlock(state) 112 mu3.Lock(state) 113 defer mu3.Unlock(state) 114 }() 115 116 wg.Add(1) 117 go func() { 118 defer wg.Done() 119 state := MakeLevelState(testMutexLevelToString) 120 mu1.Lock(state) 121 defer mu1.Unlock(state) 122 mu2.Lock(state) 123 defer mu2.Unlock(state) 124 }() 125 126 wg.Add(1) 127 go func() { 128 defer wg.Done() 129 state := MakeLevelState(testMutexLevelToString) 130 mu1.Lock(state) 131 defer mu1.Unlock(state) 132 mu3.Lock(state) 133 defer mu3.Unlock(state) 134 }() 135 136 wg.Add(1) 137 go func() { 138 defer wg.Done() 139 state := MakeLevelState(testMutexLevelToString) 140 mu2.Lock(state) 141 defer mu2.Unlock(state) 142 mu3.Lock(state) 143 defer mu3.Unlock(state) 144 }() 145 146 wg.Add(1) 147 go func() { 148 defer wg.Done() 149 state := MakeLevelState(testMutexLevelToString) 150 mu1.Lock(state) 151 defer mu1.Unlock(state) 152 }() 153 154 wg.Add(1) 155 go func() { 156 defer wg.Done() 157 state := MakeLevelState(testMutexLevelToString) 158 mu2.Lock(state) 159 defer mu2.Unlock(state) 160 }() 161 162 wg.Add(1) 163 go func() { 164 defer wg.Done() 165 state := MakeLevelState(testMutexLevelToString) 166 mu3.Lock(state) 167 defer mu3.Unlock(state) 168 }() 169 } 170 171 func TestLeveledMutexMultiFlow(t *testing.T) { 172 mu1 := MakeLeveledMutex(MutexLevel(testFirst), &sync.Mutex{}) 173 mu2 := MakeLeveledMutex(MutexLevel(testSecond), &sync.Mutex{}) 174 mu3 := MakeLeveledMutex(MutexLevel(testThird), &sync.Mutex{}) 175 176 var wg sync.WaitGroup 177 runLockSubsequences(&wg, mu1, mu2, mu3) 178 wg.Wait() 179 } 180 181 func TestLeveledRWMutexSingleFlow(t *testing.T) { 182 mu1 := MakeLeveledRWMutex(MutexLevel(testFirst), &sync.RWMutex{}) 183 mu2 := MakeLeveledRWMutex(MutexLevel(testSecond), &sync.RWMutex{}) 184 mu3 := MakeLeveledRWMutex(MutexLevel(testThird), &sync.RWMutex{}) 185 186 state := MakeLevelState(testMutexLevelToString) 187 188 mu1.AssertUnlocked(state) 189 mu1.Lock(state) 190 mu1.AssertLocked(state) 191 mu1.AssertAnyLocked(state) 192 193 defer func() { 194 mu1.AssertLocked(state) 195 mu1.AssertAnyLocked(state) 196 mu1.Unlock(state) 197 mu1.AssertUnlocked(state) 198 }() 199 200 mu2.AssertUnlocked(state) 201 mu2.RLock(state) 202 mu2.AssertRLocked(state) 203 mu2.AssertAnyLocked(state) 204 205 defer func() { 206 mu2.AssertRLocked(state) 207 mu2.AssertAnyLocked(state) 208 mu2.RUnlock(state) 209 mu2.AssertUnlocked(state) 210 }() 211 212 mu3.AssertUnlocked(state) 213 mu3.Lock(state) 214 mu3.AssertLocked(state) 215 mu3.AssertAnyLocked(state) 216 217 defer func() { 218 mu3.AssertLocked(state) 219 mu3.AssertAnyLocked(state) 220 mu3.Unlock(state) 221 mu3.AssertUnlocked(state) 222 }() 223 } 224 225 func TestLeveledRWMutexIncorrect(t *testing.T) { 226 mu1 := MakeLeveledRWMutex(MutexLevel(testFirst), &sync.RWMutex{}) 227 mu2 := MakeLeveledRWMutex(MutexLevel(testSecond), &sync.RWMutex{}) 228 mu3 := MakeLeveledRWMutex(MutexLevel(testThird), &sync.RWMutex{}) 229 230 state := MakeLevelState(testMutexLevelToString) 231 232 require.Panics(t, func() { 233 mu1.AssertLocked(state) 234 }) 235 require.Panics(t, func() { 236 mu1.AssertRLocked(state) 237 }) 238 require.Panics(t, func() { 239 mu1.AssertAnyLocked(state) 240 }) 241 242 mu2.RLock(state) 243 244 require.Panics(t, func() { 245 mu2.AssertUnlocked(state) 246 }) 247 248 defer func() { 249 mu2.RUnlock(state) 250 }() 251 252 require.Panics(t, func() { 253 mu2.AssertLocked(state) 254 255 require.Panics(t, func() { 256 mu2.AssertLocked(state) 257 }) 258 require.Panics(t, func() { 259 mu2.AssertRLocked(state) 260 }) 261 require.Panics(t, func() { 262 mu2.AssertAnyLocked(state) 263 }) 264 }) 265 266 // This must leave mu2 read-locked. 267 require.Panics(t, func() { 268 mu2.RLock(state) 269 }) 270 271 // These must leave mu1 unlocked. 272 require.Panics(t, func() { 273 mu1.RLock(state) 274 }) 275 require.Panics(t, func() { 276 mu1.Lock(state) 277 }) 278 279 mu3.Lock(state) 280 defer mu3.Unlock(state) 281 282 require.Panics(t, func() { 283 mu3.AssertRLocked(state) 284 }) 285 286 // This must leave mu3 locked. 287 require.Panics(t, func() { 288 mu3.RUnlock(state) 289 }) 290 291 // These must leave mu2 read-locked. 292 require.Panics(t, func() { 293 mu2.Unlock(state) 294 }) 295 require.Panics(t, func() { 296 mu2.RUnlock(state) 297 }) 298 } 299 300 func TestLeveledRWMutexMultiFlow(t *testing.T) { 301 mu1 := MakeLeveledMutex(MutexLevel(testFirst), &sync.Mutex{}) 302 mu2 := MakeLeveledRWMutex(MutexLevel(testSecond), &sync.RWMutex{}) 303 mu3 := MakeLeveledRWMutex(MutexLevel(testThird), &sync.RWMutex{}) 304 305 var wg sync.WaitGroup 306 307 runLockSubsequences(&wg, mu1, mu2, mu3) 308 runLockSubsequences(&wg, mu1, mu2.RLocker(), mu3) 309 runLockSubsequences(&wg, mu1, mu2, mu3.RLocker()) 310 runLockSubsequences(&wg, mu1, mu2.RLocker(), mu3.RLocker()) 311 312 wg.Wait() 313 }