@dfroehli42/infinispan
Version:
Infinispan Javascript client
181 lines (151 loc) • 6.23 kB
JavaScript
var _ = require('underscore');
var f = require('../lib/functional');
var t = require('./utils/testing'); // Testing dependency
var tests = require('./tests'); // Shared tests
describe('Infinispan cluster client', function() {
var client = t.client(t.cluster1, t.authOpts);
// Since Jasmine 1.3 does not have beforeAll callback and stats resets is a
// bit slow, execute it as first test so that it only gets executed once.
// @TODO Uncomment and fix this method when ISPN-10777 is implemented and available in JDG server.
/*it('resets statistics', function(done) { client
.then(t.resetStats)
.then(t.assert(t.clear()))
.catch(t.failed(done)).finally(done);
});*/
it('can get cluster topology from a server node', function(done) { client
.then(t.assert(t.getMembers(), t.toContain(t.cluster)))
.catch(t.failed(done)).finally(done);
});
it('can use consistent hashing to direct key-based ops to owner nodes', function(done) { client
.then(routeConsistentHash())
.catch(t.failed(done)).finally(done);
});
it('can load balance key-less operations in round-robin fashion', function(done) { client
.then(routeRoundRobin())
.then(t.assert(t.clear()))
.catch(t.failed(done)).finally(done);
});
if (process.env.protocol == null || process.env.protocol >= '2.5') {
it('can iterate over entries in a cluster, one entry at the time',
tests.iterateEntries('cluster', 1, client)
);
it('can iterate over entries in a cluster, more than one entry at the time',
tests.iterateEntries('cluster', 3, client)
);
}
it('can remove listener in cluster', function(done) { client
.then(t.assert(t.clear()))
.then(t.on('create', t.expectEvent('listen-distinct-1', done, false, 'v1')))
.then(t.assert(t.putIfAbsent('listen-distinct-1', 'v1'), t.toBeTruthy))
.then(t.on('create', t.expectEvent('listen-distinct-2', done, true, 'v2')))
.then(t.assert(t.putIfAbsent('listen-distinct-2', 'v2'), t.toBeTruthy))
.catch(t.failed(done));
});
it('can execute a script remotely to store and retrieve data in cluster mode',
tests.execPutGet(
'spec/utils/typed-put-get.js', 'cluster', client, t.toBe('cluster-typed-value')
)
);
it('can execute a script remotely to store and retrieve data in distributed mode',
tests.execPutGet(
'spec/utils/typed-put-get-dist.js', 'dist-cluster', client
, toEqualJson(_.range(t.clusterSize())
.map(function() { return 'dist-cluster-typed-value'; }))
)
);
it('can execute a distributed script remotely that returns undefined', function(done) {
client
.then(t.loadAndExec('spec/utils/typed-null-return-dist.js'))
.then(t.assert(t.exec('typed-null-return-dist.js'),
toEqualJson(_.range(t.clusterSize())
.map(function() { return ''; }))))
.catch(t.failed(done)).finally(done);
});
it('can get ignore topology updates with client configuration', function(done) {
t.client(t.cluster1, {topologyUpdates: false})
.then(t.assert(t.getMembers(), t.toEqual([t.cluster1])))
.then(t.disconnect())
.catch(t.failed(done)).finally(done);
});
function toEqualJson(value) {
return function(actual) {
expect(JSON.parse(actual)).toEqual(value);
}
}
// Since Jasmine 1.3 does not have afterAll callback, this disconnect test must be last
it('disconnects client', function(done) { client
.then(t.disconnect())
.catch(t.failed(done))
.finally(done);
});
function routeRoundRobin() {
// Key-less operations should be executed in round-robin fashion.
// This test verifies that if two putAll operations are executed,
// these calls end up in different nodes by checking that each only
// affects one node's statistics
return function(client) {
var statsBefore = getStats(client, t.cluster);
var data = _.map(_.range(t.clusterSize()), function(i) {
return [{key: 'round-robin-' + i + '0', value: i + '0'},
{key: 'round-robin-' + i + '1', value: i + '1'}]
});
var puts = statsBefore.then(function() {
return pmap(data, function(pairs) {
return client.putAll(pairs);
});
});
var statsAfter = _.map(_.range(t.clusterSize()), function() {
return puts.then(function() { return client.stats(); });
});
return Promise.all(f.cat([statsBefore], statsAfter)).then(function(stats) {
_.forEach(_.tail(stats), function(stat) {
expect(stat.stores).toBe(stats[0].stores + 2);
});
return client;
});
}
}
function routeConsistentHash() {
return function(client) {
var members = client.getTopologyInfo().getMembers();
var ownerPairs = members.map(function (member, index) {
if(index == members.length - 1)
return [members[index], members[0]];
return [members[index], members[index+1]];
});
var keys = _.map(ownerPairs, function(pair) {
return t.findKeyForServers(client, pair);
});
var statsBefore = getStats(client, t.cluster);
var puts = statsBefore.then(function() {
return pmap(keys, function(key) {
return client.put(key, "value");
});
});
var statsAfter = _.map(t.cluster, function() {
return puts.then(function() { return client.stats(); });
});
return Promise.all(f.cat([statsBefore], statsAfter)).then(function(stats) {
_.forEach(_.tail(stats), function(stat) {
expect(stat.stores).toBe(1);
expect(stat.currentNumberOfEntries).toBe(2 * (stats[0].stores + 1));
});
return client;
});
}
}
function getStats(c, cluster) {
var stats = pmap(cluster, function() {
return c.stats();
});
return stats.then(function(stats) {
_.forEach(stats, function(stat) {
expect(stat.stores).toBe(stats[0].stores);
});
return stats[0];
});
}
function pmap(obj, iteratee, context) {
return Promise.all(_.map(obj, iteratee, context));
}
});