Added timeout to leadership election

This commit is contained in:
Chris Blanchard 2015-07-31 16:03:09 +01:00
parent 3bdaaa9169
commit 6f5e927f70
2 changed files with 52 additions and 3 deletions

View file

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

View file

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