Merge branch 'master' of github.com:vibe-d/vibe-core

This commit is contained in:
Sönke Ludwig 2017-02-19 13:52:54 +01:00
commit 531398e28d
14 changed files with 377 additions and 8 deletions

View file

@ -459,11 +459,12 @@ struct FileStream {
}
size_t read(ubyte[] dst, IOMode mode)
{
{
auto res = asyncAwait!(FileIOCallback,
cb => eventDriver.files.read(m_fd, ctx.ptr, dst, mode, cb),
cb => eventDriver.files.cancelRead(m_fd)
);
ctx.ptr += res[2];
enforce(res[1] == IOStatus.ok, "Failed to read data from disk.");
return res[2];
}

27
tests/args.d Normal file
View file

@ -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();
}

10
tests/args.sh Executable file
View file

@ -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'

107
tests/dirwatcher.d Normal file
View file

@ -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;
}

View file

@ -1,4 +1,4 @@
/++ dub.sdl:
/+ dub.sdl:
name "test"
description "Tests vibe.d's std.concurrency integration"
dependency "vibe-core" path="../"

View file

@ -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));
}

View file

@ -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();
}

View file

@ -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);
}

View file

@ -1,4 +1,4 @@
/++ dub.sdl:
/+ dub.sdl:
name "test"
dependency "vibe-core" path=".."
+/
@ -12,16 +12,23 @@ void main()
{
auto f = openFile("test.dat", FileMode.createTrunc);
assert(f.size == 0);
assert(f.tell == 0);
f.write(bytes!(1, 2, 3, 4, 5));
assert(f.size == 5);
assert(f.tell == 5);
f.seek(0);
assert(f.tell == 0);
f.write(bytes!(1, 2, 3, 4, 5));
assert(f.size == 5);
assert(f.tell == 5);
f.write(bytes!(6, 7, 8, 9, 10));
assert(f.size == 10);
assert(f.tell == 10);
ubyte[5] dst;
f.seek(2);
assert(f.tell == 2);
f.read(dst);
assert(f.tell == 7);
assert(dst[] == bytes!(3, 4, 5, 6, 7));
f.close();

View file

@ -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();
});
}

View file

@ -1,4 +1,4 @@
/++ dub.sdl:
/+ dub.sdl:
name "test"
description "TCP disconnect task issue"
dependency "vibe-core" path="../"

View file

@ -1,4 +1,4 @@
/++ dub.sdl:
/+ dub.sdl:
name "test"
description "TCP disconnect task issue"
dependency "vibe-core" path="../"

View file

@ -1,7 +1,8 @@
/++ dub.sdl:
/+ dub.sdl:
name "test"
description "Invalid memory operation on TCP connection leakage at shutdown"
dependency "vibe-core" path="../"
debugVersions "VibeAsyncLog"
+/
module test;

View file

@ -21,7 +21,13 @@ if [ ${BUILD_EXAMPLE=1} -eq 1 ]; then
fi
if [ ${RUN_TEST=1} -eq 1 ]; then
for ex in `\ls -1 tests/*.d`; do
echo "[INFO] Running test $ex"
dub --temp-build --compiler=$DC --single $ex # --override-config vibe-core/$CONFIG
script="${ex:0:-2}.sh"
if [ -e "$script" ]; then
echo "[INFO] Running test scipt $script"
(cd tests && "./${script:6}")
else
echo "[INFO] Running test $ex"
dub --temp-build --compiler=$DC --single $ex # --override-config vibe-core/$CONFIG
fi
done
fi