Nim/tests/async/tasyncclosestall.nim
Miran 8088633250
faster CIs (#13803)
* ttables: smaller table, 5x speedup

* thavlak: less iterations, less loops; 30% speedup

* tasyncclosestall: shorter timeout; 35% speedup

* gcleak4: less iterations, 2x speedup

* ttimes: remove deprecated stuff

* tdangerisrelease: remove cpp backend, 3x speedup

* tfrexp1: smaller range, 2x speedup

* trtree: fix warnings, less iterations, 6x speedup

* tasyncawait_cyclebreaker: smaller swarm size; 2x speedup

* trealloc: smaller number of iterations; 10x speedup

* towned_binary_tree: less iterations, 4x speedup

* tclosure: remove unused code, less iterations; 2x speedup

* twaitany: less durations; 1.4x speedup

* tasync_misc: less iterations, 2x speedup

* t8535: smaller sleep, 1.5x speedup

* tmanyjoin: smaller sleep, 2x speedup

* t12221: shorter sleeps, removed two slower tests; 1.6x speedup

* tfuturestream: smaller sleep; 1.5x speedup

* growobjcrash: less iterations; 2x speedup

* ttryrecv: smaller sleep; 1.5x speedup

* treusetvar: less threads; 2x speedup

* delete tthreadanalysis2, basically a duplicate of tthreadanalysis

* t7758: less iterations, 1.5x speedup

* tasyncawait: smaller swarm, less messages; 1.5x speedup

* tjsandnativeasync: smaller sleep, 1.5x speedup

* tpendingcheck: smaller sleep, 1.5x speedup

* remove rodfiles test category

* move tseq from its own category to 'collections' category

* remove unneeded tests and helpers from 'assert' category

* stdlib: merge tbitops2 into tbitops

* remove 'trepr2' from 'stdlib' cat

* merge 'tstreams' into one file

* remove 'tinefficient_const_table' from 'ccbugs' cat

* merge 'tcollections_to_string' into 'tcollections'

* tblocking_channel: smaller sleep, small speedup

* tconvexhull: less iterartions; 1.2x speedup

* merge 'tdeepcopy2' into 'tdeepcopy'

* merge 'tdisjoint_slice2' into 'tdisjoint_slice1'

* tmissing_deepcopy: smaller sequence

* tsendtwice: smaller arrays; 5x speedup

* remove 'tindexerrorformatbounds'

* disable multimethod tests

* remove 'gc:none' and 'refc' without 'd:useRealtimeGC' from gc tests

* koch.nim: bootstrap just with '-d:release', no need for 'csource'

* add github workflow for documentation

* testament: no need for 8 sub-second decimals
2020-03-30 13:18:12 +02:00

101 lines
3.4 KiB
Nim

discard """
disabled: "windows"
outputsub: "send has errored. As expected. All good!"
exitcode: 0
"""
import asyncdispatch, asyncnet
when defined(windows):
from winlean import ERROR_NETNAME_DELETED
else:
from posix import EBADF
# This reproduces a case where a socket remains stuck waiting for writes
# even when the socket is closed.
const
timeout = 8000
var port = Port(0)
var sent = 0
proc keepSendingTo(c: AsyncSocket) {.async.} =
while true:
# This write will eventually get stuck because the client is not reading
# its messages.
let sendFut = c.send("Foobar" & $sent & "\n", flags = {})
if not await withTimeout(sendFut, timeout):
# The write is stuck. Let's simulate a scenario where the socket
# does not respond to PING messages, and we close it. The above future
# should complete after the socket is closed, not continue stalling.
echo("Socket has stalled, closing it")
c.close()
let timeoutFut = withTimeout(sendFut, timeout)
yield timeoutFut
if timeoutFut.failed:
let errCode = ((ref OSError)(timeoutFut.error)).errorCode
# The behaviour differs across platforms. On Windows ERROR_NETNAME_DELETED
# is raised which we classif as a "diconnection error", hence we overwrite
# the flags above in the `send` call so that this error is raised.
#
# On Linux the EBADF error code is raised, this is because the socket
# is closed.
#
# This means that by default the behaviours will differ between Windows
# and Linux. I think this is fine though, it makes sense mainly because
# Windows doesn't use a IO readiness model. We can fix this later if
# necessary to reclassify ERROR_NETNAME_DELETED as not a "disconnection
# error" (TODO)
when defined(windows):
if errCode == ERROR_NETNAME_DELETED:
echo("send has errored. As expected. All good!")
quit(QuitSuccess)
else:
raise newException(ValueError, "Test failed. Send failed with code " & $errCode)
else:
if errCode == EBADF:
echo("send has errored. As expected. All good!")
quit(QuitSuccess)
else:
raise newException(ValueError, "Test failed. Send failed with code " & $errCode)
# The write shouldn't succeed and also shouldn't be stalled.
if timeoutFut.read():
raise newException(ValueError, "Test failed. Send was expected to fail.")
else:
raise newException(ValueError, "Test failed. Send future is still stalled.")
sent.inc(1)
proc startClient() {.async.} =
let client = newAsyncSocket()
await client.connect("localhost", port)
echo("Connected")
let firstLine = await client.recvLine()
echo("Received first line as a client: ", firstLine)
echo("Now not reading anymore")
while true: await sleepAsync(1000)
proc debug() {.async.} =
while true:
echo("Sent ", sent)
await sleepAsync(1000)
proc server() {.async.} =
var s = newAsyncSocket()
s.setSockOpt(OptReuseAddr, true)
s.bindAddr(port)
s.listen()
let (addr2, port2) = s.getLocalAddr
port = port2
# We're now ready to accept connections, so start the client
asyncCheck startClient()
asyncCheck debug()
while true:
let client = await accept(s)
asyncCheck keepSendingTo(client)
when isMainModule:
waitFor server()