refactored clock management to server side, basic unit test framework

This commit is contained in:
Alec Maier
2020-05-03 05:55:14 -04:00
parent 7e7977a4c8
commit de0e365ed5
7 changed files with 78 additions and 131 deletions

View File

@@ -1,70 +0,0 @@
const express = require("express");
const open = require("open");
const app = express();
const http = require("http");
const server = http.createServer(app);
const path = require("path");
const io = require('socket.io')(server);
// const debugMode = Array.from(process.argv.map( (arg)=>arg.trim().toLowerCase() )).some((it)=> it.includes("debug"));
const useSocket = Array.from(process.argv.map( (arg)=>arg.trim().toLowerCase() )).some((it)=> it.includes("socket"));
const openBrowser = Array.from(process.argv.map( (arg)=>arg.trim() )).some((it)=> it.includes("openBrowser"));
const port = Array
.from(process.argv.map( (arg) => {
return arg.trim().toLowerCase();
}))
.filter( (arg) => {
return /port=\d+/.test(arg);
})
.map( (arg) => {
return /port=(\d+)/.exec(arg)[1];
})[0] || 5000;
// const logger = require("./modules/logger")(debugMode);
app.set("port", port);
app.use(express.static(__dirname));
app.use(express.static(path.join(__dirname, 'images')));
app.use(express.static(path.join(__dirname, 'fonts')));
app.use(express.static(path.join(__dirname, 'views')));
app.use(express.static(path.join(__dirname, 'scripts')));
app.use(express.static(path.join(__dirname, 'stylesheets')));
app.use(express.static(path.join(__dirname, 'spec')));
app.get("/tests",function(request, response){
response.sendFile(__dirname + "/views/SpecRunner.html");
});
if(useSocket) {
console.log("Awaiting test results from browser...");
io.on("connection", function(socket){
socket.on("all-results", function(data) {
console.log("TOTAL: " + data.totalCount);
console.log("SUCCESS: " + (data.totalCount - (data.failureCount + data.pendingCount)));
console.log("FAILURES: " + data.failureCount);
console.log("SKIPPED: " + data.pendingCount + "\n");
data.failureCount > 0 ? console.log("FAILURE") : console.log("SUCCESS");
process.exit( data.failureCount > 0 ? 1 : 0);
});
});
}
server.listen(port, function() {
console.log(`Navigate to http://localhost:${port}/tests to view the in-browser tests.`);
});
// is this really that easy? ...wow.
if(openBrowser) {
console.log("Trying to open browser...");
if(useSocket) {
open("http://localhost:" + port + "/tests?socket=true");
} else {
open("http://localhost:" + port + "/tests");
}
}

View File

@@ -4,8 +4,7 @@
"description": "",
"main": "index.js",
"scripts": {
"test": "jasmine",
"test:all": "jasmine && node browsertest.js openBrowser socket"
"test": "jasmine"
},
"author": "",
"license": "ISC",

View File

@@ -1,8 +1,12 @@
const debugMode = Array.from(process.argv.map( (arg)=>arg.trim().toLowerCase() )).includes("debug");
const LOGGER = require("./static/modules/logger")(debugMode);
module.exports = class {
constructor(CronJob) {
// TODO: do better than a plain object
this.activeGames = {};
this.timers = {};
// cron job for periodically clearing finished games
this.job = new CronJob('0 0 */2 * * *', function() {
@@ -48,13 +52,24 @@ module.exports = class {
}
}
timerExpired(code) {
endGameDueToTimeExpired(code) {
if (this.timers[code]) {
clearInterval(this.timers[code]);
}
let game = this.findGame(code);
if (game) {
LOGGER.debug("Game " + code + " has ended due to expired timer.");
game.winningTeam = "wolf";
game.status = "ended";
}
}
clearGameTimer(code) {
if (this.timers[code]) {
clearInterval(this.timers[code]);
LOGGER.debug("game paused and timer cleared for " + code);
}
}
resumeGame(code) {
let game = this.findGame(code);
@@ -64,6 +79,8 @@ module.exports = class {
let newDate = new Date(game.endTime);
newDate.setTime(newTime);
game.endTime = newDate.toJSON();
LOGGER.debug("Game " + code + " timer has been unpaused, starting clock anew...");
this.startGameClock(code, newDate - Date.now());
}
}
@@ -72,18 +89,32 @@ module.exports = class {
if (game) {
game.pauseTime = (new Date()).toJSON();
game.paused = true;
this.clearGameTimer(code);
}
}
startGameClock(code, time) {
LOGGER.debug("timer started for game " + code);
let moduleScope = this;
if (this.timers[code]) {
clearInterval(this.timers[code]);
}
this.timers[code] = setInterval(function() {
moduleScope.endGameDueToTimeExpired(code)
}, time);
}
startGame(gameData) {
let game = this.findGame(gameData.code);
if (game) {
LOGGER.debug("game " + gameData.code + " started");
game.status = "started";
game.players = gameData.players;
if (game.time) {
let d = new Date();
d.setMinutes(d.getMinutes() + parseInt(game.time));
game.endTime = d.toJSON();
this.startGameClock(gameData.code, game.time * 60 * 1000); // provided time is in minutes
}
}
}

View File

@@ -5,7 +5,7 @@ const socketIO = require('socket.io');
const app = express();
const server = http.Server(app);
const io = socketIO(server);
const ServerHelper = require('server-helper.js');
const ServerHelper = require('./server-helper.js');
const secure = require('express-force-https');
app.use(secure);
@@ -13,6 +13,9 @@ app.use(secure);
const CronJob = require('cron').CronJob;
const serverHelper = new ServerHelper(CronJob);
const debugMode = Array.from(process.argv.map( (arg)=>arg.trim().toLowerCase() )).includes("debug");
const LOGGER = require("./static/modules/logger")(debugMode);
app.set('port', 5000);
app.use('/static', express.static(__dirname + '/static')); // Routing

View File

@@ -175,7 +175,7 @@ function renderGame() {
// build the clock
if (currentGame.time) {
renderClock();
updateClock();
document.getElementById("pause-container").innerHTML = currentGame.paused ?
"<img alt='pause' src='../assets/images/play-button.svg' id='play-pause'/>"
: "<img alt='pause' src='../assets/images/pause-button.svg' id='play-pause'/>";
@@ -323,33 +323,30 @@ function flipDown(){
card.classList.remove("flip-up");
}
function renderClock() {
clock = setInterval(function() {
const start = currentGame.paused ? new Date(currentGame.pauseTime) : new Date();
const end = new Date(currentGame.endTime);
const delta = end - start;
if (currentGame.paused) {
clearInterval(clock);
}
if (delta <= 0) {
endGameDueToTimeExpired();
} else {
let seconds = Math.floor( (delta / 1000) % 60);
let minutes = Math.floor( (delta / 1000 / 60) % 60);
let hours = Math.floor( (delta / (1000*60*60)) % 24);
seconds = seconds < 10 ? "0" + seconds : seconds;
minutes = minutes < 10 ? "0" + minutes : minutes;
document.getElementById("clock").innerText = hours > 0
? hours + ":" + minutes + ":" + seconds
: minutes + ":" + seconds;
function displayTime() {
const start = currentGame.paused ? new Date(currentGame.pauseTime) : new Date();
const end = new Date(currentGame.endTime);
const delta = end - start;
let seconds = Math.floor((delta / 1000) % 60);
let minutes = Math.floor((delta / 1000 / 60) % 60);
let hours = Math.floor((delta / (1000 * 60 * 60)) % 24);
}
}, 1000);
seconds = seconds < 10 ? "0" + seconds : seconds;
minutes = minutes < 10 ? "0" + minutes : minutes;
document.getElementById("clock").innerText = hours > 0
? hours + ":" + minutes + ":" + seconds
: minutes + ":" + seconds;
}
function endGameDueToTimeExpired() {
function updateClock() {
clearInterval(clock);
socket.emit("timerExpired", currentGame.accessCode);
if (document.getElementById("clock") !== null) {
displayTime();
clock = setInterval(function() {
displayTime();
}, 1000);
}
}
function killPlayer() {

20
static/modules/logger.js Normal file
View File

@@ -0,0 +1,20 @@
module.exports = function(debugMode = false){
return {
log(message = "") {
const now = new Date();
console.log('LOG ', now.toGMTString(), ': ', message);
},
debug(message = "") {
if (!debugMode) return;
const now = new Date();
console.debug('DEBUG ', now.toGMTString(), ': ', message);
},
error(message = "") {
if (!debugMode) return;
const now = new Date();
console.error('ERROR ', now.toGMTString(), ': ', message);
}
};
};

View File

@@ -1,33 +0,0 @@
<!DOCTYPE html>
<html lang="en">>
<head>
<meta charset="utf-8">
<title>Werewolf unit tests</title>
<link rel="shortcut icon" type="image/png" href="lib/jasmine-3.5.0/jasmine_favicon.png">
<link rel="stylesheet" href="lib/jasmine-3.5.0/jasmine.css">
<script src="../lib/jasmine-3.5.0/jasmine.js"></script>
<script src="../lib/jasmine-3.5.0/jasmine-html.js"></script>
<script src="../lib/jasmine-3.5.0/boot.js"></script>
<script src="../node_modules/socket.io-client/dist/socket.io.js"></script>
<!-- include source files here... -->
<!--<script src="/scripts/games.js" type="module"></script>-->
<!--<script src="../server-helper.js" type="module"></script>-->
<!-- include spec files here... -->
<script src="/spec/SpecHelper.js" type="module"></script>
<script src="/spec/HomeSpec.js" type="module"></script>
<style>
div#playground {
visibility: hidden;
}
</style>
</head>
<body>
<div id="playground"></div>
</body>
</html>