diff --git a/tests/args.d b/tests/args.d new file mode 100644 index 0000000..c62d823 --- /dev/null +++ b/tests/args.d @@ -0,0 +1,27 @@ +/+ dub.json: +{ + "name": "tests", + "description": "Command-line argument test", + "dependencies": { + "vibe-core": {"path": "../"} + } +} ++/ +module test; + +import vibe.core.args; +import vibe.core.log; + +import std.stdio; + +shared static this() +{ + string argtest; + readOption("argtest", &argtest, "Test argument"); + writeln("argtest=", argtest); +} + +void main() +{ + finalizeCommandLineOptions(); +} diff --git a/tests/args.sh b/tests/args.sh new file mode 100755 index 0000000..67c66ff --- /dev/null +++ b/tests/args.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -e +die() { echo "$@" 1>&2 ; exit 1; } + +( dub args.d | grep -q '^argtest=$' ) || die "Fail (no argument)" +( dub args.d --argtest=aoeu | grep -q '^argtest=aoeu$' ) || die "Fail (with argument)" +( ( ! dub args.d --inexisting 2>&1 ) | grep -qF 'Unrecognized command line option' ) || die "Fail (unknown argument)" + +echo 'OK' diff --git a/tests/dirwatcher.d b/tests/dirwatcher.d new file mode 100644 index 0000000..bdd20fa --- /dev/null +++ b/tests/dirwatcher.d @@ -0,0 +1,107 @@ +/+ dub.json: +{ + "name": "tests", + "description": "Test for vibe.d's DirectoryWatcher.", + "dependencies": { + "vibe-core": {"path": "../"} + } +} ++/ +import vibe.core.core; +import vibe.core.file; +import vibe.core.log; +import vibe.core.path; +import std.algorithm : canFind, all; +import std.file, std.process; +import std.format : format; +import std.conv : to; +import std.path : buildPath; +import std.typecons : No, Yes; +import core.exception : AssertError; +import core.time : msecs, seconds; + +void runTest() +{ + auto dir = buildPath(tempDir, format("dirwatcher_test_%d", thisProcessID())); + mkdir(dir); + scope(exit) rmdirRecurse(dir); + + DirectoryWatcher watcher; + try watcher = Path(dir).watchDirectory(No.recursive); + catch (AssertError e) { + logInfo("DirectoryWatcher not yet implemented. Skipping test."); + return; + } + DirectoryChange[] changes; + assert(!watcher.readChanges(changes, 500.msecs)); + + auto foo = dir.buildPath("foo"); + + alias Type = DirectoryChangeType; + static DirectoryChange dc(Type t, string p) { return DirectoryChange(t, Path(p)); } + void check(DirectoryChange[] expected) + { + sleep(100.msecs); + assert(watcher.readChanges(changes, 100.msecs), "Could not read changes for " ~ expected.to!string); + assert(expected.all!((a)=> changes.canFind(a))(), "Change is not what was expected, got: " ~ changes.to!string ~ " but expected: " ~ expected.to!string); + assert(!watcher.readChanges(changes, 0.msecs), "Changes were returned when they shouldn't have, for " ~ expected.to!string); + } + + write(foo, null); + check([dc(Type.added, foo)]); + sleep(1.seconds); // OSX has a second resolution on file modification times + write(foo, [0, 1]); + check([dc(Type.modified, foo)]); + remove(foo); + check([dc(Type.removed, foo)]); + write(foo, null); + sleep(1.seconds); + write(foo, [0, 1]); + sleep(100.msecs); + remove(foo); + check([dc(Type.added, foo), dc(Type.modified, foo), dc(Type.removed, foo)]); + + auto subdir = dir.buildPath("subdir"); + mkdir(subdir); + check([dc(Type.added, subdir)]); + auto bar = subdir.buildPath("bar"); + write(bar, null); + assert(!watcher.readChanges(changes, 100.msecs)); + remove(bar); + watcher = Path(dir).watchDirectory(Yes.recursive); + write(foo, null); + sleep(1.seconds); + write(foo, [0, 1]); + sleep(100.msecs); + remove(foo); + + write(bar, null); + sleep(1.seconds); + write(bar, [0, 1]); + sleep(100.msecs); + remove(bar); + check([dc(Type.added, foo), dc(Type.modified, foo), dc(Type.removed, foo), + dc(Type.added, bar), dc(Type.modified, bar), dc(Type.removed, bar)]); + + write(foo, null); + sleep(100.msecs); + rename(foo, bar); + sleep(100.msecs); + remove(bar); + check([dc(Type.added, foo), dc(Type.removed, foo), dc(Type.added, bar), dc(Type.removed, bar)]); + +} + +int main() +{ + int ret = 0; + runTask({ + try runTest(); + catch (Throwable th) { + logError("Test failed: %s", th.toString()); + ret = 1; + } finally exitEventLoop(true); + }); + runEventLoop(); + return ret; +} diff --git a/tests/vibe.core.concurrency.1408.d b/tests/vibe.core.concurrency.1408.d new file mode 100644 index 0000000..3ae0c21 --- /dev/null +++ b/tests/vibe.core.concurrency.1408.d @@ -0,0 +1,58 @@ +/+ dub.sdl: + name "tests" + description "std.concurrency integration issue" + dependency "vibe-core" path="../" + versions "VibeDefaultMain" ++/ +module test; + +import vibe.core.concurrency; +import vibe.core.core; +import vibe.core.log; +import core.time : msecs; +import std.functional : toDelegate; + +void test() +{ + auto t = runTask({ + bool gotit; + receive((int i) { assert(i == 10); gotit = true; }); + assert(gotit); + sleep(10.msecs); + }); + + t.tid.send(10); + t.tid.send(11); // never received + t.join(); + + // ensure that recycled fibers will get a clean message queue + auto t2 = runTask({ + bool gotit; + receive((int i) { assert(i == 12); gotit = true; }); + assert(gotit); + }); + t2.tid.send(12); + t2.join(); + + // test worker tasks + auto t3 = runWorkerTaskH({ + bool gotit; + receive((int i) { assert(i == 13); gotit = true; }); + assert(gotit); + }); + + t3.tid.send(13); + sleep(10.msecs); + + logInfo("Success."); + + exitEventLoop(true); +} + +shared static this() +{ +setLogFormat(FileLogger.Format.threadTime, FileLogger.Format.threadTime); + runTask(toDelegate(&test)); +} + + diff --git a/tests/vibe.core.core.1590.d b/tests/vibe.core.core.1590.d new file mode 100644 index 0000000..b7660fa --- /dev/null +++ b/tests/vibe.core.core.1590.d @@ -0,0 +1,59 @@ +/+ dub.sdl: + name "tests" + description "Semaphore hang" + dependency "vibe-core" path="../" ++/ +module test; +import std.stdio; +import std.socket; +import std.datetime; +import std.functional; +import core.time; +import vibe.core.core; +import vibe.core.log; +import vibe.core.concurrency; +import vibe.core.connectionpool; + +class Conn {} + +void main() +{ + runTask({ + // create pool with 2 max connections + bool[int] results; + auto pool = new ConnectionPool!Conn({ return new Conn; }, 2); + auto task = Task.getThis(); // main task + void worker(int id) { + { + auto conn = pool.lockConnection(); // <-- worker(4) hangs here + sleep(1.msecs); // <-- important, without sleep everything works fine + } + task.send(id); // send signal to the main task + } + // run 4 tasks (2 * pool max connections) + runTask(&worker, 1); + runTask(&worker, 2); + runTask(&worker, 3); + runTask(&worker, 4); + + // wait for first signal and run one more task + results[receiveOnly!int] = true; + runTask(&worker, 5); + + // wait for other signals + results[receiveOnly!int] = true; + results[receiveOnly!int] = true; + results[receiveOnly!int] = true; + results[receiveOnly!int] = true; + + foreach (r; results.byKey) + assert(r >= 1 && r <= 5); + + exitEventLoop(); + }); + + setTimer(1.seconds, { assert(false, "Test has hung."); }); + + runEventLoop(); +} + diff --git a/tests/vibe.core.core.refcount.d b/tests/vibe.core.core.refcount.d new file mode 100644 index 0000000..c372cd9 --- /dev/null +++ b/tests/vibe.core.core.refcount.d @@ -0,0 +1,51 @@ +/+ dub.sdl: + name "tests" + description "Invalid ref count after runTask" + dependency "vibe-core" path="../" ++/ +module test; +import vibe.core.core; +import std.stdio; + +struct RC { + int* rc; + this(int* rc) { this.rc = rc; } + this(this) { + if (rc) { + (*rc)++; + writefln("addref %s", *rc); + } + } + ~this() { + if (rc) { + (*rc)--; + writefln("release %s", *rc); + } + } +} + +void main() +{ + int rc = 1; + bool done = false; + + { + auto s = RC(&rc); + assert(rc == 1); + runTask((RC st) { + assert(rc == 2); + st = RC.init; + assert(rc == 1); + exitEventLoop(); + done = true; + }, s); + assert(rc == 2); + } + + assert(rc == 1); + + runEventLoop(); + + assert(rc == 0); + assert(done); +} diff --git a/tests/vibe.core.net.1376.d b/tests/vibe.core.net.1376.d new file mode 100644 index 0000000..4e01fd9 --- /dev/null +++ b/tests/vibe.core.net.1376.d @@ -0,0 +1,42 @@ +/+ dub.sdl: + name "tests" + description "TCP disconnect task issue" + dependency "vibe-core" path="../" + versions "VibeDefaultMain" ++/ +module test; + +import vibe.core.core; +import vibe.core.net; +import core.time : msecs; + +shared static this() +{ + listenTCP(11375,(conn){ + auto td = runTask!TCPConnection((conn) { + ubyte [3] buf; + try { + conn.read(buf); + assert(false, "Expected read() to throw an exception."); + } catch (Exception) {} // expected + }, conn); + sleep(10.msecs); + conn.close(); + }); + + runTask({ + try { + auto conn = connectTCP("127.0.0.1", 11375); + conn.write("a"); + conn.close(); + } catch (Exception e) assert(false, e.msg); + + try { + auto conn = connectTCP("127.0.0.1", 11375); + conn.close(); + } catch (Exception e) assert(false, e.msg); + + sleep(50.msecs); + exitEventLoop(); + }); +}