...
1 package locker
2
3 import (
4 "math/rand"
5 "strconv"
6 "sync"
7 "testing"
8 "time"
9 )
10
11 func TestLockCounter(t *testing.T) {
12 l := &lockCtr{}
13 l.inc()
14
15 if l.waiters != 1 {
16 t.Fatal("counter inc failed")
17 }
18
19 l.dec()
20 if l.waiters != 0 {
21 t.Fatal("counter dec failed")
22 }
23 }
24
25 func TestLockerLock(t *testing.T) {
26 l := New()
27 l.Lock("test")
28 ctr := l.locks["test"]
29
30 if ctr.count() != 0 {
31 t.Fatalf("expected waiters to be 0, got :%d", ctr.waiters)
32 }
33
34 chDone := make(chan struct{})
35 go func() {
36 l.Lock("test")
37 close(chDone)
38 }()
39
40 chWaiting := make(chan struct{})
41 go func() {
42 for range time.Tick(1 * time.Millisecond) {
43 if ctr.count() == 1 {
44 close(chWaiting)
45 break
46 }
47 }
48 }()
49
50 select {
51 case <-chWaiting:
52 case <-time.After(3 * time.Second):
53 t.Fatal("timed out waiting for lock waiters to be incremented")
54 }
55
56 select {
57 case <-chDone:
58 t.Fatal("lock should not have returned while it was still held")
59 default:
60 }
61
62 if err := l.Unlock("test"); err != nil {
63 t.Fatal(err)
64 }
65
66 select {
67 case <-chDone:
68 case <-time.After(3 * time.Second):
69 t.Fatalf("lock should have completed")
70 }
71
72 if ctr.count() != 0 {
73 t.Fatalf("expected waiters to be 0, got: %d", ctr.count())
74 }
75 }
76
77 func TestLockerUnlock(t *testing.T) {
78 l := New()
79
80 l.Lock("test")
81 l.Unlock("test")
82
83 chDone := make(chan struct{})
84 go func() {
85 l.Lock("test")
86 close(chDone)
87 }()
88
89 select {
90 case <-chDone:
91 case <-time.After(3 * time.Second):
92 t.Fatalf("lock should not be blocked")
93 }
94 }
95
96 func TestLockerConcurrency(t *testing.T) {
97 l := New()
98
99 var wg sync.WaitGroup
100 for i := 0; i <= 10000; i++ {
101 wg.Add(1)
102 go func() {
103 l.Lock("test")
104
105 l.Unlock("test")
106 wg.Done()
107 }()
108 }
109
110 chDone := make(chan struct{})
111 go func() {
112 wg.Wait()
113 close(chDone)
114 }()
115
116 select {
117 case <-chDone:
118 case <-time.After(10 * time.Second):
119 t.Fatal("timeout waiting for locks to complete")
120 }
121
122
123 if ctr, exists := l.locks["test"]; exists {
124 t.Fatalf("lock should not exist: %v", ctr)
125 }
126 }
127
128 func BenchmarkLocker(b *testing.B) {
129 l := New()
130 for i := 0; i < b.N; i++ {
131 l.Lock("test")
132 l.Unlock("test")
133 }
134 }
135
136 func BenchmarkLockerParallel(b *testing.B) {
137 l := New()
138 b.SetParallelism(128)
139 b.RunParallel(func(pb *testing.PB) {
140 for pb.Next() {
141 l.Lock("test")
142 l.Unlock("test")
143 }
144 })
145 }
146
147 func BenchmarkLockerMoreKeys(b *testing.B) {
148 l := New()
149 var keys []string
150 for i := 0; i < 64; i++ {
151 keys = append(keys, strconv.Itoa(i))
152 }
153 b.SetParallelism(128)
154 b.RunParallel(func(pb *testing.PB) {
155 for pb.Next() {
156 k := keys[rand.Intn(len(keys))]
157 l.Lock(k)
158 l.Unlock(k)
159 }
160 })
161 }
162
View as plain text