github.com/dmmcquay/sia@v1.3.1-0.20180712220038-9f8d535311b9/sync/trymutex_test.go (about) 1 package sync 2 3 import ( 4 "sync" 5 "testing" 6 "time" 7 ) 8 9 // TestTryMutexBasicMutex verifies that Lock and Unlock work the same as a 10 // normal mutex would. 11 func TestTryMutexBasicMutex(t *testing.T) { 12 // Check that two calls to lock will execute in the correct order. 13 var tm TryMutex 14 var data int 15 tm.Lock() 16 go func() { 17 data = 15 18 tm.Unlock() 19 }() 20 tm.Lock() 21 if data != 15 { 22 t.Error("Locking did not safely protect the data") 23 } 24 tm.Unlock() 25 } 26 27 // TestTryMutexConcurrentLocking checks that doing lots of concurrent locks is 28 // handled as expected. 29 func TestTryMutexConcurrentLocking(t *testing.T) { 30 if testing.Short() { 31 t.SkipNow() 32 } 33 34 // Try executing multiple additions concurrently. 35 var tm TryMutex 36 var data int 37 var wg sync.WaitGroup 38 for i := 0; i < 250; i++ { 39 wg.Add(1) 40 go func() { 41 tm.Lock() 42 data++ 43 tm.Unlock() 44 wg.Done() 45 }() 46 } 47 wg.Wait() 48 if data != 250 { 49 t.Error("Locking did not safely protect the data") 50 } 51 } 52 53 // TestTryMutexBasicTryLock checks that a TryLock will succeed if nobody is 54 // holding a lock, and will fail if the lock is being held. 55 func TestTryMutexBasicTryLock(t *testing.T) { 56 // Lock and then TryLock. 57 var tm TryMutex 58 tm.Lock() 59 if tm.TryLock() { 60 t.Error("TryLock should have failed") 61 } 62 tm.Unlock() 63 64 tm.Lock() 65 tm.Unlock() 66 67 // TryLock and then TryLock. 68 if !tm.TryLock() { 69 t.Error("Could not get a blank lock") 70 } 71 if tm.TryLock() { 72 t.Error("should not have been able to get the lock") 73 } 74 tm.Unlock() 75 } 76 77 // TestTryMutexConcurrentTries attempts to grab locks from many threads, giving 78 // the race detector a chance to detect any issues. 79 func TestTryMutexConncurrentTries(t *testing.T) { 80 if testing.Short() { 81 t.SkipNow() 82 } 83 84 // Try executing multiple additions concurrently. 85 var tm TryMutex 86 var data int 87 var wg sync.WaitGroup 88 for i := 0; i < 250; i++ { 89 wg.Add(1) 90 go func() { 91 for !tm.TryLock() { 92 } 93 94 data++ 95 tm.Unlock() 96 wg.Done() 97 }() 98 } 99 wg.Wait() 100 if data != 250 { 101 t.Error("Locking did not safely protect the data") 102 } 103 } 104 105 // TestTryMutexTimed checks that a timed lock will correctly time out if it 106 // cannot grab a lock. 107 func TestTryMutexTimed(t *testing.T) { 108 if testing.Short() { 109 t.SkipNow() 110 } 111 112 var tm TryMutex 113 tm.Lock() 114 115 startTime := time.Now() 116 if tm.TryLockTimed(time.Millisecond * 500) { 117 t.Error("was able to grab a locked lock") 118 } 119 120 wait := time.Now().Sub(startTime) 121 if wait < time.Millisecond*450 { 122 t.Error("lock did not wait the correct amount of time before timing out", wait) 123 } 124 if wait > time.Millisecond*900 { 125 t.Error("lock waited too long before timing out", wait) 126 } 127 128 tm.Unlock() 129 if !tm.TryLockTimed(time.Millisecond * 1) { 130 t.Error("Unable to get an unlocked lock") 131 } 132 tm.Unlock() 133 } 134 135 // TestTryMutexTimedConcurrent checks that a timed lock will correctly time out 136 // if it cannot grab a lock. 137 func TestTryMutexTimedConcurrent(t *testing.T) { 138 if testing.Short() { 139 t.SkipNow() 140 } 141 142 var tm TryMutex 143 144 // Engage a lock and launch a gothread to wait for a lock, fail, and then 145 // call unlock. 146 tm.Lock() 147 go func() { 148 startTime := time.Now() 149 if tm.TryLockTimed(time.Millisecond * 500) { 150 t.Error("was able to grab a locked lock") 151 } 152 153 wait := time.Now().Sub(startTime) 154 if wait < time.Millisecond*450 { 155 t.Error("lock did not wait the correct amount of time before timing out:", wait) 156 } 157 if wait > time.Millisecond*900 { 158 t.Error("lock waited too long before timing out", wait) 159 } 160 161 tm.Unlock() 162 }() 163 164 // Try to get a lock, but don't wait long enough. 165 if tm.TryLockTimed(time.Millisecond * 250) { 166 // Lock shoud time out because the gothread responsible for releasing 167 // the lock will be idle for 500 milliseconds. 168 t.Error("Lock should have timed out") 169 } 170 if !tm.TryLockTimed(time.Millisecond * 950) { 171 // Lock should be successful - the above thread should finish in under 172 // 950 milliseconds. 173 t.Error("Lock should have been successful") 174 } 175 tm.Unlock() 176 }