From 6f5e927f70fc974b2affe7daf972173648c7a60c Mon Sep 17 00:00:00 2001 From: Chris Blanchard Date: Fri, 31 Jul 2015 16:03:09 +0100 Subject: [PATCH] Added timeout to leadership election --- lib/gather/gather.js | 35 ++++++++++++++++++++++++++++++++--- spec/gather.js | 20 ++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/lib/gather/gather.js b/lib/gather/gather.js index 67dc59b..4222bd9 100644 --- a/lib/gather/gather.js +++ b/lib/gather/gather.js @@ -20,6 +20,8 @@ function Gather () { } this.TEAM_SIZE = 6; this.gatherers = []; + this.ELECTION_INTERVAL = 10000; // 10 Seconds (temporarily) + this.electionStartTime = null; this.initState(); } @@ -129,7 +131,11 @@ Gather.prototype.marines = function () { Gather.prototype.toJson = function () { return { gatherers: this.gatherers, - state: this.current + state: this.current, + election: { + startTime: this.electionStartTime, + interval: this.ELECTION_INTERVAL + } } }; @@ -198,25 +204,43 @@ StateMachine.create({ { name: "initState", from: "none", to: "gathering" }, { name: "addGatherer", from: "gathering", to: "election" }, { name: "selectLeader", from: "election", to: "selection" }, + { name: "electionTimeout", from: "election", to: "selection" }, { name: "confirmSelection", from: "selection", to: "done" }, { name: "removeGatherer", from: ["gathering", "election", "selection"], to: "gathering" } ], callbacks: { + // Gathering State onbeforeaddGatherer: function (event, from, to, user) { this.addUser(user); if (this.gatherers.length !== 12) { return false; } }, + + // Election State onbeforeselectLeader: function (event, from, to, voter, candidate) { this.voteForLeader(voter, candidate); if (this.leaderVotes().length !== 12) { return false; } }, - onbeforeremoveGatherer: function (event, from, to, user) { - this.removeUser(user); + + onenterelection: function () { + // Setup timer for elections + var self = this; + self.electionStartTime = new Date(); + setTimeout(function () { + if (self.can("electionTimeout")) { + self.electionTimeout(); + } + }, self.ELECTION_INTERVAL); }, + + onleaveelection: function () { + this.electionStartTime = null; + }, + + // Selection State onenterselection: function () { // Remove all leaders and teams this.gatherers.forEach(function (gatherer, index, array) { @@ -244,9 +268,14 @@ StateMachine.create({ this.assignAlienLeader(parseInt(rank.pop().candidate, 0)); this.assignMarineLeader(parseInt(rank.pop().candidate, 0)); }, + onbeforeconfirmSelection: function (event, from, to, leader) { return (this.aliens().length === this.TEAM_SIZE && this.marines().length === this.TEAM_SIZE); + }, + + onbeforeremoveGatherer: function (event, from, to, user) { + this.removeUser(user); } } }); diff --git a/spec/gather.js b/spec/gather.js index c564a34..1d7f136 100644 --- a/spec/gather.js +++ b/spec/gather.js @@ -43,6 +43,23 @@ describe("Gather Model:", function () { }); }); + describe("Election Tmimeout", function () { + it ("starts a timer and transitions to next state when timer runs out", function (done) { + gather.ELECTION_INTERVAL = 100; // 1 second + assert.isNull(gather.electionStartTime); + gatherers.forEach(function (gatherer) { + gather.addGatherer(gatherer); + }); + assert.equal(gather.current, "election"); + assert.isNotNull(gather.electionStartTime); + setTimeout(function () { + assert.equal(gather.current, "selection"); + assert.isNull(gather.electionStartTime); + done(); + }, 200); + }); + }); + describe("Election", function () { beforeEach(function () { gatherers.forEach(function (gatherer) { @@ -58,6 +75,7 @@ describe("Gather Model:", function () { assert.equal(gather.leaderVotes().length, 1); assert.equal(gather.leaderVotes()[0], candidate.id); }); + it ("retains state of 'election' until all votes cast", function () { var candidate = gatherers[0]; gatherers.forEach(function (voter, index) { @@ -235,6 +253,8 @@ describe("Gather Model:", function () { var output = gather.toJson(); assert.isArray(output.gatherers); assert.isString(output.state); + assert.isNull(output.election.startTime); + assert.equal(output.election.interval, gather.ELECTION_INTERVAL); }); });