Skip to content

Commit c9268a7

Browse files
committed
test: fix mock server reporting ready before copas starts dispatching requests
race condition that only triggered in some setups (WSL for me)
1 parent 0c7152c commit c9268a7

4 files changed

Lines changed: 98 additions & 37 deletions

File tree

DependencyControl.json

Lines changed: 82 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
{
4141
"name": ".moon",
4242
"url": "@{fileBaseUrl}@{fileName}",
43-
"sha1": "42AFEF27FF1B53FD88A23E4E96085F342A8E4BA6"
43+
"sha1": "5F5CEE335196ACB7C7D2D7B3B4929B2A8B91E3B4"
4444
}
4545
],
4646
"requiredModules": [
@@ -93,7 +93,7 @@
9393
{
9494
"name": ".moon",
9595
"url": "@{fileBaseUrl}@{fileName}",
96-
"sha1": "9D86C61973B0F19383AEC85A13FCD7C00FBCAA75"
96+
"sha1": "347F082AA79C6DB9E58672C246F553CDCB668ACB"
9797
},
9898
{
9999
"name": "/Common.moon",
@@ -108,7 +108,7 @@
108108
{
109109
"name": "/ConfigHandler.moon",
110110
"url": "@{fileBaseUrl}@{fileName}",
111-
"sha1": "976A2F1B5EF87DBA0F98EC8544230EC55F3B9C3B"
111+
"sha1": "1B8EE7C531794148B63B09BDC1197EEA66D5E98B"
112112
},
113113
{
114114
"name": "/ConfigView.moon",
@@ -123,12 +123,7 @@
123123
{
124124
"name": "/Downloader.moon",
125125
"url": "@{fileBaseUrl}@{fileName}",
126-
"sha1": "A36FC8823AEC86E8B4CD138EA4F86DFBADCEF448"
127-
},
128-
{
129-
"name": "/DownloadManager.moon",
130-
"url": "@{fileBaseUrl}@{fileName}",
131-
"sha1": "989E147B32287EAC26456266402C6C69877EE121"
126+
"sha1": "0FC493932D84FDF629B18DE260565C5CFCDD8714"
132127
},
133128
{
134129
"name": "/Enum.moon",
@@ -140,6 +135,11 @@
140135
"url": "@{fileBaseUrl}@{fileName}",
141136
"sha1": "3699FF01202D89D227BBE214E37DA056A93DED20"
142137
},
138+
{
139+
"name": "/FileLock.moon",
140+
"url": "@{fileBaseUrl}@{fileName}",
141+
"sha1": "E2434F8C39E118364FC60F465BF07F9F79086CA7"
142+
},
143143
{
144144
"name": "/FileOps.moon",
145145
"url": "@{fileBaseUrl}@{fileName}",
@@ -158,7 +158,7 @@
158158
{
159159
"name": "/Lock.moon",
160160
"url": "@{fileBaseUrl}@{fileName}",
161-
"sha1": "68515CB1EA45191529EF4A75F0E88387A9085F15"
161+
"sha1": "982B95D6B0AFB567997B43D7741CB69B357B6977"
162162
},
163163
{
164164
"name": "/Logger.moon",
@@ -168,17 +168,22 @@
168168
{
169169
"name": "/ModuleLoader.moon",
170170
"url": "@{fileBaseUrl}@{fileName}",
171-
"sha1": "47BE77247A9E2732BE9D50F8251D16E92B4D5AB8"
171+
"sha1": "1A6E9FC0077B56EF9BB8FD47108852BA0864B14C"
172172
},
173173
{
174174
"name": "/ModuleProvider.moon",
175175
"url": "@{fileBaseUrl}@{fileName}",
176-
"sha1": "951409F023D8D7159D9AD4B218B4A93CEB9067AC"
176+
"sha1": "5F634C4B566E70D962C606D55D94A7AC4FE1C253"
177+
},
178+
{
179+
"name": "/NamedSemaphore.moon",
180+
"url": "@{fileBaseUrl}@{fileName}",
181+
"sha1": "5C40B2EDFFE229912E52B6B9722B71C9A4F3C67B"
177182
},
178183
{
179184
"name": "/Record.moon",
180185
"url": "@{fileBaseUrl}@{fileName}",
181-
"sha1": "671C3F05B0A533FBF08C68559DE84E2837790344"
186+
"sha1": "9671CF860C24069572ED72BEB086637544036407"
182187
},
183188
{
184189
"name": "/ScriptTargetFilter.moon",
@@ -201,14 +206,15 @@
201206
"sha1": "F48B4E3EBA9ADBB22745714060B454C22CE75AB9"
202207
},
203208
{
204-
"name": "/TerribleMutex.moon",
209+
"name": "/BadMutex.moon",
205210
"url": "@{fileBaseUrl}@{fileName}",
206-
"sha1": "6B1C4E43BB588DDD2DE0FF730F3F288C641C535E"
211+
"sha1": "6B1C4E43BB588DDD2DE0FF730F3F288C641C535E",
212+
"delete": true
207213
},
208214
{
209215
"name": "/Timer.moon",
210216
"url": "@{fileBaseUrl}@{fileName}",
211-
"sha1": "5E3C81C8D90BC8D04D2A9B42494506F66381142D"
217+
"sha1": "5CD3E71061C48F8209B4849398B333DBAEB03ADD"
212218
},
213219
{
214220
"name": "/UnitTestSuite.moon",
@@ -218,28 +224,65 @@
218224
{
219225
"name": "/UpdateFeed.moon",
220226
"url": "@{fileBaseUrl}@{fileName}",
221-
"sha1": "7588536CDE3DA5DE9AE6BD667A4D81271A35D69C"
227+
"sha1": "9C060E835FEEFF275B261E8638CF028D17CEE44B"
222228
},
223229
{
224230
"name": "/Updater.moon",
225231
"url": "@{fileBaseUrl}@{fileName}",
226-
"sha1": "2A76F7DA351389F03B219CDC16D54E797A424965"
232+
"sha1": "8DEF5E943716147B1879E387FA15EEE0E03DA49D"
227233
},
228234
{
229235
"name": "/ZipArchiver.moon",
230236
"url": "@{fileBaseUrl}@{fileName}",
231237
"sha1": "93A4D958835DECFE594F6D8CAEF050992523E4DB"
232238
},
239+
{
240+
"name": "/helpers/ffi-posix.moon",
241+
"url": "@{fileBaseUrl}@{fileName}",
242+
"sha1": "70CCC5FBFB48234DAD013854E8845541CC28A94F"
243+
},
244+
{
245+
"name": "/helpers/ffi-windows.moon",
246+
"url": "@{fileBaseUrl}@{fileName}",
247+
"sha1": "8A2ABE7CB6011F4F7D390C9FB9E396B337B3584C"
248+
},
249+
{
250+
"name": "/shims/BadMutex.moon",
251+
"url": "@{fileBaseUrl}@{fileName}",
252+
"sha1": "269B7FE920886A1A294A71305CFD4974F6EF3F48"
253+
},
254+
{
255+
"name": "/shims/DownloadManager.moon",
256+
"url": "@{fileBaseUrl}@{fileName}",
257+
"sha1": "38D6884F543E23512F7132CA4E3A5F627E3A1B7B"
258+
},
259+
{
260+
"name": "/shims/PreciseTimer.moon",
261+
"url": "@{fileBaseUrl}@{fileName}",
262+
"sha1": "D46B97F295F555FE74E184CC16424F5004F33687"
263+
},
233264
{
234265
"name": ".moon",
235266
"url": "@{fileBaseUrl}@{fileName}",
236-
"sha1": "3EB678551149E3E71EBCAA4504D19AE2F5DDB088",
267+
"sha1": "D57577BD7500F56A84F127B422FF2A724302BDED",
268+
"type": "test"
269+
},
270+
{
271+
"name": "/BadMutex.moon",
272+
"url": "@{fileBaseUrl}@{fileName}",
273+
"sha1": "BDEA61A6DD65512495FD919754E8E14D351A48EE",
237274
"type": "test"
238275
},
239276
{
240277
"name": "/Common.moon",
241278
"url": "@{fileBaseUrl}@{fileName}",
242-
"sha1": "890EE068F0FA76B126C2459F8A91850ED1582956",
279+
"sha1": "B732E2879AD3F80A941771FF3783BC3CE58E625E",
280+
"type": "test"
281+
},
282+
{
283+
"name": "/ffi-posix.moon",
284+
"url": "@{fileBaseUrl}@{fileName}",
285+
"sha1": "535A053FE09841BDB4C757A77B7FB3EA360EA745",
243286
"type": "test"
244287
},
245288
{
@@ -260,6 +303,12 @@
260303
"sha1": "7785C25F8060AD519EFA2BF9D9E41BF9D984A43A",
261304
"type": "test"
262305
},
306+
{
307+
"name": "/Lock.moon",
308+
"url": "@{fileBaseUrl}@{fileName}",
309+
"sha1": "7AE20FBFD526FE42965AADDD738A88BDD143E8F6",
310+
"type": "test"
311+
},
263312
{
264313
"name": "/ModuleProvider.moon",
265314
"url": "@{fileBaseUrl}@{fileName}",
@@ -278,6 +327,12 @@
278327
"sha1": "278632008FE11ADB967B4761A2BFD1AB344C12B8",
279328
"type": "test"
280329
},
330+
{
331+
"name": "/Timer.moon",
332+
"url": "@{fileBaseUrl}@{fileName}",
333+
"sha1": "9666CC4536FE09F6382EEDC5C2580280F7912111",
334+
"type": "test"
335+
},
281336
{
282337
"name": "/UpdateFeed.moon",
283338
"url": "@{fileBaseUrl}@{fileName}",
@@ -293,17 +348,9 @@
293348
{
294349
"name": "/helpers/MockHttpServerController.moon",
295350
"url": "@{fileBaseUrl}@{fileName}",
296-
"sha1": "CE361BB092ECBD1671B579CDF6A3FA181F4EC737",
351+
"sha1": "C699B32FF02A9600C0C42DE90402EAB99A8A474A",
297352
"type": "test"
298353
}
299-
],
300-
"requiredModules": [
301-
{
302-
"moduleName": "requireffi.requireffi",
303-
"version": "0.1.1",
304-
"optional": true,
305-
"feed": "@{feed:ffi-experiments}"
306-
}
307354
]
308355
}
309356
},
@@ -377,7 +424,12 @@
377424
"Updater: Fixed a potential issue where a multi-assignment statement could corrupt record fields after an unsuccessful update.",
378425
"Automatic update scheduling is now centralized in the DependencyControl Toolbox and runs in a single Aegisub environment at startup, covering all installed scripts including modules not loaded by any automation script. Previously, each automation script's environment scheduled redundant checks for every module it loaded.",
379426
"Record: Added `getAllRegisteredRecords()` to expose the full live record registry to tooling.",
380-
"Modules with a DependencyControl unit test suite now have their test menus registered automatically by the Toolbox. Automation scripts register their own test menus when they call `registerMacros` through DependencyControl."
427+
"Modules with a DependencyControl unit test suite now have their test menus registered automatically by the Toolbox. Automation scripts register their own test menus when they call `registerMacros` through DependencyControl.",
428+
"Lock: Locks are now per-resource — distinct namespace/resource pairs can be held at the same time instead of contending over a single global mutex — and accept an optional `Global` scope that enforces mutual exclusion across separate Aegisub instances (now used when reading and writing shared config files). A Global lock is backed by an OS advisory file lock that the system releases automatically if the holder crashes, so a crashed process can never leave a config file permanently locked.",
429+
"Lock: While a lock is held it records its holder (name, process id, and lease expiry) in a side file for troubleshooting, and logs a warning when it is waiting on a holder whose lease has lapsed (a likely crash or stall). The recorded lease is honored by waiters; an `overrideExpiry` option lets a waiter apply its own expiry instead.",
430+
"Lock: Added `renew(threshold)` to extend a held lock's lease during long operations (refreshing only when the remaining lease drops below the threshold, so it is cheap to call from a busy loop), and a `Lock.guard` helper that acquires a lock, runs a function, and always releases it (even if the function errors).",
431+
"Updater: The in-progress-update flag is no longer stored in the config file; concurrent updates are now coordinated by a dedicated cross-process lock that the system releases automatically if an updater crashes. The lease is renewed throughout long downloads, and a new `Updater.isRunning()` reports whether (and which script) an update is currently running.",
432+
"Timer: Exposed a shared monotonic `Timer.getTime()` clock, added stopwatch-style `start()`, `stop()`, and `reset()` methods, and PT.PreciseTimer is now provided through the same bundled-provider mechanism as BM.BadMutex and DM.DownloadManager (set DEPCTRL_FORCE_BUILTIN_TIMER=1 to force DepCtrl's implementation)."
381433
]
382434
}
383435
},

modules/l0/DependencyControl/test.moon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1807,7 +1807,7 @@ UnitTestSuite constants.DEPCTRL_NAMESPACE, (DepCtrl, ...) ->
18071807

18081808
JsonSchema: (controls\requireTest "JsonSchema") basePath
18091809

1810-
FfiPosix: (controls\requireTest "FfiPosix")!
1810+
FfiPosix: (controls\requireTest "ffi-posix")!
18111811

18121812
DownloaderIntegration: {
18131813
_description: "Real-HTTP Downloader tests against a local test server (runs when launchable)."
File renamed without changes.

modules/l0/DependencyControl/test/helpers/MockHttpServerController.moon

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,23 @@ class MockHttpServerController
7676
io.stderr\write "Starting mock HTTP server with command: #{startCommand}...\n"
7777
spawnDetached startCommand
7878

79-
-- ready once the port accepts a connection
80-
deadline = socket.gettime! + @timeout
81-
while socket.gettime! < deadline
79+
-- Ready only once the server actually answers HTTP. A bare TCP connect succeeds as
80+
-- soon as the kernel accepts into the listen backlog (which can happen before copas
81+
-- starts dispatching requests).
82+
isServing = ->
8283
conn = socket.tcp!
83-
conn\settimeout 0.2
84-
connected = conn\connect "127.0.0.1", port
84+
conn\settimeout 0.5
85+
unless conn\connect "127.0.0.1", port
86+
conn\close!
87+
return false
88+
conn\send "GET /status/200 HTTP/1.0\r\nHost: 127.0.0.1\r\n\r\n"
89+
statusLine = conn\receive "*l"
8590
conn\close!
86-
return @ if connected
91+
return statusLine != nil and statusLine\match("^HTTP/") != nil
92+
93+
deadline = socket.gettime! + @timeout
94+
while socket.gettime! < deadline
95+
return @ if isServing!
8796
socket.sleep 0.05
8897
error "mock HTTP server didn't start on port #{port} within #{@timeout}s"
8998

0 commit comments

Comments
 (0)