You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-06 02:15:48 +03:00
Merge remote-tracking branch 'node_redis/master'
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,2 +1,4 @@
|
||||
node_modules
|
||||
.tern-port
|
||||
.nyc_output
|
||||
coverage
|
||||
|
@@ -1,6 +1,6 @@
|
||||
examples/
|
||||
benches/
|
||||
test.js
|
||||
test/
|
||||
diff_multi_bench_output.js
|
||||
generate_commands.js
|
||||
multi_bench.js
|
||||
|
7
.travis.yml
Normal file
7
.travis.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
language: node_js
|
||||
sudo: true
|
||||
node_js:
|
||||
- "0.10"
|
||||
- "0.12"
|
||||
- "iojs-v2"
|
||||
after_success: npm run coverage
|
165
README.md
165
README.md
@@ -1,24 +1,17 @@
|
||||
redis - a node.js redis client
|
||||
===========================
|
||||
|
||||
This is a complete Redis client for node.js. It supports all Redis commands, including many recently added commands like EVAL from
|
||||
experimental Redis server branches.
|
||||
[](https://travis-ci.org/NodeRedis/node_redis)
|
||||
[](https://coveralls.io/r/NodeRedis/node_redis?branch=)
|
||||
|
||||
This is a complete Redis client for node.js. It supports all Redis commands,
|
||||
including many recently added commands like EVAL from experimental Redis server
|
||||
branches.
|
||||
|
||||
Install with:
|
||||
|
||||
npm install redis
|
||||
|
||||
Pieter Noordhuis has provided a binding to the official `hiredis` C library, which is non-blocking and fast. To use `hiredis`, do:
|
||||
|
||||
npm install hiredis redis
|
||||
|
||||
If `hiredis` is installed, `node_redis` will use it by default. Otherwise, a pure JavaScript parser will be used.
|
||||
|
||||
If you use `hiredis`, be sure to rebuild it whenever you upgrade your version of node. There are mysterious failures that can
|
||||
happen between node and native code modules after a node upgrade.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Simple example, included as `examples/simple.js`:
|
||||
@@ -57,34 +50,9 @@ This will display:
|
||||
1: hashtest 2
|
||||
mjr:~/work/node_redis (master)$
|
||||
|
||||
|
||||
## Performance
|
||||
|
||||
Here are typical results of `multi_bench.js` which is similar to `redis-benchmark` from the Redis distribution.
|
||||
It uses 50 concurrent connections with no pipelining.
|
||||
|
||||
JavaScript parser:
|
||||
|
||||
PING: 20000 ops 42283.30 ops/sec 0/5/1.182
|
||||
SET: 20000 ops 32948.93 ops/sec 1/7/1.515
|
||||
GET: 20000 ops 28694.40 ops/sec 0/9/1.740
|
||||
INCR: 20000 ops 39370.08 ops/sec 0/8/1.269
|
||||
LPUSH: 20000 ops 36429.87 ops/sec 0/8/1.370
|
||||
LRANGE (10 elements): 20000 ops 9891.20 ops/sec 1/9/5.048
|
||||
LRANGE (100 elements): 20000 ops 1384.56 ops/sec 10/91/36.072
|
||||
|
||||
hiredis parser:
|
||||
|
||||
PING: 20000 ops 46189.38 ops/sec 1/4/1.082
|
||||
SET: 20000 ops 41237.11 ops/sec 0/6/1.210
|
||||
GET: 20000 ops 39682.54 ops/sec 1/7/1.257
|
||||
INCR: 20000 ops 40080.16 ops/sec 0/8/1.242
|
||||
LPUSH: 20000 ops 41152.26 ops/sec 0/3/1.212
|
||||
LRANGE (10 elements): 20000 ops 36563.07 ops/sec 1/8/1.363
|
||||
LRANGE (100 elements): 20000 ops 21834.06 ops/sec 0/9/2.287
|
||||
|
||||
The performance of `node_redis` improves dramatically with pipelining, which happens automatically in most normal programs.
|
||||
|
||||
Note that the API is entire asynchronous. To get data back from the server,
|
||||
you'll need to use a callback. The return value from most of the API is a
|
||||
backpressure indicator.
|
||||
|
||||
### Sending Commands
|
||||
|
||||
@@ -176,15 +144,16 @@ resume sending when you get `drain`.
|
||||
`client` will emit `idle` when there are no outstanding commands that are awaiting a response.
|
||||
|
||||
## redis.createClient()
|
||||
If you have `redis-server` running on the same computer as node, then the defaults for
|
||||
port and host are probably fine and you don't need to supply any arguments. `createClient()` returns a `RedisClient` object.
|
||||
|
||||
### overloading
|
||||
* redis.createClient() = redis.createClient(6379, '127.0.0.1', {})
|
||||
* redis.createClient(options) = redis.createClient(6379, '127.0.0.1', options)
|
||||
* redis.createClient(unix_socket, options)
|
||||
* redis.createClient(port, host, options)
|
||||
* `redis.createClient(port,host,options)`
|
||||
* `redis.createClient()` is equivalent to `redis.createClient(6379, '127.0.0.1', {})`
|
||||
* `redis.createClient(options)` is equivalent to `redis.createClient(6379, '127.0.0.1', options)`
|
||||
* `redis.createClient(unix_socket, options)`
|
||||
|
||||
If you have `redis-server` running on the same computer as node, then the defaults for
|
||||
port and host are probably fine. `options` in an object with the following possible properties:
|
||||
`options` is an object with the following possible properties:
|
||||
|
||||
* `parser`: which Redis protocol reply parser to use. Defaults to `hiredis` if that module is installed.
|
||||
This may also be set to `javascript`.
|
||||
@@ -237,7 +206,6 @@ You can force an IPv6 if you set the family to 'IPv6'. See nodejs net or dns mod
|
||||
client.end();
|
||||
```
|
||||
|
||||
`createClient()` returns a `RedisClient` object that is named `client` in all of the examples here.
|
||||
|
||||
|
||||
## client.auth(password, callback)
|
||||
@@ -658,6 +626,105 @@ client.zadd(args, function (err, response) {
|
||||
});
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
Much effort has been spent to make `node_redis` as fast as possible for common
|
||||
operations. As pipelining happens naturally from shared connections, overall
|
||||
efficiency goes up.
|
||||
|
||||
Here are typical results of `multi_bench.js` which is similar to
|
||||
`redis-benchmark` from the Redis distribution. It uses 5 concurrent connections
|
||||
and shows the difference between pipelines of 1 and 50.
|
||||
|
||||
JavaScript parser:
|
||||
|
||||
Client count: 5, node version: 0.10.32, server version: 2.8.18, parser: javascript
|
||||
PING, 1/5 min/max/avg/p95: 0/ 3/ 0.05/ 1.00 1103ms total, 18132.37 ops/sec
|
||||
PING, 50/5 min/max/avg/p95: 0/ 4/ 0.81/ 2.00 327ms total, 61162.08 ops/sec
|
||||
SET 4B str, 1/5 min/max/avg/p95: 0/ 2/ 0.05/ 0.00 1104ms total, 18115.94 ops/sec
|
||||
SET 4B str, 50/5 min/max/avg/p95: 0/ 3/ 0.83/ 2.00 333ms total, 60060.06 ops/sec
|
||||
SET 4B buf, 1/5 min/max/avg/p95: 0/ 2/ 0.09/ 1.00 1876ms total, 10660.98 ops/sec
|
||||
SET 4B buf, 50/5 min/max/avg/p95: 0/ 11/ 2.55/ 4.00 1025ms total, 19512.20 ops/sec
|
||||
GET 4B str, 1/5 min/max/avg/p95: 0/ 1/ 0.05/ 1.00 1117ms total, 17905.10 ops/sec
|
||||
GET 4B str, 50/5 min/max/avg/p95: 0/ 3/ 0.87/ 2.00 347ms total, 57636.89 ops/sec
|
||||
GET 4B buf, 1/5 min/max/avg/p95: 0/ 1/ 0.05/ 1.00 1110ms total, 18018.02 ops/sec
|
||||
GET 4B buf, 50/5 min/max/avg/p95: 0/ 2/ 0.85/ 2.00 342ms total, 58479.53 ops/sec
|
||||
SET 4KiB str, 1/5 min/max/avg/p95: 0/ 1/ 0.05/ 1.00 1119ms total, 17873.10 ops/sec
|
||||
SET 4KiB str, 50/5 min/max/avg/p95: 0/ 3/ 0.89/ 2.00 358ms total, 55865.92 ops/sec
|
||||
SET 4KiB buf, 1/5 min/max/avg/p95: 0/ 1/ 0.09/ 1.00 1894ms total, 10559.66 ops/sec
|
||||
SET 4KiB buf, 50/5 min/max/avg/p95: 0/ 7/ 2.57/ 4.00 1031ms total, 19398.64 ops/sec
|
||||
GET 4KiB str, 1/5 min/max/avg/p95: 0/ 6/ 0.06/ 1.00 1248ms total, 16025.64 ops/sec
|
||||
GET 4KiB str, 50/5 min/max/avg/p95: 0/ 3/ 1.03/ 2.00 415ms total, 48192.77 ops/sec
|
||||
GET 4KiB buf, 1/5 min/max/avg/p95: 0/ 1/ 0.06/ 1.00 1177ms total, 16992.35 ops/sec
|
||||
GET 4KiB buf, 50/5 min/max/avg/p95: 0/ 10/ 1.02/ 2.00 409ms total, 48899.76 ops/sec
|
||||
INCR, 1/5 min/max/avg/p95: 0/ 2/ 0.05/ 0.55 1137ms total, 17590.15 ops/sec
|
||||
INCR, 50/5 min/max/avg/p95: 0/ 2/ 0.85/ 2.00 343ms total, 58309.04 ops/sec
|
||||
LPUSH, 1/5 min/max/avg/p95: 0/ 1/ 0.06/ 1.00 1143ms total, 17497.81 ops/sec
|
||||
LPUSH, 50/5 min/max/avg/p95: 0/ 3/ 0.87/ 2.00 350ms total, 57142.86 ops/sec
|
||||
LRANGE 10, 1/5 min/max/avg/p95: 0/ 2/ 0.06/ 1.00 1283ms total, 15588.46 ops/sec
|
||||
LRANGE 10, 50/5 min/max/avg/p95: 0/ 3/ 1.12/ 2.00 449ms total, 44543.43 ops/sec
|
||||
LRANGE 100, 1/5 min/max/avg/p95: 0/ 1/ 0.09/ 1.00 1932ms total, 10351.97 ops/sec
|
||||
LRANGE 100, 50/5 min/max/avg/p95: 0/ 5/ 2.46/ 4.00 985ms total, 20304.57 ops/sec
|
||||
SET 4MiB buf, 1/5 min/max/avg/p95: 1/ 4/ 1.37/ 2.00 691ms total, 723.59 ops/sec
|
||||
SET 4MiB buf, 50/5 min/max/avg/p95: 3/ 166/ 57.66/ 116.00 601ms total, 831.95 ops/sec
|
||||
GET 4MiB str, 1/5 min/max/avg/p95: 84/ 110/ 93.18/ 106.95 9320ms total, 10.73 ops/sec
|
||||
GET 4MiB str, 50/5 min/max/avg/p95: 156/7375/3400.10/6840.40 8928ms total, 11.20 ops/sec
|
||||
GET 4MiB buf, 1/5 min/max/avg/p95: 84/ 105/ 91.21/ 99.00 9129ms total, 10.95 ops/sec
|
||||
GET 4MiB buf, 50/5 min/max/avg/p95: 424/5704/3518.94/5626.65 9145ms total, 10.93 ops/sec
|
||||
|
||||
If you use very large responses in your application, the JavaScript parser
|
||||
performs badly. Until the JS parser is fixed, you can use the C-based `hiredis`
|
||||
parser bound to the official `hiredis` C library. To use `hiredis`, do:
|
||||
|
||||
npm install hiredis redis
|
||||
|
||||
If the `hiredis` npm module is installed, `node_redis` will use it by default.
|
||||
Otherwise, the pure JavaScript parser will be used.
|
||||
|
||||
If you use `hiredis`, be sure to rebuild it whenever you upgrade your version of
|
||||
node. There are mysterious failures that can happen between node and native
|
||||
code modules after a node upgrade.
|
||||
|
||||
Most users find that the JS parser is faster than the `hiredis` parser. Because
|
||||
of the pain associated with upgrading native code modules, you should only use
|
||||
`hiredis` if your application needs it.
|
||||
|
||||
hiredis parser:
|
||||
|
||||
Client count: 5, node version: 0.10.32, server version: 2.8.18, parser: hiredis
|
||||
PING, 1/5 min/max/avg/p95: 0/ 3/ 0.05/ 1.00 1092ms total, 18315.02 ops/sec
|
||||
PING, 50/5 min/max/avg/p95: 0/ 5/ 0.87/ 2.00 347ms total, 57636.89 ops/sec
|
||||
SET 4B str, 1/5 min/max/avg/p95: 0/ 2/ 0.06/ 1.00 1151ms total, 17376.19 ops/sec
|
||||
SET 4B str, 50/5 min/max/avg/p95: 0/ 3/ 0.83/ 2.00 334ms total, 59880.24 ops/sec
|
||||
SET 4B buf, 1/5 min/max/avg/p95: 0/ 3/ 0.09/ 1.00 1932ms total, 10351.97 ops/sec
|
||||
SET 4B buf, 50/5 min/max/avg/p95: 0/ 9/ 2.64/ 4.00 1059ms total, 18885.74 ops/sec
|
||||
GET 4B str, 1/5 min/max/avg/p95: 0/ 1/ 0.06/ 0.00 1185ms total, 16877.64 ops/sec
|
||||
GET 4B str, 50/5 min/max/avg/p95: 0/ 3/ 0.85/ 2.00 341ms total, 58651.03 ops/sec
|
||||
GET 4B buf, 1/5 min/max/avg/p95: 0/ 1/ 0.06/ 0.00 1179ms total, 16963.53 ops/sec
|
||||
GET 4B buf, 50/5 min/max/avg/p95: 0/ 3/ 0.85/ 2.00 340ms total, 58823.53 ops/sec
|
||||
SET 4KiB str, 1/5 min/max/avg/p95: 0/ 1/ 0.06/ 1.00 1210ms total, 16528.93 ops/sec
|
||||
SET 4KiB str, 50/5 min/max/avg/p95: 0/ 3/ 0.93/ 2.00 372ms total, 53763.44 ops/sec
|
||||
SET 4KiB buf, 1/5 min/max/avg/p95: 0/ 1/ 0.10/ 1.00 1967ms total, 10167.77 ops/sec
|
||||
SET 4KiB buf, 50/5 min/max/avg/p95: 0/ 6/ 2.63/ 4.00 1053ms total, 18993.35 ops/sec
|
||||
GET 4KiB str, 1/5 min/max/avg/p95: 0/ 6/ 0.06/ 1.00 1176ms total, 17006.80 ops/sec
|
||||
GET 4KiB str, 50/5 min/max/avg/p95: 0/ 4/ 1.00/ 2.00 399ms total, 50125.31 ops/sec
|
||||
GET 4KiB buf, 1/5 min/max/avg/p95: 0/ 1/ 0.06/ 1.00 1158ms total, 17271.16 ops/sec
|
||||
GET 4KiB buf, 50/5 min/max/avg/p95: 0/ 3/ 0.99/ 2.00 398ms total, 50251.26 ops/sec
|
||||
INCR, 1/5 min/max/avg/p95: 0/ 1/ 0.05/ 0.00 1112ms total, 17985.61 ops/sec
|
||||
INCR, 50/5 min/max/avg/p95: 0/ 3/ 0.84/ 2.00 339ms total, 58997.05 ops/sec
|
||||
LPUSH, 1/5 min/max/avg/p95: 0/ 1/ 0.05/ 1.00 1131ms total, 17683.47 ops/sec
|
||||
LPUSH, 50/5 min/max/avg/p95: 0/ 3/ 0.86/ 2.00 345ms total, 57971.01 ops/sec
|
||||
LRANGE 10, 1/5 min/max/avg/p95: 0/ 1/ 0.06/ 1.00 1228ms total, 16286.64 ops/sec
|
||||
LRANGE 10, 50/5 min/max/avg/p95: 0/ 3/ 0.95/ 2.00 382ms total, 52356.02 ops/sec
|
||||
LRANGE 100, 1/5 min/max/avg/p95: 0/ 1/ 0.08/ 1.00 1567ms total, 12763.24 ops/sec
|
||||
LRANGE 100, 50/5 min/max/avg/p95: 0/ 6/ 1.68/ 3.00 675ms total, 29629.63 ops/sec
|
||||
SET 4MiB buf, 1/5 min/max/avg/p95: 1/ 4/ 1.37/ 2.00 692ms total, 722.54 ops/sec
|
||||
SET 4MiB buf, 50/5 min/max/avg/p95: 3/ 183/ 57.79/ 125.00 605ms total, 826.45 ops/sec
|
||||
GET 4MiB str, 1/5 min/max/avg/p95: 5/ 16/ 8.14/ 12.95 816ms total, 122.55 ops/sec
|
||||
GET 4MiB str, 50/5 min/max/avg/p95: 24/ 323/ 202.98/ 309.00 519ms total, 192.68 ops/sec
|
||||
GET 4MiB buf, 1/5 min/max/avg/p95: 6/ 13/ 8.01/ 11.95 802ms total, 124.69 ops/sec
|
||||
GET 4MiB buf, 50/5 min/max/avg/p95: 16/ 480/ 203.85/ 435.70 531ms total, 188.32 ops/sec
|
||||
|
||||
## TODO
|
||||
|
||||
Better tests for auth, disconnect/reconnect, and all combinations thereof.
|
||||
@@ -674,7 +741,7 @@ I think there are more performance improvements left in there for smaller values
|
||||
comment again with indignation!)
|
||||
|
||||
## Contributors
|
||||
Some people have have added features and fixed bugs in `node_redis` other than me.
|
||||
Many people have have added features and fixed bugs in `node_redis`.
|
||||
|
||||
Ordered by date of first contribution.
|
||||
[Auto-generated](http://github.com/dtrejo/node-authors) on Wed Jul 25 2012 19:14:59 GMT-0700 (PDT).
|
||||
@@ -740,5 +807,3 @@ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||

|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var source = new Buffer(100),
|
||||
dest = new Buffer(100), i, j, k, tmp, count = 1000000, bytes = 100;
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var Parser = require('../lib/parser/hiredis').Parser;
|
||||
var assert = require('assert');
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var client = require('../index').createClient()
|
||||
, client2 = require('../index').createClient()
|
||||
, assert = require('assert');
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("../index").createClient(null, null, {
|
||||
// max_attempts: 4
|
||||
});
|
||||
|
@@ -1,16 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
var json = {
|
||||
encode: JSON.stringify,
|
||||
decode: JSON.parse
|
||||
};
|
||||
|
||||
var MsgPack = require('node-msgpack');
|
||||
msgpack = {
|
||||
encode: MsgPack.pack,
|
||||
decode: function(str) { return MsgPack.unpack(new Buffer(str)); }
|
||||
};
|
||||
|
||||
bison = require('bison');
|
||||
|
||||
module.exports = json;
|
||||
//module.exports = msgpack;
|
||||
//module.exports = bison;
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var msgpack = require('node-msgpack');
|
||||
var bison = require('bison');
|
||||
var codec = {
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var client = require("redis").createClient(),
|
||||
client2 = require("redis").createClient();
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
* Refactor tests, and improve test coverage (Ben Coe)
|
||||
* Fix extraneous error output due to pubsub tests (Mikael Kohlmyr)
|
||||
|
||||
## v0.12.1 - Aug 10, 2014
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var net = require('net');
|
||||
|
||||
var proxyPort = 6379;
|
||||
|
@@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
'use strict';
|
||||
|
||||
var colors = require('colors'),
|
||||
fs = require('fs'),
|
||||
_ = require('underscore'),
|
||||
@@ -35,8 +37,8 @@ before_lines.forEach(function(b, i) {
|
||||
return;
|
||||
}
|
||||
|
||||
b_words = b.split(' ').filter(is_whitespace);
|
||||
a_words = a.split(' ').filter(is_whitespace);
|
||||
var b_words = b.split(' ').filter(is_whitespace);
|
||||
var a_words = a.split(' ').filter(is_whitespace);
|
||||
|
||||
var ops =
|
||||
[b_words, a_words]
|
||||
@@ -47,7 +49,7 @@ before_lines.forEach(function(b, i) {
|
||||
var isNaN = !num && num !== 0;
|
||||
return !isNaN;
|
||||
});
|
||||
if (ops.length != 2) return
|
||||
if (ops.length !== 2) return;
|
||||
|
||||
var delta = ops[1] - ops[0];
|
||||
var pct = ((delta / ops[0]) * 100).toPrecision(3);
|
||||
@@ -58,7 +60,7 @@ before_lines.forEach(function(b, i) {
|
||||
pct = humanize_diff(pct, '%');
|
||||
console.log(
|
||||
// name of test
|
||||
command_name(a_words) == command_name(b_words)
|
||||
command_name(a_words) === command_name(b_words)
|
||||
? command_name(a_words) + ':'
|
||||
: '404:',
|
||||
// results of test
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient();
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("../index"),
|
||||
client = redis.createClient(null, null, {
|
||||
command_queue_high_water: 5,
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("../index"),
|
||||
client = redis.createClient();
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient();
|
||||
|
||||
@@ -14,7 +16,7 @@ redis.RedisClient.prototype.parse_info = function (callback) {
|
||||
obj[parts[0]] = parts[1];
|
||||
}
|
||||
});
|
||||
callback(obj)
|
||||
callback(obj);
|
||||
});
|
||||
};
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
// Read a file from disk, store it in Redis, then read it back from Redis.
|
||||
|
||||
var redis = require("redis"),
|
||||
@@ -11,7 +13,7 @@ var redis = require("redis"),
|
||||
|
||||
// Read a file from fs, store it in Redis, get it back from Redis, write it back to fs.
|
||||
fs.readFile(filename, function (err, data) {
|
||||
if (err) throw err
|
||||
if (err) throw err;
|
||||
console.log("Read " + data.length + " bytes from filesystem.");
|
||||
|
||||
client.set(filename, data, redis.print); // set entire file
|
||||
@@ -21,7 +23,7 @@ fs.readFile(filename, function (err, data) {
|
||||
} else {
|
||||
fs.writeFile("duplicate_" + filename, reply, function (err) {
|
||||
if (err) {
|
||||
console.log("Error on write: " + err)
|
||||
console.log("Error on write: " + err);
|
||||
} else {
|
||||
console.log("File written.");
|
||||
}
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var client = require("redis").createClient();
|
||||
|
||||
client.mget(["sessions started", "sessions started", "foo"], function (err, res) {
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var client = require("../index").createClient(),
|
||||
util = require("util");
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient(), set_size = 20;
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient(), multi;
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
client1 = redis.createClient(),
|
||||
client2 = redis.createClient(),
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
client1 = redis.createClient(), msg_count = 0,
|
||||
client2 = redis.createClient();
|
||||
|
38
examples/scan.js
Normal file
38
examples/scan.js
Normal file
@@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient();
|
||||
|
||||
var cursor = '0';
|
||||
|
||||
function scan() {
|
||||
client.scan(
|
||||
cursor,
|
||||
"MATCH", "q:job:*",
|
||||
"COUNT", "10",
|
||||
function(err, res) {
|
||||
if (err) throw err;
|
||||
|
||||
// Update the cursor position for the next scan
|
||||
cursor = res[0];
|
||||
|
||||
// From <http://redis.io/commands/scan>:
|
||||
// "An iteration starts when the cursor is set to 0,
|
||||
// and terminates when the cursor returned by the server is 0."
|
||||
if (cursor === '0') {
|
||||
return console.log('Iteration complete');
|
||||
} else {
|
||||
// Remember: more or less than COUNT or no keys may be returned
|
||||
// See http://redis.io/commands/scan#the-count-option
|
||||
// Also, SCAN may return the same key multiple times
|
||||
// See http://redis.io/commands/scan#scan-guarantees
|
||||
|
||||
if (res[1].length > 0) {
|
||||
console.log('Array of matching keys', res[1]);
|
||||
}
|
||||
|
||||
return scan();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient();
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient();
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
// Sending commands in response to other commands.
|
||||
// This example runs "type" against every key in the database
|
||||
//
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var client = require("redis").createClient();
|
||||
|
||||
function print_results(obj) {
|
||||
|
@@ -1,9 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient("/tmp/redis.sock"),
|
||||
profiler = require("v8-profiler");
|
||||
|
||||
client.on("connect", function () {
|
||||
console.log("Got Unix socket connection.")
|
||||
console.log("Got Unix socket connection.");
|
||||
});
|
||||
|
||||
client.on("error", function (err) {
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
// A simple web server that generates dyanmic content based on responses from Redis
|
||||
|
||||
var http = require("http"), server,
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var http = require("http"),
|
||||
fs = require("fs");
|
||||
|
||||
|
89
index.js
89
index.js
@@ -1,6 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
/*global Buffer require exports console setTimeout */
|
||||
|
||||
var net = require("net"),
|
||||
URL = require("url"),
|
||||
util = require("./lib/util"),
|
||||
Queue = require("./lib/queue"),
|
||||
to_array = require("./lib/to_array"),
|
||||
@@ -14,10 +17,10 @@ var net = require("net"),
|
||||
// can set this to true to enable for all connections
|
||||
exports.debug_mode = false;
|
||||
|
||||
var arraySlice = Array.prototype.slice
|
||||
var arraySlice = Array.prototype.slice;
|
||||
function trace() {
|
||||
if (!exports.debug_mode) return;
|
||||
console.log.apply(null, arraySlice.call(arguments))
|
||||
console.log.apply(null, arraySlice.call(arguments));
|
||||
}
|
||||
|
||||
// hiredis might not be installed
|
||||
@@ -138,7 +141,7 @@ RedisClient.prototype.unref = function () {
|
||||
trace("Not connected yet, will unref later");
|
||||
this.once("connect", function () {
|
||||
this.unref();
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -216,7 +219,7 @@ RedisClient.prototype.do_auth = function () {
|
||||
}, 2000); // TODO - magic number alert
|
||||
return;
|
||||
} else if (err.toString().match("no password is set")) {
|
||||
console.log("Warning: Redis server does not require a password, but a password was supplied.")
|
||||
console.log("Warning: Redis server does not require a password, but a password was supplied.");
|
||||
err = null;
|
||||
res = "OK";
|
||||
} else {
|
||||
@@ -609,7 +612,7 @@ function try_callback(callback, reply) {
|
||||
function reply_to_object(reply) {
|
||||
var obj = {}, j, jl, key, val;
|
||||
|
||||
if (reply.length === 0) {
|
||||
if (reply.length === 0 || !Array.isArray(reply)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -647,7 +650,7 @@ RedisClient.prototype.return_reply = function (reply) {
|
||||
// If the "reply" here is actually a message received asynchronously due to a
|
||||
// pubsub subscription, don't pop the command queue as we'll only be consuming
|
||||
// the head command prematurely.
|
||||
if (Array.isArray(reply) && reply.length > 0 && reply[0]) {
|
||||
if (this.pub_sub_mode && Array.isArray(reply) && reply.length > 0 && reply[0]) {
|
||||
type = reply[0].toString();
|
||||
}
|
||||
|
||||
@@ -671,7 +674,7 @@ RedisClient.prototype.return_reply = function (reply) {
|
||||
|
||||
if (command_obj && !command_obj.sub_command) {
|
||||
if (typeof command_obj.callback === "function") {
|
||||
if (this.options.detect_buffers && command_obj.buffer_args === false) {
|
||||
if (this.options.detect_buffers && command_obj.buffer_args === false && 'exec' !== command_obj.command.toLowerCase()) {
|
||||
// If detect_buffers option was specified, then the reply from the parser will be Buffers.
|
||||
// If this command did not use Buffer arguments, then convert the reply to Strings here.
|
||||
reply = reply_to_strings(reply);
|
||||
@@ -1105,15 +1108,24 @@ Multi.prototype.HMSET = Multi.prototype.hmset;
|
||||
Multi.prototype.exec = function (callback) {
|
||||
var self = this;
|
||||
var errors = [];
|
||||
var wants_buffers = [];
|
||||
// drain queue, callback will catch "QUEUED" or error
|
||||
// TODO - get rid of all of these anonymous functions which are elegant but slow
|
||||
this.queue.forEach(function (args, index) {
|
||||
var command = args[0], obj;
|
||||
var command = args[0], obj, i, il, buffer_args;
|
||||
if (typeof args[args.length - 1] === "function") {
|
||||
args = args.slice(1, -1);
|
||||
} else {
|
||||
args = args.slice(1);
|
||||
}
|
||||
// Keep track of who wants buffer responses:
|
||||
buffer_args = false;
|
||||
for (i = 0, il = args.length; i < il; i += 1) {
|
||||
if (Buffer.isBuffer(args[i])) {
|
||||
buffer_args = true;
|
||||
}
|
||||
}
|
||||
wants_buffers.push(buffer_args);
|
||||
if (args.length === 1 && Array.isArray(args[0])) {
|
||||
args = args[0];
|
||||
}
|
||||
@@ -1148,12 +1160,18 @@ Multi.prototype.exec = function (callback) {
|
||||
}
|
||||
}
|
||||
|
||||
var i, il, reply, args;
|
||||
var i, il, reply, to_buffer, args;
|
||||
|
||||
if (replies) {
|
||||
for (i = 1, il = self.queue.length; i < il; i += 1) {
|
||||
reply = replies[i - 1];
|
||||
args = self.queue[i];
|
||||
to_buffer = wants_buffers[i];
|
||||
|
||||
// If we asked for strings, even in detect_buffers mode, then return strings:
|
||||
if (self._client.options.detect_buffers && to_buffer === false) {
|
||||
replies[i - 1] = reply = reply_to_strings(reply);
|
||||
}
|
||||
|
||||
// TODO - confusing and error-prone that hgetall is special cased in two places
|
||||
if (reply && args[0].toLowerCase() === "hgetall") {
|
||||
@@ -1212,40 +1230,29 @@ RedisClient.prototype.eval = RedisClient.prototype.EVAL = function () {
|
||||
});
|
||||
};
|
||||
|
||||
exports.createClient = function(arg0, arg1, options) {
|
||||
if (typeof arg0 === 'object' || arg0 === undefined) {
|
||||
options = arg0 || options;
|
||||
return createClient_tcp(default_port, default_host, options);
|
||||
}
|
||||
if (typeof arg0 === 'number' || typeof arg0 === 'string' && arg0.match(/^\d+$/)){
|
||||
return createClient_tcp(arg0, arg1, options);
|
||||
}
|
||||
if (typeof arg0 === 'string') {
|
||||
options = arg1 || {};
|
||||
|
||||
exports.createClient = function(arg0, arg1, arg2){
|
||||
if( arguments.length === 0 ){
|
||||
var parsed = URL.parse(arg0, true, true);
|
||||
if (parsed.hostname) {
|
||||
if (parsed.auth) {
|
||||
options.auth_pass = parsed.auth.split(':')[1];
|
||||
}
|
||||
return createClient_tcp((parsed.port || default_port), parsed.hostname, options);
|
||||
}
|
||||
|
||||
// createClient()
|
||||
return createClient_tcp(default_port, default_host, {});
|
||||
|
||||
} else if( typeof arg0 === 'number' ||
|
||||
typeof arg0 === 'string' && arg0.match(/^\d+$/) ){
|
||||
|
||||
// createClient( 3000, host, options)
|
||||
// createClient('3000', host, options)
|
||||
return createClient_tcp(arg0, arg1, arg2);
|
||||
|
||||
} else if( typeof arg0 === 'string' ){
|
||||
|
||||
// createClient( '/tmp/redis.sock', options)
|
||||
return createClient_unix(arg0,arg1);
|
||||
|
||||
} else if( arg0 !== null && typeof arg0 === 'object' ){
|
||||
|
||||
// createClient(options)
|
||||
return createClient_tcp(default_port, default_host, arg0 );
|
||||
|
||||
} else if( arg0 === null && arg1 === null ){
|
||||
|
||||
// for backward compatibility
|
||||
// createClient(null,null,options)
|
||||
return createClient_tcp(default_port, default_host, arg2);
|
||||
|
||||
} else {
|
||||
return createClient_unix(arg0, options);
|
||||
}
|
||||
throw new Error('unknown type of connection in createClient()');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var createClient_unix = function(path, options){
|
||||
var cnxOptions = {
|
||||
@@ -1258,7 +1265,7 @@ var createClient_unix = function(path, options){
|
||||
redis_client.address = path;
|
||||
|
||||
return redis_client;
|
||||
}
|
||||
};
|
||||
|
||||
var createClient_tcp = function (port_arg, host_arg, options) {
|
||||
var cnxOptions = {
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
// This file was generated by ./generate_commands.js on Wed Apr 23 2014 14:51:21 GMT-0700 (PDT)
|
||||
module.exports = [
|
||||
"append",
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var events = require("events"),
|
||||
util = require("../util"),
|
||||
hiredis = require("hiredis");
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var events = require("events"),
|
||||
util = require("../util");
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
// Queue class adapted from Tim Caswell's pattern library
|
||||
// http://github.com/creationix/pattern/blob/master/lib/pattern/queue.js
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
function to_array(args) {
|
||||
var len = args.length,
|
||||
arr = new Array(len), i;
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
// Support for very old versions of node where the module was called "sys". At some point, we should abandon this.
|
||||
|
||||
var util;
|
||||
|
@@ -1,3 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("./index"),
|
||||
metrics = require("metrics"),
|
||||
num_clients = parseInt(process.argv[2], 10) || 5,
|
||||
@@ -7,7 +9,7 @@ var redis = require("./index"),
|
||||
client_options = {
|
||||
return_buffers: false
|
||||
},
|
||||
small_str, large_str, small_buf, large_buf;
|
||||
small_str, large_str, small_buf, large_buf, very_large_str, very_large_buf;
|
||||
|
||||
redis.debug_mode = false;
|
||||
|
||||
@@ -37,6 +39,7 @@ function Test(args) {
|
||||
this.commands_completed = 0;
|
||||
this.max_pipeline = this.args.pipeline || num_requests;
|
||||
this.client_options = args.client_options || client_options;
|
||||
this.num_requests = args.reqs || num_requests;
|
||||
|
||||
this.connect_latency = new metrics.Histogram();
|
||||
this.ready_latency = new metrics.Histogram();
|
||||
@@ -89,13 +92,13 @@ Test.prototype.on_clients_ready = function () {
|
||||
Test.prototype.fill_pipeline = function () {
|
||||
var pipeline = this.commands_sent - this.commands_completed;
|
||||
|
||||
while (this.commands_sent < num_requests && pipeline < this.max_pipeline) {
|
||||
while (this.commands_sent < this.num_requests && pipeline < this.max_pipeline) {
|
||||
this.commands_sent++;
|
||||
pipeline++;
|
||||
this.send_next();
|
||||
}
|
||||
|
||||
if (this.commands_completed === num_requests) {
|
||||
if (this.commands_completed === this.num_requests) {
|
||||
this.print_stats();
|
||||
this.stop_clients();
|
||||
}
|
||||
@@ -134,78 +137,63 @@ Test.prototype.print_stats = function () {
|
||||
var duration = Date.now() - this.test_start;
|
||||
|
||||
console.log("min/max/avg/p95: " + this.command_latency.print_line() + " " + lpad(duration, 6) + "ms total, " +
|
||||
lpad((num_requests / (duration / 1000)).toFixed(2), 8) + " ops/sec");
|
||||
lpad((this.num_requests / (duration / 1000)).toFixed(2), 8) + " ops/sec");
|
||||
};
|
||||
|
||||
small_str = "1234";
|
||||
small_buf = new Buffer(small_str);
|
||||
large_str = (new Array(4097).join("-"));
|
||||
large_str = (new Array(4096 + 1).join("-"));
|
||||
large_buf = new Buffer(large_str);
|
||||
very_large_str = (new Array((4 * 1024 * 1024) + 1).join("-"));
|
||||
very_large_buf = new Buffer(very_large_str);
|
||||
|
||||
tests.push(new Test({descr: "PING", command: "ping", args: [], pipeline: 1}));
|
||||
tests.push(new Test({descr: "PING", command: "ping", args: [], pipeline: 50}));
|
||||
tests.push(new Test({descr: "PING", command: "ping", args: [], pipeline: 200}));
|
||||
tests.push(new Test({descr: "PING", command: "ping", args: [], pipeline: 20000}));
|
||||
|
||||
tests.push(new Test({descr: "SET small str", command: "set", args: ["foo_rand000000000000", small_str], pipeline: 1}));
|
||||
tests.push(new Test({descr: "SET small str", command: "set", args: ["foo_rand000000000000", small_str], pipeline: 50}));
|
||||
tests.push(new Test({descr: "SET small str", command: "set", args: ["foo_rand000000000000", small_str], pipeline: 200}));
|
||||
tests.push(new Test({descr: "SET small str", command: "set", args: ["foo_rand000000000000", small_str], pipeline: 20000}));
|
||||
tests.push(new Test({descr: "SET 4B str", command: "set", args: ["foo_rand000000000000", small_str], pipeline: 1}));
|
||||
tests.push(new Test({descr: "SET 4B str", command: "set", args: ["foo_rand000000000000", small_str], pipeline: 50}));
|
||||
|
||||
tests.push(new Test({descr: "SET small buf", command: "set", args: ["foo_rand000000000000", small_buf], pipeline: 1}));
|
||||
tests.push(new Test({descr: "SET small buf", command: "set", args: ["foo_rand000000000000", small_buf], pipeline: 50}));
|
||||
tests.push(new Test({descr: "SET small buf", command: "set", args: ["foo_rand000000000000", small_buf], pipeline: 200}));
|
||||
tests.push(new Test({descr: "SET small buf", command: "set", args: ["foo_rand000000000000", small_buf], pipeline: 20000}));
|
||||
tests.push(new Test({descr: "SET 4B buf", command: "set", args: ["foo_rand000000000000", small_buf], pipeline: 1}));
|
||||
tests.push(new Test({descr: "SET 4B buf", command: "set", args: ["foo_rand000000000000", small_buf], pipeline: 50}));
|
||||
|
||||
tests.push(new Test({descr: "GET small str", command: "get", args: ["foo_rand000000000000"], pipeline: 1}));
|
||||
tests.push(new Test({descr: "GET small str", command: "get", args: ["foo_rand000000000000"], pipeline: 50}));
|
||||
tests.push(new Test({descr: "GET small str", command: "get", args: ["foo_rand000000000000"], pipeline: 200}));
|
||||
tests.push(new Test({descr: "GET small str", command: "get", args: ["foo_rand000000000000"], pipeline: 20000}));
|
||||
tests.push(new Test({descr: "GET 4B str", command: "get", args: ["foo_rand000000000000"], pipeline: 1}));
|
||||
tests.push(new Test({descr: "GET 4B str", command: "get", args: ["foo_rand000000000000"], pipeline: 50}));
|
||||
|
||||
tests.push(new Test({descr: "GET small buf", command: "get", args: ["foo_rand000000000000"], pipeline: 1, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET small buf", command: "get", args: ["foo_rand000000000000"], pipeline: 50, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET small buf", command: "get", args: ["foo_rand000000000000"], pipeline: 200, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET small buf", command: "get", args: ["foo_rand000000000000"], pipeline: 20000, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET 4B buf", command: "get", args: ["foo_rand000000000000"], pipeline: 1, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET 4B buf", command: "get", args: ["foo_rand000000000000"], pipeline: 50, client_opts: { return_buffers: true} }));
|
||||
|
||||
tests.push(new Test({descr: "SET large str", command: "set", args: ["foo_rand000000000001", large_str], pipeline: 1}));
|
||||
tests.push(new Test({descr: "SET large str", command: "set", args: ["foo_rand000000000001", large_str], pipeline: 50}));
|
||||
tests.push(new Test({descr: "SET large str", command: "set", args: ["foo_rand000000000001", large_str], pipeline: 200}));
|
||||
tests.push(new Test({descr: "SET large str", command: "set", args: ["foo_rand000000000001", large_str], pipeline: 20000}));
|
||||
tests.push(new Test({descr: "SET 4KiB str", command: "set", args: ["foo_rand000000000001", large_str], pipeline: 1}));
|
||||
tests.push(new Test({descr: "SET 4KiB str", command: "set", args: ["foo_rand000000000001", large_str], pipeline: 50}));
|
||||
|
||||
tests.push(new Test({descr: "SET large buf", command: "set", args: ["foo_rand000000000001", large_buf], pipeline: 1}));
|
||||
tests.push(new Test({descr: "SET large buf", command: "set", args: ["foo_rand000000000001", large_buf], pipeline: 50}));
|
||||
tests.push(new Test({descr: "SET large buf", command: "set", args: ["foo_rand000000000001", large_buf], pipeline: 200}));
|
||||
tests.push(new Test({descr: "SET large buf", command: "set", args: ["foo_rand000000000001", large_buf], pipeline: 20000}));
|
||||
tests.push(new Test({descr: "SET 4KiB buf", command: "set", args: ["foo_rand000000000001", large_buf], pipeline: 1}));
|
||||
tests.push(new Test({descr: "SET 4KiB buf", command: "set", args: ["foo_rand000000000001", large_buf], pipeline: 50}));
|
||||
|
||||
tests.push(new Test({descr: "GET large str", command: "get", args: ["foo_rand000000000001"], pipeline: 1}));
|
||||
tests.push(new Test({descr: "GET large str", command: "get", args: ["foo_rand000000000001"], pipeline: 50}));
|
||||
tests.push(new Test({descr: "GET large str", command: "get", args: ["foo_rand000000000001"], pipeline: 200}));
|
||||
tests.push(new Test({descr: "GET large str", command: "get", args: ["foo_rand000000000001"], pipeline: 20000}));
|
||||
tests.push(new Test({descr: "GET 4KiB str", command: "get", args: ["foo_rand000000000001"], pipeline: 1}));
|
||||
tests.push(new Test({descr: "GET 4KiB str", command: "get", args: ["foo_rand000000000001"], pipeline: 50}));
|
||||
|
||||
tests.push(new Test({descr: "GET large buf", command: "get", args: ["foo_rand000000000001"], pipeline: 1, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET large buf", command: "get", args: ["foo_rand000000000001"], pipeline: 50, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET large buf", command: "get", args: ["foo_rand000000000001"], pipeline: 200, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET large buf", command: "get", args: ["foo_rand000000000001"], pipeline: 20000, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET 4KiB buf", command: "get", args: ["foo_rand000000000001"], pipeline: 1, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET 4KiB buf", command: "get", args: ["foo_rand000000000001"], pipeline: 50, client_opts: { return_buffers: true} }));
|
||||
|
||||
tests.push(new Test({descr: "INCR", command: "incr", args: ["counter_rand000000000000"], pipeline: 1}));
|
||||
tests.push(new Test({descr: "INCR", command: "incr", args: ["counter_rand000000000000"], pipeline: 50}));
|
||||
tests.push(new Test({descr: "INCR", command: "incr", args: ["counter_rand000000000000"], pipeline: 200}));
|
||||
tests.push(new Test({descr: "INCR", command: "incr", args: ["counter_rand000000000000"], pipeline: 20000}));
|
||||
|
||||
tests.push(new Test({descr: "LPUSH", command: "lpush", args: ["mylist", small_str], pipeline: 1}));
|
||||
tests.push(new Test({descr: "LPUSH", command: "lpush", args: ["mylist", small_str], pipeline: 50}));
|
||||
tests.push(new Test({descr: "LPUSH", command: "lpush", args: ["mylist", small_str], pipeline: 200}));
|
||||
tests.push(new Test({descr: "LPUSH", command: "lpush", args: ["mylist", small_str], pipeline: 20000}));
|
||||
|
||||
tests.push(new Test({descr: "LRANGE 10", command: "lrange", args: ["mylist", "0", "9"], pipeline: 1}));
|
||||
tests.push(new Test({descr: "LRANGE 10", command: "lrange", args: ["mylist", "0", "9"], pipeline: 50}));
|
||||
tests.push(new Test({descr: "LRANGE 10", command: "lrange", args: ["mylist", "0", "9"], pipeline: 200}));
|
||||
tests.push(new Test({descr: "LRANGE 10", command: "lrange", args: ["mylist", "0", "9"], pipeline: 20000}));
|
||||
|
||||
tests.push(new Test({descr: "LRANGE 100", command: "lrange", args: ["mylist", "0", "99"], pipeline: 1}));
|
||||
tests.push(new Test({descr: "LRANGE 100", command: "lrange", args: ["mylist", "0", "99"], pipeline: 50}));
|
||||
tests.push(new Test({descr: "LRANGE 100", command: "lrange", args: ["mylist", "0", "99"], pipeline: 200}));
|
||||
tests.push(new Test({descr: "LRANGE 100", command: "lrange", args: ["mylist", "0", "99"], pipeline: 20000}));
|
||||
|
||||
tests.push(new Test({descr: "SET 4MiB buf", command: "set", args: ["foo_rand000000000002", very_large_buf], pipeline: 1, reqs: 500}));
|
||||
tests.push(new Test({descr: "SET 4MiB buf", command: "set", args: ["foo_rand000000000002", very_large_buf], pipeline: 50, reqs: 500}));
|
||||
|
||||
tests.push(new Test({descr: "GET 4MiB str", command: "get", args: ["foo_rand000000000002"], pipeline: 1, reqs: 100}));
|
||||
tests.push(new Test({descr: "GET 4MiB str", command: "get", args: ["foo_rand000000000002"], pipeline: 50, reqs: 100}));
|
||||
|
||||
tests.push(new Test({descr: "GET 4MiB buf", command: "get", args: ["foo_rand000000000002"], pipeline: 1, reqs: 100, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET 4MiB buf", command: "get", args: ["foo_rand000000000002"], pipeline: 50, reqs: 100, client_opts: { return_buffers: true} }));
|
||||
|
||||
function next() {
|
||||
var test = tests.shift();
|
||||
|
19
package.json
19
package.json
@@ -3,18 +3,27 @@
|
||||
"version": "0.12.1",
|
||||
"description": "Redis client library",
|
||||
"keywords": [
|
||||
"redis",
|
||||
"database"
|
||||
"database",
|
||||
"redis"
|
||||
],
|
||||
"author": "Matt Ranney <mjr@ranney.com>",
|
||||
"license": "MIT",
|
||||
"main": "./index.js",
|
||||
"scripts": {
|
||||
"test": "node ./test.js"
|
||||
"coverage": "nyc report --reporter=text-lcov | coveralls",
|
||||
"test": "nyc ./node_modules/.bin/_mocha ./test/*.js ./test/commands/*.js ./test/parser/*.js --timeout=8000"
|
||||
},
|
||||
"devDependencies": {
|
||||
"metrics": ">=0.1.5",
|
||||
"async": "^1.3.0",
|
||||
"colors": "~0.6.0-1",
|
||||
"underscore": "~1.4.4"
|
||||
"coveralls": "^2.11.2",
|
||||
"hiredis": "^0.4.0",
|
||||
"metrics": ">=0.1.5",
|
||||
"mocha": "^2.2.5",
|
||||
"nyc": "^3.0.0",
|
||||
"tcp-port-used": "^0.1.2",
|
||||
"underscore": "~1.4.4",
|
||||
"uuid": "^2.0.1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@@ -1,12 +0,0 @@
|
||||
var redis = require("./")
|
||||
//redis.debug_mode = true
|
||||
var PORT = process.argv[2] || 6379;
|
||||
var HOST = process.argv[3] || '127.0.0.1';
|
||||
|
||||
var c = redis.createClient(PORT, HOST)
|
||||
c.unref()
|
||||
c.info(function (err, reply) {
|
||||
if (err) process.exit(-1)
|
||||
if (!reply.length) process.exit(-1)
|
||||
process.stdout.write(reply.length.toString())
|
||||
})
|
91
test/auth.spec.js
Normal file
91
test/auth.spec.js
Normal file
@@ -0,0 +1,91 @@
|
||||
var assert = require("assert");
|
||||
var config = require("./lib/config");
|
||||
var helper = require('./helper')
|
||||
var path = require('path');
|
||||
var redis = config.redis;
|
||||
|
||||
describe("client authentication", function () {
|
||||
before(function (done) {
|
||||
helper.stopRedis(function () {
|
||||
helper.startRedis('./conf/password.conf', done);
|
||||
});
|
||||
});
|
||||
|
||||
function allTests(parser, ip) {
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var args = config.configureClient(parser, ip);
|
||||
var auth = 'porkchopsandwiches';
|
||||
var client = null;
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
it("allows auth to be provided with 'auth' method", function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.auth(auth, function (err, res) {
|
||||
assert.strictEqual(null, err);
|
||||
assert.strictEqual("OK", res.toString());
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it("raises error when auth is bad", function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
|
||||
client.once('error', function (error) {
|
||||
assert.ok(/ERR invalid password/.test(error))
|
||||
return done();
|
||||
});
|
||||
|
||||
client.auth(auth + 'bad');
|
||||
});
|
||||
|
||||
if (ip === 'IPv4') {
|
||||
it('allows auth to be provided as config option for client', function (done) {
|
||||
client = redis.createClient('redis://foo:' + auth + '@' + config.HOST[ip] + ':' + config.PORT);
|
||||
client.on("ready", function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
it('allows auth to be provided as part of redis url', function (done) {
|
||||
var args = config.configureClient(parser, ip, {
|
||||
auth_pass: auth
|
||||
});
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.on("ready", function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('reconnects with appropriate authentication', function (done) {
|
||||
var readyCount = 0;
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.auth(auth);
|
||||
client.on("ready", function () {
|
||||
readyCount++;
|
||||
if (readyCount === 1) {
|
||||
client.stream.destroy();
|
||||
} else {
|
||||
return done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
|
||||
after(function (done) {
|
||||
helper.stopRedis(function () {
|
||||
helper.startRedis('./conf/redis.conf', done);
|
||||
});
|
||||
});
|
||||
});
|
64
test/commands/blpop.spec.js
Normal file
64
test/commands/blpop.spec.js
Normal file
@@ -0,0 +1,64 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'blpop' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
var bclient;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('pops value immediately if list contains values', function (done) {
|
||||
bclient = redis.createClient.apply(redis.createClient, args);
|
||||
client.rpush("blocking list", "initial value", helper.isNumber(1));
|
||||
bclient.blpop("blocking list", 0, function (err, value) {
|
||||
assert.strictEqual(value[0], "blocking list");
|
||||
assert.strictEqual(value[1], "initial value");
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('waits for value if list is not yet populated', function (done) {
|
||||
bclient = redis.createClient.apply(redis.createClient, args);
|
||||
bclient.blpop("blocking list 2", 5, function (err, value) {
|
||||
assert.strictEqual(value[0], "blocking list 2");
|
||||
assert.strictEqual(value[1], "initial value");
|
||||
return done(err);
|
||||
});
|
||||
client.rpush("blocking list 2", "initial value", helper.isNumber(1));
|
||||
});
|
||||
|
||||
it('times out after specified time', function (done) {
|
||||
bclient = redis.createClient.apply(redis.createClient, args);
|
||||
bclient.BLPOP("blocking list", 1, function (err, res) {
|
||||
assert.strictEqual(res, null);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
bclient.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
61
test/commands/client.spec.js
Normal file
61
test/commands/client.spec.js
Normal file
@@ -0,0 +1,61 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'client' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
var pattern = /addr=/;
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(function (err) {
|
||||
if (!helper.serverVersionAtLeast(client, [2, 4, 0])) {
|
||||
err = Error('script not supported in redis <= 2.4.0')
|
||||
}
|
||||
return done(err);
|
||||
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
describe('list', function () {
|
||||
it('lists connected clients', function (done) {
|
||||
client.client("list", helper.match(pattern, done));
|
||||
});
|
||||
|
||||
it("lists connected clients when invoked with multi's chaining syntax", function (done) {
|
||||
client.multi().client("list").exec(function(err, results) {
|
||||
assert(pattern.test(results[0]), "expected string '" + results + "' to match " + pattern.toString());
|
||||
return done()
|
||||
})
|
||||
});
|
||||
|
||||
it("lists connected clients when invoked with multi's array syntax", function (done) {
|
||||
client.multi().client("list").exec(function(err, results) {
|
||||
assert(pattern.test(results[0]), "expected string '" + results + "' to match " + pattern.toString());
|
||||
return done()
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
106
test/commands/dbsize.spec.js
Normal file
106
test/commands/dbsize.spec.js
Normal file
@@ -0,0 +1,106 @@
|
||||
var async = require('async');
|
||||
var assert = require('assert');
|
||||
var config = require("../lib/config");
|
||||
var helper = require('../helper');
|
||||
var redis = config.redis;
|
||||
var uuid = require('uuid');
|
||||
|
||||
describe("The 'dbsize' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var key, value;
|
||||
|
||||
beforeEach(function () {
|
||||
key = uuid.v4();
|
||||
value = uuid.v4();
|
||||
});
|
||||
|
||||
describe("when not connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.quit();
|
||||
});
|
||||
client.on('end', function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it("reports an error", function (done) {
|
||||
client.dbsize([], function (err, res) {
|
||||
assert.equal(err.message, 'Redis connection gone from end event.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(function (err, res) {
|
||||
helper.isString("OK")(err, res);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
it("returns a zero db size", function (done) {
|
||||
client.dbsize([], function (err, res) {
|
||||
helper.isNotError()(err, res);
|
||||
helper.isType.number()(err, res);
|
||||
assert.strictEqual(res, 0, "Initial db size should be 0");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when more data is added to Redis", function () {
|
||||
var oldSize;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client.dbsize([], function (err, res) {
|
||||
helper.isType.number()(err, res);
|
||||
assert.strictEqual(res, 0, "Initial db size should be 0");
|
||||
|
||||
oldSize = res;
|
||||
|
||||
client.set(key, value, function (err, res) {
|
||||
helper.isNotError()(err, res);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("returns a larger db size", function (done) {
|
||||
client.dbsize([], function (err, res) {
|
||||
helper.isNotError()(err, res);
|
||||
helper.isType.positiveNumber()(err, res);
|
||||
assert.strictEqual(true, (oldSize < res), "Adding data should increase db size.");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
51
test/commands/del.spec.js
Normal file
51
test/commands/del.spec.js
Normal file
@@ -0,0 +1,51 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'del' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('allows a single key to be deleted', function (done) {
|
||||
client.set('foo', 'bar');
|
||||
client.del('foo', helper.isNumber(1));
|
||||
client.get('foo', helper.isNull(done));
|
||||
});
|
||||
|
||||
it('allows del to be called on a key that does not exist', function (done) {
|
||||
client.del('foo', helper.isNumber(0, done));
|
||||
});
|
||||
|
||||
it('allows multiple keys to be deleted', function (done) {
|
||||
client.mset('foo', 'bar', 'apple', 'banana');
|
||||
client.del('foo', 'apple', helper.isNumber(2));
|
||||
client.get('foo', helper.isNull());
|
||||
client.get('apple', helper.isNull(done));
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
199
test/commands/eval.spec.js
Normal file
199
test/commands/eval.spec.js
Normal file
@@ -0,0 +1,199 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var crypto = require("crypto");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'eval' method", function () {
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(function (err) {
|
||||
if (!helper.serverVersionAtLeast(client, [2, 5, 0])) {
|
||||
err = Error('exec not supported in redis <= 2.5.0')
|
||||
}
|
||||
return done(err);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
it('converts a float to an integer when evaluated', function (done) {
|
||||
client.eval("return 100.5", 0, helper.isNumber(100, done));
|
||||
});
|
||||
|
||||
it('returns a string', function (done) {
|
||||
client.eval("return 'hello world'", 0, helper.isString('hello world', done));
|
||||
});
|
||||
|
||||
it('converts boolean true to integer 1', function (done) {
|
||||
client.eval("return true", 0, helper.isNumber(1, done));
|
||||
});
|
||||
|
||||
it('converts boolean false to null', function (done) {
|
||||
client.eval("return false", 0, helper.isNull(done));
|
||||
});
|
||||
|
||||
it('converts lua status code to string representation', function (done) {
|
||||
client.eval("return {ok='fine'}", 0, helper.isString('fine', done));
|
||||
});
|
||||
|
||||
it('converts lua error to an error response', function (done) {
|
||||
client.eval("return {err='this is an error'}", 0, helper.isError(done));
|
||||
});
|
||||
|
||||
it('represents a lua table appropritely', function (done) {
|
||||
client.eval("return {1,2,3,'ciao',{1,2}}", 0, function (err, res) {
|
||||
assert.strictEqual(5, res.length);
|
||||
assert.strictEqual(1, res[0]);
|
||||
assert.strictEqual(2, res[1]);
|
||||
assert.strictEqual(3, res[2]);
|
||||
assert.strictEqual("ciao", res[3]);
|
||||
assert.strictEqual(2, res[4].length);
|
||||
assert.strictEqual(1, res[4][0]);
|
||||
assert.strictEqual(2, res[4][1]);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('populates keys and argv correctly', function (done) {
|
||||
client.eval("return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", 2, "a", "b", "c", "d", function (err, res) {
|
||||
assert.strictEqual(4, res.length);
|
||||
assert.strictEqual("a", res[0]);
|
||||
assert.strictEqual("b", res[1]);
|
||||
assert.strictEqual("c", res[2]);
|
||||
assert.strictEqual("d", res[3]);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('allows arguments to be provided in array rather than as multiple parameters', function (done) {
|
||||
client.eval(["return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", 2, "a", "b", "c", "d"], function (err, res) {
|
||||
assert.strictEqual(4, res.length);
|
||||
assert.strictEqual("a", res[0]);
|
||||
assert.strictEqual("b", res[1]);
|
||||
assert.strictEqual("c", res[2]);
|
||||
assert.strictEqual("d", res[3]);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('evalsha', function () {
|
||||
var source = "return redis.call('get', 'sha test')";
|
||||
var sha = crypto.createHash('sha1').update(source).digest('hex');
|
||||
|
||||
beforeEach(function (done) {
|
||||
client.set("sha test", "eval get sha test", function (err, res) {
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('allows a script to be executed that accesses the redis API', function (done) {
|
||||
client.eval(source, 0, helper.isString('eval get sha test', done));
|
||||
});
|
||||
|
||||
it('can execute a script if the SHA exists', function (done) {
|
||||
client.evalsha(sha, 0, helper.isString('eval get sha test', done));
|
||||
});
|
||||
|
||||
it('throws an error if SHA does not exist', function (done) {
|
||||
client.evalsha('ffffffffffffffffffffffffffffffffffffffff', 0, helper.isError(done));
|
||||
});
|
||||
});
|
||||
|
||||
it('allows a key to be incremented, and performs appropriate conversion from LUA type', function (done) {
|
||||
client.set("incr key", 0, function (err, reply) {
|
||||
if (err) return done(err);
|
||||
client.eval("local foo = redis.call('incr','incr key')\n" + "return {type(foo),foo}", 0, function (err, res) {
|
||||
assert.strictEqual(2, res.length);
|
||||
assert.strictEqual("number", res[0]);
|
||||
assert.strictEqual(1, res[1]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('allows a bulk operation to be performed, and performs appropriate conversion from LUA type', function (done) {
|
||||
client.set("bulk reply key", "bulk reply value", function (err, res) {
|
||||
client.eval("local foo = redis.call('get','bulk reply key'); return {type(foo),foo}", 0, function (err, res) {
|
||||
assert.strictEqual(2, res.length);
|
||||
assert.strictEqual("string", res[0]);
|
||||
assert.strictEqual("bulk reply value", res[1]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('allows a multi mulk operation to be performed, with the appropriate type conversion', function (done) {
|
||||
client.multi()
|
||||
.del("mylist")
|
||||
.rpush("mylist", "a")
|
||||
.rpush("mylist", "b")
|
||||
.rpush("mylist", "c")
|
||||
.exec(function (err, replies) {
|
||||
if (err) return done(err);
|
||||
client.eval("local foo = redis.call('lrange','mylist',0,-1); return {type(foo),foo[1],foo[2],foo[3],# foo}", 0, function (err, res) {
|
||||
assert.strictEqual(5, res.length);
|
||||
assert.strictEqual("table", res[0]);
|
||||
assert.strictEqual("a", res[1]);
|
||||
assert.strictEqual("b", res[2]);
|
||||
assert.strictEqual("c", res[3]);
|
||||
assert.strictEqual(3, res[4]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an appropriate representation of Lua status reply', function (done) {
|
||||
client.eval("local foo = redis.call('set','mykey','myval'); return {type(foo),foo['ok']}", 0, function (err, res) {
|
||||
assert.strictEqual(2, res.length);
|
||||
assert.strictEqual("table", res[0]);
|
||||
assert.strictEqual("OK", res[1]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an appropriate representation of a Lua error reply', function (done) {
|
||||
client.set("error reply key", "error reply value", function (err, res) {
|
||||
if (err) return done(err);
|
||||
client.eval("local foo = redis.pcall('incr','error reply key'); return {type(foo),foo['err']}", 0, function (err, res) {
|
||||
assert.strictEqual(2, res.length);
|
||||
assert.strictEqual("table", res[0]);
|
||||
assert.strictEqual("ERR value is not an integer or out of range", res[1]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an appropriate representation of a Lua nil reply', function (done) {
|
||||
client.del("nil reply key", function (err, res) {
|
||||
if (err) return done(err);
|
||||
client.eval("local foo = redis.call('get','nil reply key'); return {type(foo),foo == false}", 0, function (err, res) {
|
||||
if (err) throw err;
|
||||
assert.strictEqual(2, res.length);
|
||||
assert.strictEqual("boolean", res[0]);
|
||||
assert.strictEqual(1, res[1]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
43
test/commands/exits.spec.js
Normal file
43
test/commands/exits.spec.js
Normal file
@@ -0,0 +1,43 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'exits' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 1 if the key exists', function (done) {
|
||||
client.set('foo', 'bar');
|
||||
client.exists('foo', helper.isNumber(1, done));
|
||||
});
|
||||
|
||||
it('returns 0 if the key does not exist', function (done) {
|
||||
client.exists('bar', helper.isNumber(0, done));
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
42
test/commands/expire.spec.js
Normal file
42
test/commands/expire.spec.js
Normal file
@@ -0,0 +1,42 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'expire' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('expires key after timeout', function (done) {
|
||||
client.set(['expiry key', 'bar'], helper.isString("OK"));
|
||||
client.EXPIRE(["expiry key", "1"], helper.isNumber(1));
|
||||
setTimeout(function () {
|
||||
client.exists(["expiry key"], helper.isNumber(0, done));
|
||||
}, 1500);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
115
test/commands/flushdb.spec.js
Normal file
115
test/commands/flushdb.spec.js
Normal file
@@ -0,0 +1,115 @@
|
||||
var async = require('async');
|
||||
var assert = require('assert');
|
||||
var config = require("../lib/config");
|
||||
var helper = require('../helper');
|
||||
var redis = config.redis;
|
||||
var uuid = require('uuid');
|
||||
|
||||
describe("The 'flushdb' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var key, key2;
|
||||
|
||||
beforeEach(function () {
|
||||
key = uuid.v4();
|
||||
key2 = uuid.v4();
|
||||
});
|
||||
|
||||
describe("when not connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.quit();
|
||||
});
|
||||
client.on('end', function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it("reports an error", function (done) {
|
||||
client.flushdb(function (err, res) {
|
||||
assert.equal(err.message, 'Redis connection gone from end event.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
describe("when there is data in Redis", function () {
|
||||
var oldSize;
|
||||
|
||||
beforeEach(function (done) {
|
||||
async.parallel([function (next) {
|
||||
client.mset(key, uuid.v4(), key2, uuid.v4(), function (err, res) {
|
||||
helper.isNotError()(err, res);
|
||||
next(err);
|
||||
});
|
||||
}, function (next) {
|
||||
client.dbsize([], function (err, res) {
|
||||
helper.isType.positiveNumber()(err, res);
|
||||
oldSize = res;
|
||||
next(err);
|
||||
});
|
||||
}], function (err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
client.flushdb(function (err, res) {
|
||||
helper.isString("OK")(err, res);
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("deletes all the keys", function (done) {
|
||||
client.mget(key, key2, function (err, res) {
|
||||
assert.strictEqual(null, err, "Unexpected error returned");
|
||||
assert.strictEqual(true, Array.isArray(res), "Results object should be an array.");
|
||||
assert.strictEqual(2, res.length, "Results array should have length 2.");
|
||||
assert.strictEqual(null, res[0], "Redis key should have been flushed.");
|
||||
assert.strictEqual(null, res[1], "Redis key should have been flushed.");
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it("results in a db size of zero", function (done) {
|
||||
client.dbsize([], function (err, res) {
|
||||
helper.isNotError()(err, res);
|
||||
helper.isType.number()(err, res);
|
||||
assert.strictEqual(0, res, "Flushing db should result in db size 0");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
92
test/commands/get.spec.js
Normal file
92
test/commands/get.spec.js
Normal file
@@ -0,0 +1,92 @@
|
||||
var async = require('async');
|
||||
var assert = require('assert');
|
||||
var config = require("../lib/config");
|
||||
var helper = require('../helper');
|
||||
var redis = config.redis;
|
||||
var uuid = require('uuid');
|
||||
|
||||
describe("The 'get' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var key, value;
|
||||
|
||||
beforeEach(function () {
|
||||
key = uuid.v4();
|
||||
value = uuid.v4();
|
||||
});
|
||||
|
||||
describe("when not connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.quit();
|
||||
});
|
||||
client.on('end', function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it("reports an error", function (done) {
|
||||
client.get(key, function (err, res) {
|
||||
assert.equal(err.message, 'Redis connection gone from end event.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
describe("when the key exists in Redis", function () {
|
||||
beforeEach(function (done) {
|
||||
client.set(key, value, function (err, res) {
|
||||
helper.isNotError()(err, res);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("gets the value correctly", function (done) {
|
||||
client.get(key, function (err, res) {
|
||||
helper.isString(value)(err, res);
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the key does not exist in Redis", function () {
|
||||
it("gets a null value", function (done) {
|
||||
client.get(key, function (err, res) {
|
||||
helper.isNull()(err, res);
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
96
test/commands/getset.spec.js
Normal file
96
test/commands/getset.spec.js
Normal file
@@ -0,0 +1,96 @@
|
||||
var async = require('async');
|
||||
var assert = require('assert');
|
||||
var config = require("../lib/config");
|
||||
var helper = require('../helper');
|
||||
var redis = config.redis;
|
||||
var uuid = require('uuid');
|
||||
|
||||
describe("The 'getset' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var key, value, value2;
|
||||
|
||||
beforeEach(function () {
|
||||
key = uuid.v4();
|
||||
value = uuid.v4();
|
||||
value2 = uuid.v4();
|
||||
});
|
||||
|
||||
describe("when not connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.quit();
|
||||
});
|
||||
client.on('end', function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it("reports an error", function (done) {
|
||||
client.get(key, function (err, res) {
|
||||
assert.equal(err.message, 'Redis connection gone from end event.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
describe("when the key exists in Redis", function () {
|
||||
beforeEach(function (done) {
|
||||
client.set(key, value, function (err, res) {
|
||||
helper.isNotError()(err, res);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("gets the value correctly", function (done) {
|
||||
client.getset(key, value2, function (err, res) {
|
||||
helper.isString(value)(err, res);
|
||||
client.get(key, function (err, res) {
|
||||
helper.isString(value2)(err, res);
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the key does not exist in Redis", function () {
|
||||
it("gets a null value", function (done) {
|
||||
client.getset(key, value, function (err, res) {
|
||||
helper.isNull()(err, res);
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
91
test/commands/hgetall.spec.js
Normal file
91
test/commands/hgetall.spec.js
Normal file
@@ -0,0 +1,91 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'hgetall' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
describe('regular client', function () {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles simple keys and values', function (done) {
|
||||
client.hmset(["hosts", "mjr", "1", "another", "23", "home", "1234"], helper.isString("OK"));
|
||||
client.HGETALL(["hosts"], function (err, obj) {
|
||||
assert.strictEqual(3, Object.keys(obj).length);
|
||||
assert.strictEqual("1", obj.mjr.toString());
|
||||
assert.strictEqual("23", obj.another.toString());
|
||||
assert.strictEqual("1234", obj.home.toString());
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles fetching keys set using an object', function (done) {
|
||||
client.hmset("msg_test", {message: "hello"}, helper.isString("OK"));
|
||||
client.hgetall("msg_test", function (err, obj) {
|
||||
assert.strictEqual(1, Object.keys(obj).length);
|
||||
assert.strictEqual(obj.message, "hello");
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles fetching a messing key', function (done) {
|
||||
client.hgetall("missing", function (err, obj) {
|
||||
assert.strictEqual(null, obj);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('binary client', function () {
|
||||
var client;
|
||||
var args = config.configureClient(parser, ip, {
|
||||
return_buffers: true
|
||||
});
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns binary results', function (done) {
|
||||
client.hmset(["bhosts", "mjr", "1", "another", "23", "home", "1234", new Buffer([0xAA, 0xBB, 0x00, 0xF0]), new Buffer([0xCC, 0xDD, 0x00, 0xF0])], helper.isString("OK"));
|
||||
client.HGETALL(["bhosts"], function (err, obj) {
|
||||
assert.strictEqual(4, Object.keys(obj).length);
|
||||
assert.strictEqual("1", obj.mjr.toString());
|
||||
assert.strictEqual("23", obj.another.toString());
|
||||
assert.strictEqual("1234", obj.home.toString());
|
||||
assert.strictEqual((new Buffer([0xAA, 0xBB, 0x00, 0xF0])).toString('binary'), Object.keys(obj)[3]);
|
||||
assert.strictEqual((new Buffer([0xCC, 0xDD, 0x00, 0xF0])).toString('binary'), obj[(new Buffer([0xAA, 0xBB, 0x00, 0xF0])).toString('binary')].toString('binary'));
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
48
test/commands/hincrby.spec.js
Normal file
48
test/commands/hincrby.spec.js
Normal file
@@ -0,0 +1,48 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'hincrby' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
var hash = "test hash";
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('increments a key that has already been set', function (done) {
|
||||
var field = "field 1";
|
||||
|
||||
client.HSET(hash, field, 33);
|
||||
client.HINCRBY(hash, field, 10, helper.isNumber(43, done));
|
||||
});
|
||||
|
||||
it('increments a key that has not been set', function (done) {
|
||||
var field = "field 2";
|
||||
|
||||
client.HINCRBY(hash, field, 10, helper.isNumber(10, done));
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
46
test/commands/hlen.spec.js
Normal file
46
test/commands/hlen.spec.js
Normal file
@@ -0,0 +1,46 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'hlen' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('reports the count of keys', function (done) {
|
||||
var hash = "test hash";
|
||||
var field1 = new Buffer("0123456789");
|
||||
var value1 = new Buffer("abcdefghij");
|
||||
var field2 = new Buffer(0);
|
||||
var value2 = new Buffer(0);
|
||||
|
||||
client.HSET(hash, field1, value1, helper.isNumber(1));
|
||||
client.HSET(hash, field2, value2, helper.isNumber(1));
|
||||
client.HLEN(hash, helper.isNumber(2, done));
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
68
test/commands/hmget.spec.js
Normal file
68
test/commands/hmget.spec.js
Normal file
@@ -0,0 +1,68 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'hmget' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
var hash = 'test hash';
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb();
|
||||
client.HMSET(hash, {"0123456789": "abcdefghij", "some manner of key": "a type of value"}, helper.isString('OK'));
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('allows keys to be specified using multiple arguments', function (done) {
|
||||
client.HMGET(hash, "0123456789", "some manner of key", function (err, reply) {
|
||||
assert.strictEqual("abcdefghij", reply[0].toString());
|
||||
assert.strictEqual("a type of value", reply[1].toString());
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('allows keys to be specified by passing an array', function (done) {
|
||||
client.HMGET(hash, ["0123456789", "some manner of key"], function (err, reply) {
|
||||
assert.strictEqual("abcdefghij", reply[0].toString());
|
||||
assert.strictEqual("a type of value", reply[1].toString());
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('allows a single key to be specified in an array', function (done) {
|
||||
client.HMGET(hash, ["0123456789"], function (err, reply) {
|
||||
assert.strictEqual("abcdefghij", reply[0].toString());
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('allows keys to be specified that have not yet been set', function (done) {
|
||||
client.HMGET(hash, "missing thing", "another missing thing", function (err, reply) {
|
||||
assert.strictEqual(null, reply[0]);
|
||||
assert.strictEqual(null, reply[1]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
61
test/commands/hmset.spec.js
Normal file
61
test/commands/hmset.spec.js
Normal file
@@ -0,0 +1,61 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'hmset' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
var hash = 'test hash';
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles redis-style syntax', function (done) {
|
||||
client.HMSET(hash, "0123456789", "abcdefghij", "some manner of key", "a type of value", helper.isString('OK'));
|
||||
client.HGETALL(hash, function (err, obj) {
|
||||
assert.equal(obj['0123456789'], 'abcdefghij');
|
||||
assert.equal(obj['some manner of key'], 'a type of value');
|
||||
return done(err);
|
||||
})
|
||||
});
|
||||
|
||||
it('handles object-style syntax', function (done) {
|
||||
client.HMSET(hash, {"0123456789": "abcdefghij", "some manner of key": "a type of value"}, helper.isString('OK'));
|
||||
client.HGETALL(hash, function (err, obj) {
|
||||
assert.equal(obj['0123456789'], 'abcdefghij');
|
||||
assert.equal(obj['some manner of key'], 'a type of value');
|
||||
return done(err);
|
||||
})
|
||||
});
|
||||
|
||||
it('allows a numeric key', function (done) {
|
||||
client.HMSET(hash, 99, 'banana', helper.isString('OK'));
|
||||
client.HGETALL(hash, function (err, obj) {
|
||||
assert.equal(obj['99'], 'banana');
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
70
test/commands/hset.spec.js
Normal file
70
test/commands/hset.spec.js
Normal file
@@ -0,0 +1,70 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'hset' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
var hash = 'test hash';
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('allows a value to be set in a hash', function (done) {
|
||||
var field = new Buffer("0123456789");
|
||||
var value = new Buffer("abcdefghij");
|
||||
|
||||
client.HSET(hash, field, value, helper.isNumber(1));
|
||||
client.HGET(hash, field, helper.isString(value.toString(), done));
|
||||
});
|
||||
|
||||
it('handles an empty value', function (done) {
|
||||
var field = new Buffer("0123456789");
|
||||
var value = new Buffer(0);
|
||||
|
||||
client.HSET(hash, field, value, helper.isNumber(1));
|
||||
client.HGET([hash, field], helper.isString("", done));
|
||||
});
|
||||
|
||||
it('handles empty key and value', function (done) {
|
||||
var field = new Buffer(0);
|
||||
var value = new Buffer(0);
|
||||
client.HSET([hash, field, value], function (err, res) {
|
||||
assert.strictEqual(res, 1);
|
||||
client.HSET(hash, field, value, helper.isNumber(0, done));
|
||||
});
|
||||
});
|
||||
|
||||
it('does not error when a buffer and array are set as fields on the same hash', function (done) {
|
||||
var hash = "test hash"
|
||||
var field1 = "buffer"
|
||||
var value1 = new Buffer("abcdefghij")
|
||||
var field2 = "array"
|
||||
var value2 = ["array contents"]
|
||||
|
||||
client.HMSET(hash, field1, value1, field2, value2, helper.isString("OK", done));
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
124
test/commands/incr.spec.js
Normal file
124
test/commands/incr.spec.js
Normal file
@@ -0,0 +1,124 @@
|
||||
var async = require('async');
|
||||
var assert = require('assert');
|
||||
var config = require("../lib/config");
|
||||
var helper = require('../helper');
|
||||
var redis = config.redis;
|
||||
var uuid = require('uuid');
|
||||
|
||||
describe("The 'incr' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var key = "sequence";
|
||||
|
||||
describe("when not connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.set(key, "9007199254740992", function (err, res) {
|
||||
helper.isNotError()(err, res);
|
||||
client.quit();
|
||||
});
|
||||
});
|
||||
client.on('end', function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
it("reports an error", function (done) {
|
||||
client.incr(function (err, res) {
|
||||
assert.equal(err.message, 'Redis connection gone from end event.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when connected and a value in Redis", function () {
|
||||
var client;
|
||||
|
||||
// Also, why tf were these disabled for hiredis? They work just fine.
|
||||
before(function (done) {
|
||||
/*
|
||||
9007199254740992 -> 9007199254740992
|
||||
9007199254740993 -> 9007199254740992
|
||||
9007199254740994 -> 9007199254740994
|
||||
9007199254740995 -> 9007199254740996
|
||||
9007199254740996 -> 9007199254740996
|
||||
9007199254740997 -> 9007199254740996
|
||||
*/
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.set(key, "9007199254740992", function (err, res) {
|
||||
helper.isNotError()(err, res);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
after(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
it("changes the last digit from 2 to 3", function (done) {
|
||||
client.incr(key, function (err, res) {
|
||||
helper.isString("9007199254740993")(err, res);
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
describe("and we call it again", function () {
|
||||
it("changes the last digit from 3 to 4", function (done) {
|
||||
client.incr(key, function (err, res) {
|
||||
helper.isString("9007199254740994")(err, res);
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
describe("and again", function () {
|
||||
it("changes the last digit from 4 to 5", function (done) {
|
||||
client.incr(key, function (err, res) {
|
||||
helper.isString("9007199254740995")(err, res);
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
describe("and again", function () {
|
||||
it("changes the last digit from 5 to 6", function (done) {
|
||||
client.incr(key, function (err, res) {
|
||||
helper.isString("9007199254740996")(err, res);
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
describe("and again", function () {
|
||||
it("changes the last digit from 6 to 7", function (done) {
|
||||
client.incr(key, function (err, res) {
|
||||
helper.isString("9007199254740997")(err, res);
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
76
test/commands/keys.spec.js
Normal file
76
test/commands/keys.spec.js
Normal file
@@ -0,0 +1,76 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var crypto = require("crypto");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'keys' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns matching keys', function (done) {
|
||||
client.mset(["test keys 1", "test val 1", "test keys 2", "test val 2"], helper.isString("OK"));
|
||||
client.KEYS(["test keys*"], function (err, results) {
|
||||
assert.strictEqual(2, results.length);
|
||||
assert.ok(~results.indexOf("test keys 1"));
|
||||
assert.ok(~results.indexOf("test keys 2"));
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles a large packet size', function (done) {
|
||||
var keys_values = [];
|
||||
|
||||
for (var i = 0; i < 200; i++) {
|
||||
var key_value = [
|
||||
"multibulk:" + crypto.randomBytes(256).toString("hex"), // use long strings as keys to ensure generation of large packet
|
||||
"test val " + i
|
||||
];
|
||||
keys_values.push(key_value);
|
||||
}
|
||||
|
||||
client.mset(keys_values.reduce(function(a, b) {
|
||||
return a.concat(b);
|
||||
}), helper.isString("OK"));
|
||||
|
||||
client.KEYS("multibulk:*", function(err, results) {
|
||||
assert.deepEqual(keys_values.map(function(val) {
|
||||
return val[0];
|
||||
}).sort(), results.sort());
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles an empty response', function (done) {
|
||||
client.KEYS(['users:*'], function (err, results) {
|
||||
assert.strictEqual(results.length, 0);
|
||||
assert.ok(Array.isArray(results));
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
66
test/commands/mget.spec.js
Normal file
66
test/commands/mget.spec.js
Normal file
@@ -0,0 +1,66 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'mget' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb();
|
||||
client.mset(["mget keys 1", "mget val 1", "mget keys 2", "mget val 2", "mget keys 3", "mget val 3"], done);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles fetching multiple keys in argument form', function (done) {
|
||||
client.mset(["mget keys 1", "mget val 1", "mget keys 2", "mget val 2", "mget keys 3", "mget val 3"], helper.isString("OK"));
|
||||
client.MGET("mget keys 1", "mget keys 2", "mget keys 3", function (err, results) {
|
||||
assert.strictEqual(3, results.length);
|
||||
assert.strictEqual("mget val 1", results[0].toString());
|
||||
assert.strictEqual("mget val 2", results[1].toString());
|
||||
assert.strictEqual("mget val 3", results[2].toString());
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles fetching multiple keys via an array', function (done) {
|
||||
client.MGET(["mget keys 1", "mget keys 2", "mget keys 3"], function (err, results) {
|
||||
assert.strictEqual("mget val 1", results[0].toString());
|
||||
assert.strictEqual("mget val 2", results[1].toString());
|
||||
assert.strictEqual("mget val 3", results[2].toString());
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles fetching multiple keys, when some keys do not exist', function (done) {
|
||||
client.MGET(["mget keys 1", "some random shit", "mget keys 2", "mget keys 3"], function (err, results) {
|
||||
assert.strictEqual(4, results.length);
|
||||
assert.strictEqual("mget val 1", results[0].toString());
|
||||
assert.strictEqual(null, results[1]);
|
||||
assert.strictEqual("mget val 2", results[2].toString());
|
||||
assert.strictEqual("mget val 3", results[3].toString());
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
141
test/commands/mset.spec.js
Normal file
141
test/commands/mset.spec.js
Normal file
@@ -0,0 +1,141 @@
|
||||
var async = require('async');
|
||||
var assert = require('assert');
|
||||
var config = require("../lib/config");
|
||||
var helper = require('../helper');
|
||||
var redis = config.redis;
|
||||
var uuid = require('uuid');
|
||||
|
||||
describe("The 'mset' method", function () {
|
||||
|
||||
function removeMochaListener () {
|
||||
var mochaListener = process.listeners('uncaughtException').pop();
|
||||
process.removeListener('uncaughtException', mochaListener);
|
||||
return mochaListener;
|
||||
}
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var key, value, key2, value2;
|
||||
|
||||
beforeEach(function () {
|
||||
key = uuid.v4();
|
||||
value = uuid.v4();
|
||||
key2 = uuid.v4();
|
||||
value2 = uuid.v4();
|
||||
});
|
||||
|
||||
describe("when not connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.quit();
|
||||
});
|
||||
client.on('end', function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it("reports an error", function (done) {
|
||||
client.mset(key, value, key2, value2, function (err, res) {
|
||||
assert.equal(err.message, 'Redis connection gone from end event.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
describe("and a callback is specified", function () {
|
||||
describe("with valid parameters", function () {
|
||||
it("sets the value correctly", function (done) {
|
||||
client.mset(key, value, key2, value2);
|
||||
client.get(key, helper.isString(value));
|
||||
client.get(key2, helper.isString(value2, done));
|
||||
});
|
||||
});
|
||||
|
||||
describe("with undefined 'key' parameter and missing 'value' parameter", function () {
|
||||
it("reports an error", function (done) {
|
||||
client.mset(undefined, function (err, res) {
|
||||
helper.isError()(err, null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with undefined 'key' and defined 'value' parameters", function () {
|
||||
it("reports an error", function () {
|
||||
client.mset(undefined, value, undefined, value2, function (err, res) {
|
||||
helper.isError()(err, null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("and no callback is specified", function () {
|
||||
describe("with valid parameters", function () {
|
||||
it("sets the value correctly", function (done) {
|
||||
client.mset(key, value, key2, value2);
|
||||
client.get(key, helper.isString(value));
|
||||
client.get(key2, helper.isString(value2, done));
|
||||
});
|
||||
});
|
||||
|
||||
describe("with undefined 'key' and missing 'value' parameter", function () {
|
||||
// this behavior is different from the 'set' behavior.
|
||||
it("throws an error", function (done) {
|
||||
var mochaListener = removeMochaListener();
|
||||
|
||||
process.once('uncaughtException', function (err) {
|
||||
process.on('uncaughtException', mochaListener);
|
||||
helper.isError()(err, null);
|
||||
return done();
|
||||
});
|
||||
|
||||
client.mset();
|
||||
});
|
||||
});
|
||||
|
||||
describe("with undefined 'key' and defined 'value' parameters", function () {
|
||||
it("throws an error", function () {
|
||||
var mochaListener = removeMochaListener();
|
||||
|
||||
process.once('uncaughtException', function (err) {
|
||||
process.on('uncaughtException', mochaListener);
|
||||
helper.isError()(err, null);
|
||||
});
|
||||
|
||||
client.mset(undefined, value, undefined, value2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
46
test/commands/msetnx.spec.js
Normal file
46
test/commands/msetnx.spec.js
Normal file
@@ -0,0 +1,46 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'msetnx' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('if any keys exist entire operation fails', function (done) {
|
||||
client.mset(["mset1", "val1", "mset2", "val2", "mset3", "val3"], helper.isString("OK"));
|
||||
client.MSETNX(["mset3", "val3", "mset4", "val4"], helper.isNumber(0));
|
||||
client.exists(["mset4"], helper.isNumber(0, done));
|
||||
});
|
||||
|
||||
it('sets multiple keys if all keys are not set', function (done) {
|
||||
client.MSETNX(["mset3", "val3", "mset4", "val4"], helper.isNumber(1));
|
||||
client.exists(["mset3"], helper.isNumber(1));
|
||||
client.exists(["mset3"], helper.isNumber(1, done));
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
250
test/commands/multi.spec.js
Normal file
250
test/commands/multi.spec.js
Normal file
@@ -0,0 +1,250 @@
|
||||
var async = require('async');
|
||||
var assert = require('assert');
|
||||
var config = require("../lib/config");
|
||||
var helper = require('../helper');
|
||||
var redis = config.redis;
|
||||
var uuid = require('uuid');
|
||||
|
||||
describe("The 'multi' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var key, value;
|
||||
|
||||
beforeEach(function () {
|
||||
key = uuid.v4();
|
||||
value = uuid.v4();
|
||||
});
|
||||
|
||||
describe("when not connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.quit();
|
||||
});
|
||||
client.on('end', function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it("reports an error", function (done) {
|
||||
client.multi();
|
||||
client.exec(function (err, res) {
|
||||
assert.equal(err.message, 'Redis connection gone from end event.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(function (err) {
|
||||
return done(err);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
it('roles back a transaction when one command in a sequence of commands fails', function (done) {
|
||||
var name = "MULTI_1", multi1, multi2;
|
||||
|
||||
// Provoke an error at queue time
|
||||
multi1 = client.multi();
|
||||
multi1.mset("multifoo", "10", "multibar", "20", helper.isString("OK"));
|
||||
multi1.set("foo2", helper.isError());
|
||||
multi1.incr("multifoo", helper.isNumber(11));
|
||||
multi1.incr("multibar", helper.isNumber(21));
|
||||
multi1.exec(function () {
|
||||
// Redis 2.6.5+ will abort transactions with errors
|
||||
// see: http://redis.io/topics/transactions
|
||||
var multibar_expected = 22;
|
||||
var multifoo_expected = 12;
|
||||
if (helper.serverVersionAtLeast(client, [2, 6, 5])) {
|
||||
multibar_expected = 1;
|
||||
multifoo_expected = 1;
|
||||
}
|
||||
|
||||
// Confirm that the previous command, while containing an error, still worked.
|
||||
multi2 = client.multi();
|
||||
multi2.incr("multibar", helper.isNumber(multibar_expected));
|
||||
multi2.incr("multifoo", helper.isNumber(multifoo_expected));
|
||||
multi2.exec(function (err, replies) {
|
||||
assert.strictEqual(multibar_expected, replies[0]);
|
||||
assert.strictEqual(multifoo_expected, replies[1]);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// I'm unclear as to the difference between this test in the test above,
|
||||
// perhaps @mranney can clarify?
|
||||
it('roles back a transaction when an error was provoked at queue time', function (done) {
|
||||
multi1 = client.multi();
|
||||
multi1.mset("multifoo_8", "10", "multibar_8", "20", helper.isString("OK"));
|
||||
multi1.set("foo2", helper.isError());
|
||||
multi1.set("foo3", helper.isError());
|
||||
multi1.incr("multifoo_8", helper.isNumber(11));
|
||||
multi1.incr("multibar_8", helper.isNumber(21));
|
||||
multi1.exec(function () {
|
||||
// Redis 2.6.5+ will abort transactions with errors
|
||||
// see: http://redis.io/topics/transactions
|
||||
var multibar_expected = 22;
|
||||
var multifoo_expected = 12;
|
||||
if (helper.serverVersionAtLeast(client, [2, 6, 5])) {
|
||||
multibar_expected = 1;
|
||||
multifoo_expected = 1;
|
||||
}
|
||||
|
||||
// Confirm that the previous command, while containing an error, still worked.
|
||||
multi2 = client.multi();
|
||||
multi2.incr("multibar_8", helper.isNumber(multibar_expected));
|
||||
multi2.incr("multifoo_8", helper.isNumber(multifoo_expected));
|
||||
multi2.exec(function (err, replies) {
|
||||
assert.strictEqual(multibar_expected, replies[0]);
|
||||
assert.strictEqual(multifoo_expected, replies[1]);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('roles back a transaction when one command in an array of commands fails', function (done) {
|
||||
// test nested multi-bulk replies
|
||||
client.multi([
|
||||
["mget", "multifoo", "multibar", function (err, res) {
|
||||
assert.strictEqual(2, res.length);
|
||||
assert.strictEqual("0", res[0].toString());
|
||||
assert.strictEqual("0", res[1].toString());
|
||||
}],
|
||||
["set", "foo2", helper.isError()],
|
||||
["incr", "multifoo", helper.isNumber(1)],
|
||||
["incr", "multibar", helper.isNumber(1)]
|
||||
]).exec(function (err, replies) {
|
||||
if (helper.serverVersionAtLeast(client, [2, 6, 5])) {
|
||||
assert.notEqual(err, null);
|
||||
assert.equal(replies, undefined);
|
||||
} else {
|
||||
assert.strictEqual(2, replies[0].length);
|
||||
assert.strictEqual("0", replies[0][0].toString());
|
||||
assert.strictEqual("0", replies[0][1].toString());
|
||||
|
||||
assert.strictEqual("1", replies[1].toString());
|
||||
assert.strictEqual("1", replies[2].toString());
|
||||
}
|
||||
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('handles multiple operations being applied to a set', function (done) {
|
||||
client.sadd("some set", "mem 1");
|
||||
client.sadd("some set", "mem 2");
|
||||
client.sadd("some set", "mem 3");
|
||||
client.sadd("some set", "mem 4");
|
||||
|
||||
// make sure empty mb reply works
|
||||
client.del("some missing set");
|
||||
client.smembers("some missing set", function (err, reply) {
|
||||
// make sure empty mb reply works
|
||||
assert.strictEqual(0, reply.length);
|
||||
});
|
||||
|
||||
// test nested multi-bulk replies with empty mb elements.
|
||||
client.multi([
|
||||
["smembers", "some set"],
|
||||
["del", "some set"],
|
||||
["smembers", "some set"]
|
||||
])
|
||||
.scard("some set")
|
||||
.exec(function (err, replies) {
|
||||
assert.strictEqual(4, replies[0].length);
|
||||
assert.strictEqual(0, replies[2].length);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('allows multiple operations to be performed using a chaining API', function (done) {
|
||||
client.multi()
|
||||
.mset('some', '10', 'keys', '20')
|
||||
.incr('some')
|
||||
.incr('keys')
|
||||
.mget('some', 'keys')
|
||||
.exec(function (err, replies) {
|
||||
assert.strictEqual(null, err);
|
||||
assert.equal('OK', replies[0]);
|
||||
assert.equal(11, replies[1]);
|
||||
assert.equal(21, replies[2]);
|
||||
assert.equal(11, replies[3][0].toString());
|
||||
assert.equal(21, replies[3][1].toString());
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('allows an array to be provided indicating multiple operations to perform', function (done) {
|
||||
// test nested multi-bulk replies with nulls.
|
||||
client.multi([
|
||||
["mget", ["multifoo", "some", "random value", "keys"]],
|
||||
["incr", "multifoo"]
|
||||
])
|
||||
.exec(function (err, replies) {
|
||||
assert.strictEqual(replies.length, 2);
|
||||
assert.strictEqual(replies[0].length, 4);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('allows multiple operations to be performed on a hash', function (done) {
|
||||
client.multi()
|
||||
.hmset("multihash", "a", "foo", "b", 1)
|
||||
.hmset("multihash", {
|
||||
extra: "fancy",
|
||||
things: "here"
|
||||
})
|
||||
.hgetall("multihash")
|
||||
.exec(function (err, replies) {
|
||||
assert.strictEqual(null, err);
|
||||
assert.equal("OK", replies[0]);
|
||||
assert.equal(Object.keys(replies[2]).length, 4);
|
||||
assert.equal("foo", replies[2].a);
|
||||
assert.equal("1", replies[2].b);
|
||||
assert.equal("fancy", replies[2].extra);
|
||||
assert.equal("here", replies[2].things);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('reports multiple exceptions when they occur', function (done) {
|
||||
if (!helper.serverVersionAtLeast(client, [2, 6, 5])) return done();
|
||||
|
||||
client.multi().set("foo").exec(function (err, reply) {
|
||||
assert(Array.isArray(err), "err should be an array");
|
||||
assert.equal(2, err.length, "err should have 2 items");
|
||||
assert(err[0].message.match(/ERR/), "First error message should contain ERR");
|
||||
assert(err[1].message.match(/EXECABORT/), "First error message should contain EXECABORT");
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
42
test/commands/randomkey.test.js
Normal file
42
test/commands/randomkey.test.js
Normal file
@@ -0,0 +1,42 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'randomkey' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a random key', function (done) {
|
||||
client.mset(["test keys 1", "test val 1", "test keys 2", "test val 2"], helper.isString('OK'));
|
||||
client.RANDOMKEY([], function (err, results) {
|
||||
assert.strictEqual(true, /test keys.+/.test(results));
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
46
test/commands/rename.spec.js
Normal file
46
test/commands/rename.spec.js
Normal file
@@ -0,0 +1,46 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'rename' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('populates the new key', function (done) {
|
||||
client.set(['foo', 'bar'], helper.isString("OK"));
|
||||
client.RENAME(["foo", "new foo"], helper.isString("OK"));
|
||||
client.exists(["new foo"], helper.isNumber(1, done));
|
||||
});
|
||||
|
||||
it('removes the old key', function (done) {
|
||||
client.set(['foo', 'bar'], helper.isString("OK"));
|
||||
client.RENAME(["foo", "new foo"], helper.isString("OK"));
|
||||
client.exists(["foo"], helper.isNumber(0, done));
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
49
test/commands/renamenx.spec.js
Normal file
49
test/commands/renamenx.spec.js
Normal file
@@ -0,0 +1,49 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'renamenx' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('renames the key if target does not yet exist', function (done) {
|
||||
client.set('foo', 'bar', helper.isString('OK'));
|
||||
client.renamenx('foo', 'foo2', helper.isNumber(1));
|
||||
client.exists('foo', helper.isNumber(0));
|
||||
client.exists(['foo2'], helper.isNumber(1, done));
|
||||
});
|
||||
|
||||
it('does not rename the key if the target exists', function (done) {
|
||||
client.set('foo', 'bar', helper.isString('OK'));
|
||||
client.set('foo2', 'apple', helper.isString('OK'));
|
||||
client.renamenx('foo', 'foo2', helper.isNumber(0));
|
||||
client.exists('foo', helper.isNumber(1));
|
||||
client.exists(['foo2'], helper.isNumber(1, done));
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
58
test/commands/sadd.spec.js
Normal file
58
test/commands/sadd.spec.js
Normal file
@@ -0,0 +1,58 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'sadd' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('allows a single value to be added to the set', function (done) {
|
||||
client.SADD('set0', 'member0', helper.isNumber(1));
|
||||
client.smembers('set0', function (err, res) {
|
||||
assert.ok(~res.indexOf('member0'));
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not add the same value to the set twice', function (done) {
|
||||
client.sadd('set0', 'member0', helper.isNumber(1));
|
||||
client.SADD('set0', 'member0', helper.isNumber(0, done));
|
||||
});
|
||||
|
||||
it('allows multiple values to be added to the set', function (done) {
|
||||
client.sadd("set0", ["member0", "member1", "member2"], helper.isNumber(3));
|
||||
client.smembers("set0", function (err, res) {
|
||||
assert.strictEqual(res.length, 3);
|
||||
assert.ok(~res.indexOf("member0"));
|
||||
assert.ok(~res.indexOf("member1"));
|
||||
assert.ok(~res.indexOf("member2"));
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
39
test/commands/scard.spec.js
Normal file
39
test/commands/scard.spec.js
Normal file
@@ -0,0 +1,39 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'scard' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns the number of values in a set', function (done) {
|
||||
client.sadd('foo', [1, 2, 3], helper.isNumber(3));
|
||||
client.scard('foo', helper.isNumber(3, done));
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
68
test/commands/script.spec.js
Normal file
68
test/commands/script.spec.js
Normal file
@@ -0,0 +1,68 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var crypto = require("crypto");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'script' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
var command = "return 99";
|
||||
var commandSha = crypto.createHash('sha1').update(command).digest('hex');
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(function (err) {
|
||||
if (!helper.serverVersionAtLeast(client, [2, 6, 0])) {
|
||||
err = Error('script not supported in redis <= 2.6.0')
|
||||
}
|
||||
return done(err);
|
||||
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
it("loads script with client.script('load')", function (done) {
|
||||
client.script("load", command, function(err, result) {
|
||||
assert.strictEqual(result, commandSha);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('allows a loaded script to be evaluated', function (done) {
|
||||
client.evalsha(commandSha, 0, helper.isString('99', done));
|
||||
})
|
||||
|
||||
it('allows a script to be loaded as part of a chained transaction', function (done) {
|
||||
client.multi().script("load", command).exec(function(err, result) {
|
||||
assert.strictEqual(result[0], commandSha);
|
||||
return done()
|
||||
})
|
||||
})
|
||||
|
||||
it("allows a script to be loaded using a transaction's array syntax", function (done) {
|
||||
client.multi([['script', 'load', command]]).exec(function(err, result) {
|
||||
assert.strictEqual(result[0], commandSha);
|
||||
return done()
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
54
test/commands/sdiff.spec.js
Normal file
54
test/commands/sdiff.spec.js
Normal file
@@ -0,0 +1,54 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'sdiff' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns set difference', function (done) {
|
||||
client.sadd('foo', 'x', helper.isNumber(1));
|
||||
client.sadd('foo', 'a', helper.isNumber(1));
|
||||
client.sadd('foo', 'b', helper.isNumber(1));
|
||||
client.sadd('foo', 'c', helper.isNumber(1));
|
||||
|
||||
client.sadd('bar', 'c', helper.isNumber(1));
|
||||
|
||||
client.sadd('baz', 'a', helper.isNumber(1));
|
||||
client.sadd('baz', 'd', helper.isNumber(1));
|
||||
|
||||
client.sdiff('foo', 'bar', 'baz', function (err, values) {
|
||||
values.sort();
|
||||
assert.equal(values.length, 2);
|
||||
assert.equal(values[0], 'b');
|
||||
assert.equal(values[1], 'x');
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
54
test/commands/sdiffstore.spec.js
Normal file
54
test/commands/sdiffstore.spec.js
Normal file
@@ -0,0 +1,54 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'sdiffstore' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('calculates set difference ands stores it in a key', function (done) {
|
||||
client.sadd('foo', 'x', helper.isNumber(1));
|
||||
client.sadd('foo', 'a', helper.isNumber(1));
|
||||
client.sadd('foo', 'b', helper.isNumber(1));
|
||||
client.sadd('foo', 'c', helper.isNumber(1));
|
||||
|
||||
client.sadd('bar', 'c', helper.isNumber(1));
|
||||
|
||||
client.sadd('baz', 'a', helper.isNumber(1));
|
||||
client.sadd('baz', 'd', helper.isNumber(1));
|
||||
|
||||
client.sdiffstore('quux', 'foo', 'bar', 'baz', helper.isNumber(2));
|
||||
|
||||
client.smembers('quux', function (err, values) {
|
||||
var members = values.sort();
|
||||
assert.deepEqual(members, [ 'b', 'x' ]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
123
test/commands/select.spec.js
Normal file
123
test/commands/select.spec.js
Normal file
@@ -0,0 +1,123 @@
|
||||
var async = require('async');
|
||||
var assert = require('assert');
|
||||
var config = require("../lib/config");
|
||||
var helper = require('../helper');
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'select' method", function () {
|
||||
|
||||
function removeMochaListener () {
|
||||
var mochaListener = process.listeners('uncaughtException').pop();
|
||||
process.removeListener('uncaughtException', mochaListener);
|
||||
return mochaListener;
|
||||
}
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
describe("when not connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.quit();
|
||||
});
|
||||
client.on('end', function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it("throws an error if redis is not connected", function (done) {
|
||||
client.select(1, function (err, res) {
|
||||
assert.equal(err.message, 'Redis connection gone from end event.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () { done(); });
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
it("changes the database and calls the callback", function (done) {
|
||||
// default value of null means database 0 will be used.
|
||||
assert.strictEqual(client.selected_db, null, "default db should be null");
|
||||
client.select(1, function (err, res) {
|
||||
helper.isNotError()(err, res);
|
||||
assert.strictEqual(client.selected_db, 1, "db should be 1 after select");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe("and a callback is specified", function () {
|
||||
describe("with a valid db index", function () {
|
||||
it("selects the appropriate database", function (done) {
|
||||
assert.strictEqual(client.selected_db, null, "default db should be null");
|
||||
client.select(1, function () {
|
||||
assert.equal(client.selected_db, 1, "we should have selected the new valid DB");
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with an invalid db index", function () {
|
||||
it("emits an error", function (done) {
|
||||
assert.strictEqual(client.selected_db, null, "default db should be null");
|
||||
client.select(9999, function (err) {
|
||||
assert.equal(err.message, 'ERR invalid DB index')
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("and no callback is specified", function () {
|
||||
describe("with a valid db index", function () {
|
||||
it("selects the appropriate database", function (done) {
|
||||
assert.strictEqual(client.selected_db, null, "default db should be null");
|
||||
client.select(1);
|
||||
setTimeout(function () {
|
||||
assert.equal(client.selected_db, 1, "we should have selected the new valid DB");
|
||||
return done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with an invalid db index", function () {
|
||||
it("throws an error when callback not provided", function (done) {
|
||||
var mochaListener = removeMochaListener();
|
||||
assert.strictEqual(client.selected_db, null, "default db should be null");
|
||||
|
||||
process.once('uncaughtException', function (err) {
|
||||
process.on('uncaughtException', mochaListener);
|
||||
assert.equal(err.message, 'ERR invalid DB index');
|
||||
return done();
|
||||
});
|
||||
|
||||
client.select(9999);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
165
test/commands/set.spec.js
Normal file
165
test/commands/set.spec.js
Normal file
@@ -0,0 +1,165 @@
|
||||
var async = require('async');
|
||||
var assert = require('assert');
|
||||
var config = require("../lib/config");
|
||||
var helper = require('../helper');
|
||||
var redis = config.redis;
|
||||
var uuid = require('uuid');
|
||||
|
||||
describe("The 'set' method", function () {
|
||||
|
||||
function removeMochaListener () {
|
||||
var mochaListener = process.listeners('uncaughtException').pop();
|
||||
process.removeListener('uncaughtException', mochaListener);
|
||||
return mochaListener;
|
||||
}
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var key, value;
|
||||
|
||||
beforeEach(function () {
|
||||
key = uuid.v4();
|
||||
value = uuid.v4();
|
||||
});
|
||||
|
||||
describe("when not connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.quit();
|
||||
});
|
||||
client.on('end', function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it("reports an error", function (done) {
|
||||
client.set(key, value, function (err, res) {
|
||||
assert.equal(err.message, 'Redis connection gone from end event.');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when connected", function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
describe("and a callback is specified", function () {
|
||||
describe("with valid parameters", function () {
|
||||
it("sets the value correctly", function (done) {
|
||||
client.set(key, value, function (err, res) {
|
||||
helper.isNotError()(err, res);
|
||||
client.get(key, function (err, res) {
|
||||
helper.isString(value)(err, res);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with undefined 'key' and missing 'value' parameter", function () {
|
||||
it("reports an error", function (done) {
|
||||
client.set(undefined, function (err, res) {
|
||||
helper.isError()(err, null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with undefined 'key' and defined 'value' parameters", function () {
|
||||
it("reports an error", function () {
|
||||
client.set(undefined, value, function (err, res) {
|
||||
helper.isError()(err, null);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("and no callback is specified", function () {
|
||||
describe("with valid parameters", function () {
|
||||
it("sets the value correctly", function (done) {
|
||||
client.set(key, value);
|
||||
setTimeout(function () {
|
||||
client.get(key, function (err, res) {
|
||||
helper.isString(value)(err, res);
|
||||
done();
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with undefined 'key' and missing 'value' parameter", function () {
|
||||
it("does not emit an error", function (done) {
|
||||
this.timeout(200);
|
||||
|
||||
client.once("error", function (err) {
|
||||
helper.isError()(err, null);
|
||||
return done(err);
|
||||
});
|
||||
|
||||
client.set();
|
||||
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
it("does not throw an error", function (done) {
|
||||
this.timeout(200);
|
||||
var mochaListener = removeMochaListener();
|
||||
|
||||
process.once('uncaughtException', function (err) {
|
||||
process.on('uncaughtException', mochaListener);
|
||||
return done(err);
|
||||
});
|
||||
|
||||
client.set();
|
||||
|
||||
setTimeout(function () {
|
||||
done();
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
describe("with undefined 'key' and defined 'value' parameters", function () {
|
||||
it("throws an error", function () {
|
||||
var mochaListener = removeMochaListener();
|
||||
|
||||
process.once('uncaughtException', function (err) {
|
||||
process.on('uncaughtException', mochaListener);
|
||||
helper.isError()(err, null);
|
||||
});
|
||||
|
||||
client.set(undefined, value);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
47
test/commands/setex.spec.js
Normal file
47
test/commands/setex.spec.js
Normal file
@@ -0,0 +1,47 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'setex' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('sets a key with an expiry', function (done) {
|
||||
client.SETEX(["setex key", "100", "setex val"], helper.isString("OK"));
|
||||
client.exists(["setex key"], helper.isNumber(1));
|
||||
client.ttl(['setex key'], function (err, ttl) {
|
||||
assert.ok(ttl > 0);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if no value is provided', function (done) {
|
||||
client.SETEX(["setex key", "100", undefined], helper.isError(done));
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
46
test/commands/setnx.spec.js
Normal file
46
test/commands/setnx.spec.js
Normal file
@@ -0,0 +1,46 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'setnx' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('sets key if it does not have a value', function (done) {
|
||||
client.setnx('foo', 'banana', helper.isNumber(1));
|
||||
client.get('foo', helper.isString('banana', done));
|
||||
});
|
||||
|
||||
it('does not set key if it already has a value', function (done) {
|
||||
client.set('foo', 'bar', helper.isString('OK'));
|
||||
client.setnx('foo', 'banana', helper.isNumber(0));
|
||||
client.get('foo', helper.isString('bar', done));
|
||||
return done();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
70
test/commands/sinter.spec.js
Normal file
70
test/commands/sinter.spec.js
Normal file
@@ -0,0 +1,70 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'sinter' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles two sets being intersected', function (done) {
|
||||
client.sadd('sa', 'a', helper.isNumber(1));
|
||||
client.sadd('sa', 'b', helper.isNumber(1));
|
||||
client.sadd('sa', 'c', helper.isNumber(1));
|
||||
|
||||
client.sadd('sb', 'b', helper.isNumber(1));
|
||||
client.sadd('sb', 'c', helper.isNumber(1));
|
||||
client.sadd('sb', 'd', helper.isNumber(1));
|
||||
|
||||
client.sinter('sa', 'sb', function (err, intersection) {
|
||||
assert.equal(intersection.length, 2);
|
||||
assert.deepEqual(intersection.sort(), [ 'b', 'c' ]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles three sets being intersected', function (done) {
|
||||
client.sadd('sa', 'a', helper.isNumber(1));
|
||||
client.sadd('sa', 'b', helper.isNumber(1));
|
||||
client.sadd('sa', 'c', helper.isNumber(1));
|
||||
|
||||
client.sadd('sb', 'b', helper.isNumber(1));
|
||||
client.sadd('sb', 'c', helper.isNumber(1));
|
||||
client.sadd('sb', 'd', helper.isNumber(1));
|
||||
|
||||
client.sadd('sc', 'c', helper.isNumber(1));
|
||||
client.sadd('sc', 'd', helper.isNumber(1));
|
||||
client.sadd('sc', 'e', helper.isNumber(1));
|
||||
|
||||
client.sinter('sa', 'sb', 'sc', function (err, intersection) {
|
||||
assert.equal(intersection.length, 1);
|
||||
assert.equal(intersection[0], 'c');
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
55
test/commands/sinterstore.spec.js
Normal file
55
test/commands/sinterstore.spec.js
Normal file
@@ -0,0 +1,55 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'sinterstore' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('calculates set intersection and stores it in a key', function (done) {
|
||||
client.sadd('sa', 'a', helper.isNumber(1));
|
||||
client.sadd('sa', 'b', helper.isNumber(1));
|
||||
client.sadd('sa', 'c', helper.isNumber(1));
|
||||
|
||||
client.sadd('sb', 'b', helper.isNumber(1));
|
||||
client.sadd('sb', 'c', helper.isNumber(1));
|
||||
client.sadd('sb', 'd', helper.isNumber(1));
|
||||
|
||||
client.sadd('sc', 'c', helper.isNumber(1));
|
||||
client.sadd('sc', 'd', helper.isNumber(1));
|
||||
client.sadd('sc', 'e', helper.isNumber(1));
|
||||
|
||||
client.sinterstore('foo', 'sa', 'sb', 'sc', helper.isNumber(1));
|
||||
|
||||
client.smembers('foo', function (err, members) {
|
||||
assert.deepEqual(members, [ 'c' ]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
43
test/commands/sismember.spec.js
Normal file
43
test/commands/sismember.spec.js
Normal file
@@ -0,0 +1,43 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'sismember' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 0 if the value is not in the set', function (done) {
|
||||
client.sismember('foo', 'banana', helper.isNumber(0, done));
|
||||
});
|
||||
|
||||
it('returns 1 if the value is in the set', function (done) {
|
||||
client.sadd('foo', 'banana', helper.isNumber(1));
|
||||
client.sismember('foo', 'banana', helper.isNumber(1, done));
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
48
test/commands/slowlog.spec.js
Normal file
48
test/commands/slowlog.spec.js
Normal file
@@ -0,0 +1,48 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'slowlog' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('logs operations in slowlog', function (done) {
|
||||
client.config("set", "slowlog-log-slower-than", 0, helper.isString("OK"));
|
||||
client.slowlog("reset", helper.isString("OK"));
|
||||
client.set("foo", "bar", helper.isString("OK"));
|
||||
client.get("foo", helper.isString("bar"));
|
||||
client.slowlog("get", function (err, res) {
|
||||
assert.equal(res.length, 3);
|
||||
assert.equal(res[0][3].length, 2);
|
||||
assert.deepEqual(res[1][3], ["set", "foo", "bar"]);
|
||||
assert.deepEqual(res[2][3], ["slowlog", "reset"]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
45
test/commands/smembers.spec.js
Normal file
45
test/commands/smembers.spec.js
Normal file
@@ -0,0 +1,45 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'smembers' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns all values in a set', function (done) {
|
||||
client.sadd('foo', 'x', helper.isNumber(1));
|
||||
client.sadd('foo', 'y', helper.isNumber(1));
|
||||
client.smembers('foo', function (err, values) {
|
||||
assert.equal(values.length, 2);
|
||||
var members = values.sort();
|
||||
assert.deepEqual(members, [ 'x', 'y' ]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
48
test/commands/smove.spec.js
Normal file
48
test/commands/smove.spec.js
Normal file
@@ -0,0 +1,48 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'smove' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('moves a value to a set that does not yet exist', function (done) {
|
||||
client.sadd('foo', 'x', helper.isNumber(1));
|
||||
client.smove('foo', 'bar', 'x', helper.isNumber(1));
|
||||
client.sismember('foo', 'x', helper.isNumber(0));
|
||||
client.sismember('bar', 'x', helper.isNumber(1, done));
|
||||
});
|
||||
|
||||
it("does not move a value if it does not exist in the first set", function (done) {
|
||||
client.sadd('foo', 'x', helper.isNumber(1));
|
||||
client.smove('foo', 'bar', 'y', helper.isNumber(0));
|
||||
client.sismember('foo', 'y', helper.isNumber(0));
|
||||
client.sismember('bar', 'y', helper.isNumber(0, done));
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
128
test/commands/sort.spec.js
Normal file
128
test/commands/sort.spec.js
Normal file
@@ -0,0 +1,128 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'sort' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb();
|
||||
setupData(client, done)
|
||||
});
|
||||
});
|
||||
|
||||
describe('alphabetical', function () {
|
||||
it('sorts in ascending alphabetical order', function (done) {
|
||||
client.sort('y', 'asc', 'alpha', function (err, sorted) {
|
||||
assert.deepEqual(sorted, ['a', 'b', 'c', 'd']);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('sorts in descending alphabetical order', function (done) {
|
||||
client.sort('y', 'desc', 'alpha', function (err, sorted) {
|
||||
assert.deepEqual(sorted, ['d', 'c', 'b', 'a']);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('numeric', function () {
|
||||
it('sorts in ascending numeric order', function (done) {
|
||||
client.sort('x', 'asc', function (err, sorted) {
|
||||
assert.deepEqual(sorted, [2, 3, 4, 9]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('sorts in descending numeric order', function (done) {
|
||||
client.sort('x', 'desc', function (err, sorted) {
|
||||
assert.deepEqual(sorted, [9, 4, 3, 2]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('pattern', function () {
|
||||
it('handles sorting with a pattern', function (done) {
|
||||
client.sort('x', 'by', 'w*', 'asc', function (err, sorted) {
|
||||
assert.deepEqual(sorted, [3, 9, 4, 2]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it("handles sorting with a 'by' pattern and 1 'get' pattern", function (done) {
|
||||
client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', function (err, sorted) {
|
||||
assert.deepEqual(sorted, ['foo', 'bar', 'baz', 'buz']);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it("handles sorting with a 'by' pattern and 2 'get' patterns", function (done) {
|
||||
client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', 'get', 'p*', function (err, sorted) {
|
||||
assert.deepEqual(sorted, ['foo', 'bux', 'bar', 'tux', 'baz', 'lux', 'buz', 'qux']);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it("sorting with a 'by' pattern and 2 'get' patterns and stores results", function (done) {
|
||||
client.sort('x', 'by', 'w*', 'asc', 'get', 'o*', 'get', 'p*', 'store', 'bacon', function (err) {
|
||||
if (err) return done(err);
|
||||
});
|
||||
|
||||
client.lrange('bacon', 0, -1, function (err, values) {
|
||||
assert.deepEqual(values, ['foo', 'bux', 'bar', 'tux', 'baz', 'lux', 'buz', 'qux']);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setupData(client, done) {
|
||||
client.rpush('y', 'd');
|
||||
client.rpush('y', 'b');
|
||||
client.rpush('y', 'a');
|
||||
client.rpush('y', 'c');
|
||||
|
||||
client.rpush('x', '3');
|
||||
client.rpush('x', '9');
|
||||
client.rpush('x', '2');
|
||||
client.rpush('x', '4');
|
||||
|
||||
client.set('w3', '4');
|
||||
client.set('w9', '5');
|
||||
client.set('w2', '12');
|
||||
client.set('w4', '6');
|
||||
|
||||
client.set('o2', 'buz');
|
||||
client.set('o3', 'foo');
|
||||
client.set('o4', 'baz');
|
||||
client.set('o9', 'bar');
|
||||
|
||||
client.set('p2', 'qux');
|
||||
client.set('p3', 'bux');
|
||||
client.set('p4', 'lux');
|
||||
client.set('p9', 'tux', done);
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
45
test/commands/spop.spec.js
Normal file
45
test/commands/spop.spec.js
Normal file
@@ -0,0 +1,45 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'spop' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a random element from the set', function (done) {
|
||||
client.sadd('zzz', 'member0', helper.isNumber(1));
|
||||
client.scard('zzz', helper.isNumber(1));
|
||||
|
||||
client.spop('zzz', function (err, value) {
|
||||
if (err) return done(err);
|
||||
assert.equal(value, 'member0');
|
||||
client.scard('zzz', helper.isNumber(0, done));
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
66
test/commands/srem.spec.js
Normal file
66
test/commands/srem.spec.js
Normal file
@@ -0,0 +1,66 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'srem' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('removes a value', function (done) {
|
||||
client.sadd('set0', 'member0', helper.isNumber(1));
|
||||
client.srem('set0', 'member0', helper.isNumber(1));
|
||||
client.scard('set0', helper.isNumber(0, done));
|
||||
});
|
||||
|
||||
it('handles attempting to remove a missing value', function (done) {
|
||||
client.srem('set0', 'member0', helper.isNumber(0, done));
|
||||
});
|
||||
|
||||
it('allows multiple values to be removed', function (done) {
|
||||
client.sadd("set0", ["member0", "member1", "member2"], helper.isNumber(3));
|
||||
client.SREM("set0", ["member1", "member2"], helper.isNumber(2));
|
||||
client.smembers("set0", function (err, res) {
|
||||
assert.strictEqual(res.length, 1);
|
||||
assert.ok(~res.indexOf("member0"));
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles a value missing from the set of values being removed', function (done) {
|
||||
client.sadd("set0", ["member0", "member1", "member2"], helper.isNumber(3));
|
||||
client.SREM("set0", ["member3", "member4"], helper.isNumber(0));
|
||||
client.smembers("set0", function (err, res) {
|
||||
assert.strictEqual(res.length, 3);
|
||||
assert.ok(~res.indexOf("member0"));
|
||||
assert.ok(~res.indexOf("member1"));
|
||||
assert.ok(~res.indexOf("member2"));
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
53
test/commands/sunion.spec.js
Normal file
53
test/commands/sunion.spec.js
Normal file
@@ -0,0 +1,53 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'sunion' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns the union of a group of sets', function (done) {
|
||||
client.sadd('sa', 'a', helper.isNumber(1));
|
||||
client.sadd('sa', 'b', helper.isNumber(1));
|
||||
client.sadd('sa', 'c', helper.isNumber(1));
|
||||
|
||||
client.sadd('sb', 'b', helper.isNumber(1));
|
||||
client.sadd('sb', 'c', helper.isNumber(1));
|
||||
client.sadd('sb', 'd', helper.isNumber(1));
|
||||
|
||||
client.sadd('sc', 'c', helper.isNumber(1));
|
||||
client.sadd('sc', 'd', helper.isNumber(1));
|
||||
client.sadd('sc', 'e', helper.isNumber(1));
|
||||
|
||||
client.sunion('sa', 'sb', 'sc', function (err, union) {
|
||||
assert.deepEqual(union.sort(), ['a', 'b', 'c', 'd', 'e']);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
56
test/commands/sunionstore.spec.js
Normal file
56
test/commands/sunionstore.spec.js
Normal file
@@ -0,0 +1,56 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'sunionstore' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('stores the result of a union', function (done) {
|
||||
client.sadd('sa', 'a', helper.isNumber(1));
|
||||
client.sadd('sa', 'b', helper.isNumber(1));
|
||||
client.sadd('sa', 'c', helper.isNumber(1));
|
||||
|
||||
client.sadd('sb', 'b', helper.isNumber(1));
|
||||
client.sadd('sb', 'c', helper.isNumber(1));
|
||||
client.sadd('sb', 'd', helper.isNumber(1));
|
||||
|
||||
client.sadd('sc', 'c', helper.isNumber(1));
|
||||
client.sadd('sc', 'd', helper.isNumber(1));
|
||||
client.sadd('sc', 'e', helper.isNumber(1));
|
||||
|
||||
client.sunionstore('foo', 'sa', 'sb', 'sc', helper.isNumber(5));
|
||||
|
||||
client.smembers('foo', function (err, members) {
|
||||
assert.equal(members.length, 5);
|
||||
assert.deepEqual(members.sort(), ['a', 'b', 'c', 'd', 'e']);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
45
test/commands/ttl.spec.js
Normal file
45
test/commands/ttl.spec.js
Normal file
@@ -0,0 +1,45 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'ttl' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns the current ttl on a key', function (done) {
|
||||
client.set(["ttl key", "ttl val"], helper.isString("OK"));
|
||||
client.expire(["ttl key", "100"], helper.isNumber(1));
|
||||
setTimeout(function () {
|
||||
client.TTL(["ttl key"], function (err, ttl) {
|
||||
assert.ok(ttl > 50 && ttl <= 100);
|
||||
return done(err);
|
||||
});
|
||||
}, 500);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
63
test/commands/type.spec.js
Normal file
63
test/commands/type.spec.js
Normal file
@@ -0,0 +1,63 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'type' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('reports string type', function (done) {
|
||||
client.set(["string key", "should be a string"], helper.isString("OK"));
|
||||
client.TYPE(["string key"], helper.isString("string", done));
|
||||
});
|
||||
|
||||
it('reports list type', function (done) {
|
||||
client.rpush(["list key", "should be a list"], helper.isNumber(1));
|
||||
client.TYPE(["list key"], helper.isString("list", done));
|
||||
});
|
||||
|
||||
it('reports set type', function (done) {
|
||||
client.sadd(["set key", "should be a set"], helper.isNumber(1));
|
||||
client.TYPE(["set key"], helper.isString("set", done));
|
||||
});
|
||||
|
||||
it('reports zset type', function (done) {
|
||||
client.zadd(["zset key", "10.0", "should be a zset"], helper.isNumber(1));
|
||||
client.TYPE(["zset key"], helper.isString("zset", done));
|
||||
});
|
||||
|
||||
it('reports hash type', function (done) {
|
||||
client.hset(["hash key", "hashtest", "should be a hash"], helper.isNumber(1));
|
||||
client.TYPE(["hash key"], helper.isString("hash", done));
|
||||
});
|
||||
|
||||
it('reports none for null key', function (done) {
|
||||
client.TYPE("not here yet", helper.isString("none", done));
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
68
test/commands/watch.spec.js
Normal file
68
test/commands/watch.spec.js
Normal file
@@ -0,0 +1,68 @@
|
||||
var assert = require("assert");
|
||||
var config = require("../lib/config");
|
||||
var helper = require("../helper");
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The 'watch' method", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
var watched = 'foobar'
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(function (err) {
|
||||
if (!helper.serverVersionAtLeast(client, [2, 2, 0])) {
|
||||
err = Error('some watch commands not supported in redis <= 2.2.0')
|
||||
}
|
||||
return done(err);
|
||||
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
it('does not execute transaction if watched key was modified prior to execution', function (done) {
|
||||
client.watch(watched);
|
||||
client.incr(watched);
|
||||
multi = client.multi();
|
||||
multi.incr(watched);
|
||||
multi.exec(helper.isNull(done));
|
||||
})
|
||||
|
||||
it('successfully modifies other keys independently of transaction', function (done) {
|
||||
client.set("unwatched", 200);
|
||||
|
||||
client.set(watched, 0);
|
||||
client.watch(watched);
|
||||
client.incr(watched);
|
||||
|
||||
var multi = client.multi()
|
||||
.incr(watched)
|
||||
.exec(function (err, replies) {
|
||||
assert.strictEqual(replies, null, "Aborted transaction multi-bulk reply should be null.");
|
||||
|
||||
client.get("unwatched", function (err, reply) {
|
||||
assert.equal(reply, 200, "Expected 200, got " + reply);
|
||||
return done(err)
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
})
|
||||
});
|
||||
});
|
5
test/conf/password.conf
Normal file
5
test/conf/password.conf
Normal file
@@ -0,0 +1,5 @@
|
||||
requirepass porkchopsandwiches
|
||||
port 6378
|
||||
bind ::1 127.0.0.1
|
||||
unixsocket /tmp/redis.sock
|
||||
unixsocketperm 755
|
4
test/conf/redis.conf
Normal file
4
test/conf/redis.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
port 6378
|
||||
bind ::1 127.0.0.1
|
||||
unixsocket /tmp/redis.sock
|
||||
unixsocketperm 755
|
100
test/helper.js
Normal file
100
test/helper.js
Normal file
@@ -0,0 +1,100 @@
|
||||
var assert = require("assert");
|
||||
var path = require('path');
|
||||
var RedisProcess = require("./lib/redis-process");
|
||||
var rp;
|
||||
|
||||
// don't start redis every time we
|
||||
// include this helper file!
|
||||
if (!process.env.REDIS_TESTS_STARTED) {
|
||||
process.env.REDIS_TESTS_STARTED = true;
|
||||
|
||||
before(function (done) {
|
||||
startRedis('./conf/redis.conf', done);
|
||||
})
|
||||
|
||||
after(function (done) {
|
||||
if (rp) rp.stop(done);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
stopRedis: function (done) {
|
||||
rp.stop(done);
|
||||
},
|
||||
startRedis: function (conf, done) {
|
||||
startRedis(conf, done);
|
||||
},
|
||||
isNumber: function (expected, done) {
|
||||
return function (err, results) {
|
||||
assert.strictEqual(null, err, "expected " + expected + ", got error: " + err);
|
||||
assert.strictEqual(expected, results, expected + " !== " + results);
|
||||
assert.strictEqual(typeof results, "number", "expected a number, got " + typeof results);
|
||||
if (done) return done();
|
||||
};
|
||||
},
|
||||
isString: function (str, done) {
|
||||
return function (err, results) {
|
||||
assert.strictEqual(null, err, "expected string '" + str + "', got error: " + err);
|
||||
assert.equal(str, results, str + " does not match " + results);
|
||||
if (done) return done();
|
||||
};
|
||||
},
|
||||
isNull: function (done) {
|
||||
return function (err, results) {
|
||||
assert.strictEqual(null, err, "expected null, got error: " + err);
|
||||
assert.strictEqual(null, results, results + " is not null");
|
||||
if (done) return done();
|
||||
};
|
||||
},
|
||||
isError: function (done) {
|
||||
return function (err, results) {
|
||||
assert.notEqual(err, null, "err is null, but an error is expected here.");
|
||||
if (done) return done();
|
||||
};
|
||||
},
|
||||
isNotError: function (done) {
|
||||
return function (err, results) {
|
||||
assert.strictEqual(err, null, "expected success, got an error: " + err);
|
||||
if (done) return done();
|
||||
};
|
||||
},
|
||||
isType: {
|
||||
number: function (done) {
|
||||
return function (err, results) {
|
||||
assert.strictEqual(null, err, "expected any number, got error: " + err);
|
||||
assert.strictEqual(typeof results, "number", results + " is not a number");
|
||||
if (done) return done();
|
||||
};
|
||||
},
|
||||
positiveNumber: function (done) {
|
||||
return function (err, results) {
|
||||
assert.strictEqual(null, err, "expected positive number, got error: " + err);
|
||||
assert.strictEqual(true, (results > 0), results + " is not a positive number");
|
||||
if (done) return done();
|
||||
};
|
||||
}
|
||||
},
|
||||
match: function (pattern, done) {
|
||||
return function (err, results) {
|
||||
assert.strictEqual(null, err, "expected " + pattern.toString() + ", got error: " + err);
|
||||
assert(pattern.test(results), "expected string '" + results + "' to match " + pattern.toString());
|
||||
if (done) return done();
|
||||
};
|
||||
},
|
||||
serverVersionAtLeast: function (connection, desired_version) {
|
||||
// Return true if the server version >= desired_version
|
||||
var version = connection.server_info.versions;
|
||||
for (var i = 0; i < 3; i++) {
|
||||
if (version[i] > desired_version[i]) return true;
|
||||
if (version[i] < desired_version[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function startRedis (conf, done) {
|
||||
RedisProcess.start(function (err, _rp) {
|
||||
rp = _rp;
|
||||
return done(err);
|
||||
}, path.resolve(__dirname, conf));
|
||||
}
|
35
test/lib/config.js
Normal file
35
test/lib/config.js
Normal file
@@ -0,0 +1,35 @@
|
||||
// helpers for configuring a redis client in
|
||||
// its various modes, ipV6, ipV4, socket.
|
||||
module.exports = (function () {
|
||||
var redis = require('../../index');
|
||||
redis.debug_mode = process.env.DEBUG ? JSON.parse(process.env.DEBUG) : false;
|
||||
|
||||
var config = {
|
||||
redis: redis,
|
||||
PORT: 6378,
|
||||
HOST: {
|
||||
IPv4: "127.0.0.1",
|
||||
IPv6: "::1"
|
||||
}
|
||||
};
|
||||
|
||||
config.configureClient = function (parser, ip, opts) {
|
||||
var args = [];
|
||||
opts = opts || {};
|
||||
|
||||
if (ip.match(/\.sock/)) {
|
||||
args.push(ip)
|
||||
} else {
|
||||
args.push(config.PORT);
|
||||
args.push(config.HOST[ip]);
|
||||
opts.family = ip;
|
||||
}
|
||||
|
||||
opts.parser = parser;
|
||||
args.push(opts);
|
||||
|
||||
return args;
|
||||
};
|
||||
|
||||
return config;
|
||||
})();
|
55
test/lib/redis-process.js
Normal file
55
test/lib/redis-process.js
Normal file
@@ -0,0 +1,55 @@
|
||||
// helper to start and stop the redis process.
|
||||
var cp = require('child_process');
|
||||
var config = require('./config');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var tcpPortUsed = require('tcp-port-used');
|
||||
|
||||
module.exports = {
|
||||
start: function (done, conf) {
|
||||
// spawn redis with our testing configuration.
|
||||
var confFile = conf || path.resolve(__dirname, '../conf/redis.conf');
|
||||
var rp = cp.spawn("redis-server", [confFile], {});
|
||||
|
||||
// wait for redis to become available, by
|
||||
// checking the port we bind on.
|
||||
waitForRedis(true, function () {
|
||||
// return an object that can be used in
|
||||
// an after() block to shutdown redis.
|
||||
return done(null, {
|
||||
stop: function (done) {
|
||||
rp.once("exit", function (code) {
|
||||
var error = null;
|
||||
if (code !== null && code !== 0) {
|
||||
error = Error('Redis shutdown failed with code ' + code);
|
||||
}
|
||||
waitForRedis(false, function () {
|
||||
return done(error);
|
||||
})
|
||||
});
|
||||
rp.kill("SIGTERM");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// wait for redis to be listening in
|
||||
// all three modes (ipv4, ipv6, socket).
|
||||
function waitForRedis (available, cb) {
|
||||
var ipV4 = false;
|
||||
var id = setInterval(function () {
|
||||
tcpPortUsed.check(config.PORT, '127.0.0.1')
|
||||
.then(function (_ipV4) {
|
||||
ipV4 = _ipV4;
|
||||
return tcpPortUsed.check(config.PORT, '::1');
|
||||
})
|
||||
.then(function (ipV6) {
|
||||
if (ipV6 === available && ipV4 === available &&
|
||||
fs.existsSync('/tmp/redis.sock') === available) {
|
||||
clearInterval(id);
|
||||
return cb();
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
}
|
18
test/lib/unref.js
Normal file
18
test/lib/unref.js
Normal file
@@ -0,0 +1,18 @@
|
||||
// spawned by the unref tests in node_redis.spec.js.
|
||||
// when configured, unref causes the client to exit
|
||||
// as soon as there are no outstanding commands.
|
||||
'use strict';
|
||||
|
||||
var redis = require("../../");
|
||||
//redis.debug_mode = true
|
||||
var HOST = process.argv[2] || '127.0.0.1';
|
||||
var PORT = process.argv[3]
|
||||
var args = PORT ? [PORT, HOST] : [HOST]
|
||||
|
||||
var c = redis.createClient.apply(redis, args);
|
||||
c.unref();
|
||||
c.info(function (err, reply) {
|
||||
if (err) process.exit(-1);
|
||||
if (!reply.length) process.exit(-1);
|
||||
process.stdout.write(reply.length.toString());
|
||||
});
|
670
test/node_redis.spec.js
Normal file
670
test/node_redis.spec.js
Normal file
@@ -0,0 +1,670 @@
|
||||
var async = require("async");
|
||||
var assert = require("assert");
|
||||
var config = require("./lib/config");
|
||||
var helper = require('./helper')
|
||||
var fork = require("child_process").fork;
|
||||
var redis = config.redis;
|
||||
|
||||
describe("The node_redis client", function () {
|
||||
|
||||
function allTests(parser, ip) {
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
describe("using " + parser + " and " + ip, function () {
|
||||
var client;
|
||||
|
||||
describe("when not connected", function () {
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
it("connects correctly", function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.on("error", done);
|
||||
|
||||
client.once("ready", function () {
|
||||
client.removeListener("error", done);
|
||||
client.get("recon 1", function (err, res) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when connected", function () {
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(done)
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
client.end();
|
||||
});
|
||||
|
||||
describe("when redis closes unexpectedly", function () {
|
||||
it("reconnects and can retrieve the pre-existing data", function (done) {
|
||||
client.on("reconnecting", function on_recon(params) {
|
||||
client.on("connect", function on_connect() {
|
||||
async.parallel([function (cb) {
|
||||
client.get("recon 1", function (err, res) {
|
||||
helper.isString("one")(err, res);
|
||||
cb();
|
||||
});
|
||||
}, function (cb) {
|
||||
client.get("recon 1", function (err, res) {
|
||||
helper.isString("one")(err, res);
|
||||
cb();
|
||||
});
|
||||
}, function (cb) {
|
||||
client.get("recon 2", function (err, res) {
|
||||
helper.isString("two")(err, res);
|
||||
cb();
|
||||
});
|
||||
}, function (cb) {
|
||||
client.get("recon 2", function (err, res) {
|
||||
helper.isString("two")(err, res);
|
||||
cb();
|
||||
});
|
||||
}], function (err, results) {
|
||||
client.removeListener("connect", on_connect);
|
||||
client.removeListener("reconnecting", on_recon);
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
client.set("recon 1", "one");
|
||||
client.set("recon 2", "two", function (err, res) {
|
||||
// Do not do this in normal programs. This is to simulate the server closing on us.
|
||||
// For orderly shutdown in normal programs, do client.quit()
|
||||
client.stream.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: we should only have a single subscription in this this
|
||||
// test but unsubscribing from the single channel indicates
|
||||
// that one subscriber still exists, let's dig into this.
|
||||
describe("and it's subscribed to a channel", function () {
|
||||
// reconnect_select_db_after_pubsub
|
||||
// Does not pass.
|
||||
// "Connection in subscriber mode, only subscriber commands may be used"
|
||||
it("reconnects, unsubscribes, and can retrieve the pre-existing data", function (done) {
|
||||
client.on("reconnecting", function on_recon(params) {
|
||||
client.on("ready", function on_connect() {
|
||||
client.unsubscribe(helper.isNotError());
|
||||
|
||||
client.on('unsubscribe', function (channel, count) {
|
||||
// we should now be out of subscriber mode.
|
||||
client.set('foo', 'bar', helper.isNumber(1));
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
client.set("recon 1", "one");
|
||||
client.subscribe("recon channel", function (err, res) {
|
||||
// Do not do this in normal programs. This is to simulate the server closing on us.
|
||||
// For orderly shutdown in normal programs, do client.quit()
|
||||
client.stream.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
it("remains subscribed", function () {
|
||||
var client2 = redis.createClient.apply(redis.createClient, args);
|
||||
|
||||
client.on("reconnecting", function on_recon(params) {
|
||||
client.on("ready", function on_connect() {
|
||||
async.parallel([function (cb) {
|
||||
client.on("message", function (channel, message) {
|
||||
try {
|
||||
helper.isString("recon channel")(null, channel);
|
||||
helper.isString("a test message")(null, message);
|
||||
} catch (err) {
|
||||
cb(err);
|
||||
}
|
||||
});
|
||||
|
||||
client2.subscribe("recon channel", function (err, res) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
return;
|
||||
}
|
||||
client2.publish("recon channel", "a test message");
|
||||
});
|
||||
}], function (err, results) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
client.subscribe("recon channel", function (err, res) {
|
||||
// Do not do this in normal programs. This is to simulate the server closing on us.
|
||||
// For orderly shutdown in normal programs, do client.quit()
|
||||
client.stream.destroy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('domain', function () {
|
||||
it('allows client to be executed from within domain', function (done) {
|
||||
var domain;
|
||||
|
||||
try {
|
||||
domain = require('domain').create();
|
||||
} catch (err) {
|
||||
console.log("Skipping " + name + " because this version of node doesn't have domains.");
|
||||
return done();
|
||||
}
|
||||
|
||||
if (domain) {
|
||||
domain.run(function () {
|
||||
client.set('domain', 'value', function (err, res) {
|
||||
assert.ok(process.domain);
|
||||
var notFound = res.not.existing.thing; // ohhh nooooo
|
||||
});
|
||||
});
|
||||
|
||||
// this is the expected and desired behavior
|
||||
domain.on('error', function (err) {
|
||||
domain.exit();
|
||||
return done()
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('monitor', function () {
|
||||
it('monitors commands on all other redis clients', function (done) {
|
||||
if (!helper.serverVersionAtLeast(client, [2, 6, 0])) return done();
|
||||
|
||||
var monitorClient = redis.createClient.apply(redis.createClient, args);
|
||||
var responses = [];
|
||||
|
||||
monitorClient.monitor(function (err, res) {
|
||||
client.mget("some", "keys", "foo", "bar");
|
||||
client.set("json", JSON.stringify({
|
||||
foo: "123",
|
||||
bar: "sdflkdfsjk",
|
||||
another: false
|
||||
}));
|
||||
});
|
||||
|
||||
monitorClient.on("monitor", function (time, args) {
|
||||
responses.push(args);
|
||||
if (responses.length === 2) {
|
||||
assert.strictEqual(5, responses[0].length);
|
||||
assert.strictEqual("mget", responses[0][0]);
|
||||
assert.strictEqual("some", responses[0][1]);
|
||||
assert.strictEqual("keys", responses[0][2]);
|
||||
assert.strictEqual("foo", responses[0][3]);
|
||||
assert.strictEqual("bar", responses[0][4]);
|
||||
assert.strictEqual(3, responses[1].length);
|
||||
assert.strictEqual("set", responses[1][0]);
|
||||
assert.strictEqual("json", responses[1][1]);
|
||||
assert.strictEqual('{"foo":"123","bar":"sdflkdfsjk","another":false}', responses[1][2]);
|
||||
monitorClient.quit(done);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('emits errors thrown from within an on("message") handler', function (done) {
|
||||
var client2 = redis.createClient.apply(redis.createClient, args);
|
||||
var name = 'channel';
|
||||
|
||||
client2.subscribe(name, function () {
|
||||
client.publish(name, "some message");
|
||||
});
|
||||
|
||||
client2.on("message", function (channel, data) {
|
||||
if (channel == name) {
|
||||
assert.equal(data, "some message");
|
||||
throw Error('forced exception');
|
||||
}
|
||||
return done();
|
||||
});
|
||||
|
||||
client2.once("error", function (err) {
|
||||
client2.end();
|
||||
assert.equal(err.message, 'forced exception');
|
||||
return done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('idle', function () {
|
||||
it('emits idle as soon as there are no outstanding commands', function (done) {
|
||||
client.on('idle', function onIdle () {
|
||||
client.removeListener("idle", onIdle);
|
||||
client.get('foo', helper.isString('bar', done));
|
||||
});
|
||||
client.set('foo', 'bar');
|
||||
});
|
||||
});
|
||||
|
||||
describe('utf8', function () {
|
||||
it('handles utf-8 keys', function (done) {
|
||||
var utf8_sample = "ಠ_ಠ";
|
||||
client.set(["utf8test", utf8_sample], helper.isString("OK"));
|
||||
client.get(["utf8test"], function (err, obj) {
|
||||
assert.strictEqual(utf8_sample, obj);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('detect_buffers', function () {
|
||||
var client;
|
||||
var args = config.configureClient(parser, ip, {
|
||||
detect_buffers: true
|
||||
});
|
||||
|
||||
beforeEach(function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.once("error", done);
|
||||
client.once("connect", function () {
|
||||
client.flushdb(function (err) {
|
||||
client.hmset("hash key 2", "key 1", "val 1", "key 2", "val 2");
|
||||
client.set("string key 1", "string value");
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('get', function () {
|
||||
describe('first argument is a string', function () {
|
||||
it('returns a string', function (done) {
|
||||
client.get("string key 1", helper.isString("string value", done));
|
||||
});
|
||||
|
||||
it('returns a string when executed as part of transaction', function (done) {
|
||||
client.multi().get("string key 1").exec(helper.isString("string value", done));
|
||||
});
|
||||
});
|
||||
|
||||
describe('first argument is a buffer', function () {
|
||||
it('returns a buffer', function (done) {
|
||||
client.get(new Buffer("string key 1"), function (err, reply) {
|
||||
assert.strictEqual(true, Buffer.isBuffer(reply));
|
||||
assert.strictEqual("<Buffer 73 74 72 69 6e 67 20 76 61 6c 75 65>", reply.inspect());
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns a bufffer when executed as part of transaction', function (done) {
|
||||
client.multi().get(new Buffer("string key 1")).exec(function (err, reply) {
|
||||
assert.strictEqual(1, reply.length);
|
||||
assert.strictEqual(true, Buffer.isBuffer(reply[0]));
|
||||
assert.strictEqual("<Buffer 73 74 72 69 6e 67 20 76 61 6c 75 65>", reply[0].inspect());
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('multi.hget', function () {
|
||||
it('can interleave string and buffer results', function (done) {
|
||||
client.multi()
|
||||
.hget("hash key 2", "key 1")
|
||||
.hget(new Buffer("hash key 2"), "key 1")
|
||||
.hget("hash key 2", new Buffer("key 2"))
|
||||
.hget("hash key 2", "key 2")
|
||||
.exec(function (err, reply) {
|
||||
assert.strictEqual(true, Array.isArray(reply));
|
||||
assert.strictEqual(4, reply.length);
|
||||
assert.strictEqual("val 1", reply[0]);
|
||||
assert.strictEqual(true, Buffer.isBuffer(reply[1]));
|
||||
assert.strictEqual("<Buffer 76 61 6c 20 31>", reply[1].inspect());
|
||||
assert.strictEqual(true, Buffer.isBuffer(reply[2]));
|
||||
assert.strictEqual("<Buffer 76 61 6c 20 32>", reply[2].inspect());
|
||||
assert.strictEqual("val 2", reply[3]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('hmget', function () {
|
||||
describe('first argument is a string', function () {
|
||||
it('returns strings for keys requested', function (done) {
|
||||
client.hmget("hash key 2", "key 1", "key 2", function (err, reply) {
|
||||
assert.strictEqual(true, Array.isArray(reply));
|
||||
assert.strictEqual(2, reply.length);
|
||||
assert.strictEqual("val 1", reply[0]);
|
||||
assert.strictEqual("val 2", reply[1]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns strings for keys requested in transaction', function (done) {
|
||||
client.multi().hmget("hash key 2", "key 1", "key 2").exec(function (err, reply) {
|
||||
assert.strictEqual(true, Array.isArray(reply));
|
||||
assert.strictEqual(1, reply.length);
|
||||
assert.strictEqual(2, reply[0].length);
|
||||
assert.strictEqual("val 1", reply[0][0]);
|
||||
assert.strictEqual("val 2", reply[0][1]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles array of strings with undefined values (repro #344)', function (done) {
|
||||
client.hmget("hash key 2", "key 3", "key 4", function(err, reply) {
|
||||
assert.strictEqual(true, Array.isArray(reply));
|
||||
assert.strictEqual(2, reply.length);
|
||||
assert.equal(null, reply[0]);
|
||||
assert.equal(null, reply[1]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles array of strings with undefined values in transaction (repro #344)', function (done) {
|
||||
client.multi().hmget("hash key 2", "key 3", "key 4").exec(function(err, reply) {
|
||||
assert.strictEqual(true, Array.isArray(reply));
|
||||
assert.strictEqual(1, reply.length);
|
||||
assert.strictEqual(2, reply[0].length);
|
||||
assert.equal(null, reply[0][0]);
|
||||
assert.equal(null, reply[0][1]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('first argument is a buffer', function () {
|
||||
it('returns buffers for keys requested', function (done) {
|
||||
client.hmget(new Buffer("hash key 2"), "key 1", "key 2", function (err, reply) {
|
||||
assert.strictEqual(true, Array.isArray(reply));
|
||||
assert.strictEqual(2, reply.length);
|
||||
assert.strictEqual(true, Buffer.isBuffer(reply[0]));
|
||||
assert.strictEqual(true, Buffer.isBuffer(reply[1]));
|
||||
assert.strictEqual("<Buffer 76 61 6c 20 31>", reply[0].inspect());
|
||||
assert.strictEqual("<Buffer 76 61 6c 20 32>", reply[1].inspect());
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it("returns buffers for keys requested in transaction", function (done) {
|
||||
client.multi().hmget(new Buffer("hash key 2"), "key 1", "key 2").exec(function (err, reply) {
|
||||
assert.strictEqual(true, Array.isArray(reply));
|
||||
assert.strictEqual(1, reply.length);
|
||||
assert.strictEqual(2, reply[0].length);
|
||||
assert.strictEqual(true, Buffer.isBuffer(reply[0][0]));
|
||||
assert.strictEqual(true, Buffer.isBuffer(reply[0][1]));
|
||||
assert.strictEqual("<Buffer 76 61 6c 20 31>", reply[0][0].inspect());
|
||||
assert.strictEqual("<Buffer 76 61 6c 20 32>", reply[0][1].inspect());
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('hgetall', function (done) {
|
||||
describe('first argument is a string', function () {
|
||||
it('returns string values', function (done) {
|
||||
client.hgetall("hash key 2", function (err, reply) {
|
||||
assert.strictEqual("object", typeof reply);
|
||||
assert.strictEqual(2, Object.keys(reply).length);
|
||||
assert.strictEqual("val 1", reply["key 1"]);
|
||||
assert.strictEqual("val 2", reply["key 2"]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns string values when executed in transaction', function (done) {
|
||||
client.multi().hgetall("hash key 2").exec(function (err, reply) {
|
||||
assert.strictEqual(1, reply.length);
|
||||
assert.strictEqual("object", typeof reply[0]);
|
||||
assert.strictEqual(2, Object.keys(reply[0]).length);
|
||||
assert.strictEqual("val 1", reply[0]["key 1"]);
|
||||
assert.strictEqual("val 2", reply[0]["key 2"]);
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('first argument is a buffer', function () {
|
||||
it('returns buffer values', function (done) {
|
||||
client.hgetall(new Buffer("hash key 2"), function (err, reply) {
|
||||
assert.strictEqual(null, err);
|
||||
assert.strictEqual("object", typeof reply);
|
||||
assert.strictEqual(2, Object.keys(reply).length);
|
||||
assert.strictEqual(true, Buffer.isBuffer(reply["key 1"]));
|
||||
assert.strictEqual(true, Buffer.isBuffer(reply["key 2"]));
|
||||
assert.strictEqual("<Buffer 76 61 6c 20 31>", reply["key 1"].inspect());
|
||||
assert.strictEqual("<Buffer 76 61 6c 20 32>", reply["key 2"].inspect());
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns buffer values when executed in transaction', function (done) {
|
||||
client.multi().hgetall(new Buffer("hash key 2")).exec(function (err, reply) {
|
||||
assert.strictEqual(1, reply.length);
|
||||
assert.strictEqual("object", typeof reply);
|
||||
assert.strictEqual(2, Object.keys(reply[0]).length);
|
||||
assert.strictEqual(true, Buffer.isBuffer(reply[0]["key 1"]));
|
||||
assert.strictEqual(true, Buffer.isBuffer(reply[0]["key 2"]));
|
||||
assert.strictEqual("<Buffer 76 61 6c 20 31>", reply[0]["key 1"].inspect());
|
||||
assert.strictEqual("<Buffer 76 61 6c 20 32>", reply[0]["key 2"].inspect());
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('unref', function () {
|
||||
it('exits subprocess as soon as final command is processed', function (done) {
|
||||
var args = config.HOST[ip] ? [config.HOST[ip], config.PORT] : [ip];
|
||||
var external = fork("./test/lib/unref.js", args);
|
||||
var id = setTimeout(function () {
|
||||
external.kill();
|
||||
return done(Error('unref subprocess timed out'));
|
||||
}, 5000);
|
||||
|
||||
external.on("close", function (code) {
|
||||
clearTimeout(id);
|
||||
assert.strictEqual(code, 0);
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('socket_nodelay', function () {
|
||||
describe('true', function () {
|
||||
var client;
|
||||
var args = config.configureClient(parser, ip, {
|
||||
socket_nodelay: true
|
||||
});
|
||||
|
||||
it("fires client.on('ready')", function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.on("ready", function () {
|
||||
assert.strictEqual(true, client.options.socket_nodelay);
|
||||
client.quit();
|
||||
|
||||
client.once('end', function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('client is functional', function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.on("ready", function () {
|
||||
assert.strictEqual(true, client.options.socket_nodelay);
|
||||
client.set(["set key 1", "set val"], helper.isString("OK"));
|
||||
client.set(["set key 2", "set val"], helper.isString("OK"));
|
||||
client.get(["set key 1"], helper.isString("set val"));
|
||||
client.get(["set key 2"], helper.isString("set val"));
|
||||
client.quit();
|
||||
|
||||
client.once('end', function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('false', function () {
|
||||
var client;
|
||||
var args = config.configureClient(parser, ip, {
|
||||
socket_nodelay: false
|
||||
});
|
||||
|
||||
it("fires client.on('ready')", function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.on("ready", function () {
|
||||
assert.strictEqual(false, client.options.socket_nodelay);
|
||||
client.quit();
|
||||
|
||||
client.once('end', function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('client is functional', function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.on("ready", function () {
|
||||
assert.strictEqual(false, client.options.socket_nodelay);
|
||||
client.set(["set key 1", "set val"], helper.isString("OK"));
|
||||
client.set(["set key 2", "set val"], helper.isString("OK"));
|
||||
client.get(["set key 1"], helper.isString("set val"));
|
||||
client.get(["set key 2"], helper.isString("set val"));
|
||||
client.quit();
|
||||
|
||||
client.once('end', function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('defaults to true', function () {
|
||||
var client;
|
||||
var args = config.configureClient(parser, ip);
|
||||
|
||||
it("fires client.on('ready')", function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.on("ready", function () {
|
||||
assert.strictEqual(true, client.options.socket_nodelay);
|
||||
client.quit();
|
||||
|
||||
client.once('end', function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('client is functional', function (done) {
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.on("ready", function () {
|
||||
assert.strictEqual(true, client.options.socket_nodelay);
|
||||
client.set(["set key 1", "set val"], helper.isString("OK"));
|
||||
client.set(["set key 2", "set val"], helper.isString("OK"));
|
||||
client.get(["set key 1"], helper.isString("set val"));
|
||||
client.get(["set key 2"], helper.isString("set val"));
|
||||
client.quit();
|
||||
|
||||
client.once('end', function () {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('retry_max_delay', function () {
|
||||
var client;
|
||||
var args = config.configureClient(parser, ip, {
|
||||
retry_max_delay: 1
|
||||
});
|
||||
|
||||
it("sets upper bound on how long client waits before reconnecting", function (done) {
|
||||
var time = new Date().getTime()
|
||||
var reconnecting = false;
|
||||
|
||||
client = redis.createClient.apply(redis.createClient, args);
|
||||
client.on('ready', function() {
|
||||
if (!reconnecting) {
|
||||
reconnecting = true;
|
||||
client.retry_delay = 1000;
|
||||
client.retry_backoff = 1;
|
||||
client.stream.end();
|
||||
} else {
|
||||
client.end();
|
||||
var lasted = new Date().getTime() - time;
|
||||
assert.ok(lasted < 1000);
|
||||
return done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('enable_offline_queue', function () {
|
||||
describe('true', function () {
|
||||
it("does not throw an error and enqueues operation", function (done) {
|
||||
var client = redis.createClient(9999, null, {
|
||||
max_attempts: 1,
|
||||
parser: parser
|
||||
});
|
||||
|
||||
client.on('error', function(e) {
|
||||
// ignore, b/c expecting a "can't connect" error
|
||||
});
|
||||
|
||||
return setTimeout(function() {
|
||||
client.set('foo', 'bar', function(err, result) {
|
||||
if (err) return done(err);
|
||||
});
|
||||
|
||||
return setTimeout(function(){
|
||||
assert.strictEqual(client.offline_queue.length, 1);
|
||||
return done();
|
||||
}, 25);
|
||||
}, 50);
|
||||
});
|
||||
});
|
||||
|
||||
describe('false', function () {
|
||||
it("does not throw an error and enqueues operation", function (done) {
|
||||
var client = redis.createClient(9999, null, {
|
||||
parser: parser,
|
||||
max_attempts: 1,
|
||||
enable_offline_queue: false
|
||||
});
|
||||
|
||||
client.on('error', function() {
|
||||
// ignore, b/c expecting a "can't connect" error
|
||||
});
|
||||
|
||||
assert.throws(function () {
|
||||
cli.set('foo', 'bar');
|
||||
});
|
||||
|
||||
assert.doesNotThrow(function () {
|
||||
client.set('foo', 'bar', function (err) {
|
||||
// should callback with an error
|
||||
assert.ok(err);
|
||||
setTimeout(function () {
|
||||
return done();
|
||||
}, 50);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
['javascript', 'hiredis'].forEach(function (parser) {
|
||||
allTests(parser, "/tmp/redis.sock");
|
||||
['IPv4', 'IPv6'].forEach(function (ip) {
|
||||
allTests(parser, ip);
|
||||
});
|
||||
});
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user