add unit test to ClosableMutex
This commit is contained in:
parent
f485e213b6
commit
8cd23e6cfc
|
@ -0,0 +1,124 @@
|
||||||
|
package syncx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestClosableMutex(t *testing.T) {
|
||||||
|
t.Run("basic lock/unlock", func(t *testing.T) {
|
||||||
|
cm := NewClosableMutex()
|
||||||
|
if !cm.TryLock() {
|
||||||
|
t.Error("TryLock should succeed on new mutex")
|
||||||
|
}
|
||||||
|
cm.Unlock()
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("multiple lock/unlock", func(t *testing.T) {
|
||||||
|
cm := NewClosableMutex()
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
if !cm.TryLock() {
|
||||||
|
t.Error("TryLock should succeed")
|
||||||
|
}
|
||||||
|
cm.Unlock()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("concurrent lock/unlock", func(t *testing.T) {
|
||||||
|
cm := NewClosableMutex()
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
// lockCount is used to count how many goroutines have acquired the lock
|
||||||
|
var lockCount atomic.Int32
|
||||||
|
|
||||||
|
// Start a goroutine that holds the lock for a short time
|
||||||
|
wg.Add(2)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
if !cm.TryLock() {
|
||||||
|
t.Error("First TryLock should succeed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
lockCount.Add(1)
|
||||||
|
cm.Unlock()
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
// if main goroutine acquires the lock, it will increment lockCount
|
||||||
|
// so check the lockCount at the second to see if the main goroutine has acquired the lock
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
if lockCount.Load() != 0 {
|
||||||
|
t.Error("Second TryLock should not succeed while the first goroutine holds the lock")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Try to acquire the lock while it's held
|
||||||
|
time.Sleep(time.Second) // Wait for the first goroutine to acquire the lock
|
||||||
|
|
||||||
|
// NOTE: will block here until the first goroutine releases the lock
|
||||||
|
if !cm.TryLock() {
|
||||||
|
t.Error("Second TryLock should block here unitl the first goroutine releases the lock, but it didn't")
|
||||||
|
cm.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
lockCount.Add(1)
|
||||||
|
|
||||||
|
// the main goroutine will increment lockCount once the first gourotine releases the lock,
|
||||||
|
// so lockCount should be 2
|
||||||
|
if lockCount.Load() != 2 {
|
||||||
|
t.Error("main gourotine should have acquired the lock")
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("must lock", func(t *testing.T) {
|
||||||
|
cm := NewClosableMutex()
|
||||||
|
cm.MustLock()
|
||||||
|
cm.Unlock()
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("close mutex", func(t *testing.T) {
|
||||||
|
cm := NewClosableMutex()
|
||||||
|
cm.Close()
|
||||||
|
if cm.TryLock() {
|
||||||
|
t.Error("TryLock should fail on closed mutex")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("panic on unlock of unlocked mutex", func(t *testing.T) {
|
||||||
|
cm := NewClosableMutex()
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r == nil {
|
||||||
|
t.Error("Expected panic on Unlock of unlocked mutex")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
cm.Unlock() // Should panic
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("panic on must lock of closed mutex", func(t *testing.T) {
|
||||||
|
cm := NewClosableMutex()
|
||||||
|
cm.Close()
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r == nil {
|
||||||
|
t.Error("Expected panic on MustLock of closed mutex")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
cm.MustLock() // Should panic
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("panic on close of closed mutex", func(t *testing.T) {
|
||||||
|
cm := NewClosableMutex()
|
||||||
|
cm.Close()
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r == nil {
|
||||||
|
t.Error("Expected panic on Close of closed mutex")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
cm.Close() // Should panic
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue