Fix rarely appearing Windows bug with close(transport).
Add tests for it. Add fromProc for all Future[T] in transports. Add testall to improve tests speed. Bump version to 2.2.4.
This commit is contained in:
parent
4290e06e77
commit
80ee289847
|
@ -5,7 +5,6 @@
|
|||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
|
||||
import chronos/[asyncloop, asyncfutures2, asyncsync, handles, transport,
|
||||
timer]
|
||||
export asyncloop, asyncfutures2, asyncsync, handles, transport, timer
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
packageName = "chronos"
|
||||
version = "2.2.3"
|
||||
version = "2.2.4"
|
||||
author = "Status Research & Development GmbH"
|
||||
description = "Chronos"
|
||||
license = "Apache License 2.0 or MIT"
|
||||
|
@ -10,43 +10,14 @@ skipDirs = @["tests"]
|
|||
requires "nim > 0.18.0"
|
||||
|
||||
task test, "Run all tests":
|
||||
|
||||
var testFiles = @[
|
||||
"testsync",
|
||||
"testsoon",
|
||||
"testtime",
|
||||
"testfut",
|
||||
"testsignal",
|
||||
"testaddress",
|
||||
"testdatagram",
|
||||
"teststream",
|
||||
"testserver",
|
||||
"testbugs",
|
||||
var commands = [
|
||||
"nim c -r -d:useSysAssert -d:useGcAssert tests/testall",
|
||||
"nim c -r tests/testall",
|
||||
"nim c -r -d:release tests/testall"
|
||||
]
|
||||
|
||||
var testCommands = @[
|
||||
"nim c -r -d:useSysAssert -d:useGcAssert",
|
||||
"nim c -r",
|
||||
"nim c -r -d:release"
|
||||
]
|
||||
|
||||
var timerCommands = @[
|
||||
" -d:asyncTimer=system",
|
||||
" -d:asyncTimer=mono"
|
||||
]
|
||||
|
||||
for tfile in testFiles:
|
||||
if tfile == "testtime":
|
||||
for cmd in testCommands:
|
||||
for def in timerCommands:
|
||||
var commandLine = cmd & def & " tests/" & tfile
|
||||
echo "\n" & commandLine
|
||||
exec commandLine
|
||||
rmFile("tests/" & tfile.toExe())
|
||||
else:
|
||||
for cmd in testCommands:
|
||||
var commandLine = cmd & " tests/" & tfile
|
||||
echo "\n" & commandLine
|
||||
exec commandLine
|
||||
rmFile("tests/" & tfile.toExe())
|
||||
|
||||
echo "\n" & commands[0]
|
||||
exec commands[0]
|
||||
echo "\n" & commands[1]
|
||||
exec commands[1]
|
||||
echo "\n" & commands[2]
|
||||
exec commands[2]
|
||||
|
|
|
@ -40,6 +40,14 @@ type
|
|||
Future*[T] = ref object of FutureBase ## Typed future.
|
||||
value: T ## Stored value
|
||||
|
||||
FutureStr*[T] = ref object of Future[T]
|
||||
## Future to hold GC strings
|
||||
gcholder*: string
|
||||
|
||||
FutureSeq*[A, B] = ref object of Future[A]
|
||||
## Future to hold GC seqs
|
||||
gcholder*: seq[B]
|
||||
|
||||
FutureVar*[T] = distinct Future[T]
|
||||
|
||||
FutureError* = object of Exception
|
||||
|
@ -92,6 +100,22 @@ proc newFutureVar*[T](fromProc = "unspecified"): FutureVar[T] =
|
|||
## that this future belongs to, is a good habit as it helps with debugging.
|
||||
result = FutureVar[T](newFuture[T](fromProc))
|
||||
|
||||
proc newFutureSeq*[A, B](fromProc = "unspecified"): FutureSeq[A, B] =
|
||||
## Create a new future which can hold/preserve GC string until future will
|
||||
## not be completed.
|
||||
##
|
||||
## Specifying ``fromProc``, which is a string specifying the name of the proc
|
||||
## that this future belongs to, is a good habit as it helps with debugging.
|
||||
setupFutureBase(fromProc)
|
||||
|
||||
proc newFutureStr*[A](fromProc = "unspecified"): FutureStr[A] =
|
||||
## Create a new future which can hold/preserve GC seq[T] until future will
|
||||
## not be completed.
|
||||
##
|
||||
## Specifying ``fromProc``, which is a string specifying the name of the proc
|
||||
## that this future belongs to, is a good habit as it helps with debugging.
|
||||
setupFutureBase(fromProc)
|
||||
|
||||
proc clean*[T](future: FutureVar[T]) =
|
||||
## Resets the ``finished`` status of ``future``.
|
||||
Future[T](future).finished = false
|
||||
|
|
|
@ -24,7 +24,7 @@ type
|
|||
ServerFlags* = enum
|
||||
## Server's flags
|
||||
ReuseAddr, ReusePort, TcpNoDelay, NoAutoRead, GCUserData, FirstPipe,
|
||||
NoPipeFlash
|
||||
NoPipeFlash, Broadcast
|
||||
|
||||
AddressFamily* {.pure.} = enum
|
||||
None, IPv4, IPv6, Unix
|
||||
|
@ -55,14 +55,6 @@ type
|
|||
Running, # Server running
|
||||
Closed # Server closed
|
||||
|
||||
FutureGCString*[T] = ref object of Future[T]
|
||||
## Future to hold GC strings
|
||||
gcholder*: string
|
||||
|
||||
FutureGCSeq*[A, B] = ref object of Future[A]
|
||||
## Future to hold GC seqs
|
||||
gcholder*: seq[B]
|
||||
|
||||
when defined(windows):
|
||||
type
|
||||
SocketServer* = ref object of RootRef
|
||||
|
@ -510,6 +502,7 @@ when defined(windows):
|
|||
ERROR_BROKEN_PIPE* = 109
|
||||
ERROR_PIPE_NOT_CONNECTED* = 233
|
||||
ERROR_NO_DATA* = 232
|
||||
ERROR_CONNECTION_ABORTED* = 1236
|
||||
|
||||
proc cancelIo*(hFile: HANDLE): WINBOOL
|
||||
{.stdcall, dynlib: "kernel32", importc: "CancelIo".}
|
||||
|
|
|
@ -141,8 +141,12 @@ when defined(windows):
|
|||
transp.buflen = bytesCount
|
||||
asyncCheck transp.function(transp, raddr)
|
||||
elif int(err) == ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt
|
||||
# CancelIO() interrupt or closeSocket() call.
|
||||
transp.state.incl(ReadPaused)
|
||||
if ReadClosed in transp.state:
|
||||
# If `ReadClosed` present, then close(transport) was called.
|
||||
transp.future.complete()
|
||||
GC_unref(transp)
|
||||
break
|
||||
else:
|
||||
transp.setReadError(err)
|
||||
|
@ -179,6 +183,12 @@ when defined(windows):
|
|||
transp.setReadError(err)
|
||||
transp.buflen = 0
|
||||
asyncCheck transp.function(transp, raddr)
|
||||
else:
|
||||
# Transport closure happens in callback, and we not started new
|
||||
# WSARecvFrom session.
|
||||
if ReadClosed in transp.state:
|
||||
if not transp.future.finished:
|
||||
transp.future.complete()
|
||||
break
|
||||
|
||||
proc resumeRead(transp: DatagramTransport) {.inline.} =
|
||||
|
@ -450,11 +460,8 @@ proc close*(transp: DatagramTransport) =
|
|||
## Closes and frees resources of transport ``transp``.
|
||||
when defined(windows):
|
||||
if {ReadClosed, WriteClosed} * transp.state == {}:
|
||||
discard cancelIo(Handle(transp.fd))
|
||||
closeSocket(transp.fd)
|
||||
transp.state.incl({WriteClosed, ReadClosed})
|
||||
transp.future.complete()
|
||||
GC_unref(transp)
|
||||
closeSocket(transp.fd)
|
||||
else:
|
||||
proc continuation(udata: pointer) =
|
||||
transp.future.complete()
|
||||
|
@ -539,7 +546,7 @@ proc newDatagramTransport6*[T](cbproc: DatagramCallback,
|
|||
|
||||
proc join*(transp: DatagramTransport): Future[void] =
|
||||
## Wait until the transport ``transp`` will be closed.
|
||||
var retFuture = newFuture[void]("datagramtransport.join")
|
||||
var retFuture = newFuture[void]("datagram.transport.join")
|
||||
proc continuation(udata: pointer) = retFuture.complete()
|
||||
if not transp.future.finished:
|
||||
transp.future.addCallback(continuation)
|
||||
|
@ -556,7 +563,7 @@ proc send*(transp: DatagramTransport, pbytes: pointer,
|
|||
nbytes: int): Future[void] =
|
||||
## Send buffer with pointer ``pbytes`` and size ``nbytes`` using transport
|
||||
## ``transp`` to remote destination address which was bounded on transport.
|
||||
var retFuture = newFuture[void]()
|
||||
var retFuture = newFuture[void]("datagram.transport.send(pointer)")
|
||||
transp.checkClosed(retFuture)
|
||||
if transp.remote.port == Port(0):
|
||||
retFuture.fail(newException(TransportError, "Remote peer not set!"))
|
||||
|
@ -571,7 +578,7 @@ proc send*(transp: DatagramTransport, pbytes: pointer,
|
|||
proc send*(transp: DatagramTransport, msg: string, msglen = -1): Future[void] =
|
||||
## Send string ``msg`` using transport ``transp`` to remote destination
|
||||
## address which was bounded on transport.
|
||||
var retFuture = FutureGCString[void]()
|
||||
var retFuture = newFutureStr[void]("datagram.transport.send(string)")
|
||||
transp.checkClosed(retFuture)
|
||||
if not isLiteral(msg):
|
||||
shallowCopy(retFuture.gcholder, msg)
|
||||
|
@ -590,7 +597,7 @@ proc send*[T](transp: DatagramTransport, msg: seq[T],
|
|||
msglen = -1): Future[void] =
|
||||
## Send string ``msg`` using transport ``transp`` to remote destination
|
||||
## address which was bounded on transport.
|
||||
var retFuture = FutureGCSeq[void, T]()
|
||||
var retFuture = newFutureSeq[void, T]("datagram.transport.send(seq)")
|
||||
transp.checkClosed(retFuture)
|
||||
if not isLiteral(msg):
|
||||
shallowCopy(retFuture.gcholder, msg)
|
||||
|
@ -609,7 +616,7 @@ proc sendTo*(transp: DatagramTransport, remote: TransportAddress,
|
|||
pbytes: pointer, nbytes: int): Future[void] =
|
||||
## Send buffer with pointer ``pbytes`` and size ``nbytes`` using transport
|
||||
## ``transp`` to remote destination address ``remote``.
|
||||
var retFuture = newFuture[void]()
|
||||
var retFuture = newFuture[void]("datagram.transport.sendTo(pointer)")
|
||||
transp.checkClosed(retFuture)
|
||||
let vector = GramVector(kind: WithAddress, buf: pbytes, buflen: nbytes,
|
||||
writer: retFuture, address: remote)
|
||||
|
@ -622,7 +629,7 @@ proc sendTo*(transp: DatagramTransport, remote: TransportAddress,
|
|||
msg: string, msglen = -1): Future[void] =
|
||||
## Send string ``msg`` using transport ``transp`` to remote destination
|
||||
## address ``remote``.
|
||||
var retFuture = FutureGCString[void]()
|
||||
var retFuture = newFutureStr[void]("datagram.transport.sendTo(string)")
|
||||
transp.checkClosed(retFuture)
|
||||
if not isLiteral(msg):
|
||||
shallowCopy(retFuture.gcholder, msg)
|
||||
|
@ -642,7 +649,7 @@ proc sendTo*[T](transp: DatagramTransport, remote: TransportAddress,
|
|||
msg: seq[T], msglen = -1): Future[void] =
|
||||
## Send sequence ``msg`` using transport ``transp`` to remote destination
|
||||
## address ``remote``.
|
||||
var retFuture = FutureGCSeq[void, T]()
|
||||
var retFuture = newFutureSeq[void, T]("datagram.transport.sendTo(seq)")
|
||||
transp.checkClosed(retFuture)
|
||||
if not isLiteral(msg):
|
||||
shallowCopy(retFuture.gcholder, msg)
|
||||
|
|
|
@ -343,13 +343,6 @@ when defined(windows):
|
|||
if ReadPending in transp.state:
|
||||
## Continuation
|
||||
transp.state.excl(ReadPending)
|
||||
if ReadClosed in transp.state:
|
||||
transp.state.incl({ReadPaused})
|
||||
if not isNil(transp.reader):
|
||||
if not transp.reader.finished:
|
||||
transp.reader.complete()
|
||||
transp.reader = nil
|
||||
break
|
||||
let err = transp.rovl.data.errCode
|
||||
if err == OSErrorCode(-1):
|
||||
let bytesCount = transp.rovl.data.bytesCount
|
||||
|
@ -364,14 +357,23 @@ when defined(windows):
|
|||
transp.roffset = transp.offset
|
||||
if transp.offset == len(transp.buffer):
|
||||
transp.state.incl(ReadPaused)
|
||||
elif int(err) == ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt
|
||||
elif int(err) in {ERROR_OPERATION_ABORTED, ERROR_CONNECTION_ABORTED,
|
||||
ERROR_BROKEN_PIPE, ERROR_NETNAME_DELETED}:
|
||||
# CancelIO() interrupt or closeSocket() call.
|
||||
transp.state.incl(ReadPaused)
|
||||
if ReadClosed in transp.state:
|
||||
if not isNil(transp.reader):
|
||||
if not transp.reader.finished:
|
||||
transp.reader.complete()
|
||||
transp.reader = nil
|
||||
# If `ReadClosed` present, then close(transport) was called.
|
||||
transp.future.complete()
|
||||
GC_unref(transp)
|
||||
elif transp.kind == TransportKind.Socket and
|
||||
(int(err) in {ERROR_NETNAME_DELETED, WSAECONNABORTED}):
|
||||
transp.state.incl({ReadEof, ReadPaused})
|
||||
elif transp.kind == TransportKind.Pipe and
|
||||
(int(err) in {ERROR_BROKEN_PIPE, ERROR_PIPE_NOT_CONNECTED}):
|
||||
(int(err) in {ERROR_PIPE_NOT_CONNECTED}):
|
||||
transp.state.incl({ReadEof, ReadPaused})
|
||||
else:
|
||||
transp.setReadError(err)
|
||||
|
@ -446,6 +448,11 @@ when defined(windows):
|
|||
if not isNil(transp.reader):
|
||||
transp.reader.complete()
|
||||
transp.reader = nil
|
||||
# Transport close happens in callback, and we not started new
|
||||
# WSARecvFrom session.
|
||||
if ReadClosed in transp.state:
|
||||
if not transp.future.finished:
|
||||
transp.future.complete()
|
||||
## Finish Loop
|
||||
break
|
||||
|
||||
|
@ -602,9 +609,6 @@ when defined(windows):
|
|||
if server.apending:
|
||||
## Continuation
|
||||
server.apending = false
|
||||
if server.status in {ServerStatus.Stopped, ServerStatus.Closed}:
|
||||
break
|
||||
else:
|
||||
if ovl.data.errCode == OSErrorCode(-1):
|
||||
var ntransp: StreamTransport
|
||||
var flags = {WinServerPipe}
|
||||
|
@ -619,7 +623,12 @@ when defined(windows):
|
|||
nil, flags)
|
||||
asyncCheck server.function(server, ntransp)
|
||||
elif int32(ovl.data.errCode) == ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt
|
||||
# CancelIO() interrupt or close call.
|
||||
if server.status == ServerStatus.Closed:
|
||||
server.loopFuture.complete()
|
||||
if not isNil(server.udata) and GCUserData in server.flags:
|
||||
GC_unref(cast[ref int](server.udata))
|
||||
GC_unref(server)
|
||||
break
|
||||
else:
|
||||
doAssert disconnectNamedPipe(Handle(server.sock)) == 1
|
||||
|
@ -627,11 +636,8 @@ when defined(windows):
|
|||
raiseTransportOsError(osLastError())
|
||||
else:
|
||||
## Initiation
|
||||
if server.status notin {ServerStatus.Stopped, ServerStatus.Closed}:
|
||||
server.apending = true
|
||||
if server.status in {ServerStatus.Stopped, ServerStatus.Closed}:
|
||||
## Server was already stopped/closed exiting
|
||||
break
|
||||
|
||||
var pipeSuffix = $cast[cstring](addr server.local.address_un)
|
||||
var pipeName = newWideCString(r"\\.\pipe\" & pipeSuffix[1 .. ^1])
|
||||
var openMode = PIPE_ACCESS_DUPLEX or FILE_FLAG_OVERLAPPED
|
||||
|
@ -653,13 +659,25 @@ when defined(windows):
|
|||
cast[POVERLAPPED](addr server.aovl))
|
||||
if res == 0:
|
||||
let err = osLastError()
|
||||
if int32(err) == ERROR_IO_PENDING:
|
||||
if int32(err) == ERROR_OPERATION_ABORTED:
|
||||
server.apending = false
|
||||
break
|
||||
elif int32(err) == ERROR_IO_PENDING:
|
||||
discard
|
||||
elif int32(err) == ERROR_PIPE_CONNECTED:
|
||||
discard
|
||||
else:
|
||||
raiseTransportOsError(err)
|
||||
break
|
||||
else:
|
||||
# Server close happens in callback, and we are not started new
|
||||
# connectNamedPipe session.
|
||||
if server.status == ServerStatus.Closed:
|
||||
if not server.loopFuture.finished:
|
||||
server.loopFuture.complete()
|
||||
if not isNil(server.udata) and GCUserData in server.flags:
|
||||
GC_unref(cast[ref int](server.udata))
|
||||
GC_unref(server)
|
||||
|
||||
proc acceptLoop(udata: pointer) {.gcsafe, nimcall.} =
|
||||
var ovl = cast[PtrCustomOverlapped](udata)
|
||||
|
@ -670,11 +688,6 @@ when defined(windows):
|
|||
if server.apending:
|
||||
## Continuation
|
||||
server.apending = false
|
||||
if server.status in {ServerStatus.Stopped, ServerStatus.Closed}:
|
||||
## Server was already stopped/closed exiting
|
||||
server.asock.closeSocket()
|
||||
break
|
||||
else:
|
||||
if ovl.data.errCode == OSErrorCode(-1):
|
||||
if setsockopt(SocketHandle(server.asock), cint(SOL_SOCKET),
|
||||
cint(SO_UPDATE_ACCEPT_CONTEXT), addr server.sock,
|
||||
|
@ -695,18 +708,19 @@ when defined(windows):
|
|||
asyncCheck server.function(server, ntransp)
|
||||
|
||||
elif int32(ovl.data.errCode) == ERROR_OPERATION_ABORTED:
|
||||
# CancelIO() interrupt
|
||||
server.asock.closeSocket()
|
||||
# CancelIO() interrupt or close.
|
||||
if server.status == ServerStatus.Closed:
|
||||
server.loopFuture.complete()
|
||||
if not isNil(server.udata) and GCUserData in server.flags:
|
||||
GC_unref(cast[ref int](server.udata))
|
||||
GC_unref(server)
|
||||
break
|
||||
else:
|
||||
server.asock.closeSocket()
|
||||
raiseTransportOsError(ovl.data.errCode)
|
||||
else:
|
||||
## Initiation
|
||||
if server.status in {ServerStatus.Stopped, ServerStatus.Closed}:
|
||||
## Server was already stopped/closed exiting
|
||||
break
|
||||
|
||||
if server.status notin {ServerStatus.Stopped, ServerStatus.Closed}:
|
||||
server.apending = true
|
||||
server.asock = createAsyncSocket(server.domain, SockType.SOCK_STREAM,
|
||||
Protocol.IPPROTO_TCP)
|
||||
|
@ -734,6 +748,15 @@ when defined(windows):
|
|||
else:
|
||||
raiseTransportOsError(err)
|
||||
break
|
||||
else:
|
||||
# Server close happens in callback, and we are not started new
|
||||
# AcceptEx session.
|
||||
if server.status == ServerStatus.Closed:
|
||||
if not server.loopFuture.finished:
|
||||
server.loopFuture.complete()
|
||||
if not isNil(server.udata) and GCUserData in server.flags:
|
||||
GC_unref(cast[ref int](server.udata))
|
||||
GC_unref(server)
|
||||
|
||||
proc resumeRead(transp: StreamTransport) {.inline.} =
|
||||
transp.state.excl(ReadPaused)
|
||||
|
@ -881,7 +904,7 @@ else:
|
|||
slen: SockLen
|
||||
sock: AsyncFD
|
||||
proto: Protocol
|
||||
var retFuture = newFuture[StreamTransport]("transport.connect")
|
||||
var retFuture = newFuture[StreamTransport]("stream.transport.connect")
|
||||
address.toSAddr(saddr, slen)
|
||||
proto = Protocol.IPPROTO_TCP
|
||||
if address.family == AddressFamily.Unix:
|
||||
|
@ -985,7 +1008,7 @@ proc stop*(server: StreamServer) =
|
|||
|
||||
proc join*(server: StreamServer): Future[void] =
|
||||
## Waits until ``server`` is not closed.
|
||||
var retFuture = newFuture[void]("stream.server.join")
|
||||
var retFuture = newFuture[void]("stream.transport.server.join")
|
||||
proc continuation(udata: pointer) = retFuture.complete()
|
||||
if not server.loopFuture.finished:
|
||||
server.loopFuture.addCallback(continuation)
|
||||
|
@ -998,6 +1021,7 @@ proc close*(server: StreamServer) =
|
|||
##
|
||||
## Please note that release of resources is not completed immediately, to be
|
||||
## sure all resources got released please use ``await server.join()``.
|
||||
when not defined(windows):
|
||||
proc continuation(udata: pointer) =
|
||||
server.loopFuture.complete()
|
||||
if not isNil(server.udata) and GCUserData in server.flags:
|
||||
|
@ -1007,12 +1031,12 @@ proc close*(server: StreamServer) =
|
|||
server.status = ServerStatus.Closed
|
||||
when defined(windows):
|
||||
if server.local.family in {AddressFamily.IPv4, AddressFamily.IPv6}:
|
||||
server.sock.closeSocket(continuation)
|
||||
server.sock.closeSocket()
|
||||
elif server.local.family in {AddressFamily.Unix}:
|
||||
if NoPipeFlash notin server.flags:
|
||||
discard flushFileBuffers(Handle(server.sock))
|
||||
doAssert disconnectNamedPipe(Handle(server.sock)) == 1
|
||||
closeHandle(server.sock, continuation)
|
||||
closeHandle(server.sock)
|
||||
else:
|
||||
server.sock.closeSocket(continuation)
|
||||
|
||||
|
@ -1157,7 +1181,7 @@ proc createStreamServer*(host: TransportAddress,
|
|||
result.init = init
|
||||
result.bufferSize = bufferSize
|
||||
result.status = Starting
|
||||
result.loopFuture = newFuture[void]("stream.server")
|
||||
result.loopFuture = newFuture[void]("stream.transport.server")
|
||||
result.udata = udata
|
||||
result.local = host
|
||||
|
||||
|
@ -1197,7 +1221,7 @@ proc write*(transp: StreamTransport, pbytes: pointer,
|
|||
nbytes: int): Future[int] =
|
||||
## Write data from buffer ``pbytes`` with size ``nbytes`` using transport
|
||||
## ``transp``.
|
||||
var retFuture = newFuture[int]()
|
||||
var retFuture = newFuture[int]("stream.transport.write(pointer)")
|
||||
transp.checkClosed(retFuture)
|
||||
var vector = StreamVector(kind: DataBuffer, writer: retFuture,
|
||||
buf: pbytes, buflen: nbytes)
|
||||
|
@ -1208,7 +1232,7 @@ proc write*(transp: StreamTransport, pbytes: pointer,
|
|||
|
||||
proc write*(transp: StreamTransport, msg: string, msglen = -1): Future[int] =
|
||||
## Write data from string ``msg`` using transport ``transp``.
|
||||
var retFuture = FutureGCString[int]()
|
||||
var retFuture = newFutureStr[int]("stream.transport.write(string)")
|
||||
transp.checkClosed(retFuture)
|
||||
if not isLiteral(msg):
|
||||
shallowCopy(retFuture.gcholder, msg)
|
||||
|
@ -1225,7 +1249,7 @@ proc write*(transp: StreamTransport, msg: string, msglen = -1): Future[int] =
|
|||
|
||||
proc write*[T](transp: StreamTransport, msg: seq[T], msglen = -1): Future[int] =
|
||||
## Write sequence ``msg`` using transport ``transp``.
|
||||
var retFuture = FutureGCSeq[int, T]()
|
||||
var retFuture = newFutureSeq[int, T]("stream.transport.write(seq)")
|
||||
transp.checkClosed(retFuture)
|
||||
if not isLiteral(msg):
|
||||
shallowCopy(retFuture.gcholder, msg)
|
||||
|
@ -1250,7 +1274,7 @@ proc writeFile*(transp: StreamTransport, handle: int,
|
|||
when defined(windows):
|
||||
if transp.kind != TransportKind.Socket:
|
||||
raise newException(TransportNoSupport, "writeFile() is not supported!")
|
||||
var retFuture = newFuture[int]("transport.writeFile")
|
||||
var retFuture = newFuture[int]("stream.transport.writeFile")
|
||||
transp.checkClosed(retFuture)
|
||||
var vector = StreamVector(kind: DataFile, writer: retFuture,
|
||||
buf: cast[pointer](size), offset: offset,
|
||||
|
@ -1309,6 +1333,7 @@ proc readOnce*(transp: StreamTransport, pbytes: pointer,
|
|||
## internal buffer, otherwise it will wait until some bytes will be received.
|
||||
checkClosed(transp)
|
||||
checkPending(transp)
|
||||
|
||||
while true:
|
||||
if transp.offset == 0:
|
||||
if (ReadError in transp.state):
|
||||
|
@ -1490,6 +1515,7 @@ proc consume*(transp: StreamTransport, n = -1): Future[int] {.async.} =
|
|||
## Return number of bytes actually consumed
|
||||
checkClosed(transp)
|
||||
checkPending(transp)
|
||||
|
||||
result = 0
|
||||
while true:
|
||||
if (ReadError in transp.state):
|
||||
|
@ -1522,7 +1548,7 @@ proc consume*(transp: StreamTransport, n = -1): Future[int] {.async.} =
|
|||
|
||||
proc join*(transp: StreamTransport): Future[void] =
|
||||
## Wait until ``transp`` will not be closed.
|
||||
var retFuture = newFuture[void]("streamtransport.join")
|
||||
var retFuture = newFuture[void]("stream.transport.join")
|
||||
proc continuation(udata: pointer) = retFuture.complete()
|
||||
if not transp.future.finished:
|
||||
transp.future.addCallback(continuation)
|
||||
|
@ -1542,7 +1568,6 @@ proc close*(transp: StreamTransport) =
|
|||
if {ReadClosed, WriteClosed} * transp.state == {}:
|
||||
transp.state.incl({WriteClosed, ReadClosed})
|
||||
when defined(windows):
|
||||
discard cancelIo(Handle(transp.fd))
|
||||
if transp.kind == TransportKind.Pipe:
|
||||
if WinServerPipe in transp.flags:
|
||||
if WinNoPipeFlash notin transp.flags:
|
||||
|
@ -1551,9 +1576,23 @@ proc close*(transp: StreamTransport) =
|
|||
else:
|
||||
if WinNoPipeFlash notin transp.flags:
|
||||
discard flushFileBuffers(Handle(transp.fd))
|
||||
if ReadPaused in transp.state:
|
||||
# If readStreamLoop() is not running we need to finish in
|
||||
# continuation step.
|
||||
closeHandle(transp.fd, continuation)
|
||||
else:
|
||||
# If readStreamLoop() is running, it will be properly finished inside
|
||||
# of readStreamLoop().
|
||||
closeHandle(transp.fd)
|
||||
elif transp.kind == TransportKind.Socket:
|
||||
if ReadPaused in transp.state:
|
||||
# If readStreamLoop() is not running we need to finish in
|
||||
# continuation step.
|
||||
closeSocket(transp.fd, continuation)
|
||||
else:
|
||||
# If readStreamLoop() is running, it will be properly finished inside
|
||||
# of readStreamLoop().
|
||||
closeSocket(transp.fd)
|
||||
else:
|
||||
closeSocket(transp.fd, continuation)
|
||||
|
||||
|
|
|
@ -5,11 +5,9 @@
|
|||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
|
||||
import strutils, unittest
|
||||
import ../chronos
|
||||
|
||||
when isMainModule:
|
||||
suite "TransportAddress test suite":
|
||||
test "initTAddress(string)":
|
||||
check $initTAddress("0.0.0.0:1") == "0.0.0.0:1"
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# Chronos Test Suite
|
||||
# (c) Copyright 2018-Present
|
||||
# Status Research & Development GmbH
|
||||
#
|
||||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
import testsync, testsoon, testtime, testfut, testsignal, testaddress,
|
||||
testdatagram, teststream, testserver, testbugs
|
|
@ -5,10 +5,10 @@
|
|||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
|
||||
import unittest
|
||||
import ../chronos
|
||||
|
||||
suite "Asynchronous issues test suite":
|
||||
const HELLO_PORT = 45679
|
||||
const TEST_MSG = "testmsg"
|
||||
const MSG_LEN = TEST_MSG.len()
|
||||
|
@ -40,8 +40,6 @@ proc issue6(): Future[bool] {.async.} =
|
|||
if data.test == "OK":
|
||||
result = true
|
||||
|
||||
when isMainModule:
|
||||
suite "Asynchronous issues test suite":
|
||||
test "Issue #6":
|
||||
var res = waitFor(issue6())
|
||||
check res == true
|
||||
|
|
|
@ -5,20 +5,30 @@
|
|||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
|
||||
import strutils, net, unittest
|
||||
import ../chronos
|
||||
|
||||
suite "Datagram Transport test suite":
|
||||
const
|
||||
TestsCount = 2000
|
||||
ClientsCount = 20
|
||||
MessagesCount = 20
|
||||
|
||||
m1 = "sendTo(pointer) test (" & $TestsCount & " messages)"
|
||||
m2 = "send(pointer) test (" & $TestsCount & " messages)"
|
||||
m3 = "sendTo(string) test (" & $TestsCount & " messages)"
|
||||
m4 = "send(string) test (" & $TestsCount & " messages)"
|
||||
m5 = "sendTo(seq[byte]) test (" & $TestsCount & " messages)"
|
||||
m6 = "send(seq[byte]) test (" & $TestsCount & " messages)"
|
||||
m7 = "Unbounded multiple clients with messages (" & $ClientsCount &
|
||||
" clients x " & $MessagesCount & " messages)"
|
||||
m8 = "Bounded multiple clients with messages (" & $ClientsCount &
|
||||
" clients x " & $MessagesCount & " messages)"
|
||||
|
||||
proc client1(transp: DatagramTransport,
|
||||
raddr: TransportAddress): Future[void] {.async.} =
|
||||
var pbytes: seq[byte]
|
||||
var nbytes: int
|
||||
transp.peekMessage(pbytes, nbytes)
|
||||
var pbytes = transp.getMessage()
|
||||
var nbytes = len(pbytes)
|
||||
if nbytes > 0:
|
||||
var data = newString(nbytes + 1)
|
||||
copyMem(addr data[0], addr pbytes[0], nbytes)
|
||||
|
@ -38,9 +48,8 @@ proc client1(transp: DatagramTransport,
|
|||
|
||||
proc client2(transp: DatagramTransport,
|
||||
raddr: TransportAddress): Future[void] {.async.} =
|
||||
var pbytes: seq[byte]
|
||||
var nbytes: int
|
||||
transp.peekMessage(pbytes, nbytes)
|
||||
var pbytes = transp.getMessage()
|
||||
var nbytes = len(pbytes)
|
||||
if nbytes > 0:
|
||||
var data = newString(nbytes + 1)
|
||||
copyMem(addr data[0], addr pbytes[0], nbytes)
|
||||
|
@ -66,9 +75,8 @@ proc client2(transp: DatagramTransport,
|
|||
|
||||
proc client3(transp: DatagramTransport,
|
||||
raddr: TransportAddress): Future[void] {.async.} =
|
||||
var pbytes: seq[byte]
|
||||
var nbytes: int
|
||||
transp.peekMessage(pbytes, nbytes)
|
||||
var pbytes = transp.getMessage()
|
||||
var nbytes = len(pbytes)
|
||||
if nbytes > 0:
|
||||
var data = newString(nbytes + 1)
|
||||
copyMem(addr data[0], addr pbytes[0], nbytes)
|
||||
|
@ -93,9 +101,8 @@ proc client3(transp: DatagramTransport,
|
|||
|
||||
proc client4(transp: DatagramTransport,
|
||||
raddr: TransportAddress): Future[void] {.async.} =
|
||||
var pbytes: seq[byte]
|
||||
var nbytes: int
|
||||
transp.peekMessage(pbytes, nbytes)
|
||||
var pbytes = transp.getMessage()
|
||||
var nbytes = len(pbytes)
|
||||
if nbytes > 0:
|
||||
var data = newString(nbytes + 1)
|
||||
copyMem(addr data[0], addr pbytes[0], nbytes)
|
||||
|
@ -120,9 +127,8 @@ proc client4(transp: DatagramTransport,
|
|||
|
||||
proc client5(transp: DatagramTransport,
|
||||
raddr: TransportAddress): Future[void] {.async.} =
|
||||
var pbytes: seq[byte]
|
||||
var nbytes: int
|
||||
transp.peekMessage(pbytes, nbytes)
|
||||
var pbytes = transp.getMessage()
|
||||
var nbytes = len(pbytes)
|
||||
if nbytes > 0:
|
||||
var data = newString(nbytes + 1)
|
||||
copyMem(addr data[0], addr pbytes[0], nbytes)
|
||||
|
@ -147,9 +153,8 @@ proc client5(transp: DatagramTransport,
|
|||
|
||||
proc client6(transp: DatagramTransport,
|
||||
raddr: TransportAddress): Future[void] {.async.} =
|
||||
var pbytes: seq[byte]
|
||||
var nbytes: int
|
||||
transp.peekMessage(pbytes, nbytes)
|
||||
var pbytes = transp.getMessage()
|
||||
var nbytes = len(pbytes)
|
||||
if nbytes > 0:
|
||||
var data = newString(nbytes + 1)
|
||||
copyMem(addr data[0], addr pbytes[0], nbytes)
|
||||
|
@ -170,9 +175,8 @@ proc client6(transp: DatagramTransport,
|
|||
|
||||
proc client7(transp: DatagramTransport,
|
||||
raddr: TransportAddress): Future[void] {.async.} =
|
||||
var pbytes: seq[byte]
|
||||
var nbytes: int
|
||||
transp.peekMessage(pbytes, nbytes)
|
||||
var pbytes = transp.getMessage()
|
||||
var nbytes = len(pbytes)
|
||||
if nbytes > 0:
|
||||
var data = newString(nbytes + 1)
|
||||
copyMem(addr data[0], addr pbytes[0], nbytes)
|
||||
|
@ -197,9 +201,8 @@ proc client7(transp: DatagramTransport,
|
|||
|
||||
proc client8(transp: DatagramTransport,
|
||||
raddr: TransportAddress): Future[void] {.async.} =
|
||||
var pbytes: seq[byte]
|
||||
var nbytes: int
|
||||
transp.peekMessage(pbytes, nbytes)
|
||||
var pbytes = transp.getMessage()
|
||||
var nbytes = len(pbytes)
|
||||
if nbytes > 0:
|
||||
var data = newString(nbytes + 1)
|
||||
copyMem(addr data[0], addr pbytes[0], nbytes)
|
||||
|
@ -224,9 +227,8 @@ proc client8(transp: DatagramTransport,
|
|||
|
||||
proc client9(transp: DatagramTransport,
|
||||
raddr: TransportAddress): Future[void] {.async.} =
|
||||
var pbytes: seq[byte]
|
||||
var nbytes: int
|
||||
transp.peekMessage(pbytes, nbytes)
|
||||
var pbytes = transp.getMessage()
|
||||
var nbytes = len(pbytes)
|
||||
if nbytes > 0:
|
||||
var data = newString(nbytes + 1)
|
||||
copyMem(addr data[0], addr pbytes[0], nbytes)
|
||||
|
@ -251,9 +253,8 @@ proc client9(transp: DatagramTransport,
|
|||
|
||||
proc client10(transp: DatagramTransport,
|
||||
raddr: TransportAddress): Future[void] {.async.} =
|
||||
var pbytes: seq[byte]
|
||||
var nbytes: int
|
||||
transp.peekMessage(pbytes, nbytes)
|
||||
var pbytes = transp.getMessage()
|
||||
var nbytes = len(pbytes)
|
||||
if nbytes > 0:
|
||||
var data = newString(nbytes + 1)
|
||||
copyMem(addr data[0], addr pbytes[0], nbytes)
|
||||
|
@ -280,9 +281,8 @@ proc client10(transp: DatagramTransport,
|
|||
|
||||
proc client11(transp: DatagramTransport,
|
||||
raddr: TransportAddress): Future[void] {.async.} =
|
||||
var pbytes: seq[byte]
|
||||
var nbytes: int
|
||||
transp.peekMessage(pbytes, nbytes)
|
||||
var pbytes = transp.getMessage()
|
||||
var nbytes = len(pbytes)
|
||||
if nbytes > 0:
|
||||
var data = newString(nbytes + 1)
|
||||
copyMem(addr data[0], addr pbytes[0], nbytes)
|
||||
|
@ -375,7 +375,7 @@ proc testSeqSendTo(): Future[int] {.async.} =
|
|||
result = counter
|
||||
|
||||
proc testSeqSend(): Future[int] {.async.} =
|
||||
## send(string) test
|
||||
## send(seq) test
|
||||
var ta = initTAddress("127.0.0.1:33341")
|
||||
var counter = 0
|
||||
var dgram1 = newDatagramTransport(client9, udata = addr counter, local = ta)
|
||||
|
@ -449,19 +449,22 @@ proc testConnReset(): Future[bool] {.async.} =
|
|||
dgram2.close()
|
||||
await dgram2.join()
|
||||
|
||||
when isMainModule:
|
||||
const
|
||||
m1 = "sendTo(pointer) test (" & $TestsCount & " messages)"
|
||||
m2 = "send(pointer) test (" & $TestsCount & " messages)"
|
||||
m3 = "sendTo(string) test (" & $TestsCount & " messages)"
|
||||
m4 = "send(string) test (" & $TestsCount & " messages)"
|
||||
m5 = "sendTo(seq[byte]) test (" & $TestsCount & " messages)"
|
||||
m6 = "send(seq[byte]) test (" & $TestsCount & " messages)"
|
||||
m7 = "Unbounded multiple clients with messages (" & $ClientsCount &
|
||||
" clients x " & $MessagesCount & " messages)"
|
||||
m8 = "Bounded multiple clients with messages (" & $ClientsCount &
|
||||
" clients x " & $MessagesCount & " messages)"
|
||||
suite "Datagram Transport test suite":
|
||||
proc testTransportClose(): Future[bool] {.async.} =
|
||||
var ta = initTAddress("127.0.0.1:45000")
|
||||
var counter = 0
|
||||
proc clientMark(transp: DatagramTransport,
|
||||
raddr: TransportAddress): Future[void] {.async.} =
|
||||
discard
|
||||
var dgram = newDatagramTransport(clientMark, local = ta)
|
||||
dgram.close()
|
||||
try:
|
||||
await wait(dgram.join(), 1.seconds)
|
||||
result = true
|
||||
except:
|
||||
discard
|
||||
|
||||
test "close(transport) test":
|
||||
check waitFor(testTransportClose()) == true
|
||||
test m1:
|
||||
check waitFor(testPointerSendTo()) == TestsCount
|
||||
test m2:
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
|
||||
import unittest
|
||||
import ../chronos
|
||||
|
||||
suite "Future[T] behavior test suite":
|
||||
proc testFuture1(): Future[int] {.async.} =
|
||||
await sleepAsync(1.milliseconds)
|
||||
await sleepAsync(0.milliseconds)
|
||||
|
||||
proc testFuture2(): Future[int] {.async.} =
|
||||
return 1
|
||||
|
@ -537,8 +537,6 @@ proc testAllZero(): bool =
|
|||
var fut = all(tseq)
|
||||
result = fut.finished
|
||||
|
||||
when isMainModule:
|
||||
suite "Future[T] behavior test suite":
|
||||
test "Async undefined behavior (#7758) test":
|
||||
check test1() == true
|
||||
test "Immediately completed asynchronous procedure test":
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
|
||||
import strutils, unittest
|
||||
import ../chronos
|
||||
|
||||
suite "Server's test suite":
|
||||
type
|
||||
CustomServer = ref object of StreamServer
|
||||
test1: string
|
||||
|
@ -112,8 +112,7 @@ proc test4(): bool =
|
|||
udata = co)
|
||||
result = waitFor client2(server, ta)
|
||||
|
||||
when isMainModule:
|
||||
suite "Server's test suite":
|
||||
|
||||
test "Stream Server start/stop test":
|
||||
check test1() == true
|
||||
test "Stream Server inherited object test":
|
||||
|
|
|
@ -5,13 +5,14 @@
|
|||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
|
||||
import unittest, strutils
|
||||
import ../chronos
|
||||
|
||||
when not defined(windows):
|
||||
import posix
|
||||
|
||||
suite "Signal handling test suite":
|
||||
when not defined(windows):
|
||||
var signalCounter = 0
|
||||
|
||||
proc signalProc(udata: pointer) =
|
||||
|
@ -28,15 +29,12 @@ when not defined(windows):
|
|||
discard posix.kill(posix.getpid(), cint(signal))
|
||||
waitFor(fut)
|
||||
signalCounter == value
|
||||
|
||||
else:
|
||||
const
|
||||
SIGINT = 0
|
||||
SIGTERM = 0
|
||||
proc test(signal, value: int): bool = true
|
||||
|
||||
when isMainModule:
|
||||
suite "Signal handling test suite":
|
||||
test "SIGINT test":
|
||||
check test(SIGINT, 31337) == true
|
||||
test "SIGTERM test":
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
|
||||
import unittest
|
||||
import ../chronos
|
||||
|
||||
suite "callSoon() tests suite":
|
||||
const CallSoonTests = 10
|
||||
var soonTest1 = 0'u
|
||||
var timeoutsTest1 = 0
|
||||
|
@ -62,8 +62,6 @@ proc test3(): bool =
|
|||
poll()
|
||||
result = soonTest2 == 987654321
|
||||
|
||||
when isMainModule:
|
||||
suite "callSoon() tests suite":
|
||||
test "User-defined callback argument test":
|
||||
var values = [0x12345678'u, 0x23456789'u, 0x3456789A'u, 0x456789AB'u,
|
||||
0x56789ABC'u, 0x6789ABCD'u, 0x789ABCDE'u, 0x89ABCDEF'u,
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
|
||||
import strutils, unittest, os
|
||||
import ../chronos
|
||||
|
||||
|
@ -14,6 +13,7 @@ when defined(windows):
|
|||
else:
|
||||
import posix
|
||||
|
||||
suite "Stream Transport test suite":
|
||||
const
|
||||
ConstantMessage = "SOMEDATA"
|
||||
BigMessagePattern = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
@ -24,6 +24,38 @@ const
|
|||
MessageSize = 20
|
||||
FilesCount = 10
|
||||
|
||||
m1 = "readLine() multiple clients with messages (" & $ClientsCount &
|
||||
" clients x " & $MessagesCount & " messages)"
|
||||
m2 = "readExactly() multiple clients with messages (" & $ClientsCount &
|
||||
" clients x " & $MessagesCount & " messages)"
|
||||
m3 = "readUntil() multiple clients with messages (" & $ClientsCount &
|
||||
" clients x " & $MessagesCount & " messages)"
|
||||
m4 = "writeFile() multiple clients (" & $FilesCount & " files)"
|
||||
m5 = "write(string)/read(int) multiple clients (" & $ClientsCount &
|
||||
" clients x " & $MessagesCount & " messages)"
|
||||
m6 = "write(seq[byte])/consume(int)/read(int) multiple clients (" &
|
||||
$ClientsCount & " clients x " & $MessagesCount & " messages)"
|
||||
m7 = "readLine() buffer overflow test"
|
||||
m8 = "readUntil() buffer overflow test"
|
||||
m11 = "readExactly() unexpected disconnect test"
|
||||
m12 = "readUntil() unexpected disconnect test"
|
||||
m13 = "readLine() unexpected disconnect empty string test"
|
||||
m14 = "Closing socket while operation pending test (issue #8)"
|
||||
m15 = "Connection refused test"
|
||||
m16 = "readOnce() read until atEof() test"
|
||||
|
||||
when defined(windows):
|
||||
var addresses = [
|
||||
initTAddress("127.0.0.1:33335"),
|
||||
initTAddress(r"/LOCAL\testpipe")
|
||||
]
|
||||
else:
|
||||
var addresses = [
|
||||
initTAddress("127.0.0.1:33335"),
|
||||
initTAddress(r"/tmp/testpipe")
|
||||
]
|
||||
var prefixes = ["[IP] ", "[UNIX] "]
|
||||
|
||||
proc serveClient1(server: StreamServer, transp: StreamTransport) {.async.} =
|
||||
while not transp.atEof():
|
||||
var data = await transp.readLine()
|
||||
|
@ -577,8 +609,8 @@ proc test13(address: TransportAddress): Future[int] {.async.} =
|
|||
server.close()
|
||||
await server.join()
|
||||
|
||||
proc serveClient14(server: StreamServer, transp: StreamTransport) {.async.} =
|
||||
discard
|
||||
# proc serveClient14(server: StreamServer, transp: StreamTransport) {.async.} =
|
||||
# discard
|
||||
|
||||
proc test14(address: TransportAddress): Future[int] {.async.} =
|
||||
var subres = 0
|
||||
|
@ -646,41 +678,22 @@ proc test16(address: TransportAddress): Future[int] {.async.} =
|
|||
server.close()
|
||||
await server.join()
|
||||
|
||||
when isMainModule:
|
||||
const
|
||||
m1 = "readLine() multiple clients with messages (" & $ClientsCount &
|
||||
" clients x " & $MessagesCount & " messages)"
|
||||
m2 = "readExactly() multiple clients with messages (" & $ClientsCount &
|
||||
" clients x " & $MessagesCount & " messages)"
|
||||
m3 = "readUntil() multiple clients with messages (" & $ClientsCount &
|
||||
" clients x " & $MessagesCount & " messages)"
|
||||
m4 = "writeFile() multiple clients (" & $FilesCount & " files)"
|
||||
m5 = "write(string)/read(int) multiple clients (" & $ClientsCount &
|
||||
" clients x " & $MessagesCount & " messages)"
|
||||
m6 = "write(seq[byte])/consume(int)/read(int) multiple clients (" &
|
||||
$ClientsCount & " clients x " & $MessagesCount & " messages)"
|
||||
m7 = "readLine() buffer overflow test"
|
||||
m8 = "readUntil() buffer overflow test"
|
||||
m11 = "readExactly() unexpected disconnect test"
|
||||
m12 = "readUntil() unexpected disconnect test"
|
||||
m13 = "readLine() unexpected disconnect empty string test"
|
||||
m14 = "Closing socket while operation pending test (issue #8)"
|
||||
m15 = "Connection refused test"
|
||||
m16 = "readOnce() read until atEof() test"
|
||||
proc testCloseTransport(address: TransportAddress): Future[int] {.async.} =
|
||||
proc client(server: StreamServer, transp: StreamTransport) {.async.} =
|
||||
discard
|
||||
var server = createStreamServer(address, client, {ReuseAddr})
|
||||
server.start()
|
||||
server.stop
|
||||
server.close()
|
||||
try:
|
||||
await wait(server.join(), 1.seconds)
|
||||
result = 1
|
||||
except:
|
||||
discard
|
||||
|
||||
when defined(windows):
|
||||
var addresses = [
|
||||
initTAddress("127.0.0.1:33335"),
|
||||
initTAddress(r"/LOCAL\testpipe")
|
||||
]
|
||||
else:
|
||||
var addresses = [
|
||||
initTAddress("127.0.0.1:33335"),
|
||||
initTAddress(r"/tmp/testpipe")
|
||||
]
|
||||
var prefixes = ["[IP] ", "[UNIX] "]
|
||||
suite "Stream Transport test suite":
|
||||
for i in 0..<len(addresses):
|
||||
test prefixes[i] & "close(transport) test":
|
||||
check waitFor(testCloseTransport(addresses[i])) == 1
|
||||
test prefixes[i] & m8:
|
||||
check waitFor(test8(addresses[i])) == 1
|
||||
test prefixes[i] & m7:
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
|
||||
import unittest
|
||||
import ../chronos
|
||||
|
||||
suite "Asynchronous sync primitives test suite":
|
||||
var testLockResult = ""
|
||||
var testEventResult = ""
|
||||
var testQueue1Result = 0
|
||||
|
@ -196,8 +196,6 @@ proc test9(): bool =
|
|||
q.putNoWait(5)
|
||||
result = (5 in q and not(6 in q))
|
||||
|
||||
when isMainModule:
|
||||
suite "Asynchronous sync primitives test suite":
|
||||
test "AsyncLock() behavior test":
|
||||
check test1() == "0123456789"
|
||||
test "AsyncEvent() behavior test":
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
# Licensed under either of
|
||||
# Apache License, version 2.0, (LICENSE-APACHEv2)
|
||||
# MIT license (LICENSE-MIT)
|
||||
|
||||
import os, unittest
|
||||
import ../chronos, ../chronos/timer
|
||||
|
||||
suite "Asynchronous timers test suite":
|
||||
const TimersCount = 10
|
||||
|
||||
proc timeWorker(time: Duration): Future[Duration] {.async.} =
|
||||
|
@ -46,8 +46,6 @@ proc testTimer(): bool =
|
|||
let d = b - a
|
||||
result = (d >= 1000.milliseconds) and (d <= 2_000.milliseconds)
|
||||
|
||||
when isMainModule:
|
||||
suite "Asynchronous timers test suite":
|
||||
test "Timer reliability test [" & asyncTimer & "]":
|
||||
check testTimer() == true
|
||||
test $TimersCount & " timers with 10ms timeout":
|
||||
|
|
Loading…
Reference in New Issue