diff options
Diffstat (limited to 'tests/async')
-rw-r--r-- | tests/async/tasynceverror.nim | 66 | ||||
-rw-r--r-- | tests/async/tfuturevar.nim | 47 | ||||
-rw-r--r-- | tests/async/tgenericasync.nim | 14 | ||||
-rw-r--r-- | tests/async/tioselectors.nim | 213 | ||||
-rw-r--r-- | tests/async/tupcoming_async.nim | 13 |
5 files changed, 275 insertions, 78 deletions
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/tfuturevar.nim b/tests/async/tfuturevar.nim new file mode 100644 index 000000000..73c0fddf7 --- /dev/null +++ b/tests/async/tfuturevar.nim @@ -0,0 +1,47 @@ +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().isNil) + doAssert(fut.finished) + + fut = newFutureVar[string]() + await manualComplete(fut, true) + doAssert(fut.read() == "Hello World") + + +waitFor main() + 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 2237de01a..71d901e69 100644 --- a/tests/async/tioselectors.nim +++ b/tests/async/tioselectors.nim @@ -217,6 +217,216 @@ when not defined(windows): 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](unsafeAddr 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[T](test: openarray[ReadyKey[T]], + 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[int]] + 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) + selector.flush() + + # 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) + selector.flush() + 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) + selector.flush() + + # 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) + when hasThreadSupport: var counter = 0 @@ -256,6 +466,9 @@ when not defined(windows): 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()) echo("All tests passed!") else: import nativesockets, winlean, os, osproc diff --git a/tests/async/tupcoming_async.nim b/tests/async/tupcoming_async.nim index e53482dae..137794afd 100644 --- a/tests/async/tupcoming_async.nim +++ b/tests/async/tupcoming_async.nim @@ -44,19 +44,8 @@ when defined(upcoming): ev.setEvent() proc timerTest() = - var timeout = 200 - var errorRate = 40.0 - var start = epochTime() waitFor(waitTimer(200)) - var finish = epochTime() - var lowlimit = float(timeout) - float(timeout) * errorRate / 100.0 - var highlimit = float(timeout) + float(timeout) * errorRate / 100.0 - var elapsed = (finish - start) * 1_000 # convert to milliseconds - if elapsed >= lowlimit and elapsed < highlimit: - echo "OK" - else: - echo "timerTest: Timeout = " & $(elapsed) & ", but must be inside of [" & - $lowlimit & ", " & $highlimit & ")" + echo "OK" proc eventTest() = var event = newAsyncEvent() |