Merge branch 'unittesting' into 'master'
Unittesting See merge request fsimphy/calendar-webapp!2
This commit is contained in:
commit
7941291386
8 changed files with 264 additions and 25 deletions
23
dub.json
23
dub.json
|
@ -4,14 +4,33 @@
|
||||||
"Johannes Loher"
|
"Johannes Loher"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"vibe-d": "0.8.1-rc.2",
|
"vibe-d": "~>0.8.1",
|
||||||
"poodinis": "~>8.0.1"
|
"poodinis": "~>8.0.1"
|
||||||
},
|
},
|
||||||
"description": "A simple webapplication to edit and view calendar entries",
|
"description": "A simple webapplication to edit and view calendar entries",
|
||||||
"copyright": "Copyright © 2017, Johannes Loher",
|
"copyright": "Copyright © 2017, Johannes Loher",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"targetType": "executable",
|
||||||
|
"targetPath": "generated",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "executable",
|
||||||
|
"versions": [
|
||||||
|
"VibeDefaultMain"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "unittest",
|
||||||
|
"targetType": "executable",
|
||||||
|
"preBuildCommands": ["dub run unit-threaded -c gen_ut_main -- -f generated/ut.d test"],
|
||||||
|
"mainSourceFile": "generated/ut.d",
|
||||||
|
"sourcePaths": ["test"],
|
||||||
|
"dependencies": {
|
||||||
|
"unit-threaded": "~>0.7.31"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"versions": [
|
"versions": [
|
||||||
"VibeDefaultMain",
|
|
||||||
"VibeUseOpenSSL11"
|
"VibeUseOpenSSL11"
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
module app;
|
module calendarwebapp.app;
|
||||||
|
|
||||||
import calendarwebapp : CalendarWebapp;
|
import calendarwebapp.calendarwebapp : CalendarWebapp;
|
||||||
import configuration : Context;
|
import calendarwebapp.configuration : Context;
|
||||||
|
|
||||||
import poodinis;
|
import poodinis;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module authenticator;
|
module calendarwebapp.authenticator;
|
||||||
|
|
||||||
import poodinis;
|
import poodinis;
|
||||||
|
|
||||||
|
@ -10,11 +10,11 @@ interface Authenticator
|
||||||
bool checkUser(string username, string password) @safe;
|
bool checkUser(string username, string password) @safe;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MongoDBAuthenticator : Authenticator
|
class MongoDBAuthenticator(Collection = MongoCollection) : Authenticator
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@Value("users")
|
@Value("users")
|
||||||
MongoCollection users;
|
Collection users;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool checkUser(string username, string password) @safe
|
bool checkUser(string username, string password) @safe
|
|
@ -1,14 +1,13 @@
|
||||||
module calendarwebapp;
|
module calendarwebapp.calendarwebapp;
|
||||||
|
|
||||||
import authenticator : Authenticator, AuthInfo;
|
import calendarwebapp.authenticator : Authenticator, AuthInfo;
|
||||||
|
import calendarwebapp.event;
|
||||||
|
|
||||||
import core.time : days;
|
import core.time : days;
|
||||||
|
|
||||||
import event;
|
|
||||||
|
|
||||||
import poodinis;
|
import poodinis;
|
||||||
|
|
||||||
import std.datetime.date : Date;
|
import std.datetime : Date;
|
||||||
import std.exception : enforce;
|
import std.exception : enforce;
|
||||||
import std.typecons : Nullable;
|
import std.typecons : Nullable;
|
||||||
|
|
||||||
|
@ -22,7 +21,7 @@ import vibe.web.web : errorDisplay, noRoute, redirect, render, SessionVar,
|
||||||
|
|
||||||
@requiresAuth class CalendarWebapp
|
@requiresAuth class CalendarWebapp
|
||||||
{
|
{
|
||||||
@noRoute AuthInfo authenticate(scope HTTPServerRequest req, scope HTTPServerResponse res) @safe
|
@noRoute AuthInfo authenticate(scope HTTPServerRequest req, scope HTTPServerResponse) @safe
|
||||||
{
|
{
|
||||||
if (!req.session || !req.session.isKeySet("auth"))
|
if (!req.session || !req.session.isKeySet("auth"))
|
||||||
{
|
{
|
|
@ -1,8 +1,8 @@
|
||||||
module configuration;
|
module calendarwebapp.configuration;
|
||||||
|
|
||||||
import authenticator : Authenticator, MongoDBAuthenticator;
|
import calendarwebapp.authenticator : Authenticator, MongoDBAuthenticator;
|
||||||
import calendarwebapp : CalendarWebapp;
|
import calendarwebapp.calendarwebapp : CalendarWebapp;
|
||||||
import event : EventStore, MongoDBEventStore;
|
import calendarwebapp.event : EventStore, MongoDBEventStore;
|
||||||
|
|
||||||
import poodinis;
|
import poodinis;
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@ public:
|
||||||
{
|
{
|
||||||
auto mongoClient = connectMongoDB("localhost");
|
auto mongoClient = connectMongoDB("localhost");
|
||||||
container.register!MongoClient.existingInstance(mongoClient);
|
container.register!MongoClient.existingInstance(mongoClient);
|
||||||
container.register!(EventStore, MongoDBEventStore);
|
container.register!(EventStore, MongoDBEventStore!());
|
||||||
container.register!(Authenticator, MongoDBAuthenticator);
|
container.register!(Authenticator, MongoDBAuthenticator!());
|
||||||
container.register!CalendarWebapp;
|
container.register!CalendarWebapp;
|
||||||
container.register!(ValueInjector!string, StringInjector);
|
container.register!(ValueInjector!string, StringInjector);
|
||||||
container.register!(ValueInjector!MongoCollection, MongoCollectionInjector);
|
container.register!(ValueInjector!MongoCollection, MongoCollectionInjector);
|
|
@ -1,9 +1,9 @@
|
||||||
module event;
|
module calendarwebapp.event;
|
||||||
|
|
||||||
import poodinis;
|
import poodinis;
|
||||||
|
|
||||||
import std.algorithm : map;
|
import std.algorithm : map;
|
||||||
import std.datetime.date : Date;
|
import std.datetime : Date;
|
||||||
import std.range.interfaces : InputRange, inputRangeObject;
|
import std.range.interfaces : InputRange, inputRangeObject;
|
||||||
import std.typecons : Nullable;
|
import std.typecons : Nullable;
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ interface EventStore
|
||||||
void removeEvent(BsonObjectID id) @safe;
|
void removeEvent(BsonObjectID id) @safe;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MongoDBEventStore : EventStore
|
class MongoDBEventStore(Collection = MongoCollection) : EventStore
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Event getEvent(BsonObjectID id) @safe
|
Event getEvent(BsonObjectID id) @safe
|
||||||
|
@ -55,7 +55,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@Value("events")
|
@Value("events")
|
||||||
MongoCollection events;
|
Collection events;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum EventType
|
enum EventType
|
53
test/calendarwebapp/testauthenticator.d
Normal file
53
test/calendarwebapp/testauthenticator.d
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
module test.calendarwebapp.testauthenticator;
|
||||||
|
|
||||||
|
import calendarwebapp.authenticator;
|
||||||
|
|
||||||
|
import poodinis;
|
||||||
|
|
||||||
|
import unit_threaded.mock;
|
||||||
|
import unit_threaded.should;
|
||||||
|
|
||||||
|
import vibe.data.bson : Bson;
|
||||||
|
|
||||||
|
interface Collection
|
||||||
|
{
|
||||||
|
Bson findOne(string[string] query) @safe;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CollectionInjector : ValueInjector!Collection
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Collection[string] collections;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void add(string key, Collection collection)
|
||||||
|
{
|
||||||
|
collections[key] = collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
override Collection get(string key) @safe
|
||||||
|
{
|
||||||
|
return collections[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@("Test MongoDBAuthenticator")
|
||||||
|
@system unittest
|
||||||
|
{
|
||||||
|
auto collection = mock!Collection;
|
||||||
|
auto container = new shared DependencyContainer;
|
||||||
|
container.register!(ValueInjector!Collection, CollectionInjector);
|
||||||
|
container.resolve!CollectionInjector.add("users", collection);
|
||||||
|
container.register!(Authenticator, MongoDBAuthenticator!(Collection))(
|
||||||
|
RegistrationOption.doNotAddConcreteTypeRegistration);
|
||||||
|
|
||||||
|
collection.returnValue!"findOne"(Bson(true), Bson(null));
|
||||||
|
collection.expect!"findOne"(["username" : "", "password" : ""]);
|
||||||
|
collection.expect!"findOne"(["username" : "foo", "password" : "bar"]);
|
||||||
|
|
||||||
|
auto authenticator = container.resolve!(Authenticator);
|
||||||
|
authenticator.checkUser("", "").shouldBeTrue;
|
||||||
|
authenticator.checkUser("foo", "bar").shouldBeFalse;
|
||||||
|
|
||||||
|
collection.verify;
|
||||||
|
}
|
168
test/calendarwebapp/testevent.d
Normal file
168
test/calendarwebapp/testevent.d
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
module test.calendarwebapp.testevent;
|
||||||
|
|
||||||
|
import calendarwebapp.event;
|
||||||
|
|
||||||
|
import poodinis;
|
||||||
|
|
||||||
|
import std.array;
|
||||||
|
import std.algorithm : map;
|
||||||
|
|
||||||
|
import unit_threaded.mock;
|
||||||
|
import unit_threaded.should;
|
||||||
|
|
||||||
|
import vibe.data.bson : Bson, BsonObjectID, serializeToBson;
|
||||||
|
|
||||||
|
interface Collection
|
||||||
|
{
|
||||||
|
Bson findOne(BsonObjectID[string] query) @safe;
|
||||||
|
Bson[] find() @safe;
|
||||||
|
Bson[] find(Bson[string][string][][string] query) @safe;
|
||||||
|
void insert(Bson document) @safe;
|
||||||
|
void remove(BsonObjectID[string] selector) @safe;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CollectionInjector : ValueInjector!Collection
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Collection[string] collections;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void add(string key, Collection collection)
|
||||||
|
{
|
||||||
|
collections[key] = collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
override Collection get(string key) @safe
|
||||||
|
{
|
||||||
|
return collections[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@("getEventMongoDBEventStore.getEvent failure")
|
||||||
|
@system unittest
|
||||||
|
{
|
||||||
|
auto collection = mock!Collection;
|
||||||
|
auto container = new shared DependencyContainer;
|
||||||
|
container.register!(ValueInjector!Collection, CollectionInjector);
|
||||||
|
container.resolve!CollectionInjector.add("events", collection);
|
||||||
|
container.register!(EventStore, MongoDBEventStore!(Collection))(
|
||||||
|
RegistrationOption.doNotAddConcreteTypeRegistration);
|
||||||
|
|
||||||
|
collection.returnValue!"findOne"(Bson(null));
|
||||||
|
|
||||||
|
auto id = BsonObjectID.fromString("599090de97355141140fc698");
|
||||||
|
collection.expect!"findOne"(["_id" : id]);
|
||||||
|
|
||||||
|
auto eventStore = container.resolve!(EventStore);
|
||||||
|
eventStore.getEvent(id).shouldThrowWithMessage!Exception("Expected object instead of null_");
|
||||||
|
collection.verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
@("MongoDBEventStore.getEvent success")
|
||||||
|
@system unittest
|
||||||
|
{
|
||||||
|
auto collection = mock!Collection;
|
||||||
|
auto container = new shared DependencyContainer;
|
||||||
|
container.register!(ValueInjector!Collection, CollectionInjector);
|
||||||
|
container.resolve!CollectionInjector.add("events", collection);
|
||||||
|
container.register!(EventStore, MongoDBEventStore!(Collection))(
|
||||||
|
RegistrationOption.doNotAddConcreteTypeRegistration);
|
||||||
|
|
||||||
|
auto id = BsonObjectID.fromString("599090de97355141140fc698");
|
||||||
|
Event event;
|
||||||
|
event.id = id;
|
||||||
|
|
||||||
|
collection.returnValue!"findOne"(event.serializeToBson);
|
||||||
|
|
||||||
|
collection.expect!"findOne"(["_id" : id]);
|
||||||
|
|
||||||
|
auto eventStore = container.resolve!(EventStore);
|
||||||
|
eventStore.getEvent(id).shouldEqual(event);
|
||||||
|
collection.verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
@("MongoDBEventStore.addEvent")
|
||||||
|
@system unittest
|
||||||
|
{
|
||||||
|
auto collection = mock!Collection;
|
||||||
|
auto container = new shared DependencyContainer;
|
||||||
|
container.register!(ValueInjector!Collection, CollectionInjector);
|
||||||
|
container.resolve!CollectionInjector.add("events", collection);
|
||||||
|
container.register!(EventStore, MongoDBEventStore!(Collection))(
|
||||||
|
RegistrationOption.doNotAddConcreteTypeRegistration);
|
||||||
|
|
||||||
|
auto id = BsonObjectID.fromString("599090de97355141140fc698");
|
||||||
|
Event event;
|
||||||
|
event.id = id;
|
||||||
|
auto serializedEvent = event.serializeToBson;
|
||||||
|
|
||||||
|
collection.returnValue!"findOne"(Bson(null), serializedEvent);
|
||||||
|
|
||||||
|
collection.expect!"findOne"(["_id" : id]);
|
||||||
|
collection.expect!"insert"(serializedEvent);
|
||||||
|
collection.expect!"findOne"(["_id" : id]);
|
||||||
|
|
||||||
|
auto eventStore = container.resolve!(EventStore);
|
||||||
|
|
||||||
|
eventStore.getEvent(id).shouldThrowWithMessage!Exception("Expected object instead of null_");
|
||||||
|
eventStore.addEvent(event);
|
||||||
|
eventStore.getEvent(id).shouldEqual(event);
|
||||||
|
|
||||||
|
collection.verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
@("MongoDBEventStore.removeEvent")
|
||||||
|
@system unittest
|
||||||
|
{
|
||||||
|
auto collection = mock!Collection;
|
||||||
|
auto container = new shared DependencyContainer;
|
||||||
|
container.register!(ValueInjector!Collection, CollectionInjector);
|
||||||
|
container.resolve!CollectionInjector.add("events", collection);
|
||||||
|
container.register!(EventStore, MongoDBEventStore!(Collection))(
|
||||||
|
RegistrationOption.doNotAddConcreteTypeRegistration);
|
||||||
|
|
||||||
|
auto id = BsonObjectID.fromString("599090de97355141140fc698");
|
||||||
|
Event event;
|
||||||
|
event.id = id;
|
||||||
|
|
||||||
|
collection.returnValue!"findOne"(event.serializeToBson, Bson(null));
|
||||||
|
|
||||||
|
collection.expect!"findOne"(["_id" : id]);
|
||||||
|
collection.expect!"remove"(["_id" : id]);
|
||||||
|
collection.expect!"findOne"(["_id" : id]);
|
||||||
|
|
||||||
|
auto eventStore = container.resolve!(EventStore);
|
||||||
|
|
||||||
|
eventStore.getEvent(id).shouldEqual(event);
|
||||||
|
eventStore.removeEvent(event.id);
|
||||||
|
eventStore.getEvent(id).shouldThrowWithMessage!Exception("Expected object instead of null_");
|
||||||
|
|
||||||
|
collection.verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
@("MongoDBEventStore.getAllEvents")
|
||||||
|
@system unittest
|
||||||
|
{
|
||||||
|
auto collection = mock!Collection;
|
||||||
|
auto container = new shared DependencyContainer;
|
||||||
|
container.register!(ValueInjector!Collection, CollectionInjector);
|
||||||
|
container.resolve!CollectionInjector.add("events", collection);
|
||||||
|
container.register!(EventStore, MongoDBEventStore!(Collection))(
|
||||||
|
RegistrationOption.doNotAddConcreteTypeRegistration);
|
||||||
|
|
||||||
|
immutable ids = [
|
||||||
|
BsonObjectID.fromString("599090de97355141140fc698"), BsonObjectID.fromString("599090de97355141140fc698"),
|
||||||
|
BsonObjectID.fromString("59cb9ad8fc0ba5751c0df02b")
|
||||||
|
];
|
||||||
|
auto events = ids.map!(id => Event(id)).array;
|
||||||
|
|
||||||
|
collection.returnValue!"find"(events.map!serializeToBson.array);
|
||||||
|
|
||||||
|
collection.expect!"find"();
|
||||||
|
|
||||||
|
auto eventStore = container.resolve!(EventStore);
|
||||||
|
|
||||||
|
eventStore.getAllEvents.array.shouldEqual(events);
|
||||||
|
|
||||||
|
collection.verify;
|
||||||
|
}
|
Loading…
Reference in a new issue