Permalink
Browse files

[test] use BDD for tests

  • Loading branch information...
1 parent 2798287 commit 99d21affee193edc0b8e9af063a32c572b86f6ce @3rd-Eden committed Feb 20, 2013
Showing with 238 additions and 223 deletions.
  1. +1 −1 Makefile
  2. +161 −0 tests/api.test.js
  3. +76 −0 tests/distribution.test.js
  4. +0 −222 tests/hashring.test.js
View
@@ -1,6 +1,6 @@
ALL_TESTS = $(shell find tests/ -name '*.test.js')
REPORTER = spec
-UI = exports
+UI = bdd
run-tests:
@./node_modules/.bin/mocha \
View
@@ -0,0 +1,161 @@
+"use strict";
+
+var Hashring = require('../');
+
+describe('HashRing', function () {
+ it('exposes the library version', function () {
+ Hashring.version.should.match(/^\d+\.\d+\.\d+$/);
+ });
+
+ describe('API', function () {
+ it('constructs with a string', function () {
+ var ring = new Hashring('192.168.0.102:11212');
+
+ ring.servers.should.have.length(1);
+ ring.ring.length.should.be.above(1);
+ });
+
+ it('constructs with a array', function () {
+ var ring = new Hashring([
+ '192.168.0.102:11212'
+ , '192.168.0.103:11212'
+ , '192.168.0.104:11212'
+ ]);
+
+ ring.servers.should.have.length(3);
+ ring.ring.length.should.be.above(1);
+ });
+
+ it('constructs with a object', function () {
+ var ring = new Hashring({
+ '192.168.0.102:11212': 2
+ , '192.168.0.103:11212': 2
+ , '192.168.0.104:11212': 2
+ });
+
+ ring.servers.should.have.length(3);
+ ring.ring.length.should.be.above(1);
+
+ ring.servers.forEach(function (server) {
+ server.weight.should.be.above(1);
+ });
+ });
+
+ it('constructs with a object with per node vnodes', function () {
+ var ring = new Hashring({
+ '192.168.0.102:11212': { 'vnodes': 40 }
+ , '192.168.0.103:11212': { 'vnodes': 50 }
+ , '192.168.0.104:11212': { 'vnodes': 5 }
+ });
+
+ ring.servers.should.have.length(3);
+ ring.ring.length.should.be.equal((40 + 50 + 5) * 3);
+
+ ring = new Hashring({
+ '192.168.0.102:11212': { 'vnodes': 4 }
+ , '192.168.0.103:11212': { 'vnodes': 3 }
+ , '192.168.0.104:11212': { 'vnodes': 5 }
+ });
+
+ ring.servers.should.have.length(3);
+ ring.ring.length.should.be.equal((4 + 3 + 5) * 3);
+ });
+
+ it('constructs with no arguments', function () {
+ var ring = new Hashring();
+
+ ring.servers.should.have.length(0);
+ ring.ring.should.have.length(0);
+ });
+
+ it('accepts different algorithms', function () {
+ var ring = new Hashring('192.168.0.102:11212', 'sha1');
+
+ ring.servers.should.have.length(1);
+ ring.algorithm.should.equal('sha1');
+ ring.ring.length.should.be.above(1);
+ });
+
+ describe("#add", function () {
+ it('adds server after zero-argument constructor', function () {
+ var ring = new Hashring();
+ ring.add('192.168.0.102:11212');
+
+ ring.servers.should.have.length(1);
+ ring.ring.length.should.be.above(1);
+ });
+ });
+
+ describe('#get', function () {
+ it('looks up keys', function () {
+ var ring = new Hashring([
+ '192.168.0.102:11212'
+ , '192.168.0.103:11212'
+ , '192.168.0.104:11212'
+ ]);
+
+ ring.find(ring.hashValue('foo')).should.be.above(-1);
+
+ // NOTE we are going to do some flaky testing ;P
+ ring.get('foo').should.equal('192.168.0.102:11212');
+ ring.get('pewpew').should.equal('192.168.0.104:11212');
+
+ // we are not gonna verify the results we are just gonna test if we don't
+ // fuck something up in the code, so it throws errors or whatever
+
+ // unicode keys, just because people roll like that
+ ring.find(ring.hashValue('привет мир, Memcached и nodejs для победы')).should.be.above(-1);
+
+ // other odd keys
+ ring.find(ring.hashValue(1)).should.be.above(-1);
+ ring.find(ring.hashValue(0)).should.be.above(-1);
+ ring.find(ring.hashValue([])).should.be.above(-1);
+ ring.find(ring.hashValue({wtf:'lol'})).should.be.above(-1);
+
+ ring.get({wtf:'lol'}).should.equal(ring.get({wtf:'amazing .toStringing'}));
+ });
+ });
+
+ describe('#swap', function () {
+ it('swaps servers', function () {
+ var ring = new Hashring([
+ '192.168.0.102:11212'
+ , '192.168.0.103:11212'
+ , '192.168.0.104:11212'
+ ])
+ , amazon = ring.get('justdied')
+ , skynet = '192.168.0.128:11212';
+
+ ring.swap(amazon, skynet);
+ ring.cache.get("justdied").should.equal(skynet);
+
+ // After a cleared cache, it should still resolve to the same server
+ ring.cache.reset();
+ ring.get('justdied').should.equal(skynet);
+ });
+ });
+
+ describe('#remove', function () {
+ it('removes servers', function () {
+ var ring = new Hashring([
+ '192.168.0.102:11212'
+ , '192.168.0.103:11212'
+ , '192.168.0.104:11212'
+ ]);
+
+ ring.remove('192.168.0.102:11212');
+ ring.ring.forEach(function (node) {
+ node.server.should.not.equal('192.168.0.102:11212');
+ });
+ });
+
+ it('Removes the last server', function () {
+ var ring = new Hashring('192.168.0.102:11212');
+ ring.remove('192.168.0.102:11212');
+
+ ring.servers.should.have.length(0);
+ ring.ring.should.have.length(0);
+ });
+ });
+ });
+});
View
@@ -0,0 +1,76 @@
+"use strict";
+
+var Hashring = require('../');
+
+describe('Hashring distributions', function () {
+ it('hashes to the exact same output as hash_ring for python', function () {
+ var fixture = require('fs').readFileSync(__dirname +'/fixture.txt')
+ .toString().split('\n');
+
+ var ring = new Hashring({
+ '0.0.0.1' : 1,
+ '0.0.0.2' : 2,
+ '0.0.0.3' : 3,
+ '0.0.0.4' : 4,
+ '0.0.0.5' : 5
+ }, 'md5');
+
+ for (var i=0; i < 100000; i++){
+ (i + ' ' + ring.get(i)).should.equal(fixture[i]);
+ }
+ });
+
+ it('has an even distribution', function () {
+ var iterations = 100000
+ , nodes = {
+ '192.168.0.102:11212': 1
+ , '192.168.0.103:11212': 1
+ , '192.168.0.104:11212': 1
+ }
+ , ring = new Hashring(nodes);
+
+ function genCode (length) {
+ length = length || 10;
+ var chars = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890"
+ , numChars = chars.length
+ , ret = ""
+ , i = 0;
+
+ for (; i < length; i++) {
+ ret += chars[parseInt(Math.random() * numChars, 10)];
+ }
+
+ return ret;
+ }
+
+ var counts = {}
+ , node
+ , i
+ , len
+ , word;
+
+ for (i = 0, len = nodes.length; i < len; i++) {
+ node = nodes[i];
+ counts[node] = 0;
+ }
+
+ for (i = 0, len = iterations; i < len; i++) {
+ word = genCode(10);
+ node = ring.get(word);
+ counts[node] = counts[node] || 0;
+ counts[node]++;
+ }
+
+ var total = Object.keys(counts).reduce(function reduce (sum, node) {
+ return sum += counts[node];
+ }, 0.0);
+
+ var delta = 0.05
+ , lower = 1.0 / 3 - 0.05
+ , upper = 1.0 / 3 + 0.05;
+
+ for (node in counts) {
+ (counts[node] / total).should.be.within(lower, upper);
+ }
+ });
+});
Oops, something went wrong.

0 comments on commit 99d21af

Please sign in to comment.