1
- //go :build deadlock_test
1
+ //asdfasdfsdfsfsfsdfgo :build deadlock_test
2
2
3
3
package mirror
4
4
5
5
import (
6
6
"context"
7
7
"os"
8
+ "os/exec"
9
+ "path"
8
10
"path/filepath"
11
+ "slices"
9
12
"sync"
10
13
"testing"
11
14
"time"
@@ -61,7 +64,6 @@ func Test_mirror_detect_race_clone(t *testing.T) {
61
64
defer wg .Done ()
62
65
if err := repo .Mirror (ctx ); err != nil {
63
66
t .Error ("unable to mirror" , "err" , err )
64
- os .Exit (1 )
65
67
}
66
68
67
69
assertLinkedFile (t , root , link1 , "file" , testName + "-2" )
@@ -83,7 +85,6 @@ func Test_mirror_detect_race_clone(t *testing.T) {
83
85
defer wg .Done ()
84
86
if err := repo .Mirror (ctx ); err != nil {
85
87
t .Error ("unable to mirror error" , "err" , err )
86
- os .Exit (1 )
87
88
}
88
89
}()
89
90
@@ -94,7 +95,7 @@ func Test_mirror_detect_race_clone(t *testing.T) {
94
95
defer os .RemoveAll (tempClone )
95
96
96
97
if cloneSHA , err := repo .Clone (ctx , tempClone , testMainBranch , nil , i % 2 == 0 ); err != nil {
97
- t .Fatalf ("unexpected error %s" , err )
98
+ t .Errorf ("unexpected error %s" , err )
98
99
} else {
99
100
if cloneSHA != fileSHA2 {
100
101
t .Errorf ("clone sha mismatch got:%s want:%s" , cloneSHA , fileSHA2 )
@@ -108,6 +109,138 @@ func Test_mirror_detect_race_clone(t *testing.T) {
108
109
109
110
}
110
111
112
+ func Test_mirror_detect_race_slow_fetch (t * testing.T ) {
113
+ // replace global git path with slower git wrapper script
114
+ cwd , _ := os .Getwd ()
115
+ gitExecutablePath = exec .Command (path .Join (cwd , "z_git_slow_fetch.sh" )).String ()
116
+
117
+ testTmpDir := mustTmpDir (t )
118
+ defer os .RemoveAll (testTmpDir )
119
+
120
+ ctx , cancel := context .WithCancel (context .TODO ())
121
+ defer cancel ()
122
+
123
+ upstream := filepath .Join (testTmpDir , testUpstreamRepo )
124
+ root := filepath .Join (testTmpDir , testRoot )
125
+
126
+ testName := t .Name ()
127
+
128
+ t .Log ("TEST-1: init upstream" )
129
+ fileSHA1 := mustInitRepo (t , upstream , "file" , testName + "-1" )
130
+
131
+ repo := mustCreateRepoAndMirror (t , upstream , root , "" , "" )
132
+ repo .mirrorTimeout = 2 * time .Minute
133
+
134
+ // verify checkout files
135
+ assertCommitLog (t , repo , "HEAD" , "" , fileSHA1 , testName + "-1" , []string {"file" })
136
+
137
+ // start mirror loop
138
+ go repo .StartLoop (ctx )
139
+ close (repo .stop )
140
+
141
+ t .Run ("slow-fetch-without-timeout" , func (t * testing.T ) {
142
+
143
+ // all following assertions will always be true
144
+ // this test is about testing deadlocks and detecting race conditions
145
+ // due to background ctx following assertions should always succeed
146
+ for range 3 {
147
+ wg := & sync.WaitGroup {}
148
+ wg .Add (1 )
149
+ go func () {
150
+ defer wg .Done ()
151
+ if err := repo .Mirror (ctx ); err != nil {
152
+ t .Error ("unable to mirror error" , "err" , err )
153
+ }
154
+ }()
155
+
156
+ wg .Add (1 )
157
+ go func () {
158
+ defer wg .Done ()
159
+
160
+ ctx := context .Background ()
161
+
162
+ time .Sleep (time .Second ) // wait for repo.Mirror to grab lock
163
+
164
+ gotHash , err := repo .Hash (ctx , "HEAD" , "" )
165
+ if err != nil {
166
+ t .Errorf ("unexpected error: %v" , err )
167
+ } else if gotHash != fileSHA1 {
168
+ t .Errorf ("ref '%s' on path '%s' SHA mismatch got:%s want:%s" , "HEAD" , "" , gotHash , fileSHA1 )
169
+ }
170
+
171
+ if got , err := repo .Subject (ctx , fileSHA1 ); err != nil {
172
+ t .Errorf ("unexpected error: %v" , err )
173
+ } else if got != testName + "-1" {
174
+ t .Errorf ("subject mismatch sha:%s got:%s want:%s" , gotHash , got , testName + "-1" )
175
+ }
176
+
177
+ if got , err := repo .ChangedFiles (ctx , fileSHA1 ); err != nil {
178
+ t .Errorf ("unexpected error: %v" , err )
179
+ } else if slices .Compare (got , []string {"file" }) != 0 {
180
+ t .Errorf ("changed file mismatch sha:%s got:%s want:%s" , gotHash , got , []string {"file" })
181
+ }
182
+ }()
183
+ wg .Wait ()
184
+ }
185
+ })
186
+
187
+ t .Run ("slow-fetch-with-client-timeout" , func (t * testing.T ) {
188
+ // all following assertions will always be true
189
+ // this test is about testing deadlocks and detecting race conditions
190
+ // due to shorter ctx timeout Hash, Subject and ChangedFiles should always fail
191
+ for range 3 {
192
+ wg := & sync.WaitGroup {}
193
+ wg .Add (1 )
194
+ go func () {
195
+ defer wg .Done ()
196
+ if err := repo .Mirror (ctx ); err != nil {
197
+ t .Error ("unable to mirror error" , "err" , err )
198
+ }
199
+ }()
200
+
201
+ wg .Add (1 )
202
+ go func () {
203
+ defer wg .Done ()
204
+ time .Sleep (time .Second ) // wait for repo.Mirror to grab lock
205
+
206
+ ctx1 , cancel1 := context .WithTimeout (context .Background (), 5 * time .Second )
207
+ if _ , err := repo .Hash (ctx1 , "HEAD" , "" ); err == nil {
208
+ t .Errorf ("error was expected due to sorter timeout" )
209
+ }
210
+
211
+ ctx2 , cancel2 := context .WithTimeout (context .Background (), 5 * time .Second )
212
+ if _ , err := repo .Subject (ctx2 , fileSHA1 ); err == nil {
213
+ t .Errorf ("error was expected due to sorter timeout" )
214
+ }
215
+
216
+ ctx3 , cancel3 := context .WithTimeout (context .Background (), 5 * time .Second )
217
+ if _ , err := repo .ChangedFiles (ctx3 , fileSHA1 ); err == nil {
218
+ t .Errorf ("error was expected due to sorter timeout" )
219
+ }
220
+
221
+ cancel1 ()
222
+ cancel2 ()
223
+ cancel3 ()
224
+ }()
225
+ wg .Wait ()
226
+ }
227
+ })
228
+
229
+ t .Run ("slow-fetch-with-mirror-timeout" , func (t * testing.T ) {
230
+ for range 3 {
231
+ ctx1 , cancel1 := context .WithTimeout (context .Background (), 5 * time .Second )
232
+
233
+ start := time .Now ()
234
+ repo .Mirror (ctx1 )
235
+ // 5s timeout + 5s waitDelay + 2s buffer
236
+ if time .Since (start ) > (5 + 5 + 2 )* time .Second {
237
+ t .Errorf ("error: mirror function should have existed after ctx timeout but it took %s" , time .Since (start ))
238
+ }
239
+ cancel1 ()
240
+ }
241
+ })
242
+ }
243
+
111
244
func Test_mirror_detect_race_repo_pool (t * testing.T ) {
112
245
testTmpDir := mustTmpDir (t )
113
246
defer os .RemoveAll (testTmpDir )
@@ -146,6 +279,7 @@ func Test_mirror_detect_race_repo_pool(t *testing.T) {
146
279
t .Log ("adding remote1" , "count" , i )
147
280
readStopped := make (chan bool )
148
281
ctx , cancel := context .WithCancel (t .Context ())
282
+ defer cancel ()
149
283
150
284
newConfig := RepoPoolConfig {
151
285
Defaults : DefaultConfig {
@@ -215,6 +349,7 @@ func Test_mirror_detect_race_repo_pool(t *testing.T) {
215
349
t .Log ("adding remote2" , "count" , i )
216
350
readStopped := make (chan bool )
217
351
ctx , cancel := context .WithCancel (t .Context ())
352
+ defer cancel ()
218
353
219
354
newConfig := RepoPoolConfig {
220
355
Defaults : DefaultConfig {
0 commit comments