diff --git a/README.md b/README.md index 046eb01..0e37f67 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ Try it out ! ```bash - docker image build -t ring-election . docker-compose up ``` Check assigned partitions to local:9000/status or change the port to 9001/9002
@@ -138,7 +137,14 @@ Tag 1.0 and public on npm

How to contribute

Take tasks from todo list, develop a new feature or fix a bug and do a pull request.
How to run tests
-npm run test +Unit tests
+npm run test

+Integration tests
+cd test/integration
+./integration.sh
+npm run integration-test
+ +

Versioning

We use (http://semver.org/) for versioning. diff --git a/package.json b/package.json index 14f4503..a24d0a3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ring-election", - "version": "0.0.16", + "version": "1.0.0", "description": "Leader and followers algorithm to make partitioning easy.", "main": "index.js", "engines": { diff --git a/test/hearthbeat.test.js b/test/hearthbeat.test.js index 2f23f9f..5564650 100644 --- a/test/hearthbeat.test.js +++ b/test/hearthbeat.test.js @@ -18,7 +18,7 @@ describe('Hearth beat', () => { setTimeout(() => { expect(count >= 10).toBeTruthy(); done(); - }, 20); + }, 200); }); it('Should do an hearth check with correct frequency', done => { @@ -33,6 +33,6 @@ describe('Hearth beat', () => { setTimeout(() => { expect(count).toBe(0); done(); - }, 20); + }, 200); }); }); diff --git a/test/integration/integration.js b/test/integration/integration.js index e98b2bc..75be6ba 100644 --- a/test/integration/integration.js +++ b/test/integration/integration.js @@ -4,64 +4,102 @@ const expect = require('expect'); const request = require('request'); var exec = require('child_process').exec; -let shouldStartWell = (err, response, body , done , nodeNumber) => { - expect(response.statusCode).toBe(200); - expect(body).toBeDefined(); - let resp = JSON.parse(body); - expect(resp.length).toBe(3); - // actually the leader has not assigned to any partition. - let leader = resp.find(node => node.partitions.length == 0); - expect(leader).toBeDefined(); - // expect other two nodes to have 5 partitions assigned per each. - resp - .filter(node => node.partitions.length > 0) - .forEach(n => { - expect(n.partitions.length).toBe(5); - }); - if(nodeNumber == 3) - done(); - }; +let basicCheck =(response, body,expectedPartitions,expectedNodes) => { + expect(response.statusCode).toBe(200); + expect(body).toBeDefined(); + let resp = JSON.parse(body); + expect(resp.length).toBe(expectedNodes); + // actually the leader has not assigned to any partition. + let leader = resp.find(node => node.partitions.length == 0); + expect(leader).toBeDefined(); + // expect other node to have 10 partitions assigned per each. + resp + .filter(node => node.partitions.length > 0) + .forEach(n => { + expect(n.partitions.length).toBe(expectedPartitions); + }); +}; -describe('Integration test', () => { +let shouldStartWell = (err, response, body, done, nodeNumber) => { + basicCheck(response, body,5 , 3); + if (nodeNumber == 3) done(); +}; + +let shouldReassignPartitions = (err, response, body, done, nodeNumber) => { + basicCheck(response, body , 10 , 2); + // restart container + if (nodeNumber == 2) { + exec('docker container restart ring-election_node-2_1', error => { + expect(error).toBeFalsy(); + if (!error) done(); + }); + } +}; + +let shouldHandleLeaderFailure = (err, response, body, done, nodeNumber) => { + basicCheck(response, body , 10 , 2); + // restart container + if (nodeNumber == 2) { + exec('docker container restart ring-election_node-0_1', error => { + expect(error).toBeFalsy(); + if (!error) done(); + }); + } +}; + +describe('Integration test', () => { it('Should start well', done => { - request('http://localhost:9000/status', (err,resp,body) => { - shouldStartWell(err,resp,body,done,1); + request('http://localhost:9000/status', (err, resp, body) => { + shouldStartWell(err, resp, body, done, 1); }); - request('http://localhost:9001/status', (err,resp,body) => { - shouldStartWell(err,resp,body,done,2); + request('http://localhost:9001/status', (err, resp, body) => { + shouldStartWell(err, resp, body, done, 2); }); - request('http://localhost:9002/status', (err,resp,body) => { - shouldStartWell(err,resp,body,done,3); + request('http://localhost:9002/status', (err, resp, body) => { + shouldStartWell(err, resp, body, done, 3); }); }); - - it('Should reassign partitions when a node is down', done => { - exec('docker container stop ring-election_node-2_1', err => { expect(err).toBeFalsy(); setTimeout(() => { - request('http://localhost:9000/status', (err, response, body) => { - expect(response.statusCode).toBe(200); - expect(body).toBeDefined(); - let resp = JSON.parse(body); - expect(resp.length).toBe(2); - // actually the leader has not assigned to any partition. - let leader = resp.find((node) => node.partitions.length == 0); - expect(leader).toBeDefined(); - // expect other node to have 5 partitions assigned per each. - resp.filter(node => node.partitions.length > 0).forEach(n => { - expect(n.partitions.length).toBe(10); - }); - exec('docker container restart ring-election_node-2_1', err => { - if(!err) - done(); - else - console.error(err); - }); + request('http://localhost:9000/status', (error, resp, body) => { + shouldReassignPartitions(error, resp, body, done, 1); + }); + request('http://localhost:9001/status', (error, resp, body) => { + shouldReassignPartitions(error, resp, body, done, 2); + }); + }, 15000); + }); + }); + + it('Another node should become leader if the leader fail', done => { + // assume that the node-0 is the leader, it should always be the leader + exec('docker container stop ring-election_node-0_1', err => { + expect(err).toBeFalsy(); + setTimeout(() => { + // another node must become the leader. + request('http://localhost:9001/status', (error, resp, body) => { + shouldHandleLeaderFailure(error, resp, body, done, 1); + }); + request('http://localhost:9002/status', (error, resp, body) => { + shouldHandleLeaderFailure(error, resp, body, done, 2); }); + // when leader is added again , it should be a follower + setTimeout(() => { + request('http://localhost:9000/status', (error, resp, body) => { + shouldReassignPartitions(error, resp, body, done); + }); + request('http://localhost:9001/status', (error, resp, body) => { + shouldReassignPartitions(error, resp, body, done); + }); + request('http://localhost:9002/status', (error, resp, body) => { + shouldReassignPartitions(error, resp, body, done); + done(); + }); + }, 10000); }, 15000); }); });