diff --git a/TelepresenceBot/server-unit/core/botLocator.js b/TelepresenceBot/server-unit/core/botLocator.js
index 96a681bd8..03f7b2c7c 100644
--- a/TelepresenceBot/server-unit/core/botLocator.js
+++ b/TelepresenceBot/server-unit/core/botLocator.js
@@ -1,25 +1,39 @@
-function BotLocator(rooms) {
- this.rooms = rooms;
-}
+module.exports = function (locationRooms) {
-BotLocator.prototype.locateFirstAvailableBotIn = function(room) {
- var botsInRoom = this.rooms[room];
-
- if(!botsInRoom) {
- return;
+ const roomsThatMatch = function (toMatch) {
+ return function (room) {
+ return toMatch == room;
+ };
}
- for (socketId in botsInRoom.sockets) {
- var socketsInBotRoom = this.rooms[socketId];
+ const roomsThatContainProperty = function (property) {
+ return function (roomName) {
+ return locationRooms[roomName].hasOwnProperty(property);
+ };
+ }
- if(botNotConnectedToHuman(socketsInBotRoom)) {
- return socketId;
- }
+ const roomsThatAreNotAlreadyConnectedToOtherSockets = function () {
+ return function (roomName) {
+ return locationRooms[roomName].length == 1;
+ };
}
-}
-function botNotConnectedToHuman(socketsInBotRoom) {
- return socketsInBotRoom.length === 1;
-}
+ const asEmptyBotRoom = function () {
+ return function (locationRoom) {
+ return Object.keys(locationRooms[locationRoom].sockets)
+ .filter(roomsThatContainProperty('length'))
+ .filter(roomsThatAreNotAlreadyConnectedToOtherSockets())
+ .pop();
+ };
+ }
-module.exports = BotLocator;
+ return {
+ locateFirstAvailableBotIn: function (locationRoom) {
+ return Object.keys(locationRooms)
+ .filter(roomsThatMatch(locationRoom))
+ .filter(roomsThatContainProperty('sockets'))
+ .map(asEmptyBotRoom())
+ .pop();
+ }
+ };
+};
diff --git a/TelepresenceBot/server-unit/core/clientType.js b/TelepresenceBot/server-unit/core/clientType.js
index 408c6281b..0355a6cba 100644
--- a/TelepresenceBot/server-unit/core/clientType.js
+++ b/TelepresenceBot/server-unit/core/clientType.js
@@ -1,15 +1,13 @@
-ClientType = {
- BOT : "bot",
- HUMAN : "human",
- TEST : "test",
- from : function(rawClientType) {
- for(var key in this) {
- if(ClientType[key] == rawClientType) {
+module.exports = ClientType = {
+ BOT: 'bot',
+ HUMAN: 'human',
+ TEST: 'test',
+ from: function (rawClientType) {
+ for (let key in this) {
+ if (ClientType[key] == rawClientType) {
return ClientType[key];
}
}
return undefined;
}
}
-
-module.exports = ClientType;
diff --git a/TelepresenceBot/server-unit/core/disconnector.js b/TelepresenceBot/server-unit/core/disconnector.js
new file mode 100644
index 000000000..ac989cf53
--- /dev/null
+++ b/TelepresenceBot/server-unit/core/disconnector.js
@@ -0,0 +1,53 @@
+module.exports = function Disconnector(rooms, connectedClients) {
+
+ const roomsThatMatch = function (toMatch) {
+ return function (room) {
+ return toMatch == room;
+ };
+ }
+
+ const roomsThatContainProperty = function (property) {
+ return function (roomName) {
+ return rooms[roomName].hasOwnProperty(property);
+ };
+ }
+
+ const thosePresentIn = function (objectToSearch) {
+ return function (key) {
+ return objectToSearch[key]
+ };
+ }
+
+ const asConnectedClient = function () {
+ return function (key) {
+ return connectedClients[key];
+ };
+ }
+
+ const connectedClientsThatContainProperty = function (property) {
+ return function (connectedClient) {
+ return connectedClient.hasOwnProperty(property);
+ }
+ }
+
+ const disconnectClient = function () {
+ return function (connectedClient) {
+ connectedClient.disconnect();
+ }
+ }
+
+ return {
+ disconnectRoom: function (roomName) {
+ Object.keys(rooms)
+ .filter(roomsThatMatch(roomName))
+ .filter(roomsThatContainProperty('sockets'))
+ .map(function (roomKey) {
+ return Object.keys(rooms[roomKey].sockets)
+ .filter(thosePresentIn(connectedClients))
+ .map(asConnectedClient())
+ .filter(connectedClientsThatContainProperty('disconnect'))
+ .every(disconnectClient());
+ });
+ }
+ };
+}
diff --git a/TelepresenceBot/server-unit/core/loggingClient.js b/TelepresenceBot/server-unit/core/loggingClient.js
deleted file mode 100644
index c1b9db949..000000000
--- a/TelepresenceBot/server-unit/core/loggingClient.js
+++ /dev/null
@@ -1,18 +0,0 @@
-function LoggingClient(client) {
- this.client = client;
-}
-
-LoggingClient.prototype.emit = function(event, dataToEmit) {
- if(this.client != undefined) {
- this.client.emit(event, dataToEmit);
- }
- console.log("\nEvent Emitted: ", event);
-
- if(dataToEmit != undefined && dataToEmit.length > 0) {
- console.log("Data Emitted: ", dataToEmit);
- }
-}
-
-module.exports = LoggingClient;
-
-
diff --git a/TelepresenceBot/server-unit/core/mover.js b/TelepresenceBot/server-unit/core/mover.js
new file mode 100644
index 000000000..70246d66b
--- /dev/null
+++ b/TelepresenceBot/server-unit/core/mover.js
@@ -0,0 +1,17 @@
+module.exports = function Mover(clientsAndRooms, emitter) {
+
+ const emitToRoom = function (direction) {
+ return function (room) {
+ emitter.to(room).emit('direction', direction);
+ }
+ }
+
+ return {
+ moveIn: function (clientId, direction) {
+ const rooms = clientsAndRooms[clientId];
+
+ Object.keys(rooms || {})
+ .every(emitToRoom(direction));
+ }
+ };
+}
diff --git a/TelepresenceBot/server-unit/core/observer.js b/TelepresenceBot/server-unit/core/observer.js
new file mode 100644
index 000000000..466d5d367
--- /dev/null
+++ b/TelepresenceBot/server-unit/core/observer.js
@@ -0,0 +1,7 @@
+module.exports = function Observer() {
+ return {
+ notify: function (eventName, eventData) {
+ return true;
+ }
+ };
+}
diff --git a/TelepresenceBot/server-unit/core/public/js/connect.js b/TelepresenceBot/server-unit/core/public/js/connect.js
index d846b4992..152f7e465 100644
--- a/TelepresenceBot/server-unit/core/public/js/connect.js
+++ b/TelepresenceBot/server-unit/core/public/js/connect.js
@@ -1,17 +1,24 @@
-var intervalId;
+const intervalId;
+
+const socketOptions ={
+ transports: ['websocket'],
+ 'force new connection': true,
+ query: 'clientType=human&room=London'
+};
+
+const socket = io(socketOptions);
$(document).ready(function(){
$("input").mousedown(function(){
console.log("mouseDown");
- var message = $(this).val();
+ const message = $(this).val();
intervalId = setInterval(function() {
sendMessage(message);
}, 100);
});
function sendMessage(message) {
- var socket = io();
socket.emit('chat message', message);
$('#messages').append($('
').text(message));
}
diff --git a/TelepresenceBot/server-unit/core/router.js b/TelepresenceBot/server-unit/core/router.js
new file mode 100644
index 000000000..cef266ce2
--- /dev/null
+++ b/TelepresenceBot/server-unit/core/router.js
@@ -0,0 +1,28 @@
+const ClientType = require('./clientType.js')
+
+module.exports = function Router(botLocator) {
+ return {
+ route: function (query, next) {
+ const roomName = query.room;
+ const rawClientType = query.clientType;
+ const clientType = ClientType.from(rawClientType);
+
+ switch (clientType) {
+ case ClientType.BOT:
+ return next();
+ case ClientType.HUMAN:
+ const availableBot = botLocator.locateFirstAvailableBotIn(roomName);
+
+ if (availableBot) {
+ query.room = availableBot;
+ return next();
+ } else {
+ return next(new Error('No bots available'));
+ }
+
+ default:
+ return next(new Error('Unrecognised clientType: ' + rawClientType));
+ }
+ }
+ };
+}
diff --git a/TelepresenceBot/server-unit/core/server.js b/TelepresenceBot/server-unit/core/server.js
index a74b0b799..cd06fadee 100644
--- a/TelepresenceBot/server-unit/core/server.js
+++ b/TelepresenceBot/server-unit/core/server.js
@@ -1,100 +1,4 @@
-var io = require('socket.io').listen(5000);
-var ClientType = require("./clientType.js");
-var LoggingClient = require("./loggingClient.js");
-var BotLocator = require("./botLocator.js");
+const ServerCreator = require('./serverCreator');
-var testClient = new LoggingClient();
-var botLocator = new BotLocator(io.sockets.adapter.rooms);
-
-io.use(function(client, next){
-
- var roomName = client.handshake.query.room;
- var rawClientType = client.handshake.query.clientType;
- var clientType = ClientType.from(rawClientType);
-
- switch(clientType) {
- case ClientType.TEST:
- case ClientType.BOT:
- return next();
- case ClientType.HUMAN:
- var human = client;
- var availableBot = botLocator.locateFirstAvailableBotIn(roomName);
-
- if(availableBot) {
- human.handshake.query.room = availableBot;
- return next();
- } else {
- return next(new Error('No bots available'));
- }
- default:
- return next(new Error('Unrecognised clientType: ' + rawClientType));
-
- }
-
-});
-
-io.sockets.on('connection', function (client) {
-
- var roomName = client.handshake.query.room;
- var rawClientType = client.handshake.query.clientType;
- var clientType = ClientType.from(rawClientType);
-
- switch(clientType) {
- case ClientType.HUMAN:
- client.join(roomName);
- testClient.emit('connected_human', asRoomsWithSocketIds());
- break;
- case ClientType.BOT:
- client.join(roomName);
- testClient.emit('connected_bot', asRoomsWithSocketIds());
- break;
- case ClientType.TEST:
- console.log('switching test client');
- testClient = new LoggingClient(client);
- testClient.emit('connected', asRoomsWithSocketIds());
- break;
- default:
- throw 'Unexpected rawClientType: ' + clientType;
- }
-
- client.on('disconnect', function() {
- disconnectRoom(client.id);
- testClient.emit('disconnected_human', asRoomsWithSocketIds());
- testClient.emit('disconnected_bot', asRoomsWithSocketIds());
- });
-
- client.on('move_in', function(direction) {
- var rooms = Object.keys(io.sockets.adapter.sids[client.id]);
- for(var i = 0; i < rooms.length; i++) {
- io.to(rooms[i]).emit('direction', direction);
- testClient.emit('direction', direction);
- }
- });
-});
-
-function disconnectRoom(name) {
- var room = io.sockets.adapter.rooms[name];
-
- if(!room) {
- return;
- }
-
- var clients = io.sockets.adapter.rooms[name].sockets;
-
- for(var client in clients) {
- var connectedClient = io.sockets.connected[client];
- connectedClient.disconnect();
- }
-}
-
-function asRoomsWithSocketIds() {
- var roomNames = Object.keys(io.sockets.adapter.rooms);
- var roomsWithSockets = {};
-
- for(var i = 0; i < roomNames.length; i++) {
- var room = io.sockets.adapter.rooms[roomNames[i]];
- roomsWithSockets[roomNames[i]] = Object.keys(room.sockets);
- }
-
- return roomsWithSockets;
-}
+const serverCreator = new ServerCreator();
+serverCreator.create();
diff --git a/TelepresenceBot/server-unit/core/serverCreator.js b/TelepresenceBot/server-unit/core/serverCreator.js
new file mode 100644
index 000000000..36c7e2212
--- /dev/null
+++ b/TelepresenceBot/server-unit/core/serverCreator.js
@@ -0,0 +1,76 @@
+const express = require('express'),
+ app = express(),
+ httpServer = require('http').createServer(app),
+ io = require('socket.io')(httpServer),
+ path = require('path'),
+ debug = require('debug')('server');
+
+let botLocator = require('./botLocator.js')(io.sockets.adapter.rooms),
+ router = require('./router.js')(botLocator),
+ disconnector = require('./disconnector.js')(io.sockets.adapter.rooms, io.sockets.connected),
+ mover = require('./mover.js')(io.sockets.adapter.sids, io),
+ observer = require('./observer.js')();
+
+module.exports = function ServerCreator() {
+ app.use(express.static(path.join(__dirname, 'public')));
+
+ app.get('/', function (req, res) {
+ res.sendFile(__dirname + '/html/index.html');
+ });
+
+ app.get('/rooms', function (req, res) {
+ res.sendFile(__dirname + '/json/rooms.json');
+ });
+
+ io.use(function (client, next) {
+ var query = client.handshake.query;
+ return router.route(query, next);
+ });
+
+ io.sockets.on('connection', function (socket) {
+ var roomName = socket.handshake.query.room;
+
+ socket.join(roomName);
+ socket.emit('joined_room', roomName);
+
+ debug('A user connected: %s and joined room: %s', socket.id, roomName);
+
+ socket.on('disconnect', function () {
+ debug('A user disconnected: %s and left room: %s', socket.id, roomName);
+ disconnector.disconnectRoom(socket.id);
+ observer.notify('disconnect', socket.id);
+ });
+
+ socket.on('move_in', function (direction) {
+ debug('Moving user: %s in direction: %s', socket.id, direction);
+ mover.moveIn(socket.id, direction);
+ observer.notify('move_in', direction)
+ });
+ });
+
+ return {
+ withRouter: function (alternativeRouter) {
+ router = alternativeRouter;
+ return this;
+ },
+ withDisconnector: function (alternativeDisconnector) {
+ disconnector = alternativeDisconnector;
+ return this;
+ },
+ withObserver: function (alternativeObserver) {
+ observer = alternativeObserver;
+ return this;
+ },
+ withMover: function (alternativeMover) {
+ mover = alternativeMover;
+ return this;
+ },
+ create: function () {
+ var server = httpServer.listen(4200, function () {
+ debug('Express server listening on port %s', 4200);
+ });
+
+ return server;
+ }
+ };
+}
diff --git a/TelepresenceBot/server-unit/core/testServer.js b/TelepresenceBot/server-unit/core/testServer.js
deleted file mode 100644
index ed088da43..000000000
--- a/TelepresenceBot/server-unit/core/testServer.js
+++ /dev/null
@@ -1,44 +0,0 @@
-var express = require('express');
-var app = express();
-var server = require('http').createServer(app);
-var io = require('socket.io')(server);
-var path = require('path');
-var debug = require('debug')('server');
-
-var server = server.listen(4200, function() {
- debug("Express server listening on port %s", 4200);
-});
-
-app.use(express.static(path.join(__dirname, 'public')));
-
-app.get('/', function(req, res) {
- res.sendFile(__dirname + '/html/index.html');
-});
-
-app.get('/rooms', function(req, res) {
- res.sendFile(__dirname + '/json/rooms.json');
-});
-
-io.sockets.on("connection", function (socket) {
- debug('a user connected');
-
- socket.on('disconnect', function(){
- debug('user disconnected');
- });
-
- socket.on('chat message', function(message){
- debug('message: %s', message);
- });
-
- socket.on("echo", function (msg, callback) {
- callback = callback || function () {};
-
- socket.emit("echo", msg);
-
- debug("on Connection");
-
- callback(null, "Done.");
- });
-});
-
-exports.server = server;
diff --git a/TelepresenceBot/server-unit/package-lock.json b/TelepresenceBot/server-unit/package-lock.json
index 4751f8d5e..c4718d8e6 100644
--- a/TelepresenceBot/server-unit/package-lock.json
+++ b/TelepresenceBot/server-unit/package-lock.json
@@ -711,6 +711,12 @@
"kindof": "https://registry.npmjs.org/kindof/-/kindof-1.0.0.tgz"
}
},
+ "native-promise-only": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz",
+ "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=",
+ "dev": true
+ },
"negotiator": {
"version": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
@@ -959,14 +965,57 @@
"dev": true
},
"sinon": {
- "version": "https://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz",
- "integrity": "sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=",
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/sinon/-/sinon-2.3.7.tgz",
+ "integrity": "sha1-FFFhSi6qsFu02HbBM1zUATLsUSc=",
"dev": true,
"requires": {
- "formatio": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz",
- "lolex": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz",
- "samsam": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz",
- "util": "https://registry.npmjs.org/util/-/util-0.10.3.tgz"
+ "diff": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz",
+ "formatio": "1.2.0",
+ "lolex": "1.6.0",
+ "native-promise-only": "0.8.1",
+ "path-to-regexp": "1.7.0",
+ "samsam": "1.2.1",
+ "text-encoding": "0.6.4",
+ "type-detect": "4.0.3"
+ },
+ "dependencies": {
+ "formatio": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz",
+ "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=",
+ "dev": true,
+ "requires": {
+ "samsam": "1.2.1"
+ }
+ },
+ "lolex": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz",
+ "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=",
+ "dev": true
+ },
+ "path-to-regexp": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz",
+ "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=",
+ "dev": true,
+ "requires": {
+ "isarray": "0.0.1"
+ }
+ },
+ "samsam": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.2.1.tgz",
+ "integrity": "sha1-7dOQk6MYQ3DLhZJDsr3yVefY6mc=",
+ "dev": true
+ },
+ "type-detect": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.3.tgz",
+ "integrity": "sha1-Dj8mcLRAmbC0bChNE2p+9Jx0wuo=",
+ "dev": true
+ }
}
},
"socket.io": {
@@ -1183,6 +1232,12 @@
"has-flag": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz"
}
},
+ "text-encoding": {
+ "version": "0.6.4",
+ "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz",
+ "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=",
+ "dev": true
+ },
"to-array": {
"version": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
"integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA="
@@ -1215,7 +1270,7 @@
"must": "https://registry.npmjs.org/must/-/must-0.12.0.tgz",
"noder.io": "https://registry.npmjs.org/noder.io/-/noder.io-1.2.0.tgz",
"should": "6.0.3",
- "sinon": "https://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz",
+ "sinon": "1.17.7",
"supertest": "0.15.0"
},
"dependencies": {
@@ -1278,6 +1333,18 @@
"integrity": "sha1-ATKgVBemEmhmQmrPEW8e1WI6XNA=",
"dev": true
},
+ "sinon": {
+ "version": "1.17.7",
+ "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz",
+ "integrity": "sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=",
+ "dev": true,
+ "requires": {
+ "formatio": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz",
+ "lolex": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz",
+ "samsam": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz",
+ "util": "https://registry.npmjs.org/util/-/util-0.10.3.tgz"
+ }
+ },
"superagent": {
"version": "0.21.0",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-0.21.0.tgz",
diff --git a/TelepresenceBot/server-unit/package.json b/TelepresenceBot/server-unit/package.json
index 5b619ad1b..7023d3b14 100644
--- a/TelepresenceBot/server-unit/package.json
+++ b/TelepresenceBot/server-unit/package.json
@@ -26,6 +26,7 @@
"fs": "0.0.1-security",
"mocha": "^3.4.2",
"should": "^11.2.1",
+ "sinon": "^2.3.7",
"supertest": "^3.0.0",
"unit.js": "^2.0.0"
}
diff --git a/TelepresenceBot/server-unit/test/apiTest.js b/TelepresenceBot/server-unit/test/apiTest.js
index 0042d89e4..89efbdf91 100644
--- a/TelepresenceBot/server-unit/test/apiTest.js
+++ b/TelepresenceBot/server-unit/test/apiTest.js
@@ -1,49 +1,46 @@
-var mocha = require('mocha'),
+const mocha = require('mocha'),
request = require('supertest'),
- debug = require('debug')('apiTest'),
expect = require('chai').expect,
- fs = require('fs')
+ fs = require('fs'),
+ ServerCreator = require('../core/serverCreator.js'),
+ io = require('socket.io-client'),
+ options = {
+ transports: ['websocket'],
+ 'force new connection': true
+ };
-var io = require('socket.io-client');
+let server;
-var server, options = {
- transports: ['websocket'],
- 'force new connection': true
-};
-
-describe("Performing GET request", function () {
+describe('API Tests - Performing GET requests.', function () {
beforeEach(function (done) {
- delete require.cache[require.resolve('../core/testServer')];
- server = require('../core/testServer').server;
- debug('server starts');
+ server = new ServerCreator().create();
done();
});
- afterEach(function(done) {
+ afterEach(function (done) {
server.close(done);
- debug('server closes');
});
- it("Should serve index.html in response to '/' call.", function (done) {
+ it('Should serve index.html in response to "/" call.', function (done) {
request(server)
.get('/')
.type('html')
.expect(200)
- .end(function(error, response) {
- var file = fs.readFileSync("../core/html/index.html", "utf8");
+ .end(function (error, response) {
+ const file = fs.readFileSync('../core/html/index.html', 'utf8');
expect(response.text).to.equal(file);
done();
});
});
- it("Should serve rooms.json in response to '/rooms' call.", function (done) {
+ it('Should serve rooms.json in response to "/rooms" call.', function (done) {
request(server)
.get('/rooms')
.type('json')
.expect(200)
- .end(function(error, response) {
- var file = fs.readFileSync("../core/json/rooms.json", "utf8");
+ .end(function (error, response) {
+ const file = fs.readFileSync('../core/json/rooms.json', 'utf8');
expect(response.text).to.equal(file);
done();
});
diff --git a/TelepresenceBot/server-unit/test/botLocatorTest.js b/TelepresenceBot/server-unit/test/botLocatorTest.js
index 5470a24bf..7c570f25d 100644
--- a/TelepresenceBot/server-unit/test/botLocatorTest.js
+++ b/TelepresenceBot/server-unit/test/botLocatorTest.js
@@ -1,87 +1,78 @@
-var should = require('should');
-var test = require('unit.js');
-var BotLocator = require("../core/botLocator.js");
+const expect = require('chai').expect
+BotLocator = require('../core/botLocator.js');
-var roomWithASingleBot = {
+const roomWithASingleBot = {
'botId': {
- sockets: {'botId':true},
- length:1
+ sockets: { 'botId': true },
+ length: 1
},
'London': {
- sockets: {'botId':true},
- length:1
+ sockets: { 'botId': true },
+ length: 1
}
};
-var roomWhereBotIsConnectedToHuman = {
+const roomWhereBotIsConnectedToHuman = {
'botId': {
- sockets: {'botId':true, 'humanId':true},
- length:2
+ sockets: { 'botId': true, 'humanId': true },
+ length: 2
},
'London': {
- sockets: {'botId':true},
- length:1
+ sockets: { 'botId': true },
+ length: 1
}
};
-var roomContainingMultipleBotsWhereOneIsConnectedToHuman = {
+const roomContainingMultipleBotsWhereOneIsConnectedToHuman = {
'botId01': {
- sockets: {'botId01':true, 'human01':true},
- length:2
+ sockets: { 'botId01': true, 'human01': true },
+ length: 2
},
'botId02': {
- sockets: {'botId02':true},
- length:1
+ sockets: { 'botId02': true },
+ length: 1
},
'London': {
- sockets: {'botId01':true, 'botId02':true},
- length:2
+ sockets: { 'botId01': true, 'botId02': true },
+ length: 2
}
};
-describe("BotLocator ",function() {
+describe('BotLocator Tests.', function () {
- it('Should give undefined when bot is not found in given room.', function(done){
- var botLocator = new BotLocator(roomWithASingleBot);
+ it('Should give undefined when bot is not found in given room.', function (done) {
+ const botLocator = new BotLocator(roomWithASingleBot);
- var bot = botLocator.locateFirstAvailableBotIn("Unexpected Room");
-
- test.value(bot)
- .isUndefined();
+ const bot = botLocator.locateFirstAvailableBotIn('Unexpected Room');
+ expect(bot).to.be.undefined;
done();
});
- it('Should give bot id when bot room does not contain other sockets.', function(done){
- var botLocator = new BotLocator(roomWithASingleBot);
-
- var bot = botLocator.locateFirstAvailableBotIn("London");
+ it('Should give bot id when bot room does not contain other sockets.', function (done) {
+ const botLocator = new BotLocator(roomWithASingleBot);
- test.string(bot)
- .is("botId");
+ const bot = botLocator.locateFirstAvailableBotIn('London');
+ expect(bot).to.equal('botId');
done();
});
- it('Should give undefined when bot room contains other sockets.', function(done){
- var botLocator = new BotLocator(roomWhereBotIsConnectedToHuman);
+ it('Should give undefined when bot room contains other sockets.', function (done) {
+ const botLocator = new BotLocator(roomWhereBotIsConnectedToHuman);
- var bot = botLocator.locateFirstAvailableBotIn("London");
-
- test.value(bot)
- .isUndefined();
+ const bot = botLocator.locateFirstAvailableBotIn('London');
+ expect(bot).to.be.undefined;
done();
});
- it('Should give first bot in room that contains multiple bots.', function(done){
- var botLocator = new BotLocator(roomContainingMultipleBotsWhereOneIsConnectedToHuman);
-
- var bot = botLocator.locateFirstAvailableBotIn("London");
+ it('Should give first bot in room that contains multiple bots.', function (done) {
+ const botLocator = new BotLocator(roomContainingMultipleBotsWhereOneIsConnectedToHuman);
- test.string(bot)
- .is('botId02');
+ const bot = botLocator.locateFirstAvailableBotIn('London');
+ expect(bot).to.equal('botId02');
done();
});
diff --git a/TelepresenceBot/server-unit/test/botTest.js b/TelepresenceBot/server-unit/test/botTest.js
deleted file mode 100644
index ab2879449..000000000
--- a/TelepresenceBot/server-unit/test/botTest.js
+++ /dev/null
@@ -1,121 +0,0 @@
-var should = require('should');
-var io = require('socket.io-client');
-var test = require('unit.js');
-
-var socketURL = 'http://0.0.0.0:5000'
-
-var options ={
- transports: ['websocket'],
- 'force new connection': true,
- query: 'clientType=bot&room=London'
-};
-
-var humanOptions ={
- transports: ['websocket'],
- 'force new connection': true,
- query: 'clientType=human&room=London'
-};
-
-var testOptions ={
- transports: ['websocket'],
- 'force new connection': true,
- query: 'clientType=test'
-};
-
-describe("TelepresenceBot Server: BotTest ",function() {
-
- it('Should add bot to Room:London on connection.', function(done) {
- var testObserver = io.connect(socketURL, testOptions);
-
- testObserver.on('connected', function(){
- var bot = io.connect(socketURL, options);
-
- testObserver.on('connected_bot', function(roomsWithSockets){
- var expectedSockets = [bot.id];
- var actualSockets = roomsWithSockets["London"];
-
- test.array(actualSockets)
- .is(expectedSockets);
-
- bot.disconnect();
- testObserver.disconnect();
- done();
- });
- });
- });
-
- it('Should remove bot from Room:London on disconnection.', function(done) {
- var testObserver = io.connect(socketURL, testOptions);
-
- testObserver.on('connected', function(){
- var bot = io.connect(socketURL, options);
-
- testObserver.on('connected_bot', function(){
- bot.disconnect();
-
- testObserver.on('disconnected_bot', function(roomsWithSockets) {
- var actualSockets = roomsWithSockets["London"];
-
- test.value(actualSockets)
- .isUndefined();
-
- testObserver.disconnect();
- done();
- });
- });
- });
- });
-
- it('Should disconnect human on bot disconnection.', function(done) {
- var testObserver = io.connect(socketURL, testOptions);
-
- testObserver.on('connected', function(){
- var bot = io.connect(socketURL, options);
-
- testObserver.on('connected_bot', function(){
- var human = io.connect(socketURL, humanOptions);
-
- testObserver.on('connected_human', function(){
- bot.disconnect();
-
- testObserver.on('disconnected_human', function(roomsWithSockets){
- var actualSockets = roomsWithSockets[bot.id];
-
- test.value(actualSockets)
- .isUndefined();
-
- testObserver.disconnect();
- done();
- });
- });
- });
- });
- });
-
- it('Should forward movement directions from human to bot.', function(done) {
- var testObserver = io.connect(socketURL, testOptions);
-
- testObserver.on('connected', function(){
- var bot = io.connect(socketURL, options);
-
- testObserver.on('connected_bot', function(){
- var human = io.connect(socketURL, humanOptions);
-
- testObserver.on('connected_human', function(){
- human.emit('move_in', 'w');
-
- bot.on('direction', function(actualDirection){
- test.string(actualDirection)
- .is('w');
-
- testObserver.disconnect();
- human.disconnect();
- bot.disconnect();
- done();
- });
- });
- });
- });
- });
-
-});
diff --git a/TelepresenceBot/server-unit/test/disconnectorTest.js b/TelepresenceBot/server-unit/test/disconnectorTest.js
new file mode 100644
index 000000000..62f2651e5
--- /dev/null
+++ b/TelepresenceBot/server-unit/test/disconnectorTest.js
@@ -0,0 +1,70 @@
+const expect = require('chai').expect,
+ Disconnector = require('../core/disconnector.js');
+
+const rooms = {
+ 'botId': {
+ sockets: { 'botId': true },
+ length: 1
+ },
+ 'botId02': {
+ sockets: { 'botId02': true },
+ length: 1
+ },
+ 'London': {
+ sockets: { 'botId': true, 'botId02': true },
+ length: 2
+ }
+};
+
+let connectedClients = {
+ called: false,
+ 'botId': {
+ disconnect: function () {
+ connectedClients.called = true;
+ }
+ }
+};
+
+let noConnectedClients = {
+ called: false,
+ disconnect: function () {
+ noConnectedClients.called = true;
+ }
+};
+
+afterEach(function (done) {
+ connectedClients.called = false;
+ noConnectedClients.called = false;
+ done();
+});
+
+describe('Disconnector Tests.', function () {
+
+ it('Should do nothing when cannot locate room in list of rooms.', function (done) {
+ const disconnector = new Disconnector(rooms, connectedClients);
+
+ disconnector.disconnectRoom('Room not present');
+
+ expect(connectedClients.called).to.be.false;
+ done();
+ });
+
+ it('Should do nothing when connected clients does contain any clients.', function (done) {
+ const disconnector = new Disconnector(rooms, noConnectedClients);
+
+ disconnector.disconnectRoom('London');
+
+ expect(noConnectedClients.called).to.be.false;
+ done();
+ });
+
+ it('Should call disconnect when disconnecting all clients in room.', function (done) {
+ const disconnector = new Disconnector(rooms, connectedClients);
+
+ disconnector.disconnectRoom('London');
+
+ expect(connectedClients.called).to.be.true;
+ done();
+ });
+
+});
diff --git a/TelepresenceBot/server-unit/test/humanTest.js b/TelepresenceBot/server-unit/test/humanTest.js
deleted file mode 100644
index 9ea293276..000000000
--- a/TelepresenceBot/server-unit/test/humanTest.js
+++ /dev/null
@@ -1,111 +0,0 @@
-var should = require('should');
-var io = require('socket.io-client');
-var test = require('unit.js');
-
-var socketURL = 'http://0.0.0.0:5000'
-
-var options ={
- transports: ['websocket'],
- 'force new connection': true,
- query: 'clientType=human&room=London'
-};
-
-var botOptions ={
- transports: ['websocket'],
- 'force new connection': true,
- query: 'clientType=bot&room=London'
-};
-
-var testOptions ={
- transports: ['websocket'],
- 'force new connection': true,
- query: 'clientType=test'
-};
-
-describe("TelepresenceBot Server: HumanTest ",function() {
-
- it('Should throw error when attempting to connect as non-human.', function(done){
- var nonHumanOptions ={
- transports: ['websocket'],
- 'force new connection': true,
- query: 'clientType=non-human'
- };
-
- var human = io.connect(socketURL, nonHumanOptions);
-
- human.on('error', function(errorMessage){
- test.string(errorMessage)
- .is("Unrecognised clientType: non-human");
-
- human.disconnect();
- done();
- });
- });
-
- it('Should refuse connection when a bot is not available', function(done){
- var human = io.connect(socketURL, options);
-
- human.on('error', function(errorMessage){
- test.string(errorMessage)
- .is("No bots available");
-
- human.disconnect();
- done();
- });
- });
-
- it('Should add human to first available bots room.', function(done) {
- var testObserver = io.connect(socketURL, testOptions);
-
- testObserver.on('connect', function(){
- var bot = io.connect(socketURL, botOptions);
-
- testObserver.on('connected_bot', function(){
- var human = io.connect(socketURL, options);
-
- testObserver.on('connected_human', function(roomsWithSockets){
- var expectedSockets = [bot.id, human.id];
- var actualSockets = roomsWithSockets[bot.id];
-
- test.array(actualSockets)
- .is(expectedSockets);
-
- human.disconnect();
- bot.disconnect();
-
- done();
- });
- });
- });
- });
-
- it('Should remove human from bots room.', function(done) {
- var testObserver = io.connect(socketURL, testOptions);
-
- testObserver.on('connect', function(){
- var bot = io.connect(socketURL, botOptions);
-
- testObserver.on('connected_bot', function(){
- var human = io.connect(socketURL, options);
-
- testObserver.on('connected_human', function(){
- human.disconnect();
-
- testObserver.on('disconnected_human', function(roomsWithSockets){
- var expectedSockets = [bot.id];
- var actualSockets = roomsWithSockets[bot.id];
-
- test.array(actualSockets)
- .is(expectedSockets);
-
- bot.disconnect();
- testObserver.disconnect();
-
- done();
- });
- });
- });
- });
- });
-
-});
diff --git a/TelepresenceBot/server-unit/test/moverTest.js b/TelepresenceBot/server-unit/test/moverTest.js
new file mode 100644
index 000000000..2146dcf2a
--- /dev/null
+++ b/TelepresenceBot/server-unit/test/moverTest.js
@@ -0,0 +1,73 @@
+const expect = require('chai').expect,
+ Mover = require('../core/mover.js');
+
+const clientsAndRooms = {
+ 'humanId': {
+ 'botId': true
+ },
+ 'botId': {
+ 'botId': true, 'London': true
+ }
+}
+
+let emitter = {
+ called: false,
+ to: function (room) {
+ return {
+ emit: function (event, valueToEmit) {
+ emitter.room = room;
+ emitter.event = event;
+ emitter.valueToEmit = valueToEmit;
+ emitter.called = true;
+ }
+ }
+ }
+}
+
+afterEach(function (done) {
+ emitter.called = false;
+ done();
+});
+
+describe('Mover Tests.', function () {
+
+ it('Should emit to botId when moving humanId in any direction.', function (done) {
+ const mover = new Mover(clientsAndRooms, emitter);
+
+ mover.moveIn('humanId', 'forward');
+
+ expect(emitter.called).to.be.true;
+ expect(emitter.room).to.equal('botId');
+ done();
+ });
+
+ it('Should emit event of direction when moving humanId in any direction.', function (done) {
+ const mover = new Mover(clientsAndRooms, emitter);
+
+ mover.moveIn('humanId', 'forward');
+
+ expect(emitter.called).to.be.true;
+ expect(emitter.event).to.equal('direction');
+ done();
+ });
+
+ it('Should emit value of forward when moving humanId in a forward direction.', function (done) {
+ const mover = new Mover(clientsAndRooms, emitter);
+
+ mover.moveIn('humanId', 'forward');
+
+ expect(emitter.called).to.be.true;
+ expect(emitter.valueToEmit).to.equal('forward');
+ done();
+ });
+
+ it('Should do nothing when a given clientId does not belong to any rooms.', function (done) {
+ const mover = new Mover(clientsAndRooms, emitter);
+
+ mover.moveIn('clientId', 'forward');
+
+ expect(emitter.called).to.be.false;
+ done();
+ });
+
+});
diff --git a/TelepresenceBot/server-unit/test/routerTest.js b/TelepresenceBot/server-unit/test/routerTest.js
new file mode 100644
index 000000000..7f06bcfd7
--- /dev/null
+++ b/TelepresenceBot/server-unit/test/routerTest.js
@@ -0,0 +1,70 @@
+const sinon = require('sinon'),
+ expect = require('chai').expect,
+ botLocator = require('../core/BotLocator.js')(),
+ router = require('../core/Router.js')(botLocator);
+
+const queryWithHuman = {
+ clientType: 'human',
+ room: 'London',
+};
+
+const queryWithBot = {
+ clientType: 'bot',
+ room: 'London',
+};
+
+const queryWithUnhandled = {
+ clientType: 'unhandled',
+ room: 'London',
+};
+
+describe('Router Tests.', function () {
+
+ it('Should replace query.room with first available bot when clientType is Human.', function (done) {
+ const firstAvailableBotId = 'ABCDEFGH123';
+
+ mockBotLocator = sinon.stub(botLocator, 'locateFirstAvailableBotIn')
+ .callsFake(function () { return firstAvailableBotId; });
+
+ router.route(queryWithHuman, onNext = function (data) {
+ expect(data).to.be.undefined;
+ expect(mockBotLocator.called).to.be.true;
+ expect(queryWithHuman.room).to.equal(firstAvailableBotId);
+ botLocator.locateFirstAvailableBotIn.restore();
+ done();
+ });
+
+ });
+
+
+ it('Should pass through Bot without any checks.', function (done) {
+ router.route(queryWithBot, onNext = function (data) {
+ expect(data).to.be.undefined;
+ done();
+ });
+
+ });
+
+ it('Should return Error when the are no available Bots.', function (done) {
+ const noAvailableBots = undefined;
+
+ mockBotLocator = sinon.stub(botLocator, 'locateFirstAvailableBotIn')
+ .callsFake(function () { return noAvailableBots; });
+
+ router.route(queryWithHuman, onNext = function (data) {
+ expect(mockBotLocator.called).to.be.true;
+ expect(data.message).to.equal('No bots available');
+ botLocator.locateFirstAvailableBotIn.restore();
+ done();
+ });
+
+ });
+
+ it('Should return Error for unhandled ClientType.', function (done) {
+ router.route(queryWithUnhandled, onNext = function (data) {
+ expect(data.message).to.equal('Unrecognised clientType: unhandled');
+ done();
+ });
+ });
+
+});
diff --git a/TelepresenceBot/server-unit/test/serverCreatorTest.js b/TelepresenceBot/server-unit/test/serverCreatorTest.js
new file mode 100644
index 000000000..46310e7d8
--- /dev/null
+++ b/TelepresenceBot/server-unit/test/serverCreatorTest.js
@@ -0,0 +1,95 @@
+const sinon = require('sinon'),
+ expect = require('chai').expect,
+ router = require('../core/Router.js')(),
+ disconnector = require('../core/Disconnector.js')(),
+ observer = require('../core/Observer.js'),
+ mover = require('../core/mover.js')(),
+ ServerCreator = require('../core/serverCreator.js');
+
+const io = require('socket.io-client');
+
+const socketUrl = 'http://localhost:4200';
+
+options = {
+ transports: ['websocket'],
+ 'force new connection': true,
+ query: 'clientType=human&room=London'
+};
+
+describe('ServerCreator Tests.', function () {
+
+ before(function (done) {
+ mockRouter = sinon.stub(router, 'route').callsFake(function (client, next) { return next(); });
+ mockMover = sinon.stub(mover, 'moveIn').callsFake(function (clientId, direction) { return true; });
+ mockDisconnector = sinon.stub(disconnector, 'disconnectRoom').callsFake(function () { return true; });
+ done();
+ });
+
+ beforeEach(function (done) {
+ server = new ServerCreator()
+ .withRouter(router)
+ .withDisconnector(disconnector)
+ .withObserver(observer)
+ .withMover(mover)
+ .create();
+
+ done();
+ });
+
+ afterEach(function (done) {
+ server.close();
+ done();
+ });
+
+ it('Should delegate to Router when client is connected.', function (done) {
+ const client = io.connect(socketUrl, options);
+
+ client.once('connect', function () {
+ client.once('joined_room', function (room) {
+ expect(mockRouter.called).to.be.true;
+ done();
+ });
+ });
+ });
+
+ it('Should emit joined_room when client is connected.', function (done) {
+ const client = io.connect(socketUrl, options);
+
+ client.once('connect', function () {
+ client.once('joined_room', function (room) {
+ expect(room).to.equal('London');
+ done();
+ });
+ });
+ });
+
+ it('Should delegate to Mover when moving in given direction.', function (done) {
+ const client = io.connect(socketUrl, options);
+
+ client.once('connect', function () {
+ client.emit('move_in', 'forward');
+ });
+
+ observer.notify = function (eventName, data) {
+ expect(mockMover.called).to.be.true;
+ expect(mockMover.callCount).to.equal(1);
+ expect(data).to.equal('forward');
+ done();
+ };
+ });
+
+ it('Should delegate to Disconnector when disconnecting an already connected client.', function (done) {
+ const client = io.connect(socketUrl, options);
+
+ client.once('connect', function () {
+ client.disconnect();
+ });
+
+ observer.notify = function (eventName, data) {
+ expect(mockDisconnector.called).to.be.true;
+ expect(mockDisconnector.callCount).to.equal(1);
+ done();
+ };
+ });
+
+});
diff --git a/TelepresenceBot/server-unit/test/socketTest.js b/TelepresenceBot/server-unit/test/socketTest.js
deleted file mode 100644
index 2b101f869..000000000
--- a/TelepresenceBot/server-unit/test/socketTest.js
+++ /dev/null
@@ -1,34 +0,0 @@
-var chai = require('chai'),
- mocha = require('mocha'),
- should = chai.should();
-
-var io = require('socket.io-client');
-
-var server, options = {
- transports: ['websocket'],
- 'force new connection': true
-};
-
-describe("echo", function () {
-
- beforeEach(function (done) {
- server = require('../core/testServer').server;
- done();
- });
-
- it("echos message", function (done) {
- var client = io.connect("http://localhost:4200", options);
-
- client.once("connect", function () {
- client.once("echo", function (message) {
- message.should.equal("Hello World");
-
- client.disconnect();
- done();
- });
-
- client.emit("echo", "Hello World");
- });
- });
-
-});