Source file
src/database/sql/closemu_test.go
1
2
3
4
5 package sql
6
7 import (
8 "testing"
9 "testing/synctest"
10 )
11
12 func TestClosingMutex(t *testing.T) {
13 start := func(t *testing.T, f func()) func() bool {
14 done := false
15 go func() {
16 f()
17 done = true
18 }()
19 return func() bool {
20 synctest.Wait()
21 return done
22 }
23 }
24
25 synctest.Test(t, func(t *testing.T) {
26 var m closingMutex
27
28
29 m.RLock()
30 m.RLock()
31 m.RUnlock()
32 m.RUnlock()
33
34
35 m.RLock()
36 lock1Done := start(t, m.Lock)
37 if lock1Done() {
38 t.Fatalf("m.Lock(): succeeded on RLocked mutex")
39 }
40 m.RLock()
41 m.RUnlock()
42 if lock1Done() {
43 t.Fatalf("m.Lock(): succeeded after one RUnlock, one RLock remains")
44 }
45 m.RUnlock()
46 if !lock1Done() {
47 t.Fatalf("m.Lock(): still blocking after all RUnlocks")
48 }
49 m.Unlock()
50
51
52 m.Lock()
53 rlock1Done := start(t, m.RLock)
54 rlock2Done := start(t, m.RLock)
55 if rlock1Done() || rlock2Done() {
56 t.Fatalf("m.RLock(): succeeded on Locked mutex")
57 }
58 m.Unlock()
59 if !rlock1Done() || !rlock2Done() {
60 t.Fatalf("m.RLock(): succeeded on Locked mutex")
61 }
62 m.RUnlock()
63 m.RUnlock()
64
65
66 m.Lock()
67 lock2Done := start(t, m.Lock)
68 if lock2Done() {
69 t.Fatalf("m.Lock(): succeeded on Locked mutex")
70 }
71 m.Unlock()
72 if !lock2Done() {
73 t.Fatalf("m.Lock(): still blocking after Unlock")
74 }
75 m.Unlock()
76
77
78 m.RLock()
79 lock3Done := start(t, m.Lock)
80 if lock3Done() {
81 t.Fatalf("m.Lock(): succeeded on RLocked mutex")
82 }
83 m.RLock()
84 m.RUnlock()
85 m.RUnlock()
86 if !lock3Done() {
87 t.Fatalf("m.Lock(): still blocking after RUnlock")
88 }
89 m.Unlock()
90 })
91 }
92
93 func TestClosingMutexLockStarvation(t *testing.T) {
94 synctest.Test(t, func(t *testing.T) {
95
96 for range 100 {
97 var m closingMutex
98
99
100 m.RLock()
101 locked := false
102 go func() {
103 m.Lock()
104 locked = true
105 m.Unlock()
106 }()
107 synctest.Wait()
108 if locked {
109 t.Errorf("lock acquired while mutex is rlocked")
110 }
111
112
113 m.RLock()
114 m.RUnlock()
115 if locked {
116 t.Errorf("lock acquired while mutex is double-rlocked")
117 }
118
119
120
121
122 m.RUnlock()
123 m.RLock()
124 if !locked {
125 t.Errorf("lock not acquired when rlock dropped")
126 }
127 m.RUnlock()
128 }
129 })
130 }
131
132 func TestClosingMutexPanics(t *testing.T) {
133 for _, test := range []struct {
134 name string
135 f func()
136 }{{
137 name: "double RUnlock",
138 f: func() {
139 var m closingMutex
140 m.RLock()
141 m.RUnlock()
142 m.RUnlock()
143 },
144 }, {
145 name: "double Unlock",
146 f: func() {
147 var m closingMutex
148 m.Lock()
149 m.Unlock()
150 m.Unlock()
151 },
152 }} {
153 var got any
154 func() {
155 defer func() {
156 got = recover()
157 }()
158 test.f()
159 }()
160 if got == nil {
161 t.Errorf("no panic, want one")
162 }
163 }
164 }
165
View as plain text