Merge pull request #1144 from strongloop/feature/parameterize-kvao-tests-2x

test/kvao: add connectorCapabilities options [2.x]
This commit is contained in:
Miroslav Bajtoš 2016-10-19 13:40:28 +02:00 committed by GitHub
commit 959a821be5
7 changed files with 86 additions and 29 deletions

19
test/helpers/bdd-if.js Normal file
View File

@ -0,0 +1,19 @@
// Copyright IBM Corp. 2016. All Rights Reserved.
// Node module: loopback-datasource-juggler
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
exports.describeIf = function describeIf(cond, name, fn) {
if (cond)
describe(name, fn);
else
describe.skip(name, fn);
};
exports.itIf = function itIf(cond, name, fn) {
if (cond)
it(name, fn);
else
it.skip(name, fn);
};

View File

@ -1,6 +1,7 @@
'use strict';
var debug = require('debug')('test');
var extend = require('util')._extend;
var fs = require('fs');
var path = require('path');
@ -8,6 +9,12 @@ if (!global.Promise)
global.Promise = require('bluebird');
module.exports = function(dataSourceFactory, connectorCapabilities) {
connectorCapabilities = extend({
// Even when the backend supports millisecond precision,
// it's better to use intervals at least 10ms long in the tests
ttlPrecision: 10,
}, connectorCapabilities);
describe('KeyValue API', function loadAllTestFiles() {
var testRoot = path.resolve(__dirname, 'kvao');
var testFiles = fs.readdirSync(testRoot);

View File

@ -1,11 +1,18 @@
'use strict';
var bdd = require('../helpers/bdd-if');
var should = require('should');
var helpers = require('./_helpers');
var Promise = require('bluebird');
module.exports = function(dataSourceFactory, connectorCapabilities) {
describe('expire', function() {
// While we support millisecond precision, for the purpose of tests
// it's better to use intervals at least 10ms long.
var ttlPrecision = connectorCapabilities.ttlPrecision || 10;
var canExpire = connectorCapabilities.canExpire !== false;
bdd.describeIf(canExpire, 'expire', function() {
var CacheItem;
beforeEach(function unpackContext() {
CacheItem = helpers.givenCacheItem(dataSourceFactory);
@ -14,7 +21,7 @@ module.exports = function(dataSourceFactory, connectorCapabilities) {
it('sets key ttl - Callback API', function(done) {
CacheItem.set('a-key', 'a-value', function(err) {
if (err) return done(err);
CacheItem.expire('a-key', 1, function(err) {
CacheItem.expire('a-key', ttlPrecision, function(err) {
if (err) return done(err);
setTimeout(function() {
CacheItem.get('a-key', function(err, value) {
@ -22,22 +29,22 @@ module.exports = function(dataSourceFactory, connectorCapabilities) {
should.equal(value, null);
done();
});
}, 20);
}, 2 * ttlPrecision);
});
});
});
it('sets key ttl - Promise API', function() {
return Promise.resolve(CacheItem.set('a-key', 'a-value'))
.then(function() { return CacheItem.expire('a-key', 1); })
.delay(20)
.then(function() { return CacheItem.expire('a-key', ttlPrecision); })
.delay(2 * ttlPrecision)
.then(function() { return CacheItem.get('a-key'); })
.then(function(value) { should.equal(value, null); });
});
it('returns error when expiring a key that has expired', function() {
return Promise.resolve(CacheItem.set('expired-key', 'a-value', 1))
.delay(20)
return Promise.resolve(CacheItem.set('expired-key', 'a-value', ttlPrecision))
.delay(2 * ttlPrecision)
.then(function() { return CacheItem.expire('expired-key', 1000); })
.then(
function() { throw new Error('expire() should have failed'); },
@ -48,7 +55,7 @@ module.exports = function(dataSourceFactory, connectorCapabilities) {
});
it('returns error when key does not exist', function() {
return CacheItem.expire('key-does-not-exist', 1).then(
return CacheItem.expire('key-does-not-exist', ttlPrecision).then(
function() { throw new Error('expire() should have failed'); },
function(err) {
err.message.should.match(/key-does-not-exist/);

View File

@ -5,6 +5,8 @@ var helpers = require('./_helpers');
var Promise = require('bluebird');
module.exports = function(dataSourceFactory, connectorCapabilities) {
var TTL_PRECISION = connectorCapabilities.ttlPrecision;
describe('get/set', function() {
var CacheItem;
beforeEach(function unpackContext() {
@ -68,8 +70,8 @@ module.exports = function(dataSourceFactory, connectorCapabilities) {
});
it('honours options.ttl', function() {
return Promise.resolve(CacheItem.set('a-key', 'a-value', { ttl: 10 }))
.delay(20)
return Promise.resolve(CacheItem.set('a-key', 'a-value', { ttl: TTL_PRECISION }))
.delay(2 * TTL_PRECISION)
.then(function() { return CacheItem.get('a-key'); })
.then(function(value) { should.equal(value, null); });
});
@ -79,22 +81,22 @@ module.exports = function(dataSourceFactory, connectorCapabilities) {
return CacheItem.get('key-does-not-exist')
.then(function(value) { should.equal(value, null); });
});
it('converts numeric options arg to options.ttl', function() {
return Promise.resolve(CacheItem.set('a-key', 'a-value', 10))
.delay(20)
.then(function() { return CacheItem.get('a-key'); })
.then(function(value) { should.equal(value, null); });
});
});
describe('set', function() {
it('converts numeric options arg to options.ttl', function() {
return Promise.resolve(CacheItem.set('a-key', 'a-value', TTL_PRECISION))
.delay(2 * TTL_PRECISION)
.then(function() { return CacheItem.get('a-key'); })
.then(function(value) { should.equal(value, null); });
});
it('resets TTL timer', function() {
return Promise.resolve(CacheItem.set('a-key', 'a-value', { ttl: 10 }))
return Promise.resolve(CacheItem.set('a-key', 'a-value', { ttl: TTL_PRECISION }))
.then(function() {
return CacheItem.set('a-key', 'another-value'); // no TTL
})
.delay(20)
.delay(2 * TTL_PRECISION)
.then(function() { return CacheItem.get('a-key'); })
.then(function(value) { should.equal(value, 'another-value'); });
});

View File

@ -1,13 +1,16 @@
'use strict';
var asyncIterators = require('async-iterators');
var bdd = require('../helpers/bdd-if');
var helpers = require('./_helpers');
var Promise = require('bluebird');
var should = require('should');
var toArray = Promise.promisify(asyncIterators.toArray);
module.exports = function(dataSourceFactory, connectorCapabilities) {
describe('iterateKeys', function() {
var canIterateKeys = connectorCapabilities.canIterateKeys !== false;
bdd.describeIf(canIterateKeys, 'iterateKeys', function() {
var CacheItem;
beforeEach(function unpackContext() {
CacheItem = helpers.givenCacheItem(dataSourceFactory);

View File

@ -1,11 +1,14 @@
'use strict';
var bdd = require('../helpers/bdd-if');
var helpers = require('./_helpers');
var Promise = require('bluebird');
var should = require('should');
module.exports = function(dataSourceFactory, connectorCapabilities) {
describe('keys', function() {
var canIterateKeys = connectorCapabilities.canIterateKeys !== false;
bdd.describeIf(canIterateKeys, 'keys', function() {
var CacheItem;
beforeEach(function unpackContext() {
CacheItem = helpers.givenCacheItem(dataSourceFactory);
@ -54,7 +57,8 @@ module.exports = function(dataSourceFactory, connectorCapabilities) {
});
});
it('handles large key set', function() {
var largeKeySets = connectorCapabilities.canIterateLargeKeySets !== false;
bdd.itIf(largeKeySets, 'handles large key set', function() {
var expectedKeys = [];
for (var ix = 0; ix < 1000; ix++)
expectedKeys.push('key-' + ix);

View File

@ -1,11 +1,25 @@
'use strict';
var bdd = require('../helpers/bdd-if');
var should = require('should');
var helpers = require('./_helpers');
var Promise = require('bluebird');
module.exports = function(dataSourceFactory, connectorCapabilities) {
describe('ttl', function() {
var TTL_PRECISION = connectorCapabilities.ttlPrecision;
// Use ~1s for stores with precision of 1 ms,
// about 3s for stores with precision of 1s.
var INITIAL_TTL = Math.max(TTL_PRECISION + 1000, TTL_PRECISION * 3);
// A small delay to allow the backend to process the request, run any
// TTL/expire checks, etc. Use 1ms for backends supporting sub-10ms
// resolution to ensure the delay is not too short..
var SMALL_DELAY = Math.max(1, Math.floor(TTL_PRECISION / 10));
var canQueryTtl = connectorCapabilities.canQueryTtl !== false;
bdd.describeIf(canQueryTtl, 'ttl', function() {
var CacheItem;
beforeEach(function unpackContext() {
CacheItem = helpers.givenCacheItem(dataSourceFactory);
@ -14,19 +28,19 @@ module.exports = function(dataSourceFactory, connectorCapabilities) {
it('gets TTL when key with unexpired TTL exists - Promise API',
function() {
return Promise.resolve(
CacheItem.set('a-key', 'a-value', { ttl: 1000 }))
.delay(1)
CacheItem.set('a-key', 'a-value', { ttl: INITIAL_TTL }))
.delay(SMALL_DELAY)
.then(function() { return CacheItem.ttl('a-key'); })
.then(function(ttl) { ttl.should.be.within(1, 1000); });
.then(function(ttl) { ttl.should.be.within(1, INITIAL_TTL); });
});
it('gets TTL when key with unexpired TTL exists - Callback API',
function(done) {
CacheItem.set('a-key', 'a-value', { ttl: 1000 }, function(err) {
CacheItem.set('a-key', 'a-value', { ttl: INITIAL_TTL }, function(err) {
if (err) return done(err);
CacheItem.ttl('a-key', function(err, ttl) {
if (err) return done(err);
ttl.should.be.within(1, 1000);
ttl.should.be.within(1, INITIAL_TTL);
done();
});
});
@ -40,7 +54,8 @@ module.exports = function(dataSourceFactory, connectorCapabilities) {
it('fails when getting TTL for a key with expired TTL', function() {
return Promise.resolve(
CacheItem.set('expired-key', 'a-value', { ttl: 10 })).delay(20)
CacheItem.set('expired-key', 'a-value', { ttl: TTL_PRECISION }))
.delay(2 * TTL_PRECISION)
.then(function() {
return CacheItem.ttl('expired-key');
})