redis-mock-js
An in-memory redis-compatible implementation written in pure
javascript. Part of the Rarefied Redis Project.
Status
Installation
npm
$ npm install redis-js
Browser
There are minified files available on github. These files currently
represent the latest version. To use in the browser, add the following
script tag:
<script src="https://github.com/wilkenstein/redis-mock-min.js">
Usage
node.js/io.js
Basic Usage
The below code demonstrates a toy example of using the client in
node.js/io.js. The toy example sets a key, gets it, then deletes it.
var redisClient = require('redis-js');
var async = require('async');
var Q = require('q');
var reply = redisClient.set('key', 'value');
if (reply === 'OK') {
var value = redisClient.get('key');
if (value === 'value') {
redisClient.del('key');
}
}
function setGetDel(callback) {
redisClient.set('key', 'value', function (err, reply) {
if (err || reply !== 'OK') {
return callback(err, reply);
}
redisClient.get('key', function (err2, reply2) {
if (err2 || reply2 !== 'value') {
return callback(err2, reply2);
}
redisClient.del('key', function (err3, reply3) {
if (err3) {
return callback(err3);
}
return callback(err3, reply3);
});
});
});
}
setGetDel(function (err) { if (err) throw err; });
function setGetDelAsync(callback) {
async.waterfall([
function (cb) {
redisClient.set('key', 'value', cb);
},
function (reply, cb) {
if (reply !== 'OK') {
return cb(new Error('reply not OK'));
}
redisClient.get('key', cb);
},
function (reply, cb) {
if (reply !== 'value') {
return cb(new Error('reply !== value'));
}
redisClient.del('key', cb);
}
], function (err, reply) {
callback(err, reply);
});
}
setGetDelAsync(function (err) { if (err) throw err; });
function setGetDelQ() {
return Q
.nfcall(redisClient.set, 'key', 'value')
.then(function (reply) {
if (reply !== 'OK') {
throw new Error('reply not OK');
}
return Q.nfcall(redisClient.get, 'key');
}, function (err) {
throw err;
})
.then(function (reply) {
if (reply !== 'value') {
throw new Error('reply !== value');
}
return Q.nfcall(redisClient.del, 'key');
}, function (err) {
throw err;
});
}
setGetDelQ()
.fail(function (err) { throw err; })
.done();
Browser
Basic Usage
The redis-mock object is exported onto the global window
object as
window.redismock
. Example toy usage:
(function () {
var redis = this.redismock;
redis.set('key', 'value');
console.log(redis.get('key'));
})();
createClient
redismock
supports the createClient
function. Currently, it ignores any arguments given to it,
and returns a copy hooked up to the same database as the instatiating redismock
object.
Example usage in node.js/io.js:
var redis = require('redis-js');
redisClient = redis.createClient();
redisClient.set("key", "value");
console.log(redisClient.get("key"));
Pub/Sub
redismock
supports all redis pub/sub commands. It models its subscription usage after the
node_redis package. Unlike redis, redismock
currently
does not care if we put a client into subscriber mode. That may change in the future, though
it shouldn't affect testing, since we shouldn't be issuing other commands in subscriber mode
anyways!
When in subscriber mode, message
, pmessage
, subscribe
, psubscribe
, unsubscribe
, and punsubscribe
events are issued on the redismock
instance (or client instance). Example usage:
(function () {
var redis = this.redismock;
var subscriber = redis.createClient();
subscriber
.on('subscribe', function (channel) {
console.log('subscribed to ' + channel);
})
.on('message', function (channel, message) {
console.log('message ' + message + ' from ' + channel);
})
.subscribe('channel');
var publisher = redis.createClient();
publisher.publish('channel', 'message');
})();
toNodeRedis
It seems silly to write a bunch of unit tests using redismock, then
create a separate path for integration testing against a real redis
server, no? That's where toNodeRedis
comes in!
toNodeRedis
allows you to convert the redismock into an actual redis
client using the node_redis package. This function will do nothing in
a non-CommonJS environment, and throw an error if the redis
package
is not installed. To facilitate automatic switching, the environment
variable REDIS_JS_TO_NODE_REDIS
can be set to 1
. If you need to
connect to a specific redis server with specific options, pass the same
arguments to toNodeRedis
as you would to redis.createClient
. When
automatically switching with environment variables, use
REDIS_JS_NODE_REDIS_PORT
, REDIS_JS_NODE_REDIS_HOST
, and
REDIS_JS_NODE_REDIS_OPTIONS
. These environment variables will be
passed onto redis.createClient
. REDIS_JS_NODE_REDIS_OPTIONS
must
be a valid JSON string, or the script will throw an error.
toPromiseStyle
is still available on the newly-formed redismock ->
node redis client, and is compatible with node redis.
Example usage:
var Q = require('q');
var client = require('redis-js').toNodeRedis().toPromiseStyle(Q.defer);
client
.set('k', 'v')
.then(function (reply) {
console.log(reply);
return redis.get('k');
})
.then(function (reply) {
console.log(reply);
return redis.del('k');
})
.then(function (reply) {
console.log(reply);
})
.fail(function (err) {
throw err;
})
.done();
toPromiseStyle
A convenience function exists on the redismock object to turn all the
redis commands into a Promise style. This function takes a Factory
Function that creates deferred objects, e.g., Q.defer
or
jQuery.Deferred
. Example usage:
var Q = require('q');
var redis = require('redis-js').toPromiseStyle(Q.defer);
function setGetAsPromise() {
return redis
.set('key', 'value')
.then(function () {
return redis.get('key');
})
.then(function (value) {
console.log(value);
})
.fail(function (err) {
console.log(err);
})
.done();
}
setGetAsPromise()
Supported Commands
The goal is to have one-to-one feature parity with all redis commands, so that this implementation can simply be dropped into an existing redis-backed codebase. Redis has a lot of commands! Some of them are easy, and some are quite complex.
Version 0.1.0 should have support for almost all redis commands, minus the hyperloglog commands and the key-movement commands, such as migrate.
To find out what commands a particular version of redis-js supports, run the following commands:
$ npm run implemented
$ npm run unimplemented
Theses two commands will print out all the implemented and
unimplemented commands, respectively.
Performance
Since premature optimization is the root of all evil, and since this
project is aimed at being written in pure JavaScript, and since this
project started as a library for unit testing, performance has not
been a primary concern. However, there have been some efforts to
ensure at least decent performance. For instance, the set
diff/inter/union commands, and sorted sets.
Going forward, load tests are in test/load
. Currently, there are
some load tests for sets and sorted sets to ensure decent
performance. We are in JavaScript, so memory consumption can vary
wildly depending on the particular load, time of day, and how many
sugars the Queen of England put in her tea this afternoon.
The load tests can be run via npm run load-test
. YMMV.
Contributing
All contributions welcome! The best places to contribute right now are
command implementations and unit tests. We're closing in on a 0.1.0
release, only a few more commands to go!
Issues or Pull Requests. For PRs, npm test
, npm run test-phantomjs
, and npm run build-min && npm run test-min
must
all succeed and test the new code before the PR will be considered.
If you'd like to become even more active in the project, drop @wilkenstein
a line!
Testing
This project uses jshint, istanbul,
karma +
mocha + chai, and plato.
To run the full test suite from source, issue the standard npm command:
$ npm test
This will run jshint against all the source files, run the full mocha
suite with a coverage report, and finally run a complexity report
against all the source files. Currently, the only source file is
redis-mock.js
. Note that you have to be running a local redis-server
at the default port for the toNodeRedis
tests to succeed
To run the mocha tests within a particular browser using karma, issue the following npm commands:
$ npm run test-phantomjs
$ npm run test-firefox
$ npm run test-chrome
$ npm run test-safari
$ npm run test-opera
$ npm run test-ie
These tests use the various karma-*-launcher projects to launch the browsers. If the browser is not installed on the system, the corresponding test command will print an error and hang.
test-phantomjs is the only test command that does not rely on external
dependencies. test-phantomjs will install the latest compatible
version of phantomjs in a tmp directory, and use that binary to run
the tests.
Creating a test is as easy as adding a new test file in
test/mocha/
. In order for the test to run across different
JavaScript engines, a somewhat specific style is required:
(function() {
var redismock = typeof require === 'function' ? require('../../redis-mock.js') : window.redismock;
if (typeof chai === 'undefined') {
var chai = typeof require === 'function' ? require('chai') : window.chai;
}
chai.config.includeStack = true;
var expect = chai.expect;
}).call(this);
Roadmap
- 0.1.3
- Browser testing and compatibility determination.
- 1.0.0
- Support for different versions of mock redis that mimic different
redis versions.
- Support for multiple redis databases in redis mock.
- 1.1.0
- 1.2.0
- Support for migrating data between mock redis instances.
- 2.0.0
- Support for migrating data from a mock redis instance to a real
redis instance.
- HyperLogLog support.
- 2.1.0
- Support for persisting a mock redis instance.
- 2.2.0
Versions
- 0.1.2
- Merge PR #15 to fix zset problems.
- 0.1.1
- npm apparently has a 0.1.0 version, so minor bump to make npm happy.
- 0.1.0
- Implement all unit tests for supported commands.
- Fix the del command.
- Fix the pubsub command.
- Bump version to reflect roadmap milestone.
- 0.0.13
- DEPRECATED
- Implement more connection commands.
- 0.0.12-7
- DEPRECATED
- Merge PR #12 to allow capitalized set options.
- 0.0.12-6
- 0.0.12-5
- 0.0.12-4
- DEPRECATED
- Merge PR #8 to support deleting arrays in the del command.
- 0.0.12-3
- DEPRECATED
- Bug fix to return 0 on scan iteration complete.
- 0.0.12-2
- DEPRECATED
- Bug fix for createClient when using toNodeRedis.
- Merge PR #7 to support hash objects and other node_redis compability issues.
- 0.0.12-1
- DEPRECATED
- Bug fix for zrevrange and zadd commands.
- 0.0.12
- DEPRECATED
- Implement transactions in earnest.
- Implement scan command.
- Expand unit tests for transactions.
- Basic unit testing for the scan command.
- 0.0.11-5
- DEPRECATED
- Bug fix in srandmember to work correctly with the count option.
- 0.0.11-4
- DEPRECATED
- Implement blpop/brpop/brpoplpush list commands.
- Unit tests for all list commands.
- 0.0.11-3
- DEPRECATED
- Bug fix for smove command.
- 0.0.11-2
- DEPRECATED
- Implement pub/sub in earnest.
- Unit test pub/sub.
- 0.0.11-1
- DEPRECATED
- Fix to lpop/rpop to del the key if the list becomes empty as a result of the operation.
- 0.0.11
- DEPRECATED
- All hash commands implemented.
- Unit tests for new hash commands.
- 0.0.10-2
- DEPRECATED
- Sorted Set time improvements at the cost of memory.
- 0.0.10-1
- DEPRECATED
- Sorted Set time improvements.
- Load tests for sorted sets.
- 0.0.10
- All sorted set commands implemented and tested.
- 0.0.9-5
- DEPRECATED
- Fix for multi commands to return errors how redis returns errors on exec.
- 0.0.9-4
- DEPRECATED
- Implemented all sorted set commands, but not yet tested.
- 0.0.9-3
- DEPRECATED
- Set time & space improvements.
- 0.0.9-2
- DEPRECATED
- Bug fix for lpush. In redis, lpush(k, v1, v2) = k: [v2, v1].
- 0.0.9-1
- DEPRECATED
- Bug fix on converting redismock to node redis using process env vars.
- 0.0.9
- DEPRECATED
- Add support for converting redismock to node redis.
- 0.0.8-1
- DEPRECATED
- Set diff, inter, and union performance improvements.
- 1st implementation of load testing.
- 0.0.8
- DEPRECATED
- Implement all set commands, including sscan.
- Unit test all set commands.
- 0.0.7-1
- DEPRECATED
- lrange fix for negative indices.
- 0.0.7
- DEPRECATED
- All string commands implemented.
- Better unit tests.
- Automatically generate and test a minified redis-mock.
- 0.0.6
- DEPRECATED
- Implement more commands.
- Implement more unit tests.
- 0.0.5
- DEPRECATED
- Full browser testing capabilities.
- All redis commands "un"-implemented.
- Added way to see implemented vs unimplemented commands.
- More unit tests and more implementations.
- 0.0.4
- DEPRECATED
- Enhanced hash support.
- Unit tests for hash commands.
- 0.0.3
- DEPRECATED
- Set, sorted set, and hash support.
- Unit tests for implemented list, set, and sorted set commands.
- Bug squashes.
- 0.0.2
- DEPRECATED
- Transaction support that works.
- Bug squashes.
- Enhanced commands.
- 0.0.1
- DEPRECATED
- Initial implementation.
- Numerous bugs.
- Incomplete commands.