pkg/locker/locker_test.go

125 lines
2 KiB
Go
Raw Normal View History

package locker
import (
"sync"
"testing"
"time"
)
func TestLockCounter(t *testing.T) {
l := &lockCtr{}
l.inc()
if l.waiters != 1 {
t.Fatal("counter inc failed")
}
l.dec()
if l.waiters != 0 {
t.Fatal("counter dec failed")
}
}
func TestLockerLock(t *testing.T) {
l := New()
l.Lock("test")
ctr := l.locks["test"]
if ctr.count() != 0 {
t.Fatalf("expected waiters to be 0, got :%d", ctr.waiters)
}
chDone := make(chan struct{})
go func() {
l.Lock("test")
close(chDone)
}()
chWaiting := make(chan struct{})
go func() {
for range time.Tick(1 * time.Millisecond) {
if ctr.count() == 1 {
close(chWaiting)
break
}
}
}()
select {
case <-chWaiting:
case <-time.After(3 * time.Second):
t.Fatal("timed out waiting for lock waiters to be incremented")
}
select {
case <-chDone:
t.Fatal("lock should not have returned while it was still held")
default:
}
if err := l.Unlock("test"); err != nil {
t.Fatal(err)
}
select {
case <-chDone:
case <-time.After(3 * time.Second):
t.Fatalf("lock should have completed")
}
if ctr.count() != 0 {
t.Fatalf("expected waiters to be 0, got: %d", ctr.count())
}
}
func TestLockerUnlock(t *testing.T) {
l := New()
l.Lock("test")
l.Unlock("test")
chDone := make(chan struct{})
go func() {
l.Lock("test")
close(chDone)
}()
select {
case <-chDone:
case <-time.After(3 * time.Second):
t.Fatalf("lock should not be blocked")
}
}
func TestLockerConcurrency(t *testing.T) {
l := New()
var wg sync.WaitGroup
for i := 0; i <= 10000; i++ {
wg.Add(1)
go func() {
l.Lock("test")
// if there is a concurrency issue, will very likely panic here
l.Unlock("test")
wg.Done()
}()
}
chDone := make(chan struct{})
go func() {
wg.Wait()
close(chDone)
}()
select {
case <-chDone:
case <-time.After(10 * time.Second):
t.Fatal("timeout waiting for locks to complete")
}
// Since everything has unlocked this should not exist anymore
if ctr, exists := l.locks["test"]; exists {
t.Fatalf("lock should not exist: %v", ctr)
}
}