summary refs log tree commit diff stats
path: root/tests/async
diff options
context:
space:
mode:
Diffstat (limited to 'tests/async')
-rw-r--r--tests/async/hello.txt1
-rw-r--r--tests/async/nim.cfg1
-rw-r--r--tests/async/t11558.nim13
-rw-r--r--tests/async/t12221.nim40
-rw-r--r--tests/async/t13889.nim27
-rw-r--r--tests/async/t14820.nim25
-rw-r--r--tests/async/t15148.nim12
-rw-r--r--tests/async/t15804.nim15
-rw-r--r--tests/async/t17045.nim28
-rw-r--r--tests/async/t20111.nim19
-rw-r--r--tests/async/t21447.nim6
-rw-r--r--tests/async/t21893.nim13
-rw-r--r--tests/async/t22210.nim41
-rw-r--r--tests/async/t22210_2.nim73
-rw-r--r--tests/async/t3075.nim29
-rw-r--r--tests/async/t6846.nim15
-rw-r--r--tests/async/t7192.nim14
-rw-r--r--tests/async/t7758.nim21
-rw-r--r--tests/async/t8982.nim33
-rw-r--r--tests/async/t9201.nim14
-rw-r--r--tests/async/tacceptcloserace.nim36
-rw-r--r--tests/async/tasyncRecvLine.nim53
-rw-r--r--tests/async/tasync_forward.nim18
-rw-r--r--tests/async/tasync_gcsafe.nim36
-rw-r--r--tests/async/tasync_gcunsafe.nim30
-rw-r--r--tests/async/tasync_in_seq_constr.nim25
-rw-r--r--tests/async/tasync_misc.nim83
-rw-r--r--tests/async/tasync_noasync.nim44
-rw-r--r--tests/async/tasync_nofuture.nim11
-rw-r--r--tests/async/tasync_traceback.nim122
-rw-r--r--tests/async/tasyncall.nim67
-rw-r--r--tests/async/tasyncawait.nim59
-rw-r--r--tests/async/tasyncclosestall.nim101
-rw-r--r--tests/async/tasyncconnect.nim5
-rw-r--r--tests/async/tasyncdial.nim52
-rw-r--r--tests/async/tasyncdiscard.nim2
-rw-r--r--tests/async/tasynceagain.nim67
-rw-r--r--tests/async/tasynceverror.nim66
-rw-r--r--tests/async/tasyncexceptions.nim7
-rw-r--r--tests/async/tasyncfile.nim33
-rw-r--r--tests/async/tasyncfilewrite.nim20
-rw-r--r--tests/async/tasyncintemplate.nim62
-rw-r--r--tests/async/tasynciossl.nim92
-rw-r--r--tests/async/tasyncnetudp.nim90
-rw-r--r--tests/async/tasyncrecursion.nim21
-rw-r--r--tests/async/tasyncsend4757.nim24
-rw-r--r--tests/async/tasyncssl.nim74
-rw-r--r--tests/async/tasynctry.nim38
-rw-r--r--tests/async/tasynctry2.nim16
-rw-r--r--tests/async/tasyncudp.nim78
-rw-r--r--tests/async/tawaitsemantics.nim76
-rw-r--r--tests/async/tbreak_must_exec_finally.nim25
-rw-r--r--tests/async/tcallbacks.nim21
-rw-r--r--tests/async/tdiscardableproc.nim9
-rw-r--r--tests/async/testmanyasyncevents.nim24
-rw-r--r--tests/async/tfuturestream.nim71
-rw-r--r--tests/async/tfuturevar.nim46
-rw-r--r--tests/async/tgeneric_async.nim43
-rw-r--r--tests/async/tgenericasync.nim14
-rw-r--r--tests/async/tioselectors.nim351
-rw-r--r--tests/async/tjsandnativeasync.nim30
-rw-r--r--tests/async/tlambda.nim7
-rw-r--r--tests/async/tmultisync.nim8
-rw-r--r--tests/async/tnewasyncudp.nim53
-rw-r--r--tests/async/tpendingcheck.nim18
-rw-r--r--tests/async/tpolltimeouts.nim19
-rw-r--r--tests/async/ttemplateinasync.nim11
-rw-r--r--tests/async/tupcoming_async.nim157
-rw-r--r--tests/async/twinasyncrw.nim56
69 files changed, 2437 insertions, 474 deletions
diff --git a/tests/async/hello.txt b/tests/async/hello.txt
new file mode 100644
index 000000000..854d6c20a
--- /dev/null
+++ b/tests/async/hello.txt
@@ -0,0 +1 @@
+hello humans!
\ No newline at end of file
diff --git a/tests/async/nim.cfg b/tests/async/nim.cfg
new file mode 100644
index 000000000..be50f572c
--- /dev/null
+++ b/tests/async/nim.cfg
@@ -0,0 +1 @@
+--experimental:strictEffects
diff --git a/tests/async/t11558.nim b/tests/async/t11558.nim
new file mode 100644
index 000000000..99961e7b6
--- /dev/null
+++ b/tests/async/t11558.nim
@@ -0,0 +1,13 @@
+discard """
+output: "Hello\n9"
+"""
+import std/asyncdispatch
+
+proc foo(): Future[string] {.async.} =
+  "Hello"
+
+proc bar(): Future[int] {.async.} =
+  result = 9
+
+echo waitFor foo()
+echo waitFor bar()
diff --git a/tests/async/t12221.nim b/tests/async/t12221.nim
new file mode 100644
index 000000000..e8bd9c11a
--- /dev/null
+++ b/tests/async/t12221.nim
@@ -0,0 +1,40 @@
+import asyncdispatch, os, times
+
+proc doubleSleep(hardSleep: int) {.async.} =
+  await sleepAsync(50)
+  sleep(hardSleep)
+
+template assertTime(target, timeTook: float): untyped {.dirty.} =
+  doAssert(timeTook*1000 > target - 1000, "Took too short, should've taken " &
+    $target & "ms, but took " & $(timeTook*1000) & "ms")
+  doAssert(timeTook*1000 < target + 1000, "Took too long, should've taken " &
+    $target & "ms, but took " & $(timeTook*1000) & "ms")
+
+var
+  start: float
+  fut: Future[void]
+
+# NOTE: this uses poll(3000) to limit timing error potential.
+start = epochTime()
+fut = sleepAsync(40) and sleepAsync(100) and doubleSleep(20)
+while not fut.finished:
+  poll(1000)
+assertTime(150, epochTime() - start)
+
+start = epochTime()
+fut = sleepAsync(40) and sleepAsync(100) and doubleSleep(50)
+while not fut.finished:
+  poll(1000)
+assertTime(200, epochTime() - start)
+
+start = epochTime()
+fut = sleepAsync(40) and sleepAsync(100) and doubleSleep(20) and sleepAsync(200)
+while not fut.finished:
+  poll(1000)
+assertTime(300, epochTime() - start)
+
+start = epochTime()
+fut = (sleepAsync(40) and sleepAsync(100) and doubleSleep(20)) or sleepAsync(300)
+while not fut.finished:
+  poll(1000)
+assertTime(150, epochTime() - start)
diff --git a/tests/async/t13889.nim b/tests/async/t13889.nim
new file mode 100644
index 000000000..fe75fe38a
--- /dev/null
+++ b/tests/async/t13889.nim
@@ -0,0 +1,27 @@
+discard """
+  output: '''
+believer Foo is saved:true
+believer Bar is saved:true
+believer Baz is saved:true
+'''
+"""
+
+import asyncdispatch
+
+var
+  promise = newFuture[bool]()
+
+proc believers(name: string) {.async.} =
+  let v = await promise
+  echo "believer " & name & " is saved:" & $v
+
+asyncCheck believers("Foo")
+asyncCheck believers("Bar")
+asyncCheck believers("Baz")
+
+proc savior() {.async.} =
+  await sleepAsync(50)
+  complete(promise, true)
+  await sleepAsync(50) # give enough time to see who was saved
+
+waitFor(savior())
diff --git a/tests/async/t14820.nim b/tests/async/t14820.nim
new file mode 100644
index 000000000..359884468
--- /dev/null
+++ b/tests/async/t14820.nim
@@ -0,0 +1,25 @@
+discard """
+output: '''
+iteration: 1
+iteration: 2
+iteration: 3
+iteration: 4
+async done
+iteration: 5
+'''
+"""
+
+import asyncdispatch, times
+
+var done = false
+proc somethingAsync() {.async.} =
+  yield sleepAsync 5000
+  echo "async done"
+  done = true
+  
+asyncCheck somethingAsync()
+var count = 0
+while not done:
+  count += 1
+  drain 1000
+  echo "iteration: ", count 
diff --git a/tests/async/t15148.nim b/tests/async/t15148.nim
new file mode 100644
index 000000000..ba14c1157
--- /dev/null
+++ b/tests/async/t15148.nim
@@ -0,0 +1,12 @@
+import asyncdispatch, asyncfile, os
+
+const Filename = "t15148.txt"
+
+proc saveEmpty() {.async.} =
+  let
+    text = ""
+    file = openAsync(Filename, fmWrite)
+  await file.write(text)
+  file.close()
+
+waitFor saveEmpty()
diff --git a/tests/async/t15804.nim b/tests/async/t15804.nim
new file mode 100644
index 000000000..8de012196
--- /dev/null
+++ b/tests/async/t15804.nim
@@ -0,0 +1,15 @@
+import asyncdispatch
+
+type
+  Foo*[E] = ref object 
+    op: proc(): Future[bool] {.gcsafe.}
+
+proc newFoo*[E](): Foo[E] =
+  result = Foo[E]()
+  result.op = proc(): Future[bool] {.gcsafe,async.} =
+    await sleepAsync(100)
+    result = false
+
+when isMainModule:
+  let f = newFoo[int]()
+  echo waitFor f.op()
diff --git a/tests/async/t17045.nim b/tests/async/t17045.nim
new file mode 100644
index 000000000..2b5acf48a
--- /dev/null
+++ b/tests/async/t17045.nim
@@ -0,0 +1,28 @@
+discard """
+  targets: "c cpp"
+  matrix: "--mm:refc; --mm:arc"
+"""
+
+type Future = ref object
+
+iterator paths: string = 
+  # without "when nimvm" everything works
+  when nimvm:
+    yield "test.md"
+  else:
+    yield "test.md"
+
+template await(f: Future): string =
+  # need this yield, also the template has to return something
+  yield f
+  "hello world"
+
+proc generatePostContextsAsync() =
+  iterator generatePostContextsAsyncIter(): Future {.closure.} =
+    for filePath in paths():
+      var temp = await Future()
+
+  # need this line
+  var nameIterVar = generatePostContextsAsyncIter
+
+generatePostContextsAsync()
\ No newline at end of file
diff --git a/tests/async/t20111.nim b/tests/async/t20111.nim
new file mode 100644
index 000000000..0aaa7d886
--- /dev/null
+++ b/tests/async/t20111.nim
@@ -0,0 +1,19 @@
+discard """
+  action: "run"
+"""
+import asyncdispatch
+type
+    Sync = object
+    Async = object
+    SyncRes = (Sync, string)
+    AsyncRes = (Async, string)
+
+proc foo(val: Sync | Async): Future[(Async, string) | (Sync, string)] {.multisync.} =
+    return (val, "hello")
+
+let
+  myAsync = Async()
+  mySync = Sync()
+
+doAssert typeof(waitFor foo(myAsync)) is AsyncRes
+doAssert typeof(foo(mySync)) is SyncRes
diff --git a/tests/async/t21447.nim b/tests/async/t21447.nim
new file mode 100644
index 000000000..e4f7ae31f
--- /dev/null
+++ b/tests/async/t21447.nim
@@ -0,0 +1,6 @@
+discard """
+  action: "compile"
+  cmd: "nim c -d:release -d:futureLogging $file"
+"""
+
+import std/asyncdispatch
diff --git a/tests/async/t21893.nim b/tests/async/t21893.nim
new file mode 100644
index 000000000..658cb02eb
--- /dev/null
+++ b/tests/async/t21893.nim
@@ -0,0 +1,13 @@
+discard """
+output: "@[97]\ntrue"
+"""
+
+import asyncdispatch
+
+proc test(): Future[bool] {.async.} =
+  const S4 = @[byte('a')]
+  echo S4
+  return true
+
+echo waitFor test()
+
diff --git a/tests/async/t22210.nim b/tests/async/t22210.nim
new file mode 100644
index 000000000..fcf939472
--- /dev/null
+++ b/tests/async/t22210.nim
@@ -0,0 +1,41 @@
+discard """
+output: '''
+stage 1
+stage 2
+stage 3
+(status: 200, data: "SOMEDATA")
+'''
+"""
+
+import std/asyncdispatch
+
+
+# bug #22210
+type
+  ClientResponse = object
+    status*: int
+    data*: string
+
+proc subFoo1(): Future[int] {.async.} =
+  await sleepAsync(100)
+  return 200
+
+proc subFoo2(): Future[string] {.async.} =
+  await sleepAsync(100)
+  return "SOMEDATA"
+
+proc testFoo(): Future[ClientResponse] {.async.} =
+  try:
+    let status = await subFoo1()
+    doAssert(status == 200)
+    let data = await subFoo2()
+    return ClientResponse(status: status, data: data)
+  finally:
+    echo "stage 1"
+    await sleepAsync(100)
+    echo "stage 2"
+    await sleepAsync(200)
+    echo "stage 3"
+
+when isMainModule:
+  echo waitFor testFoo()
\ No newline at end of file
diff --git a/tests/async/t22210_2.nim b/tests/async/t22210_2.nim
new file mode 100644
index 000000000..9db664a32
--- /dev/null
+++ b/tests/async/t22210_2.nim
@@ -0,0 +1,73 @@
+import std/asyncdispatch
+
+
+# bug #22210
+type
+  ClientResponse = object
+    status*: int
+    data*: string
+
+proc subFoo1(): Future[int] {.async.} =
+  await sleepAsync(100)
+  return 200
+
+proc subFoo2(): Future[string] {.async.} =
+  await sleepAsync(100)
+  return "SOMEDATA"
+
+
+proc testFoo2(): Future[ClientResponse] {.async.} =
+  var flag = 0
+  try:
+    let status = await subFoo1()
+    doAssert(status == 200)
+    let data = await subFoo2()
+    result = ClientResponse(status: status, data: data)
+  finally:
+    inc flag
+    await sleepAsync(100)
+    inc flag
+    await sleepAsync(200)
+    inc flag
+  doAssert flag == 3
+
+discard waitFor testFoo2()
+
+proc testFoo3(): Future[ClientResponse] {.async.} =
+  var flag = 0
+  try:
+    let status = await subFoo1()
+    doAssert(status == 200)
+    let data = await subFoo2()
+    if false:
+      return ClientResponse(status: status, data: data)
+  finally:
+    inc flag
+    await sleepAsync(100)
+    inc flag
+    await sleepAsync(200)
+    inc flag
+  doAssert flag == 3
+
+discard waitFor testFoo3()
+
+
+proc testFoo4(): Future[ClientResponse] {.async.} =
+  var flag = 0
+  try:
+    let status = await subFoo1()
+    doAssert(status == 200)
+    let data = await subFoo2()
+    if status == 200:
+      return ClientResponse(status: status, data: data)
+    else:
+      return ClientResponse()
+  finally:
+    inc flag
+    await sleepAsync(100)
+    inc flag
+    await sleepAsync(200)
+    inc flag
+  doAssert flag == 3
+
+discard waitFor testFoo4()
diff --git a/tests/async/t3075.nim b/tests/async/t3075.nim
new file mode 100644
index 000000000..d26aa0a36
--- /dev/null
+++ b/tests/async/t3075.nim
@@ -0,0 +1,29 @@
+import asyncnet, asyncdispatch, strtabs
+
+type
+  WebSocketCallback = proc (client: WebSocket, message: WebSocketMessage) {.closure, gcsafe.}
+  WebSocketRecvClosure = proc (ws: WebSocket): Future[string] {.gcsafe.}
+
+  WebSocketMessage = ref object
+    msg: string
+
+  WebSocket = ref object
+    socket:     AsyncSocket
+    header:     StringTableRef
+    onOpen:     WebSocketCallback
+    onMessage:  WebSocketCallback
+    onClose:    WebSocketCallback
+
+proc recv(ws: WebSocket, p: WebSocketRecvClosure): Future[string] {.async.}=
+  if not ws.socket.isClosed():
+    result = await ws.p()
+    if result == "":
+      ws.socket.close()
+      if ws.onClose != nil:
+        ws.onClose(ws, nil)
+  return result
+
+proc reҁvSize(ws: WebSocket, size: int): Future[string] {.async.} =
+  proc recvSizeClosure(ws: WebSocket): Future[string] {.async.} =
+    return await ws.socket.recv(size)
+  return await ws.recv(recvSizeClosure)
diff --git a/tests/async/t6846.nim b/tests/async/t6846.nim
new file mode 100644
index 000000000..7fe38f3b3
--- /dev/null
+++ b/tests/async/t6846.nim
@@ -0,0 +1,15 @@
+discard """
+  exitcode: 0
+  output: "hello world"
+  disabled: windows
+"""
+
+import asyncdispatch
+import asyncfile
+
+var asyncStdout = 1.AsyncFD.newAsyncFile()
+proc doStuff: Future[void] {.async.} =
+  await asyncStdout.write "hello world\n"
+
+let fut = doStuff()
+doAssert fut.finished, "Poll is needed unnecessarily. See #6846."
diff --git a/tests/async/t7192.nim b/tests/async/t7192.nim
new file mode 100644
index 000000000..9ac0e07c0
--- /dev/null
+++ b/tests/async/t7192.nim
@@ -0,0 +1,14 @@
+discard """
+output: '''
+testCallback()
+'''
+"""
+
+import asyncdispatch
+
+proc testCallback() =
+  echo "testCallback()"
+
+when true:
+  callSoon(testCallback)
+  poll()
diff --git a/tests/async/t7758.nim b/tests/async/t7758.nim
new file mode 100644
index 000000000..fe6d32ad3
--- /dev/null
+++ b/tests/async/t7758.nim
@@ -0,0 +1,21 @@
+import asyncdispatch
+import std/unittest
+
+proc task() {.async.} =
+  const tSleep = 40
+  await sleepAsync(tSleep)
+
+proc main() =
+  var counter = 0
+  var f = task()
+  while not f.finished:
+    inc(counter)
+    poll(10)
+
+  const slack = 1
+    # because there is overhead in `async` + `sleepAsync`
+    # as can be seen by increasing `tSleep` from 40 to 49, which increases the number
+    # of failures.
+  check counter <= 4 + slack
+
+for i in 0 .. 10: main()
diff --git a/tests/async/t8982.nim b/tests/async/t8982.nim
new file mode 100644
index 000000000..5face7edf
--- /dev/null
+++ b/tests/async/t8982.nim
@@ -0,0 +1,33 @@
+discard """
+output: '''
+timeout
+runForever should throw ValueError, this is expected
+'''
+"""
+
+
+import asyncdispatch
+
+proc failingAwaitable(p: int) {.async.} =
+  await sleepAsync(500)
+  if p > 0:
+    raise newException(Exception, "my exception")
+
+proc main() {.async.} =
+  let fut = failingAwaitable(1)
+  try:
+    await fut or sleepAsync(100)
+    if fut.finished:
+      echo "finished"
+    else:
+      echo "timeout"
+  except:
+    echo "failed"
+
+
+# Previously this would raise "An attempt was made to complete a Future more than once."
+try:
+  asyncCheck main()
+  runForever()
+except ValueError:
+  echo "runForever should throw ValueError, this is expected"
diff --git a/tests/async/t9201.nim b/tests/async/t9201.nim
new file mode 100644
index 000000000..5aaba7063
--- /dev/null
+++ b/tests/async/t9201.nim
@@ -0,0 +1,14 @@
+discard """
+  exitcode: 0
+"""
+
+# Derived from issue #9201
+import asyncdispatch, macros
+
+macro newAsyncProc(name: untyped): untyped =
+  expectKind name, nnkStrLit
+  let pName = genSym(nskProc, name.strVal)
+  result = getAst async quote do:
+    proc `pName`() = discard
+
+newAsyncProc("hello")
diff --git a/tests/async/tacceptcloserace.nim b/tests/async/tacceptcloserace.nim
new file mode 100644
index 000000000..fee6537d2
--- /dev/null
+++ b/tests/async/tacceptcloserace.nim
@@ -0,0 +1,36 @@
+discard """
+  exitcode: 0
+  output: ""
+"""
+
+import asyncdispatch, net, os, nativesockets
+
+# bug: https://github.com/nim-lang/Nim/issues/5279
+
+proc setupServerSocket(hostname: string, port: Port): AsyncFD =
+  let fd = createNativeSocket()
+  if fd == osInvalidSocket:
+    raiseOSError(osLastError())
+  setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
+  var aiList = getAddrInfo(hostname, port)
+  if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
+    freeAddrInfo(aiList)
+    raiseOSError(osLastError())
+  freeAddrInfo(aiList)
+  if listen(fd) != 0:
+    raiseOSError(osLastError())
+  setBlocking(fd, false)
+  result = fd.AsyncFD
+  register(result)
+
+const port = Port(5614)
+for i in 0..100:
+  let serverFd = setupServerSocket("localhost", port)
+  serverFd.accept().callback = proc(fut: Future[AsyncFD]) =
+    if not fut.failed:
+      fut.read().closeSocket()
+
+  var fd = createAsyncNativeSocket()
+  waitFor fd.connect("localhost", port)
+  serverFd.closeSocket()
+  fd.closeSocket()
diff --git a/tests/async/tasyncRecvLine.nim b/tests/async/tasyncRecvLine.nim
new file mode 100644
index 000000000..a13a171c3
--- /dev/null
+++ b/tests/async/tasyncRecvLine.nim
@@ -0,0 +1,53 @@
+discard """
+output: '''
+Hello World
+Hello World
+'''
+"""
+
+import asyncdispatch, asyncnet
+
+const recvLinePort = Port(6047)
+
+proc setupTestServer(): AsyncSocket =
+  result = newAsyncSocket()
+  result.setSockOpt(OptReuseAddr, true)
+  result.bindAddr(recvLinePort)
+  result.listen()
+
+proc testUnbuffered(): Future[void] {.async.} =
+  let serverSock = setupTestServer()
+  let serverAcceptClientFut = serverSock.accept()
+
+  let clientSock = newAsyncSocket(buffered = false)
+  let clientConnectFut = clientSock.connect("localhost", recvLinePort)
+
+  let serverAcceptedClient = await serverAcceptClientFut
+  await clientConnectFut
+
+  await serverAcceptedClient.send("Hello World\c\L")
+
+  echo await clientSock.recvLine()
+
+  clientSock.close()
+  serverSock.close()
+
+proc testBuffered(): Future[void] {.async.} =
+  let serverSock = setupTestServer()
+  let serverAcceptClientFut = serverSock.accept()
+
+  let clientSock = newAsyncSocket(buffered = true)
+  let clientConnectFut = clientSock.connect("localhost", recvLinePort)
+
+  let serverAcceptedClient = await serverAcceptClientFut
+  await clientConnectFut
+
+  await serverAcceptedClient.send("Hello World\c\L")
+
+  echo await clientSock.recvLine()
+
+  clientSock.close()
+  serverSock.close()
+
+waitFor testUnbuffered()
+waitFor testBuffered()
diff --git a/tests/async/tasync_forward.nim b/tests/async/tasync_forward.nim
new file mode 100644
index 000000000..99527032f
--- /dev/null
+++ b/tests/async/tasync_forward.nim
@@ -0,0 +1,18 @@
+
+import asyncdispatch
+
+# bug #1970
+
+proc foo {.async.}
+
+proc foo {.async.} =
+  discard
+
+# With additional pragmas:
+proc bar {.async, cdecl.}
+
+proc bar {.async.} =
+  discard
+
+proc verifyCdeclPresent(p: proc : Future[void] {.cdecl.}) = discard
+verifyCdeclPresent(bar)
diff --git a/tests/async/tasync_gcsafe.nim b/tests/async/tasync_gcsafe.nim
new file mode 100644
index 000000000..bc0eb4271
--- /dev/null
+++ b/tests/async/tasync_gcsafe.nim
@@ -0,0 +1,36 @@
+discard """
+  cmd: "nim c --threads:on $file"
+  output: '''
+1
+2
+3
+'''
+"""
+
+doAssert compileOption("threads"), "this test will not do anything useful without --threads:on"
+
+import asyncdispatch
+
+var globalDummy: ref int
+proc gcUnsafeProc() =
+    if not globalDummy.isNil:
+        echo globalDummy[]
+    echo "1"
+
+proc gcSafeAsyncProcWithNoAnnotation() {.async.} =
+    echo "2"
+
+proc gcSafeAsyncProcWithAnnotation() {.gcsafe, async.} =
+    echo "3"
+
+proc gcUnsafeAsyncProc() {.async.} =
+    # We should be able to call gcUnsafe
+    gcUnsafeProc()
+
+    # We should be able to call async implicitly gcsafe
+    await gcSafeAsyncProcWithNoAnnotation()
+
+    # We should be able to call async explicitly gcsafe
+    await gcSafeAsyncProcWithAnnotation()
+
+waitFor gcUnsafeAsyncProc()
diff --git a/tests/async/tasync_gcunsafe.nim b/tests/async/tasync_gcunsafe.nim
new file mode 100644
index 000000000..f3e6bc691
--- /dev/null
+++ b/tests/async/tasync_gcunsafe.nim
@@ -0,0 +1,30 @@
+discard """
+  errormsg: "'anotherGCSafeAsyncProc (Async)' is not GC-safe as it calls 'asyncGCUnsafeProc'"
+  cmd: "nim c --threads:on $file"
+  file: "asyncmacro.nim"
+"""
+
+doAssert compileOption("threads"), "this test will not do anything useful without --threads:on"
+
+import asyncdispatch
+
+var globalDummy: ref int
+proc gcUnsafeProc() =
+    if not globalDummy.isNil:
+        echo globalDummy[]
+
+proc asyncExplicitlyGCSafeProc() {.gcsafe, async.} =
+    echo "hi"
+
+proc asyncImplicitlyGCSafeProc() {.async.} =
+    echo "hi"
+
+proc asyncGCUnsafeProc() {.async.} =
+    gcUnsafeProc()
+
+proc anotherGCSafeAsyncProc() {.async, gcsafe.} =
+    # We should be able to call other gcsafe procs
+    await asyncExplicitlyGCSafeProc()
+    await asyncImplicitlyGCSafeProc()
+    # But we can't call gcunsafe procs
+    await asyncGCUnsafeProc()
diff --git a/tests/async/tasync_in_seq_constr.nim b/tests/async/tasync_in_seq_constr.nim
new file mode 100644
index 000000000..3d6dae245
--- /dev/null
+++ b/tests/async/tasync_in_seq_constr.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''
+@[1, 2, 3, 4]
+123
+'''
+"""
+
+# bug #5314, bug #6626
+
+import asyncdispatch
+
+proc bar(i: int): Future[int] {.async.} =
+    await sleepAsync(2)
+    result = i
+
+proc foo(): Future[seq[int]] {.async.} =
+    await sleepAsync(2)
+    result = @[1, 2, await bar(3), 4] # <--- The bug is here
+
+proc foo2() {.async.} =
+    await sleepAsync(2)
+    echo(await bar(1), await bar(2), await bar(3))
+
+echo waitFor foo()
+waitFor foo2()
diff --git a/tests/async/tasync_misc.nim b/tests/async/tasync_misc.nim
new file mode 100644
index 000000000..ec1418e8c
--- /dev/null
+++ b/tests/async/tasync_misc.nim
@@ -0,0 +1,83 @@
+import json, asyncdispatch
+block: #6100
+  let done = newFuture[int]()
+  done.complete(1)
+
+  proc asyncSum: Future[int] {.async.} =
+    for _ in 1..1_000_000:
+      result += await done
+
+  let res = waitFor asyncSum()
+  doAssert(res == 1_000_000)
+
+block: #7985
+  proc getData(): Future[JsonNode] {.async.} =
+    result = %*{"value": 1}
+
+  type
+    MyData = object
+      value: BiggestInt
+
+  proc main() {.async.} =
+    let data = to(await(getData()), MyData)
+    doAssert($data == "(value: 1)")
+
+  waitFor(main())
+
+block: #8399
+  proc bar(): Future[string] {.async.} = discard
+
+  proc foo(line: string) {.async.} =
+    var res =
+      case line[0]
+      of '+', '-': @[]
+      of '$': (let x = await bar(); @[""])
+      else: @[]
+
+    doAssert(res == @[""])
+
+  waitFor foo("$asd")
+
+block: # nkCheckedFieldExpr
+  proc bar(): Future[JsonNode] {.async.} =
+    return newJInt(5)
+
+  proc foo() {.async.} =
+    let n = 10 + (await bar()).num
+    doAssert(n == 15)
+
+  waitFor foo()
+
+block: # 12743
+
+  template templ = await sleepAsync 0
+
+  proc prc {.async.} = templ
+
+  waitFor prc()
+
+block: # issue #13899
+  proc someConnect() {.async.} =
+    await sleepAsync(1)
+  proc someClose() {.async.} =
+    await sleepAsync(2)
+  proc testFooFails(): Future[bool] {.async.} =
+    await someConnect()
+    defer:
+      await someClose()
+      result = true
+  proc testFooSucceed(): Future[bool] {.async.} =
+    try:
+      await someConnect()
+    finally:
+      await someClose()
+      result = true
+  doAssert waitFor testFooSucceed()
+  doAssert waitFor testFooFails()
+
+block: # issue #9313
+  doAssert compiles(block:
+    proc a() {.async.} =
+      echo "Hi"
+      quit(0)
+  )
diff --git a/tests/async/tasync_noasync.nim b/tests/async/tasync_noasync.nim
new file mode 100644
index 000000000..0927148bf
--- /dev/null
+++ b/tests/async/tasync_noasync.nim
@@ -0,0 +1,44 @@
+discard """
+  cmd: "nim check --hints:off --warnings:off $file"
+  action: "reject"
+  nimout: '''
+tasync_noasync.nim(21, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead
+tasync_noasync.nim(25, 12) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead
+tasync_noasync.nim(28, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead
+tasync_noasync.nim(31, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead
+tasync_noasync.nim(35, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead
+tasync_noasync.nim(38, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead
+tasync_noasync.nim(40, 8) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead
+'''
+"""
+import async
+
+proc a {.async.} =
+  discard
+
+# Bad await usage
+proc nonAsyncProc =
+  await a()
+
+proc nestedNonAsyncProc {.async.} =
+  proc nested =
+    await a()
+
+iterator customIterator: int =
+  await a()
+
+macro awaitInMacro =
+  await a()
+
+type DummyRef = ref object of RootObj
+method awaitInMethod(_: DummyRef) {.base.} =
+  await a()
+
+proc improperMultisync {.multisync.} =
+  await a()
+
+await a()
+
+# if we overload a fallback handler to get
+# await only available within {.async.}
+# we would need `{.dirty.}` templates for await
diff --git a/tests/async/tasync_nofuture.nim b/tests/async/tasync_nofuture.nim
new file mode 100644
index 000000000..16155601a
--- /dev/null
+++ b/tests/async/tasync_nofuture.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "await expects Future[T], got int"
+  cmd: "nim c $file"
+  file: "asyncmacro.nim"
+"""
+import async
+
+proc a {.async.} =
+  await 0
+
+waitFor a()
diff --git a/tests/async/tasync_traceback.nim b/tests/async/tasync_traceback.nim
new file mode 100644
index 000000000..98f71b192
--- /dev/null
+++ b/tests/async/tasync_traceback.nim
@@ -0,0 +1,122 @@
+discard """
+  exitcode: 0
+  output: "Matched"
+"""
+import asyncdispatch, strutils
+
+# Tests to ensure our exception trace backs are friendly.
+
+# --- Simple test. ---
+#
+# What does this look like when it's synchronous?
+#
+# tasync_traceback.nim(23) tasync_traceback
+# tasync_traceback.nim(21) a
+# tasync_traceback.nim(18) b
+# Error: unhandled exception: b failure [OSError]
+#
+# Good (not quite ideal, but gotta work within constraints) traceback,
+# when exception is unhandled:
+#
+# <traceback for the unhandled exception>
+# <very much a bunch of noise>
+# <would be ideal to customise this>
+# <(the code responsible is in excpt:raiseExceptionAux)>
+# Error: unhandled exception: b failure
+# ===============
+# Async traceback
+# ===============
+#
+# tasync_traceback.nim(23) tasync_traceback
+#
+# tasync_traceback.nim(21) a
+# tasync_traceback.nim(18) b
+
+var result = ""
+
+proc b(): Future[int] {.async.} =
+  if true:
+    raise newException(OSError, "b failure")
+
+proc a(): Future[int] {.async.} =
+  return await b()
+
+let aFut = a()
+try:
+  discard waitFor aFut
+except Exception as exc:
+  result.add(exc.msg & "\n")
+result.add("\n")
+
+# From #6803
+proc bar(): Future[string] {.async.} =
+  await sleepAsync(100)
+  if true:
+    raise newException(OSError, "bar failure")
+
+proc foo(): Future[string] {.async.} = return await bar()
+
+try:
+  result.add(waitFor(foo()) & "\n")
+except Exception as exc:
+  result.add(exc.msg & "\n")
+result.add("\n")
+
+# Use re to parse the result
+import re
+const expected = """
+b failure
+Async traceback:
+  tasync_traceback\.nim\(\d+?\) tasync_traceback
+  tasync_traceback\.nim\(\d+?\) a \(Async\)
+  tasync_traceback\.nim\(\d+?\) b \(Async\)
+Exception message: b failure
+
+
+bar failure
+Async traceback:
+  tasync_traceback\.nim\(\d+?\) tasync_traceback
+  asyncdispatch\.nim\(\d+?\) waitFor
+  asyncdispatch\.nim\(\d+?\) poll
+    ## Processes asynchronous completion events
+  asyncdispatch\.nim\(\d+?\) runOnce
+  asyncdispatch\.nim\(\d+?\) processPendingCallbacks
+    ## Executes pending callbacks
+  tasync_traceback\.nim\(\d+?\) bar \(Async\)
+Exception message: bar failure
+
+"""
+
+# TODO: is asyncmacro good enough location for fooIter traceback/debugging? just put the callsite info for all?
+
+let resLines = splitLines(result.strip)
+let expLines = splitLines(expected.strip)
+
+when not defined(cpp): # todo fixme
+  if resLines.len != expLines.len:
+    echo("Not matched! Wrong number of lines!")
+    echo expLines.len
+    echo resLines.len
+    echo("Expected: -----------")
+    echo expected
+    echo("Gotten: -------------")
+    echo result
+    echo("---------------------")
+    quit(QuitFailure)
+
+  var ok = true
+  for i in 0 ..< resLines.len:
+    if not resLines[i].match(re(expLines[i])):
+      echo "Not matched! Line ", i + 1
+      echo "Expected:"
+      echo expLines[i]
+      echo "Actual:"
+      echo resLines[i]
+      ok = false
+
+  if ok:
+    echo("Matched")
+  else:
+    quit(QuitFailure)
+else:
+  echo("Matched")
diff --git a/tests/async/tasyncall.nim b/tests/async/tasyncall.nim
index 60ba557cc..3c318dbf7 100644
--- a/tests/async/tasyncall.nim
+++ b/tests/async/tasyncall.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tasyncall.nim"
   exitcode: 0
 """
 import times, sequtils
@@ -7,14 +6,14 @@ import asyncdispatch
 
 const
   taskCount = 10
-  sleepDuration = 500
+  sleepDuration = 50
 
 proc futureWithValue(x: int): Future[int] {.async.} =
   await sleepAsync(sleepDuration)
   return x
 
 proc futureWithoutValue() {.async.} =
-  await sleepAsync(1000)
+  await sleepAsync(sleepDuration)
 
 proc testFuturesWithValue(x: int): seq[int] =
   var tasks = newSeq[Future[int]](taskCount)
@@ -40,29 +39,55 @@ proc testVarargs(x, y, z: int): seq[int] =
 
   result = waitFor all(a, b, c)
 
+proc testWithDupes() =
+  var
+    tasks = newSeq[Future[void]](taskCount)
+    fut = futureWithoutValue()
+
+  for i in 0..<taskCount:
+    tasks[i] = fut
+
+  waitFor all(tasks)
+
 block:
-  let
-    startTime = cpuTime()
-    results = testFuturesWithValue(42)
-    expected = repeat(42, taskCount)
-    execTime = cpuTime() - startTime
+    let
+      startTime = cpuTime()
+      results = testFuturesWithValue(42)
+      expected = repeat(42, taskCount)
+      execTime = cpuTime() - startTime
 
-  doAssert execTime * 1000 < taskCount * sleepDuration
-  doAssert results == expected
+    doAssert execTime * 1000 < taskCount * sleepDuration
+    doAssert results == expected
 
 block:
-  let startTime = cpuTime()
-  testFuturesWithoutValues()
-  let execTime = cpuTime() - startTime
+    let startTime = cpuTime()
+    testFuturesWithoutValues()
+    let execTime = cpuTime() - startTime
 
-  doAssert execTime * 1000 < taskCount * sleepDuration
+    doAssert execTime * 1000 < taskCount * sleepDuration
 
 block:
-  let
-    startTime = cpuTime()
-    results = testVarargs(1, 2, 3)
-    expected = @[1, 2, 3]
-    execTime = cpuTime() - startTime
+    let startTime = cpuTime()
+    testWithDupes()
+    let execTime = cpuTime() - startTime
+
+    doAssert execTime * 1000 < taskCount * sleepDuration
+
+block:
+    let
+      startTime = cpuTime()
+      results = testVarargs(1, 2, 3)
+      expected = @[1, 2, 3]
+      execTime = cpuTime() - startTime
+
+    doAssert execTime * 100 < taskCount * sleepDuration
+    doAssert results == expected
+
+block:
+    let
+      noIntFuturesFut = all(newSeq[Future[int]]())
+      noVoidFuturesFut = all(newSeq[Future[void]]())
 
-  doAssert execTime * 100 < taskCount * sleepDuration
-  doAssert results == expected
+    doAssert noIntFuturesFut.finished and not noIntFuturesFut.failed
+    doAssert noVoidFuturesFut.finished and not noVoidFuturesFut.failed
+    doAssert noIntFuturesFut.read() == @[]
diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim
index 9fe9507ad..e86542b2d 100644
--- a/tests/async/tasyncawait.nim
+++ b/tests/async/tasyncawait.nim
@@ -1,65 +1,56 @@
-discard """
-  file: "tasyncawait.nim"
-  output: "5000"
-"""
-import asyncdispatch, nativesockets, net, strutils, os
-
+import asyncdispatch, asyncnet, nativesockets, net, strutils
+from stdtest/netutils import bindAvailablePort
 var msgCount = 0
 
 const
-  swarmSize = 50
-  messagesToSend = 100
+  swarmSize = 40
+  messagesToSend = 50
 
 var clientCount = 0
 
-proc sendMessages(client: TAsyncFD) {.async.} =
-  for i in 0 .. <messagesToSend:
+proc sendMessages(client: AsyncFD) {.async.} =
+  for i in 0 ..< messagesToSend:
     await send(client, "Message " & $i & "\c\L")
 
-proc launchSwarm(port: TPort) {.async.} =
-  for i in 0 .. <swarmSize:
-    var sock = newAsyncNativeSocket()
+proc launchSwarm(port: Port) {.async.} =
+  for i in 0 ..< swarmSize:
+    var sock = createAsyncNativeSocket()
 
     await connect(sock, "localhost", port)
     await sendMessages(sock)
     closeSocket(sock)
 
-proc readMessages(client: TAsyncFD) {.async.} =
+proc readMessages(client: AsyncFD) {.async.} =
+  # wrapping the AsyncFd into a AsyncSocket object
+  var sockObj = newAsyncSocket(client)
+  var (ipaddr, port) = sockObj.getPeerAddr()
+  doAssert ipaddr == "127.0.0.1"
+  (ipaddr, port) = sockObj.getLocalAddr()
+  doAssert ipaddr == "127.0.0.1"
   while true:
-    var line = await recvLine(client)
+    var line = await recvLine(sockObj)
     if line == "":
       closeSocket(client)
       clientCount.inc
       break
     else:
-      if line.startswith("Message "):
+      if line.startsWith("Message "):
         msgCount.inc
       else:
         doAssert false
 
-proc createServer(port: TPort) {.async.} =
-  var server = newAsyncNativeSocket()
-  block:
-    var name: Sockaddr_in
-    when defined(windows):
-      name.sin_family = toInt(AF_INET).int16
-    else:
-      name.sin_family = toInt(AF_INET)
-    name.sin_port = htons(uint16(port))
-    name.sin_addr.s_addr = htonl(INADDR_ANY)
-    if bindAddr(server.SocketHandle, cast[ptr SockAddr](addr(name)),
-                sizeof(name).Socklen) < 0'i32:
-      raiseOSError(osLastError())
-
+proc createServer(server: AsyncFD) {.async.} =
   discard server.SocketHandle.listen()
   while true:
     asyncCheck readMessages(await accept(server))
 
-asyncCheck createServer(TPort(10335))
-asyncCheck launchSwarm(TPort(10335))
+let server = createAsyncNativeSocket()
+let port = bindAvailablePort(server.SocketHandle)
+asyncCheck createServer(server)
+asyncCheck launchSwarm(port)
 while true:
   poll()
   if clientCount == swarmSize: break
 
-assert msgCount == swarmSize * messagesToSend
-echo msgCount
+doAssert msgCount == swarmSize * messagesToSend
+doAssert msgCount == 2000
diff --git a/tests/async/tasyncclosestall.nim b/tests/async/tasyncclosestall.nim
new file mode 100644
index 000000000..d1c7a5fba
--- /dev/null
+++ b/tests/async/tasyncclosestall.nim
@@ -0,0 +1,101 @@
+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()
diff --git a/tests/async/tasyncconnect.nim b/tests/async/tasyncconnect.nim
index 3dac379b2..564f6c67c 100644
--- a/tests/async/tasyncconnect.nim
+++ b/tests/async/tasyncconnect.nim
@@ -1,7 +1,6 @@
 discard """
-  file: "tasyncconnect.nim"
-  exitcode: 1
   outputsub: "Error: unhandled exception: Connection refused"
+  exitcode: 1
 """
 
 import
@@ -19,7 +18,7 @@ when defined(windows) or defined(nimdoc):
     quit("Error: unhandled exception: Connection refused")
 else:
     proc testAsyncConnect() {.async.} =
-        var s = newAsyncNativeSocket()
+        var s = createAsyncNativeSocket()
 
         await s.connect(testHost, testPort)
 
diff --git a/tests/async/tasyncdial.nim b/tests/async/tasyncdial.nim
new file mode 100644
index 000000000..f0377dfd5
--- /dev/null
+++ b/tests/async/tasyncdial.nim
@@ -0,0 +1,52 @@
+discard """
+  output: '''
+OK AF_INET
+OK AF_INET6
+'''
+"""
+
+import
+  nativesockets, os, asyncdispatch
+
+proc setupServerSocket(hostname: string, port: Port, domain: Domain): AsyncFD =
+  ## Creates a socket, binds it to the specified address, and starts listening for connections.
+  ## Registers the descriptor with the dispatcher of the current thread
+  ## Raises OSError in case of an error.
+  let fd = createNativeSocket(domain)
+  setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
+  var aiList = getAddrInfo(hostname, port, domain)
+  if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
+    freeAddrInfo(aiList)
+    raiseOSError(osLastError())
+  freeAddrInfo(aiList)
+  if listen(fd) != 0:
+    raiseOSError(osLastError())
+  setBlocking(fd, false)
+  result = fd.AsyncFD
+  register(result)
+
+proc doTest(domain: static[Domain]) {.async.} =
+  const
+    testHost = when domain == Domain.AF_INET6: "::1" else: "127.0.0.1"
+    testPort = Port(17384)
+  let serverFd = setupServerSocket(testHost, testPort, domain)
+  let acceptFut = serverFd.accept()
+  let clientFdFut = dial(testHost, testPort)
+
+  let serverClientFd = await acceptFut
+  serverFd.closeSocket()
+
+  let clientFd = await clientFdFut
+
+  let recvFut = serverClientFd.recv(2)
+  await clientFd.send("Hi")
+  let msg = await recvFut
+
+  serverClientFd.closeSocket()
+  clientFd.closeSocket()
+
+  if msg == "Hi":
+    echo "OK ", domain
+
+waitFor(doTest(Domain.AF_INET))
+waitFor(doTest(Domain.AF_INET6))
diff --git a/tests/async/tasyncdiscard.nim b/tests/async/tasyncdiscard.nim
index e7c87ad42..64e6021c3 100644
--- a/tests/async/tasyncdiscard.nim
+++ b/tests/async/tasyncdiscard.nim
@@ -10,7 +10,7 @@ discard """
 6
 '''
 """
-import asyncio, asyncdispatch, asyncnet
+import asyncdispatch, asyncnet
 
 proc main {.async.} =
   proc f: Future[int] {.async.} =
diff --git a/tests/async/tasynceagain.nim b/tests/async/tasynceagain.nim
new file mode 100644
index 000000000..94c3645dc
--- /dev/null
+++ b/tests/async/tasynceagain.nim
@@ -0,0 +1,67 @@
+discard """
+  disabled: "windows"
+  exitcode: 0
+"""
+# AsyncSocketBug.nim
+# Jens Alfke (@snej) -- 16 July 2020
+# Demonstrates data loss by Nim's AsyncSocket.
+# Just run it, and it will raise an assertion failure within a minute.
+
+import asyncdispatch, asyncnet, strformat, strutils, sugar
+
+const FrameSize = 9999   # Exact size not important, but larger sizes fail quicker
+
+proc runServer() {.async.} =
+  # Server side:
+  var server = newAsyncSocket()
+  server.bindAddr(Port(9001))
+  server.listen()
+  let client = await server.accept()
+  echo "Server got client connection"
+  var lastN = 0
+  while true:
+    let frame = await client.recv(FrameSize)
+    doAssert frame.len == FrameSize
+    let n = frame[0..<6].parseInt()
+    echo "RCVD #", n, ":  ", frame[0..80], "..."
+    if n != lastN + 1:
+      echo &"******** ERROR: Server received #{n}, but last was #{lastN}!"
+    doAssert n == lastN + 1
+    lastN = n
+    await sleepAsync 100
+
+
+proc main() {.async.} =
+  asyncCheck runServer()
+
+  # Client side:
+  let socket = newAsyncSocket(buffered = false)
+  await socket.connect("localhost", Port(9001))
+  echo "Client socket connected"
+
+  var sentCount = 0
+  var completedCount = 0
+
+  while sentCount < 2000:
+    sentCount += 1
+    let n = sentCount
+
+    var message = &"{n:06} This is message #{n} of ∞. Please stay tuned for more. "
+    #echo ">>> ", message
+    while message.len < FrameSize:
+      message = message & message
+    let frame = message[0..<FrameSize]
+
+    capture n:
+      socket.send(frame).addCallback proc(f: Future[void]) =
+        # Callback when the send completes:
+        assert not f.failed
+        echo "SENT #", n
+        if n != completedCount + 1:
+          echo &"******** ERROR: Client completed #{n}, but last completed was #{completedCount}!"
+        # If this assert is enabled, it will trigger earlier than the server-side assert above:
+        assert n == completedCount + 1
+        completedCount = n
+    await sleepAsync 1
+
+waitFor main()
\ No newline at end of file
diff --git a/tests/async/tasynceverror.nim b/tests/async/tasynceverror.nim
deleted file mode 100644
index dd05c831b..000000000
--- a/tests/async/tasynceverror.nim
+++ /dev/null
@@ -1,66 +0,0 @@
-discard """
-  file: "tasynceverror.nim"
-  exitcode: 1
-  outputsub: "Error: unhandled exception: "
-"""
-# error message is actually different on OSX
-import
-    asyncdispatch,
-    asyncnet,
-    nativesockets,
-    os
-
-
-const
-    testHost = "127.0.0.1"
-    testPort = Port(17357)
-
-
-when defined(windows) or defined(nimdoc):
-    # TODO: just make it work on Windows for now.
-    quit("Error: unhandled exception: Connection reset by peer")
-else:
-    proc createListenSocket(host: string, port: Port): TAsyncFD =
-        result = newAsyncNativeSocket()
-
-        SocketHandle(result).setSockOptInt(SOL_SOCKET, SO_REUSEADDR, 1)
-
-        var aiList = getAddrInfo(host, port, AF_INET)
-        if SocketHandle(result).bindAddr(aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
-          dealloc(aiList)
-          raiseOSError(osLastError())
-        dealloc(aiList)
-
-        if SocketHandle(result).listen(1) < 0'i32:
-            raiseOSError(osLastError())
-
-
-    proc testAsyncSend() {.async.} =
-        var
-            ls = createListenSocket(testHost, testPort)
-            s = newAsyncSocket()
-
-        await s.connect(testHost, testPort)
-
-        var ps = await ls.accept()
-        closeSocket(ls)
-
-        await ps.send("test 1", flags={})
-        s.close()
-        # This send should raise EPIPE
-        await ps.send("test 2", flags={})
-        SocketHandle(ps).close()
-
-
-    # The bug was, when the poll function handled EvError for us,
-    # our callbacks may never get executed, thus making the event
-    # loop block indefinitely. This is a timer to keep everything
-    # rolling. 400 ms is an arbitrary value, should be enough though.
-    proc timer() {.async.} =
-        await sleepAsync(400)
-        echo("Timer expired.")
-        quit(2)
-
-
-    asyncCheck(testAsyncSend())
-    waitFor(timer())
diff --git a/tests/async/tasyncexceptions.nim b/tests/async/tasyncexceptions.nim
index efe31ef27..de61c099d 100644
--- a/tests/async/tasyncexceptions.nim
+++ b/tests/async/tasyncexceptions.nim
@@ -1,7 +1,6 @@
 discard """
-  file: "tasyncexceptions.nim"
-  exitcode: 1
   outputsub: "Error: unhandled exception: foobar"
+  exitcode: 1
 """
 import asyncdispatch
 
@@ -20,7 +19,7 @@ proc processClient(fd: int) {.async.} =
   var line = await recvLine(fd)
   var foo = line[0]
   if foo == 'g':
-    raise newException(EBase, "foobar")
+    raise newException(Exception, "foobar")
 
 proc serve() {.async.} =
 
@@ -28,7 +27,7 @@ proc serve() {.async.} =
     var fut = await accept()
     await processClient(fut)
 
-when isMainModule:
+when true:
   proc main =
     var fut = serve()
     fut.callback =
diff --git a/tests/async/tasyncfile.nim b/tests/async/tasyncfile.nim
index 26a9bb391..d95850c31 100644
--- a/tests/async/tasyncfile.nim
+++ b/tests/async/tasyncfile.nim
@@ -1,6 +1,9 @@
 discard """
-  file: "tasyncfile.nim"
-  exitcode: 0
+output: '''
+13
+hello humans!
+13
+'''
 """
 import asyncfile, asyncdispatch, os
 
@@ -11,9 +14,10 @@ proc main() {.async.} =
   # Simple write/read test.
   block:
     var file = openAsync(fn, fmReadWrite)
-    await file.write("test")
+    await file.write("testing")
     file.setFilePos(0)
     await file.write("foo")
+    file.setFileSize(4)
     file.setFilePos(0)
     let data = await file.readAll()
     doAssert data == "foot"
@@ -24,7 +28,7 @@ proc main() {.async.} =
     var file = openAsync(fn, fmAppend)
     await file.write("\ntest2")
     let errorTest = file.readAll()
-    echo await errorTest
+    yield errorTest
     doAssert errorTest.failed
     file.close()
     file = openAsync(fn, fmRead)
@@ -33,4 +37,25 @@ proc main() {.async.} =
     doAssert data == "foot\ntest2"
     file.close()
 
+  # Issue #5531
+  block:
+    removeFile(fn)
+    var file = openAsync(fn, fmWrite)
+    await file.write("test2")
+    file.close()
+    file = openAsync(fn, fmWrite)
+    await file.write("t3")
+    file.close()
+    file = openAsync(fn, fmRead)
+    let data = await file.readAll()
+    doAssert data == "t3"
+    file.close()
+
+  # Issue #7347
+  block:
+    var file = openAsync( parentDir(currentSourcePath) / "hello.txt")
+    echo file.getFileSize()
+    echo await file.readAll()
+    echo file.getFilePos()
+
 waitFor main()
diff --git a/tests/async/tasyncfilewrite.nim b/tests/async/tasyncfilewrite.nim
new file mode 100644
index 000000000..72a2df0b0
--- /dev/null
+++ b/tests/async/tasyncfilewrite.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''string 1
+string 2
+string 3
+'''
+"""
+# bug #5532
+import os, asyncfile, asyncdispatch
+
+const F = "test_async.txt"
+
+removeFile(F)
+let f = openAsync(F, fmWrite)
+var futs = newSeq[Future[void]]()
+for i in 1..3:
+  futs.add(f.write("string " & $i & "\n"))
+waitFor(all(futs))
+f.close()
+echo readFile(F)
+removeFile(F)
diff --git a/tests/async/tasyncintemplate.nim b/tests/async/tasyncintemplate.nim
new file mode 100644
index 000000000..4bddb1d18
--- /dev/null
+++ b/tests/async/tasyncintemplate.nim
@@ -0,0 +1,62 @@
+discard """
+  output: '''
+42
+43
+43
+1
+2
+3
+4
+'''
+"""
+
+# xxx move to tests/async/tasyncintemplate.nim
+import asyncdispatch
+
+block: # bug #16159
+  template foo() =
+    proc temp(): Future[int] {.async.} = return 42
+    proc tempVoid(): Future[void] {.async.} = echo await temp()
+  foo()
+  waitFor tempVoid()
+
+block: # aliasing `void`
+  template foo() =
+    type Foo = void
+    proc temp(): Future[int] {.async.} = return 43
+    proc tempVoid(): Future[Foo] {.async.} = echo await temp()
+    proc tempVoid2() {.async.} = echo await temp()
+  foo()
+  waitFor tempVoid()
+  waitFor tempVoid2()
+
+block: # sanity check
+  template foo() =
+    proc bad(): int {.async.} = discard
+  doAssert not compiles(bad())
+
+block: # bug #16786
+  block:
+    proc main(a: int|string)=
+      proc bar(b: int|string) = echo b
+      bar(a)
+    main(1)
+
+  block:
+    proc main(a: int) : Future[void] {.async.} =
+      proc bar(b: int): Future[void] {.async.} = echo b
+      await bar(a)
+    waitFor main(2)
+
+  block:
+    proc main(a: int) : Future[void] {.async.} =
+      proc bar(b: int | string): Future[void] {.async.} = echo b
+      await bar(a)
+    waitFor main(3)
+
+  block:
+    # bug
+    proc main(a: int|string) =
+      proc bar(b: int): Future[void] {.async.} = echo b
+      waitFor bar(a)
+    main(4)
diff --git a/tests/async/tasynciossl.nim b/tests/async/tasynciossl.nim
deleted file mode 100644
index ba856760e..000000000
--- a/tests/async/tasynciossl.nim
+++ /dev/null
@@ -1,92 +0,0 @@
-discard """
-  file: "tasynciossl.nim"
-  cmd: "nim $target --hints:on --define:ssl $options $file"
-  output: "20000"
-"""
-import sockets, asyncio, strutils, times
-
-var disp {.threadvar.}: PDispatcher
-disp = newDispatcher()
-var msgCount = 0
-
-when defined(ssl):
-  var ctx = newContext(verifyMode = CVerifyNone,
-      certFile = "tests/testdata/mycert.pem", keyFile = "tests/testdata/mycert.pem")
-
-  var ctx1 = newContext(verifyMode = CVerifyNone)
-
-const
-  swarmSize = 50
-  messagesToSend = 100
-
-proc swarmConnect(s: PAsyncSocket) =
-  #echo("Connected")
-  for i in 1..messagesToSend:
-    s.send("Message " & $i & "\c\L")
-  s.close()
-
-proc serverRead(s: PAsyncSocket) =
-  var line = ""
-  assert s.readLine(line)
-  if line != "":
-    #echo(line)
-    if line.startsWith("Message "):
-      msgCount.inc()
-    else:
-      assert(false)
-  else:
-    s.close()
-
-proc serverAccept(s: PAsyncSocket) =
-  var client: PAsyncSocket
-  new(client)
-  s.accept(client)
-  client.handleRead = serverRead
-  disp.register(client)
-
-proc launchSwarm(disp: var PDispatcher, port: TPort, count: int,
-                 buffered = true, useSSL = false) =
-  for i in 1..count:
-    var client = asyncSocket()
-    when defined(ssl):
-      if useSSL:
-        ctx1.wrapSocket(client)
-    client.handleConnect = swarmConnect
-    disp.register(client)
-    client.connect("localhost", port)
-
-proc createSwarm(port: TPort, buffered = true, useSSL = false) =
-  var server = asyncSocket()
-  when defined(ssl):
-    if useSSL:
-      ctx.wrapSocket(server)
-  server.handleAccept = serverAccept
-  disp.register(server)
-  server.bindAddr(port)
-  server.listen()
-  disp.launchSwarm(port, swarmSize, buffered, useSSL)
-
-when defined(ssl):
-  const serverCount = 4
-else:
-  const serverCount = 2
-
-createSwarm(TPort(10235))
-createSwarm(TPort(10236), false)
-
-when defined(ssl):
-  createSwarm(TPort(10237), true, true)
-  createSwarm(TPort(10238), false, true)
-
-var startTime = epochTime()
-while true:
-  if epochTime() - startTime >= 300.0:
-    break
-  if not disp.poll(): break
-  if disp.len == serverCount:
-    # Only the servers are left in the dispatcher. All clients finished,
-    # we need to therefore break.
-    break
-
-assert msgCount == (swarmSize * messagesToSend) * serverCount
-echo(msgCount)
diff --git a/tests/async/tasyncnetudp.nim b/tests/async/tasyncnetudp.nim
new file mode 100644
index 000000000..dade96fb2
--- /dev/null
+++ b/tests/async/tasyncnetudp.nim
@@ -0,0 +1,90 @@
+# It is a reproduction of the 'tnewasyncudp' test code, but using a high level
+# of asynchronous procedures. Output: "5000"
+import asyncdispatch, asyncnet, nativesockets, net, strutils
+
+var msgCount = 0
+var recvCount = 0
+
+const
+  messagesToSend = 100
+  swarmSize = 50
+  serverPort = 10333
+
+var
+  sendports = 0
+  recvports = 0
+
+proc saveSendingPort(port: Port) =
+  sendports = sendports + int(port)
+
+proc saveReceivedPort(port: Port) =
+  recvports = recvports + int(port)
+
+proc launchSwarm(serverIp: string, serverPort: Port) {.async.} =
+  var i = 0
+
+  while i < swarmSize:
+    var sock = newAsyncSocket(nativesockets.AF_INET, nativesockets.SOCK_DGRAM,
+                              Protocol.IPPROTO_UDP, false)
+
+    bindAddr(sock, address = "127.0.0.1")
+
+    let (null, localPort) = getLocalAddr(sock)
+
+    var k = 0
+    
+    while k < messagesToSend:
+      let message = "Message " & $(i * messagesToSend + k)
+
+      await asyncnet.sendTo(sock, serverIp, serverPort, message)
+
+      let (data, fromIp, fromPort) = await recvFrom(sock, 16384)
+
+      if data == message:
+        saveSendingPort(localPort)
+
+        inc(recvCount)
+
+      inc(k)
+    
+    close(sock)
+
+    inc(i)
+
+proc readMessages(server: AsyncSocket) {.async.} =
+  let maxResponses = (swarmSize * messagesToSend)
+
+  var i = 0
+  
+  while i < maxResponses:
+    let (data, fromIp, fromPort) = await recvFrom(server, 16384)
+
+    if data.startsWith("Message ") and fromIp == "127.0.0.1":
+      await sendTo(server, fromIp, fromPort, data)
+
+      inc(msgCount)
+
+      saveReceivedPort(fromPort)
+
+    inc(i)
+
+proc createServer() {.async.} =
+  var server = newAsyncSocket(nativesockets.AF_INET, nativesockets.SOCK_DGRAM, Protocol.IPPROTO_UDP, false)
+  
+  bindAddr(server, Port(serverPort), "127.0.0.1")
+
+  asyncCheck readMessages(server)
+
+asyncCheck createServer()
+asyncCheck launchSwarm("127.0.0.1", Port(serverPort))
+
+while true:
+  poll()
+
+  if recvCount == swarmSize * messagesToSend:
+    break
+
+doAssert msgCount == swarmSize * messagesToSend
+doAssert sendports == recvports
+
+echo msgCount
\ No newline at end of file
diff --git a/tests/async/tasyncrecursion.nim b/tests/async/tasyncrecursion.nim
new file mode 100644
index 000000000..7c12dbb0e
--- /dev/null
+++ b/tests/async/tasyncrecursion.nim
@@ -0,0 +1,21 @@
+discard """
+output: "50005000"
+"""
+import asyncdispatch
+
+proc asyncRecursionCycle*(counter: int): Future[int] =
+  var retFuture = newFuture[int]("asyncRecursionTest")
+  retFuture.complete(counter + 1)
+  return retFuture
+
+proc asyncRecursionTest*(): Future[int] {.async.} =
+  var i = 0
+  result = 0
+  while i < 10_000:
+    inc(result, await asyncRecursionCycle(i))
+    inc(i)
+
+when true:
+  setGlobalDispatcher(newDispatcher())
+  var i = waitFor asyncRecursionTest()
+  echo i
diff --git a/tests/async/tasyncsend4757.nim b/tests/async/tasyncsend4757.nim
new file mode 100644
index 000000000..29873a905
--- /dev/null
+++ b/tests/async/tasyncsend4757.nim
@@ -0,0 +1,24 @@
+import asyncdispatch, asyncnet
+
+var port: Port
+proc createServer() {.async.} =
+  var server = newAsyncSocket()
+  server.setSockOpt(OptReuseAddr, true)
+  bindAddr(server)
+  port = getLocalAddr(server)[1]
+  server.listen()
+  while true:
+    let client = await server.accept()
+    discard await client.recvLine()
+
+asyncCheck createServer()
+
+var done = false
+proc f(): Future[void] {.async.} =
+  let s = createAsyncNativeSocket()
+  await s.connect("localhost", port)
+  await s.send("123")
+  done = true
+
+waitFor f()
+doAssert done
diff --git a/tests/async/tasyncssl.nim b/tests/async/tasyncssl.nim
new file mode 100644
index 000000000..57de3271d
--- /dev/null
+++ b/tests/async/tasyncssl.nim
@@ -0,0 +1,74 @@
+discard """
+  cmd: "nim $target --hints:on --define:ssl $options $file"
+  disabled: osx
+"""
+
+import asyncdispatch, asyncnet, net, strutils
+import stdtest/testutils
+
+when defined(ssl):
+  var port0: Port
+  var msgCount = 0
+
+  const
+    swarmSize = 10
+    messagesToSend = 50
+
+  var clientCount = 0
+
+  proc sendMessages(client: AsyncSocket) {.async.} =
+    for i in 0 ..< messagesToSend:
+      await send(client, "Message " & $i & "\c\L")
+
+  proc launchSwarm(port: Port) {.async.} =
+    for i in 0 ..< swarmSize:
+      var sock = newAsyncSocket()
+      var clientContext = newContext(verifyMode = CVerifyNone)
+      clientContext.wrapSocket(sock)
+      await connect(sock, "localhost", port)
+      await sendMessages(sock)
+      close(sock)
+
+  proc readMessages(client: AsyncSocket) {.async.} =
+    while true:
+      var line = await recvLine(client)
+      if line == "":
+        close(client)
+        inc(clientCount)
+        break
+      else:
+        if line.startsWith("Message "):
+          inc(msgCount)
+        else:
+          doAssert false
+
+  proc createServer() {.async.} =
+    let serverContext = newContext(verifyMode = CVerifyNone,
+                                   certFile = "tests/testdata/mycert.pem",
+                                   keyFile = "tests/testdata/mycert.pem")
+    var server = newAsyncSocket()
+    serverContext.wrapSocket(server)
+    server.setSockOpt(OptReuseAddr, true)
+    bindAddr(server)
+    port0 = getLocalAddr(server)[1]
+    server.listen()
+    while true:
+      let client = await accept(server)
+      serverContext.wrapConnectedSocket(client, handshakeAsServer)
+      asyncCheck readMessages(client)
+
+  asyncCheck createServer()
+  asyncCheck launchSwarm(port0)
+  while true:
+    poll()
+    if clientCount == swarmSize: break
+
+  template cond(): bool = msgCount == swarmSize * messagesToSend
+  when defined(windows):
+    # currently: msgCount == 0
+    flakyAssert cond()
+  elif defined(linux) and int.sizeof == 8:
+    # currently:  msgCount == 10
+    flakyAssert cond()
+    doAssert msgCount > 0
+  else: doAssert cond(), $msgCount
diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim
index 5930f296f..25eab87fb 100644
--- a/tests/async/tasynctry.nim
+++ b/tests/async/tasynctry.nim
@@ -1,51 +1,51 @@
 discard """
-  file: "tasynctry.nim"
-  exitcode: 0
-  output: '''
+output: '''
 Generic except: Test
 Specific except
 Multiple idents in except
 Multiple except branches
 Multiple except branches 2
+success
 '''
+targets: "c"
 """
-import asyncdispatch
+import asyncdispatch, strutils
 
 # Here we are testing the ability to catch exceptions.
 
 proc foobar() {.async.} =
   if 5 == 5:
-    raise newException(EInvalidIndex, "Test")
+    raise newException(IndexDefect, "Test")
 
 proc catch() {.async.} =
   # TODO: Create a test for when exceptions are not caught.
   try:
     await foobar()
   except:
-    echo("Generic except: ", getCurrentExceptionMsg())
+    echo("Generic except: ", getCurrentExceptionMsg().splitLines[0])
 
   try:
     await foobar()
-  except EInvalidIndex:
+  except IndexDefect:
     echo("Specific except")
 
   try:
     await foobar()
-  except OSError, EInvalidField, EInvalidIndex:
+  except OSError, FieldDefect, IndexDefect:
     echo("Multiple idents in except")
 
   try:
     await foobar()
-  except OSError, EInvalidField:
+  except OSError, FieldDefect:
     assert false
-  except EInvalidIndex:
+  except IndexDefect:
     echo("Multiple except branches")
 
   try:
     await foobar()
-  except EInvalidIndex:
+  except IndexDefect:
     echo("Multiple except branches 2")
-  except OSError, EInvalidField:
+  except OSError, FieldDefect:
     assert false
 
 waitFor catch()
@@ -102,3 +102,17 @@ assert y.waitFor() == 2
 
 y = test4()
 assert y.waitFor() == 2
+
+# bug #14279
+
+proc expandValue: Future[int] {.async.} =
+  return 0
+
+proc a(b: int): Future[void] {.async.} =
+  return
+
+proc b: Future[void] {.async.} =
+  await a(await expandValue())
+  echo "success"
+
+waitFor(b())
diff --git a/tests/async/tasynctry2.nim b/tests/async/tasynctry2.nim
deleted file mode 100644
index 444a058be..000000000
--- a/tests/async/tasynctry2.nim
+++ /dev/null
@@ -1,16 +0,0 @@
-discard """
-  file: "tasynctry2.nim"
-  errormsg: "\'yield\' cannot be used within \'try\' in a non-inlined iterator"
-  line: 15
-"""
-import asyncdispatch
-
-proc foo(): Future[bool] {.async.} = discard
-
-proc test5(): Future[int] {.async.} =
-  try:
-    discard await foo()
-    raise newException(ValueError, "Test5")
-  except:
-    discard await foo()
-    result = 0
diff --git a/tests/async/tasyncudp.nim b/tests/async/tasyncudp.nim
deleted file mode 100644
index 57e2be85d..000000000
--- a/tests/async/tasyncudp.nim
+++ /dev/null
@@ -1,78 +0,0 @@
-discard """
-  file: "tasyncudp.nim"
-  output: "2000"
-"""
-import asyncio, sockets, strutils, times
-
-const
-  swarmSize = 5
-  messagesToSend = 200
-
-var
-  disp = newDispatcher()
-  msgCount = 0
-  currentClient = 0
-
-proc serverRead(s: PAsyncSocket) =
-  var data = ""
-  var address = ""
-  var port: TPort
-  if s.recvFromAsync(data, 9, address, port):
-    assert address == "127.0.0.1"
-    msgCount.inc()
-
-  discard """
-
-  var line = ""
-  assert s.recvLine(line)
-
-  if line == "":
-    assert(false)
-  else:
-    if line.startsWith("Message "):
-      msgCount.inc()
-    else:
-      assert(false)
-  """
-
-proc swarmConnect(s: PAsyncSocket) =
-  for i in 1..messagesToSend:
-    s.send("Message\c\L")
-
-proc createClient(disp: var PDispatcher, port: TPort,
-                  buffered = true) =
-  currentClient.inc()
-  var client = asyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP,
-                           buffered = buffered)
-  client.handleConnect = swarmConnect
-  disp.register(client)
-  client.connect("localhost", port)
-
-proc createServer(port: TPort, buffered = true) =
-  var server = asyncSocket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP,
-                           buffered = buffered)
-  server.handleRead = serverRead
-  disp.register(server)
-  server.bindAddr(port)
-
-let serverCount = 2
-
-createServer(TPort(10335), false)
-createServer(TPort(10336), true)
-var startTime = epochTime()
-while true:
-  if epochTime() - startTime >= 300.0:
-    break
-
-  if not disp.poll():
-    break
-
-  if (msgCount div messagesToSend) * serverCount == currentClient:
-    createClient(disp, TPort(10335), false)
-    createClient(disp, TPort(10336), true)
-
-  if msgCount == messagesToSend * serverCount * swarmSize:
-    break
-
-assert msgCount == messagesToSend * serverCount * swarmSize
-echo(msgCount)
diff --git a/tests/async/tawaitsemantics.nim b/tests/async/tawaitsemantics.nim
index 3e0c3903e..67903cc5e 100644
--- a/tests/async/tawaitsemantics.nim
+++ b/tests/async/tawaitsemantics.nim
@@ -1,18 +1,20 @@
 discard """
-  file: "tawaitsemantics.nim"
-  exitcode: 0
-  output: '''
-Error caught
-Test infix
-Test call
+output: '''
+Error can be caught using yield
+Infix `or` raises
+Infix `and` raises
+All() raises
+Awaiting a async procedure call raises
+Awaiting a future raises
 '''
 """
 
 import asyncdispatch
 
 # This tests the behaviour of 'await' under different circumstances.
-# For example, when awaiting Future variable and this future has failed the
-# exception shouldn't be raised as described here
+# Specifically, when an awaited future raises an exception then `await` should
+# also raise that exception by `read`'ing that future. In cases where you don't
+# want this behaviour, you can use `yield`.
 # https://github.com/nim-lang/Nim/issues/4170
 
 proc thrower(): Future[void] =
@@ -23,37 +25,71 @@ proc dummy: Future[void] =
   result = newFuture[void]()
   result.complete()
 
-proc testInfix() {.async.} =
-  # Test the infix operator semantics.
+proc testInfixOr() {.async.} =
+  # Test the infix `or` operator semantics.
   var fut = thrower()
   var fut2 = dummy()
-  await fut or fut2 # Shouldn't raise.
-  # TODO: what about: await thrower() or fut2?
+  await fut or fut2 # Should raise!
+
+proc testInfixAnd() {.async.} =
+  # Test the infix `and` operator semantics.
+  var fut = thrower()
+  var fut2 = dummy()
+  await fut and fut2 # Should raise!
+
+proc testAll() {.async.} =
+  # Test the `all` semantics.
+  var fut = thrower()
+  var fut2 = dummy()
+  await all(fut, fut2) # Should raise!
 
 proc testCall() {.async.} =
   await thrower()
 
+proc testAwaitFut() {.async.} =
+  var fut = thrower()
+  await fut # This should raise.
+
 proc tester() {.async.} =
   # Test that we can handle exceptions without 'try'
   var fut = thrower()
   doAssert fut.finished
   doAssert fut.failed
   doAssert fut.error.msg == "Test"
-  await fut # We are awaiting a 'Future', so no `read` occurs.
+  yield fut # We are yielding a 'Future', so no `read` occurs.
   doAssert fut.finished
   doAssert fut.failed
   doAssert fut.error.msg == "Test"
-  echo("Error caught")
+  echo("Error can be caught using yield")
+
+  fut = testInfixOr()
+  yield fut
+  doAssert fut.finished
+  doAssert fut.failed
+  echo("Infix `or` raises")
 
-  fut = testInfix()
-  await fut
+  fut = testInfixAnd()
+  yield fut
   doAssert fut.finished
-  doAssert(not fut.failed)
-  echo("Test infix")
+  doAssert fut.failed
+  echo("Infix `and` raises")
+
+  fut = testAll()
+  yield fut
+  doAssert fut.finished
+  doAssert fut.failed
+  echo("All() raises")
 
   fut = testCall()
-  await fut
+  yield fut
+  doAssert fut.failed
+  echo("Awaiting a async procedure call raises")
+
+  # Test that await will read the future and raise an exception.
+  fut = testAwaitFut()
+  yield fut
   doAssert fut.failed
-  echo("Test call")
+  echo("Awaiting a future raises")
+
 
 waitFor(tester())
diff --git a/tests/async/tbreak_must_exec_finally.nim b/tests/async/tbreak_must_exec_finally.nim
new file mode 100644
index 000000000..8780e6149
--- /dev/null
+++ b/tests/async/tbreak_must_exec_finally.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''
+finally handler 8
+do not duplicate this one
+'''
+"""
+
+# bug #15243
+
+import asyncdispatch
+
+proc f() {.async.} =
+  try:
+    while true:
+      try:
+        await sleepAsync(400)
+        break
+      finally:
+        var localHere = 8
+        echo "finally handler ", localHere
+  finally:
+    echo "do not duplicate this one"
+
+when isMainModule:
+  waitFor f()
diff --git a/tests/async/tcallbacks.nim b/tests/async/tcallbacks.nim
new file mode 100644
index 000000000..bd82d5824
--- /dev/null
+++ b/tests/async/tcallbacks.nim
@@ -0,0 +1,21 @@
+discard """
+  exitcode: 0
+  output: '''
+1
+2
+3
+5
+'''
+"""
+import asyncfutures
+
+let f1: Future[int] = newFuture[int]()
+f1.addCallback(proc() = echo 1)
+f1.addCallback(proc() = echo 2)
+f1.addCallback(proc() = echo 3)
+f1.complete(10)
+
+let f2: Future[int] = newFuture[int]()
+f2.addCallback(proc() = echo 4)
+f2.callback = proc() = echo 5
+f2.complete(10)
diff --git a/tests/async/tdiscardableproc.nim b/tests/async/tdiscardableproc.nim
new file mode 100644
index 000000000..93cd83be9
--- /dev/null
+++ b/tests/async/tdiscardableproc.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "Cannot make async proc discardable. Futures have to be checked with `asyncCheck` instead of discarded"
+"""
+
+import async
+
+proc foo {.async, discardable.} = discard
+
+foo()
diff --git a/tests/async/testmanyasyncevents.nim b/tests/async/testmanyasyncevents.nim
new file mode 100644
index 000000000..9fdd01b4f
--- /dev/null
+++ b/tests/async/testmanyasyncevents.nim
@@ -0,0 +1,24 @@
+discard """
+output: '''
+hasPendingOperations: false
+triggerCount: 100
+'''
+disabled: "windows"
+"""
+
+import asyncDispatch
+
+var triggerCount = 0
+var evs = newSeq[AsyncEvent]()
+
+for i in 0 ..< 100: # has to be lower than the typical physical fd limit
+  var ev = newAsyncEvent()
+  evs.add(ev)
+  addEvent(ev, proc(fd: AsyncFD): bool {.gcsafe,closure.} = triggerCount += 1; true)
+
+for ev in evs:
+  ev.trigger()
+
+drain()
+echo "hasPendingOperations: ", hasPendingOperations()
+echo "triggerCount: ", triggerCount
diff --git a/tests/async/tfuturestream.nim b/tests/async/tfuturestream.nim
new file mode 100644
index 000000000..a019df400
--- /dev/null
+++ b/tests/async/tfuturestream.nim
@@ -0,0 +1,71 @@
+discard """
+output: '''
+0
+1
+2
+3
+4
+5
+Done
+Finished
+'''
+"""
+import asyncdispatch
+
+var fs = newFutureStream[int]()
+
+proc alpha() {.async.} =
+  for i in 0 .. 5:
+    await fs.write(i)
+    await sleepAsync(100)
+
+  echo("Done")
+  fs.complete()
+
+proc beta() {.async.} =
+  while not fs.finished:
+    let (hasValue, value) = await fs.read()
+    if hasValue:
+      echo(value)
+
+  echo("Finished")
+
+asyncCheck alpha()
+waitFor beta()
+
+template ensureCallbacksAreScheduled =
+  # callbacks are called directly if the dispatcher is not running
+  discard getGlobalDispatcher()
+
+proc testCompletion() {.async.} =
+  ensureCallbacksAreScheduled
+
+  var stream = newFutureStream[string]()
+
+  for i in 1..5:
+    await stream.write($i)
+
+  var readFuture = stream.readAll()
+  stream.complete()
+  yield readFuture
+  let data = readFuture.read()
+  doAssert(data.len == 5, "actual data len = " & $data.len)
+
+waitFor testCompletion()
+
+# TODO: Something like this should work eventually.
+# proc delta(): FutureStream[string] {.async.} =
+#   for i in 0 .. 5:
+#     await sleepAsync(1000)
+#     result.put($i)
+
+#   return ""
+
+# proc omega() {.async.} =
+#   let fut = delta()
+#   while not fut.finished():
+#     echo(await fs.takeAsync())
+
+#   echo("Finished")
+
+# waitFor omega()
diff --git a/tests/async/tfuturevar.nim b/tests/async/tfuturevar.nim
new file mode 100644
index 000000000..b70f1d166
--- /dev/null
+++ b/tests/async/tfuturevar.nim
@@ -0,0 +1,46 @@
+import asyncdispatch
+
+proc completeOnReturn(fut: FutureVar[string], x: bool) {.async.} =
+  if x:
+    fut.mget() = ""
+    fut.mget.add("foobar")
+    return
+
+proc completeOnImplicitReturn(fut: FutureVar[string], x: bool) {.async.} =
+  if x:
+    fut.mget() = ""
+    fut.mget.add("foobar")
+
+proc failureTest(fut: FutureVar[string], x: bool) {.async.} =
+  if x:
+    raise newException(Exception, "Test")
+
+proc manualComplete(fut: FutureVar[string], x: bool) {.async.} =
+  if x:
+    fut.mget() = "Hello World"
+    fut.complete()
+    return
+
+proc main() {.async.} =
+  var fut: FutureVar[string]
+
+  fut = newFutureVar[string]()
+  await completeOnReturn(fut, true)
+  doAssert(fut.read() == "foobar")
+
+  fut = newFutureVar[string]()
+  await completeOnImplicitReturn(fut, true)
+  doAssert(fut.read() == "foobar")
+
+  fut = newFutureVar[string]()
+  let retFut = failureTest(fut, true)
+  yield retFut
+  doAssert(fut.read().len == 0)
+  doAssert(fut.finished)
+
+  fut = newFutureVar[string]()
+  await manualComplete(fut, true)
+  doAssert(fut.read() == "Hello World")
+
+
+waitFor main()
diff --git a/tests/async/tgeneric_async.nim b/tests/async/tgeneric_async.nim
index af6370181..bab2d1a31 100644
--- a/tests/async/tgeneric_async.nim
+++ b/tests/async/tgeneric_async.nim
@@ -1,9 +1,40 @@
+discard """
+output: "1\nmessa"
+"""
 
-import asyncdispatch
+import async
 
-when true:
-  # bug #2377
-  proc test[T](v: T) {.async.} =
-    echo $v
+# bug #2377
+proc test[T](v: T) {.async.} =
+  echo $v
+
+asyncCheck test[int](1)
+
+# More complex case involving typedesc and static params
+type
+  SomeMsg = object
+    data: string
+
+template msgId(M: type SomeMsg): int = 1
+
+proc recvMsg(): Future[tuple[msgId: int, msgData: string]] {.async.} =
+  return (1, "message")
+
+proc read(data: string, T: type SomeMsg, maxBytes: int): T =
+  result.data = data[0 ..< min(data.len, maxBytes)]
+
+proc nextMsg*(MsgType: typedesc,
+              maxBytes: static[int]): Future[MsgType] {.async.} =
+  const wantedId = MsgType.msgId
+
+  while true:
+    var (nextMsgId, nextMsgData) = await recvMsg()
+    if nextMsgId == wantedId:
+      return nextMsgData.read(MsgType, maxBytes)
+
+proc main {.async.} =
+  let msg = await nextMsg(SomeMsg, 5)
+  echo msg.data
+
+asyncCheck main()
 
-  asyncCheck test[int](1)
diff --git a/tests/async/tgenericasync.nim b/tests/async/tgenericasync.nim
new file mode 100644
index 000000000..ab704238a
--- /dev/null
+++ b/tests/async/tgenericasync.nim
@@ -0,0 +1,14 @@
+discard """
+  output: '''123
+abc'''
+"""
+
+# bug #4856
+
+import asyncdispatch
+
+proc say[T](t: T): Future[void] {.async.} =
+  echo $t
+
+waitFor(say(123))
+waitFor(say("abc"))
diff --git a/tests/async/tioselectors.nim b/tests/async/tioselectors.nim
index ed2fea84f..f53767408 100644
--- a/tests/async/tioselectors.nim
+++ b/tests/async/tioselectors.nim
@@ -1,8 +1,7 @@
 discard """
-  file: "tioselectors.nim"
   output: "All tests passed!"
 """
-import ioselectors
+import selectors
 
 const hasThreadSupport = compileOption("threads")
 
@@ -12,11 +11,10 @@ template processTest(t, x: untyped) =
   if not x: echo(t & " FAILED\r\n")
 
 when not defined(windows):
-  import os, posix, osproc, nativesockets, times
+  import os, posix, nativesockets
 
-  const supportedPlatform = defined(macosx) or defined(freebsd) or
-                            defined(netbsd) or defined(openbsd) or
-                            defined(linux)
+  when ioselSupportedPlatform:
+    import osproc
 
   proc socket_notification_test(): bool =
     proc create_test_socket(): SocketHandle =
@@ -38,9 +36,6 @@ when not defined(windows):
     var client_socket = create_test_socket()
     var server_socket = create_test_socket()
 
-    registerHandle(selector, server_socket, {Event.Read}, 0)
-    registerHandle(selector, client_socket, {Event.Write}, 0)
-
     var option : int32 = 1
     if setsockopt(server_socket, cint(SOL_SOCKET), cint(SO_REUSEADDR),
                   addr(option), sizeof(option).SockLen) < 0:
@@ -49,18 +44,25 @@ when not defined(windows):
     var aiList = getAddrInfo("0.0.0.0", Port(13337))
     if bindAddr(server_socket, aiList.ai_addr,
                 aiList.ai_addrlen.Socklen) < 0'i32:
-      dealloc(aiList)
+      freeAddrInfo(aiList)
       raiseOSError(osLastError())
-    discard server_socket.listen()
-    dealloc(aiList)
+    if server_socket.listen() == -1:
+      raiseOSError(osLastError())
+    freeAddrInfo(aiList)
 
     aiList = getAddrInfo("127.0.0.1", Port(13337))
     discard posix.connect(client_socket, aiList.ai_addr,
                           aiList.ai_addrlen.Socklen)
-    dealloc(aiList)
-    discard selector.select(100)
-    var rc1 = selector.select(100)
-    assert(len(rc1) == 2)
+
+    registerHandle(selector, server_socket, {Event.Read}, 0)
+    registerHandle(selector, client_socket, {Event.Write}, 0)
+
+    freeAddrInfo(aiList)
+
+    # make sure both sockets are selected
+    var nevs = 0
+    while nevs < 2:
+      nevs += selector.select(100).len
 
     var sockAddress: SockAddr
     var addrLen = sizeof(sockAddress).Socklen
@@ -79,7 +81,7 @@ when not defined(windows):
     var rc2 = selector.select(100)
     assert(len(rc2) == 1)
 
-    var read_count = posix.recv(server2_socket, addr (buffer[0]), 128, 0)
+    var read_count = posix.recv(server2_socket, addr buffer[0], 128, 0)
     if read_count == -1:
       raiseOSError(osLastError())
 
@@ -127,15 +129,15 @@ when not defined(windows):
     var selector = newSelector[int]()
     var event = newSelectEvent()
     selector.registerEvent(event, 1)
-    selector.flush()
-    event.setEvent()
+    var rc0 = selector.select(0)
+    event.trigger()
     var rc1 = selector.select(0)
-    event.setEvent()
+    event.trigger()
     var rc2 = selector.select(0)
     var rc3 = selector.select(0)
-    assert(len(rc1) == 1 and len(rc2) == 1 and len(rc3) == 0)
-    var ev1 = rc1[0].data
-    var ev2 = rc2[0].data
+    assert(len(rc0) == 0 and len(rc1) == 1 and len(rc2) == 1 and len(rc3) == 0)
+    var ev1 = selector.getData(rc1[0].fd)
+    var ev2 = selector.getData(rc2[0].fd)
     assert(ev1 == 1 and ev2 == 1)
     selector.unregister(event)
     event.close()
@@ -143,28 +145,29 @@ when not defined(windows):
     selector.close()
     result = true
 
-  when supportedPlatform:
+  when ioselSupportedPlatform:
     proc timer_notification_test(): bool =
       var selector = newSelector[int]()
       var timer = selector.registerTimer(100, false, 0)
-      var rc1 = selector.select(140)
-      var rc2 = selector.select(140)
-      assert(len(rc1) == 1 and len(rc2) == 1)
+      var rc1 = selector.select(10000)
+      var rc2 = selector.select(10000)
+      # if this flakes, see tests/m14634.nim
+      assert len(rc1) == 1 and len(rc2) == 1, $(len(rc1), len(rc2))
       selector.unregister(timer)
-      selector.flush()
+      discard selector.select(0)
       selector.registerTimer(100, true, 0)
-      var rc3 = selector.select(120)
-      var rc4 = selector.select(120)
-      assert(len(rc3) == 1 and len(rc4) == 0)
+      var rc4 = selector.select(10000)
+      var rc5 = selector.select(1000) # this will be an actual wait, keep it small
+      assert len(rc4) == 1 and len(rc5) == 0, $(len(rc4), len(rc5))
       assert(selector.isEmpty())
       selector.close()
       result = true
 
     proc process_notification_test(): bool =
       var selector = newSelector[int]()
-      var process2 = startProcess("/bin/sleep", "", ["2"], nil,
+      var process2 = startProcess("sleep", "", ["2"], nil,
                            {poStdErrToStdOut, poUsePath})
-      discard startProcess("/bin/sleep", "", ["1"], nil,
+      discard startProcess("sleep", "", ["1"], nil,
                            {poStdErrToStdOut, poUsePath})
 
       selector.registerProcess(process2.processID, 0)
@@ -194,12 +197,14 @@ when not defined(windows):
       var s1 = selector.registerSignal(SIGUSR1, 1)
       var s2 = selector.registerSignal(SIGUSR2, 2)
       var s3 = selector.registerSignal(SIGTERM, 3)
-      selector.flush()
-
+      discard selector.select(0)
       discard posix.kill(pid, SIGUSR1)
       discard posix.kill(pid, SIGUSR2)
       discard posix.kill(pid, SIGTERM)
       var rc = selector.select(0)
+      var cd0 = selector.getData(rc[0].fd)
+      var cd1 = selector.getData(rc[1].fd)
+      var cd2 = selector.getData(rc[2].fd)
       selector.unregister(s1)
       selector.unregister(s2)
       selector.unregister(s3)
@@ -212,11 +217,234 @@ when not defined(windows):
           raiseOSError(osLastError())
 
       assert(len(rc) == 3)
-      assert(rc[0].data + rc[1].data + rc[2].data == 6) # 1 + 2 + 3
+      assert(cd0 + cd1 + cd2 == 6, $(cd0 + cd1 + cd2)) # 1 + 2 + 3
       assert(equalMem(addr sigset1o, addr sigset2o, sizeof(Sigset)))
       assert(selector.isEmpty())
       result = true
 
+  when defined(macosx) or defined(freebsd) or defined(openbsd) or
+       defined(netbsd):
+
+    proc rename(frompath: cstring, topath: cstring): cint
+       {.importc: "rename", header: "<stdio.h>".}
+
+    proc createFile(name: string): cint =
+      result = posix.open(cstring(name), posix.O_CREAT or posix.O_RDWR)
+      if result == -1:
+        raiseOsError(osLastError())
+
+    proc writeFile(name: string, data: string) =
+      let fd = posix.open(cstring(name), posix.O_APPEND or posix.O_RDWR)
+      if fd == -1:
+        raiseOsError(osLastError())
+      let length = len(data).cint
+      if posix.write(fd, cast[pointer](addr data[0]),
+                     len(data).cint) != length:
+        raiseOsError(osLastError())
+      if posix.close(fd) == -1:
+        raiseOsError(osLastError())
+
+    proc closeFile(fd: cint) =
+      if posix.close(fd) == -1:
+        raiseOsError(osLastError())
+
+    proc removeFile(name: string) =
+      let err = posix.unlink(cstring(name))
+      if err == -1:
+        raiseOsError(osLastError())
+
+    proc createDir(name: string) =
+      let err = posix.mkdir(cstring(name), 0x1FF)
+      if err == -1:
+        raiseOsError(osLastError())
+
+    proc removeDir(name: string) =
+      let err = posix.rmdir(cstring(name))
+      if err == -1:
+        raiseOsError(osLastError())
+
+    proc chmodPath(name: string, mode: cint) =
+      let err = posix.chmod(cstring(name), Mode(mode))
+      if err == -1:
+        raiseOsError(osLastError())
+
+    proc renameFile(names: string, named: string) =
+      let err = rename(cstring(names), cstring(named))
+      if err == -1:
+        raiseOsError(osLastError())
+
+    proc symlink(names: string, named: string) =
+      let err = posix.symlink(cstring(names), cstring(named))
+      if err == -1:
+        raiseOsError(osLastError())
+
+    proc openWatch(name: string): cint =
+      result = posix.open(cstring(name), posix.O_RDONLY)
+      if result == -1:
+        raiseOsError(osLastError())
+
+    const
+      testDirectory = "/tmp/kqtest"
+
+    type
+      valType = object
+        fd: cint
+        events: set[Event]
+
+    proc vnode_test(): bool =
+      proc validate(test: openArray[ReadyKey],
+                    check: openArray[valType]): bool =
+        result = false
+        if len(test) == len(check):
+          for checkItem in check:
+            result = false
+            for testItem in test:
+              if testItem.fd == checkItem.fd and
+                 checkItem.events <= testItem.events:
+                result = true
+                break
+            if not result:
+              break
+
+      var res: seq[ReadyKey]
+      var selector = newSelector[int]()
+      var events = {Event.VnodeWrite, Event.VnodeDelete, Event.VnodeExtend,
+                    Event.VnodeAttrib, Event.VnodeLink, Event.VnodeRename,
+                    Event.VnodeRevoke}
+
+      result = true
+      discard posix.unlink(testDirectory)
+
+      createDir(testDirectory)
+      var dirfd = posix.open(cstring(testDirectory), posix.O_RDONLY)
+      if dirfd == -1:
+        raiseOsError(osLastError())
+
+      selector.registerVnode(dirfd, events, 1)
+      discard selector.select(0)
+
+      # chmod testDirectory to 0777
+      chmodPath(testDirectory, 0x1FF)
+      res = selector.select(0)
+      doAssert(len(res) == 1)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(res[0].fd == dirfd and
+               {Event.Vnode, Event.VnodeAttrib} <= res[0].events)
+
+      # create subdirectory
+      createDir(testDirectory & "/test")
+      res = selector.select(0)
+      doAssert(len(res) == 1)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(res[0].fd == dirfd and
+               {Event.Vnode, Event.VnodeWrite,
+                Event.VnodeLink} <= res[0].events)
+
+      # open test directory for watching
+      var testfd = openWatch(testDirectory & "/test")
+      selector.registerVnode(testfd, events, 2)
+      doAssert(len(selector.select(0)) == 0)
+
+      # rename test directory
+      renameFile(testDirectory & "/test", testDirectory & "/renamed")
+      res = selector.select(0)
+      doAssert(len(res) == 2)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(validate(res,
+                 [valType(fd: dirfd, events: {Event.Vnode, Event.VnodeWrite}),
+                  valType(fd: testfd,
+                          events: {Event.Vnode, Event.VnodeRename})])
+              )
+
+      # remove test directory
+      removeDir(testDirectory & "/renamed")
+      res = selector.select(0)
+      doAssert(len(res) == 2)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(validate(res,
+                 [valType(fd: dirfd, events: {Event.Vnode, Event.VnodeWrite,
+                                              Event.VnodeLink}),
+                  valType(fd: testfd,
+                          events: {Event.Vnode, Event.VnodeDelete})])
+              )
+      # create file new test file
+      testfd = createFile(testDirectory & "/testfile")
+      res = selector.select(0)
+      doAssert(len(res) == 1)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(res[0].fd == dirfd and
+               {Event.Vnode, Event.VnodeWrite} <= res[0].events)
+
+      # close new test file
+      closeFile(testfd)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(len(selector.select(0)) == 0)
+
+      # chmod test file with 0666
+      chmodPath(testDirectory & "/testfile", 0x1B6)
+      doAssert(len(selector.select(0)) == 0)
+
+      testfd = openWatch(testDirectory & "/testfile")
+      selector.registerVnode(testfd, events, 1)
+      discard selector.select(0)
+
+      # write data to test file
+      writeFile(testDirectory & "/testfile", "TESTDATA")
+      res = selector.select(0)
+      doAssert(len(res) == 1)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(res[0].fd == testfd and
+              {Event.Vnode, Event.VnodeWrite,
+               Event.VnodeExtend} <= res[0].events)
+
+      # symlink test file
+      symlink(testDirectory & "/testfile", testDirectory & "/testlink")
+      res = selector.select(0)
+      doAssert(len(res) == 1)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(res[0].fd == dirfd and
+               {Event.Vnode, Event.VnodeWrite} <= res[0].events)
+
+      # remove test file
+      removeFile(testDirectory & "/testfile")
+      res = selector.select(0)
+      doAssert(len(res) == 2)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(validate(res,
+                [valType(fd: testfd, events: {Event.Vnode, Event.VnodeDelete}),
+                 valType(fd: dirfd, events: {Event.Vnode, Event.VnodeWrite})])
+              )
+
+      # remove symlink
+      removeFile(testDirectory & "/testlink")
+      res = selector.select(0)
+      doAssert(len(res) == 1)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(res[0].fd == dirfd and
+               {Event.Vnode, Event.VnodeWrite} <= res[0].events)
+
+      # remove testDirectory
+      removeDir(testDirectory)
+      res = selector.select(0)
+      doAssert(len(res) == 1)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(res[0].fd == dirfd and
+               {Event.Vnode, Event.VnodeDelete} <= res[0].events)
+
+  proc pipe_test(): bool =
+    # closing the read end of a pipe will result in it automatically
+    # being removed from the kqueue; make sure no exception is raised
+    var s = newSelector[int]()
+    var fds: array[2, cint]
+    discard pipe(fds)
+    s.registerHandle(fds[1], {Write}, 0)
+    discard close(fds[0])
+    let res = s.select(-1)
+    doAssert(res.len == 1)
+    s.unregister(fds[1])
+    discard close(fds[1])
+    return true
+
   when hasThreadSupport:
 
     var counter = 0
@@ -224,7 +452,6 @@ when not defined(windows):
     proc event_wait_thread(event: SelectEvent) {.thread.} =
       var selector = newSelector[int]()
       selector.registerEvent(event, 1)
-      selector.flush()
       var rc = selector.select(1000)
       if len(rc) == 1:
         inc(counter)
@@ -233,16 +460,16 @@ when not defined(windows):
 
     proc mt_event_test(): bool =
       var
-        thr: array [0..7, Thread[SelectEvent]]
+        thr: array[0..7, Thread[SelectEvent]]
       var selector = newSelector[int]()
-      var sock = newNativeSocket()
+      var sock = createNativeSocket()
       var event = newSelectEvent()
       for i in 0..high(thr):
         createThread(thr[i], event_wait_thread, event)
       selector.registerHandle(sock, {Event.Read}, 1)
       discard selector.select(500)
       selector.unregister(sock)
-      event.setEvent()
+      event.trigger()
       joinThreads(thr)
       assert(counter == 1)
       result = true
@@ -252,17 +479,21 @@ when not defined(windows):
   when hasThreadSupport:
     processTest("Multithreaded user event notification test...",
                 mt_event_test())
-  when supportedPlatform:
+  when ioselSupportedPlatform:
     processTest("Timer notification test...", timer_notification_test())
     processTest("Process notification test...", process_notification_test())
     processTest("Signal notification test...", signal_notification_test())
+  when defined(macosx) or defined(freebsd) or defined(openbsd) or
+       defined(netbsd):
+    processTest("File notification test...", vnode_test())
+    processTest("Pipe test...", pipe_test())
   echo("All tests passed!")
 else:
   import nativesockets, winlean, os, osproc
 
   proc socket_notification_test(): bool =
     proc create_test_socket(): SocketHandle =
-      var sock = newNativeSocket()
+      var sock = createNativeSocket()
       setBlocking(sock, false)
       result = sock
 
@@ -285,19 +516,24 @@ else:
     var aiList = getAddrInfo("0.0.0.0", Port(13337))
     if bindAddr(server_socket, aiList.ai_addr,
                 aiList.ai_addrlen.Socklen) < 0'i32:
-      dealloc(aiList)
+      freeAddrInfo(aiList)
       raiseOSError(osLastError())
     discard server_socket.listen()
-    dealloc(aiList)
+    freeAddrInfo(aiList)
 
     aiList = getAddrInfo("127.0.0.1", Port(13337))
     discard connect(client_socket, aiList.ai_addr,
                     aiList.ai_addrlen.Socklen)
-    dealloc(aiList)
+    freeAddrInfo(aiList)
     # for some reason Windows select doesn't return both
     # descriptors from first call, so we need to make 2 calls
-    discard selector.select(100)
-    var rcm = selector.select(100)
+    var n = 0
+    var rcm = selector.select(1000)
+    while n < 10 and len(rcm) < 2:
+      sleep(1000)
+      rcm = selector.select(1000)
+      inc(n)
+
     assert(len(rcm) == 2)
 
     var sockAddress = SockAddr()
@@ -314,10 +550,10 @@ else:
 
     selector.updateHandle(client_socket, {Event.Read})
 
-    var rc2 = selector.select(100)
+    var rc2 = selector.select(1000)
     assert(len(rc2) == 1)
 
-    var read_count = recv(server2_socket, addr (buffer[0]), 128, 0)
+    var read_count = recv(server2_socket, addr buffer[0], 128, 0)
     if read_count == -1:
       raiseOSError(osLastError())
 
@@ -361,15 +597,15 @@ else:
     var selector = newSelector[int]()
     var event = newSelectEvent()
     selector.registerEvent(event, 1)
-    selector.flush()
-    event.setEvent()
+    discard selector.select(0)
+    event.trigger()
     var rc1 = selector.select(0)
-    event.setEvent()
+    event.trigger()
     var rc2 = selector.select(0)
     var rc3 = selector.select(0)
     assert(len(rc1) == 1 and len(rc2) == 1 and len(rc3) == 0)
-    var ev1 = rc1[0].data
-    var ev2 = rc2[0].data
+    var ev1 = selector.getData(rc1[0].fd)
+    var ev2 = selector.getData(rc2[0].fd)
     assert(ev1 == 1 and ev2 == 1)
     selector.unregister(event)
     event.close()
@@ -383,19 +619,18 @@ else:
     proc event_wait_thread(event: SelectEvent) {.thread.} =
       var selector = newSelector[int]()
       selector.registerEvent(event, 1)
-      selector.flush()
-      var rc = selector.select(500)
+      var rc = selector.select(1500)
       if len(rc) == 1:
         inc(counter)
       selector.unregister(event)
       assert(selector.isEmpty())
 
     proc mt_event_test(): bool =
-      var thr: array [0..7, Thread[SelectEvent]]
+      var thr: array[0..7, Thread[SelectEvent]]
       var event = newSelectEvent()
       for i in 0..high(thr):
         createThread(thr[i], event_wait_thread, event)
-      event.setEvent()
+      event.trigger()
       joinThreads(thr)
       assert(counter == 1)
       result = true
diff --git a/tests/async/tjsandnativeasync.nim b/tests/async/tjsandnativeasync.nim
new file mode 100644
index 000000000..c4db3bcfb
--- /dev/null
+++ b/tests/async/tjsandnativeasync.nim
@@ -0,0 +1,30 @@
+discard """
+  output: '''hi
+bye'''
+"""
+
+import async, times
+when defined(js):
+    proc sleepAsync(t: int): Future[void] =
+        var promise = newPromise() do(resolve: proc()):
+            {.emit: """
+            setTimeout(function(){
+                `resolve`();
+            }, `t`);
+            """.}
+        result = promise
+else:
+    from asyncdispatch import sleepAsync, waitFor
+
+proc foo() {.async.} =
+    echo "hi"
+    var s = epochTime()
+    await sleepAsync(200)
+    var e = epochTime()
+    doAssert(e - s > 0.1)
+    echo "bye"
+
+when defined(js):
+    discard foo()
+else:
+    waitFor foo()
diff --git a/tests/async/tlambda.nim b/tests/async/tlambda.nim
index e0ff1f483..8f570689b 100644
--- a/tests/async/tlambda.nim
+++ b/tests/async/tlambda.nim
@@ -1,7 +1,7 @@
 
 # bug 2007
 
-import asyncdispatch, asyncnet, logging, json, uri, strutils, future
+import asyncdispatch, asyncnet, logging, json, uri, strutils, sugar
 
 type
   Builder = ref object
@@ -27,7 +27,7 @@ proc newBuild*(onProgress: ProgressCB): Build =
   result.onProgress = onProgress
 
 proc start(build: Build, repo, hash: string) {.async.} =
-  let path = repo.parseUri().path.toLower()
+  let path = repo.parseUri().path.toLowerAscii()
 
 proc onProgress(builder: Builder, message: string) {.async.} =
   debug($message)
@@ -51,5 +51,8 @@ proc main() =
 
   var builder = newBuilder()
 
+  # Test {.async.} pragma with do notation: #5995
+  builder.client = newClient("builder") do(client: Client, msg: JsonNode) {.async.}:
+    await onMessage(builder, msg)
 
 main()
diff --git a/tests/async/tmultisync.nim b/tests/async/tmultisync.nim
new file mode 100644
index 000000000..9ef9b105c
--- /dev/null
+++ b/tests/async/tmultisync.nim
@@ -0,0 +1,8 @@
+import asyncdispatch, net, asyncnet
+
+proc recvTwice(socket: Socket | AsyncSocket,
+               size: int): Future[string] {.multisync.} =
+  var x = await socket.recv(size)
+  var y = await socket.recv(size+1)
+  return x & "aboo" & y
+
diff --git a/tests/async/tnewasyncudp.nim b/tests/async/tnewasyncudp.nim
index 7025fa20d..68de796a0 100644
--- a/tests/async/tnewasyncudp.nim
+++ b/tests/async/tnewasyncudp.nim
@@ -1,5 +1,4 @@
 discard """
-  file: "tnewasyncudp.nim"
   output: "5000"
 """
 import asyncdispatch, nativesockets, net, strutils, os
@@ -29,31 +28,40 @@ proc saveReceivedPort(port: int) =
 
 proc prepareAddress(intaddr: uint32, intport: uint16): ptr Sockaddr_in =
   result = cast[ptr Sockaddr_in](alloc0(sizeof(Sockaddr_in)))
-  when defined(windows):
-    result.sin_family = toInt(nativesockets.AF_INET).int16
-  else:
-    result.sin_family = toInt(nativesockets.AF_INET)
-  result.sin_port = htons(intport)
-  result.sin_addr.s_addr = htonl(intaddr)
+  result.sin_family = typeof(result.sin_family)(toInt(nativesockets.AF_INET))
+  result.sin_port = nativesockets.htons(intport)
+  result.sin_addr.s_addr = nativesockets.htonl(intaddr)
 
 proc launchSwarm(name: ptr SockAddr) {.async.} =
   var i = 0
   var k = 0
+  var buffer: array[16384, char]
+  var slen = sizeof(Sockaddr_in).SockLen
+  var saddr = Sockaddr_in()
   while i < swarmSize:
-    var peeraddr = prepareAddress(INADDR_ANY, 0)
-    var sock = newAsyncNativeSocket(nativesockets.AF_INET,
-                                    nativesockets.SOCK_DGRAM,
-                                    Protocol.IPPROTO_UDP)
+    var peeraddr = prepareAddress(INADDR_LOOPBACK, 0)
+    var sock = createAsyncNativeSocket(nativesockets.AF_INET,
+                                       nativesockets.SOCK_DGRAM,
+                                       Protocol.IPPROTO_UDP)
     if bindAddr(sock.SocketHandle, cast[ptr SockAddr](peeraddr),
               sizeof(Sockaddr_in).Socklen) < 0'i32:
       raiseOSError(osLastError())
     let sockport = getSockName(sock.SocketHandle).int
     k = 0
     while k < messagesToSend:
+      zeroMem(addr(buffer[0]), 16384)
+      zeroMem(cast[pointer](addr(saddr)), sizeof(Sockaddr_in))
       var message = "Message " & $(i * messagesToSend + k)
       await sendTo(sock, addr message[0], len(message),
                    name, sizeof(Sockaddr_in).SockLen)
-      saveSendingPort(sockport)
+      var size = await recvFromInto(sock, cast[pointer](addr buffer[0]),
+                                    16384, cast[ptr SockAddr](addr saddr),
+                                    addr slen)
+      size = 0
+      var grammString = $cast[cstring](addr buffer)
+      if grammString == message:
+        saveSendingPort(sockport)
+        inc(recvCount)
       inc(k)
     closeSocket(sock)
     inc(i)
@@ -72,25 +80,26 @@ proc readMessages(server: AsyncFD) {.async.} =
                                   16384, cast[ptr SockAddr](addr(saddr)),
                                   addr(slen))
     size = 0
-    var grammString = $buffer
-    if grammString.startswith("Message ") and
-       saddr.sin_addr.s_addr == 0x100007F:
+    var grammString = $cast[cstring](addr buffer)
+    if grammString.startsWith("Message ") and
+       saddr.sin_addr.s_addr == nativesockets.ntohl(INADDR_LOOPBACK.uint32):
+      await sendTo(server, addr grammString[0], len(grammString),
+                   cast[ptr SockAddr](addr saddr), slen)
       inc(msgCount)
-      saveReceivedPort(ntohs(saddr.sin_port).int)
-      inc(recvCount)
+      saveReceivedPort(nativesockets.ntohs(saddr.sin_port).int)
     inc(i)
 
 proc createServer() {.async.} =
-  var name = prepareAddress(INADDR_ANY, serverPort)
-  var server = newAsyncNativeSocket(nativesockets.AF_INET,
-                                    nativesockets.SOCK_DGRAM,
-                                    Protocol.IPPROTO_UDP)
+  var name = prepareAddress(INADDR_LOOPBACK, serverPort)
+  var server = createAsyncNativeSocket(nativesockets.AF_INET,
+                                       nativesockets.SOCK_DGRAM,
+                                       Protocol.IPPROTO_UDP)
   if bindAddr(server.SocketHandle, cast[ptr SockAddr](name),
               sizeof(Sockaddr_in).Socklen) < 0'i32:
     raiseOSError(osLastError())
   asyncCheck readMessages(server)
 
-var name = prepareAddress(0x7F000001, serverPort) # 127.0.0.1
+var name = prepareAddress(INADDR_LOOPBACK, serverPort) # 127.0.0.1
 asyncCheck createServer()
 asyncCheck launchSwarm(cast[ptr SockAddr](name))
 while true:
diff --git a/tests/async/tpendingcheck.nim b/tests/async/tpendingcheck.nim
new file mode 100644
index 000000000..4eceb0353
--- /dev/null
+++ b/tests/async/tpendingcheck.nim
@@ -0,0 +1,18 @@
+discard """
+  output: ""
+"""
+
+import asyncdispatch
+
+doAssert(not hasPendingOperations())
+
+proc test() {.async.} =
+  await sleepAsync(50)
+
+var f = test()
+while not f.finished:
+  doAssert(hasPendingOperations())
+  poll(10)
+f.read
+
+doAssert(not hasPendingOperations())
diff --git a/tests/async/tpolltimeouts.nim b/tests/async/tpolltimeouts.nim
new file mode 100644
index 000000000..dac33732d
--- /dev/null
+++ b/tests/async/tpolltimeouts.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "true"
+"""
+# Issue https://github.com/nim-lang/Nim/issues/4262
+import asyncdispatch, times
+
+proc foo(): Future[int] {.async.} =
+  return 1
+
+proc bar(): Future[int] {.async.} =
+  return await foo()
+
+let start = epochTime()
+let barFut = bar()
+
+while not barFut.finished:
+  poll(2000)
+
+echo(epochTime() - start < 1.0)
diff --git a/tests/async/ttemplateinasync.nim b/tests/async/ttemplateinasync.nim
new file mode 100644
index 000000000..f4a2da538
--- /dev/null
+++ b/tests/async/ttemplateinasync.nim
@@ -0,0 +1,11 @@
+discard """
+  output: 42
+"""
+
+import asyncdispatch
+
+proc foo(): Future[int] {.async.} =
+  template ret() = return 42
+  ret()
+
+echo (waitFor foo())
diff --git a/tests/async/tupcoming_async.nim b/tests/async/tupcoming_async.nim
new file mode 100644
index 000000000..0b6e53454
--- /dev/null
+++ b/tests/async/tupcoming_async.nim
@@ -0,0 +1,157 @@
+discard """
+  output: '''
+OK
+'''
+"""
+
+when defined(upcoming):
+  import asyncdispatch, times, streams, posix
+  from ioselectors import ioselSupportedPlatform
+
+  proc delayedSet(ev: AsyncEvent, timeout: int): Future[void] {.async.} =
+    await sleepAsync(timeout)
+    ev.trigger()
+
+  proc waitEvent(ev: AsyncEvent, closeEvent = false): Future[void] =
+    var retFuture = newFuture[void]("waitEvent")
+    proc cb(fd: AsyncFD): bool =
+      retFuture.complete()
+      if closeEvent:
+        return true
+      else:
+        return false
+    addEvent(ev, cb)
+    return retFuture
+
+  proc eventTest() =
+    var event = newAsyncEvent()
+    var fut = waitEvent(event)
+    asyncCheck(delayedSet(event, 500))
+    waitFor(fut or sleepAsync(1000))
+    if not fut.finished:
+      echo "eventTest: Timeout expired before event received!"
+
+  proc eventTest5304() =
+    # Event should not be signaled if it was uregistered,
+    # even in case, when poll() was not called yet.
+    # Issue #5304.
+    var unregistered = false
+    let e = newAsyncEvent()
+    addEvent(e) do (fd: AsyncFD) -> bool:
+      assert(not unregistered)
+    e.trigger()
+    e.unregister()
+    unregistered = true
+    poll()
+
+  proc eventTest5298() =
+    # Event must raise `AssertionDefect` if event was unregistered twice.
+    # Issue #5298.
+    let e = newAsyncEvent()
+    var eventReceived = false
+    addEvent(e) do (fd: AsyncFD) -> bool:
+      eventReceived = true
+      return true
+    e.trigger()
+    while not eventReceived:
+      poll()
+    try:
+      e.unregister()
+    except AssertionDefect:
+      discard
+    e.close()
+
+  proc eventTest5331() =
+    # Event must not raise any exceptions while was unregistered inside of
+    # own callback.
+    # Issue #5331.
+    let e = newAsyncEvent()
+    addEvent(e) do (fd: AsyncFD) -> bool:
+      e.unregister()
+      e.close()
+    e.trigger()
+    poll()
+
+  when ioselSupportedPlatform or defined(windows):
+
+    import osproc
+
+    proc waitTimer(timeout: int): Future[void] =
+      var retFuture = newFuture[void]("waitTimer")
+      proc cb(fd: AsyncFD): bool =
+        retFuture.complete()
+      addTimer(timeout, true, cb)
+      return retFuture
+
+    proc waitProcess(p: Process): Future[void] =
+      var retFuture = newFuture[void]("waitProcess")
+      proc cb(fd: AsyncFD): bool =
+        retFuture.complete()
+      addProcess(p.processID(), cb)
+      return retFuture
+
+    proc timerTest() =
+      waitFor(waitTimer(200))
+
+    proc processTest() =
+      when defined(windows):
+        var process = startProcess("ping.exe", "",
+                                   ["127.0.0.1", "-n", "2", "-w", "100"], nil,
+                                   {poStdErrToStdOut, poUsePath, poInteractive,
+                                   poDaemon})
+      else:
+        var process = startProcess("sleep", "", ["1"], nil,
+                                   {poStdErrToStdOut, poUsePath})
+      var fut = waitProcess(process)
+      waitFor(fut or waitTimer(2000))
+      if fut.finished and process.peekExitCode() == 0:
+        discard
+      else:
+        echo "processTest: Timeout expired before process exited!"
+
+  when ioselSupportedPlatform:
+
+    proc waitSignal(signal: int): Future[void] =
+      var retFuture = newFuture[void]("waitSignal")
+      proc cb(fd: AsyncFD): bool =
+        retFuture.complete()
+      addSignal(signal, cb)
+      return retFuture
+
+    proc delayedSignal(signal: int, timeout: int): Future[void] {.async.} =
+      await waitTimer(timeout)
+      var pid = posix.getpid()
+      discard posix.kill(pid, signal.cint)
+
+    proc signalTest() =
+      var fut = waitSignal(posix.SIGINT)
+      asyncCheck(delayedSignal(posix.SIGINT, 500))
+      waitFor(fut or waitTimer(1000))
+      if not fut.finished:
+        echo "signalTest: Timeout expired before signal received!"
+
+  when ioselSupportedPlatform:
+    timerTest()
+    eventTest()
+    eventTest5304()
+    eventTest5298()
+    eventTest5331()
+    processTest()
+    signalTest()
+    echo "OK"
+  elif defined(windows):
+    timerTest()
+    eventTest()
+    eventTest5304()
+    eventTest5298()
+    eventTest5331()
+    processTest()
+    echo "OK"
+  else:
+    eventTest()
+    eventTest5304()
+    eventTest5298()
+    eventTest5331()
+    echo "OK"
+else:
+  echo "OK"
diff --git a/tests/async/twinasyncrw.nim b/tests/async/twinasyncrw.nim
index 17b7d1cf5..f0a8f6a62 100644
--- a/tests/async/twinasyncrw.nim
+++ b/tests/async/twinasyncrw.nim
@@ -1,10 +1,6 @@
-discard """
-  file: "twinasyncrw.nim"
-  output: "5000"
-"""
 when defined(windows):
   import asyncdispatch, nativesockets, net, strutils, os, winlean
-
+  from stdtest/netutils import bindAvailablePort
   var msgCount = 0
 
   const
@@ -14,7 +10,7 @@ when defined(windows):
   var clientCount = 0
 
   proc winConnect*(socket: AsyncFD, address: string, port: Port,
-    domain = Domain.AF_INET): Future[void] =
+      domain = Domain.AF_INET): Future[void] =
     var retFuture = newFuture[void]("winConnect")
     proc cb(fd: AsyncFD): bool =
       var ret = SocketHandle(fd).getSockOptInt(cint(SOL_SOCKET), cint(SO_ERROR))
@@ -23,7 +19,7 @@ when defined(windows):
           retFuture.complete()
           return true
       else:
-          retFuture.fail(newException(OSError, osErrorMsg(OSErrorCode(ret))))
+          retFuture.fail(newOSError(OSErrorCode(ret)))
           return true
 
     var aiList = getAddrInfo(address, port, domain)
@@ -47,9 +43,9 @@ when defined(windows):
           success = false
       it = it.ai_next
 
-    dealloc(aiList)
+    freeAddrInfo(aiList)
     if not success:
-      retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+      retFuture.fail(newOSError(lastError))
     return retFuture
 
   proc winRecv*(socket: AsyncFD, size: int,
@@ -67,7 +63,7 @@ when defined(windows):
         if flags.isDisconnectionError(lastError):
           retFuture.complete("")
         else:
-          retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+          retFuture.fail(newOSError(lastError))
       elif res == 0:
         # Disconnected
         retFuture.complete("")
@@ -92,7 +88,7 @@ when defined(windows):
         if flags.isDisconnectionError(lastError):
           retFuture.complete(0)
         else:
-          retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+          retFuture.fail(newOSError(lastError))
       else:
         retFuture.complete(res)
     # TODO: The following causes a massive slowdown.
@@ -116,7 +112,7 @@ when defined(windows):
         if flags.isDisconnectionError(lastError):
           retFuture.complete()
         else:
-          retFuture.fail(newException(OSError, osErrorMsg(lastError)))
+          retFuture.fail(newOSError(lastError))
       else:
         written.inc(res)
         if res != netSize:
@@ -140,7 +136,7 @@ when defined(windows):
         var client = nativesockets.accept(sock.SocketHandle,
                                           cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
         if client == osInvalidSocket:
-          retFuture.fail(newException(OSError, osErrorMsg(osLastError())))
+          retFuture.fail(newOSError(osLastError()))
         else:
           retFuture.complete((getAddrString(cast[ptr SockAddr](addr sockAddress)), client.AsyncFD))
 
@@ -183,7 +179,7 @@ when defined(windows):
     ## **Note**: This procedure is mostly used for testing. You likely want to
     ## use ``asyncnet.recvLine`` instead.
 
-    template addNLIfEmpty(): stmt =
+    template addNLIfEmpty() =
       if result.len == 0:
         result.add("\c\L")
 
@@ -204,12 +200,12 @@ when defined(windows):
       add(result, c)
 
   proc sendMessages(client: AsyncFD) {.async.} =
-    for i in 0 .. <messagesToSend:
+    for i in 0 ..< messagesToSend:
       await winSend(client, "Message " & $i & "\c\L")
 
   proc launchSwarm(port: Port) {.async.} =
-    for i in 0 .. <swarmSize:
-      var sock = newNativeSocket()
+    for i in 0 ..< swarmSize:
+      var sock = createNativeSocket()
       setBlocking(sock, false)
 
       await winConnect(AsyncFD(sock), "localhost", port)
@@ -224,34 +220,24 @@ when defined(windows):
         clientCount.inc
         break
       else:
-        if line.startswith("Message "):
+        if line.startsWith("Message "):
           msgCount.inc
         else:
           doAssert false
 
-  proc createServer(port: Port) {.async.} =
-    var server = newNativeSocket()
-    setBlocking(server, false)
-    block:
-      var name = Sockaddr_in()
-      name.sin_family = toInt(Domain.AF_INET).int16
-      name.sin_port = htons(uint16(port))
-      name.sin_addr.s_addr = htonl(INADDR_ANY)
-      if bindAddr(server, cast[ptr SockAddr](addr(name)),
-                  sizeof(name).Socklen) < 0'i32:
-        raiseOSError(osLastError())
-
+  proc createServer(server: SocketHandle) {.async.} =
     discard server.listen()
     while true:
       asyncCheck readMessages(await winAccept(AsyncFD(server)))
 
-  asyncCheck createServer(Port(10335))
-  asyncCheck launchSwarm(Port(10335))
+  var server = createNativeSocket()
+  setBlocking(server, false)
+  let port = bindAvailablePort(server)
+  asyncCheck createServer(server)
+  asyncCheck launchSwarm(port)
   while true:
     poll()
     if clientCount == swarmSize: break
 
   assert msgCount == swarmSize * messagesToSend
-  echo msgCount
-else:
-  echo(5000)
+  doAssert msgCount == 5000