@depup/fakeredis 2.0.0-depup.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codeclimate.yml +15 -0
- package/.editorconfig +16 -0
- package/.jshintrc +6 -0
- package/.travis.yml +14 -0
- package/Changelog.md +53 -0
- package/README.md +31 -0
- package/changes.json +10 -0
- package/covertest +16 -0
- package/lib/backend.js +1951 -0
- package/lib/connection.js +474 -0
- package/lib/helpers.js +172 -0
- package/main.js +268 -0
- package/package.json +56 -0
- package/redis.test.js +2352 -0
- package/runtest +10 -0
- package/test.js +1025 -0
package/test.js
ADDED
|
@@ -0,0 +1,1025 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var fake = require("./main"),
|
|
4
|
+
|
|
5
|
+
OK = "OK",
|
|
6
|
+
PONG = "PONG",
|
|
7
|
+
|
|
8
|
+
BAD_ARGS = "wrong number of arguments",
|
|
9
|
+
BAD_TYPE = "Operation against a key holding the wrong kind of value",
|
|
10
|
+
BAD_INT = "value is not an integer or out of range",
|
|
11
|
+
BAD_FLOAT = "value is not a valid float",
|
|
12
|
+
BAD_SYNTAX = "syntax error",
|
|
13
|
+
BAD_INDEX = "index out of range",
|
|
14
|
+
BAD_DB = "invalid DB index",
|
|
15
|
+
BAD_SETEX = "invalid expire time in SETEX",
|
|
16
|
+
BAD_SORT = "One or more scores can't be converted into double";
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
// So lets go.
|
|
20
|
+
|
|
21
|
+
process.stdout.write('testing fakeredis ...\n\n');
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
// Keys and strings.
|
|
25
|
+
|
|
26
|
+
(function () {
|
|
27
|
+
var redis = fake.createClient("stuff"),
|
|
28
|
+
redis2 = fake.createClient("stuff");
|
|
29
|
+
|
|
30
|
+
redis.AUTH("password", test("AUTH", null, "OK"));
|
|
31
|
+
|
|
32
|
+
redis.SET("hello", "world", test("SET", null, OK));
|
|
33
|
+
redis.GET("hello", test("SET / GET", null, "world"));
|
|
34
|
+
|
|
35
|
+
redis.SET("what", "who");
|
|
36
|
+
redis.GETSET("what", "where", test("GETSET", null, "who"));
|
|
37
|
+
redis.MGET("hello", "nonex", "what", test("MGET", null, [ "world", null, "where" ]));
|
|
38
|
+
redis.DEL("hello", "nonex", "what", test("DEL count", null, 2));
|
|
39
|
+
redis.GET("hello", test("SET / DEL / GET", null, null));
|
|
40
|
+
|
|
41
|
+
redis.SET("hello", "vmvl");
|
|
42
|
+
redis.GETBIT("hello", 7, test("GETBIT", null, 0));
|
|
43
|
+
redis.GETBIT("hello", 14, test("GETBIT", null, 0));
|
|
44
|
+
redis.GETBIT("hello", 21, test("GETBIT", null, 1));
|
|
45
|
+
redis.SETBIT("hello", 7, 1, test("SETBIT", null, 0));
|
|
46
|
+
redis.SETBIT("hello", 14, 1, test("SETBIT", null, 0));
|
|
47
|
+
redis.SETBIT("hello", 21, 0, test("GETBIT", null, 1));
|
|
48
|
+
redis.GETBIT("hello", 7, test("GETBIT", null, 1));
|
|
49
|
+
redis.GETBIT("hello", 14, test("GETBIT", null, 1));
|
|
50
|
+
redis.GETBIT("hello", 21, test("GETBIT", null, 0));
|
|
51
|
+
|
|
52
|
+
redis.STRLEN("hello", test("STRLEN", null, 4));
|
|
53
|
+
redis.SETBIT("hello", 33, 1);
|
|
54
|
+
redis.SETBIT("hello", 34, 1);
|
|
55
|
+
redis.SETBIT("hello", 37, 1);
|
|
56
|
+
redis.STRLEN("hello", test("SETBIT refits buffer", null, 5));
|
|
57
|
+
redis.GET("hello", test("SETBIT char from bits", null, "world"));
|
|
58
|
+
|
|
59
|
+
redis.SETRANGE("hi", 0, "Hello World", test("SETRANGE upsert", null, 11));
|
|
60
|
+
redis.GET("hi", test("SETRANGE", null, "Hello World"));
|
|
61
|
+
redis.GETRANGE("hi", -5, -1, test("GETRANGE negneg", null, "World"));
|
|
62
|
+
redis.SETRANGE("hi", 6, "Redis", test("SETRANGE offset", null, 11));
|
|
63
|
+
redis.GET("hi", test("SETRANGE", null, "Hello Redis"));
|
|
64
|
+
|
|
65
|
+
redis.EXPIRE("hello", 15);
|
|
66
|
+
redis.DECR("hello", test("SET / DECR", BAD_INT, null));
|
|
67
|
+
redis.TTL("hello", test("EXPIRE / TTL", null, 15));
|
|
68
|
+
redis.PERSIST("hello");
|
|
69
|
+
redis.send_command("pttl", [ "hello" ], test("PERSIST / PTTL", null, -1));
|
|
70
|
+
redis.send_command("pexpireat", [ "hello", Date.now () + 250 ]);
|
|
71
|
+
redis.MSETNX("somekey", "someval", "hello", "non-world", test("MSETNX is safe", null, 0));
|
|
72
|
+
redis.GET("hello", test("GET expiring", null, "world"));
|
|
73
|
+
redis.APPEND("hello", " of mine", test("APPEND upset", null,("world of mine" ).length));
|
|
74
|
+
redis.INCR("hello", test("INCR upset", BAD_INT, null));
|
|
75
|
+
redis.DECRBY("nonx", 5, test("DECR nonexist", null, -5));
|
|
76
|
+
|
|
77
|
+
redis.SETEX("nonx", 0, "hello", test("SETEX fail", BAD_SETEX, null));
|
|
78
|
+
redis.SETNX("nonx", "dont!", test("SETNX fail", null, 0));
|
|
79
|
+
redis.SET("nonx", "hello", "EX", 0, test("SET with EX fail", BAD_INT, null));
|
|
80
|
+
redis.SET("nonx", "hello", "PX", 0, test("SET with PX fail", BAD_INT, null));
|
|
81
|
+
redis.SET("nonx", "dont!", "NX", test("SET with NX fail", null, null));
|
|
82
|
+
redis.MSET("nonx", "do", test("MSET", null, OK));
|
|
83
|
+
redis.send_command("psetex", [ "nonx", 1000, "disappear" ], test("PSETEX", null, OK));
|
|
84
|
+
redis.GET("nonx", test("PSETEX set", null, "disappear"));
|
|
85
|
+
redis.TTL("nonx", test("PSETEX expire", null, 1));
|
|
86
|
+
redis.GETSET("nonx", "stay");
|
|
87
|
+
redis.TTL("nonx", test("GETSET persists", null, -1));
|
|
88
|
+
redis.DEL("nonx");
|
|
89
|
+
|
|
90
|
+
redis.SET("flop", "dont!", "XX", test("SET with XX fail", null, null));
|
|
91
|
+
|
|
92
|
+
redis.BITCOUNT(test("BITCOUNT missing key parameter", BAD_ARGS, null));
|
|
93
|
+
redis.BITCOUNT("absentKey", test("BITCOUNT absent key", null, 0));
|
|
94
|
+
redis.SET("bitCountKey", "foobar");
|
|
95
|
+
redis.BITCOUNT("bitCountKey", test("BITCOUNT of valid key", null, 26));
|
|
96
|
+
redis.BITCOUNT("bitCountKey", 0, -1, test("BITCOUNT using explicit range", null, 26));
|
|
97
|
+
redis.BITCOUNT("bitCountKey", 0, 0, test("BITCOUNT of first character", null, 4));
|
|
98
|
+
redis.BITCOUNT("bitCountKey", -1, -1, test("BITCOUNT of last character", null, 4));
|
|
99
|
+
redis.BITCOUNT("bitCountKey", 0, 3, test("BITCOUNT of substring", null, 19));
|
|
100
|
+
|
|
101
|
+
// Sets.
|
|
102
|
+
|
|
103
|
+
redis.SADD("hello", "kuku", "buku", test("SADD typerror", BAD_TYPE, null));
|
|
104
|
+
redis.SADD("myset", [ "ala", "bala" ], test("SADD multiarg", null, 2));
|
|
105
|
+
redis.SADD("myset", "niza", "bala", test("SADD delta", null, 1));
|
|
106
|
+
redis.SCARD("hello", test("SCARD typerror", BAD_TYPE, null));
|
|
107
|
+
redis.SCARD("myset", test("SCARD", null, 3));
|
|
108
|
+
redis.SADD("set2", 1, 2, 3, 4, 5);
|
|
109
|
+
redis.SADD("set3", "xxx", "zzz", "yyy");
|
|
110
|
+
redis.SUNIONSTORE("output", [ "nonex1", "myset", "set2", "set3", "nonex2" ], test("SUNIONSTORE", null, 11));
|
|
111
|
+
redis.SISMEMBER("output", "xxx", test("SISMEMBER union 3 sets", null, 1));
|
|
112
|
+
redis.SINTER("myset", "output", test("SINTER", null, [ "ala", "bala", "niza" ]));
|
|
113
|
+
redis.SINTER("myset", "outputs", test("SINTER nonex empty 1", null, []));
|
|
114
|
+
redis.SINTER("outputs", "myset", test("SINTER nonex empty 2", null, []));
|
|
115
|
+
redis.SADD("set3", "ala", 3, 4, "kukukuku");
|
|
116
|
+
redis.SDIFFSTORE("output", "output", "set3", test("SDIFFSTORE", null, 5));
|
|
117
|
+
redis.SMEMBERS("output", test("SMEMBERS", null, [ "1", "2", "5", "bala", "niza" ]));
|
|
118
|
+
redis.SISMEMBER("output", "bala", test("SISMEMBER yes", null, 1));
|
|
119
|
+
redis.SISMEMBER("output", "what", test("SISMEMBER no", null, 0));
|
|
120
|
+
redis.SISMEMBER("nonex", "what", test("SISMEMBER nonex", null, 0));
|
|
121
|
+
redis.SISMEMBER("hello", "what", test("SISMEMBER bad", BAD_TYPE, null));
|
|
122
|
+
|
|
123
|
+
redis.SADD("otherset", "whatever");
|
|
124
|
+
redis.SINTERSTORE("nothing", "otherset", "output", test("SINTERSTORE empty out", null, 0));
|
|
125
|
+
redis.TYPE("nothing", test("SINTERSTORE empty out / TYPE", null, "none"));
|
|
126
|
+
|
|
127
|
+
redis.DEL("set3");
|
|
128
|
+
redis.SPOP("set3", test("SPOP nothing", null, null));
|
|
129
|
+
redis.SINTER("output", function (err, members) {
|
|
130
|
+
redis.SPOP("output", function (err, member) {
|
|
131
|
+
member = member ? member.toString() : "!?@#?!@?#";
|
|
132
|
+
|
|
133
|
+
var expected = members
|
|
134
|
+
.map(function (entry) { return entry.toString(); })
|
|
135
|
+
.filter(function (entry) { return entry !== member; });
|
|
136
|
+
|
|
137
|
+
redis2.SDIFF("output", test("SPOP(client 2 )", null, expected));
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
// Sorted sets.
|
|
143
|
+
|
|
144
|
+
redis.ZADD("myzset", [ 1, "one", 2, "two", 3, "three" ], test("ZADD", null, 3));
|
|
145
|
+
redis.ZCARD("myzset", test("ZCARD", null, 3));
|
|
146
|
+
redis.ZCARD("whatwhat", test("ZCARD nonex", null, 0));
|
|
147
|
+
redis.ZCARD("myset", test("ZCARD bad", BAD_TYPE, null));
|
|
148
|
+
redis.ZRANGE("myzset", 1, -1, test("ZRANGE pos neg", null, [ "two", "three" ]));
|
|
149
|
+
redis.ZRANGE("myzset", 0, 1, test("ZRANGE pos pos", null, [ "one", "two" ]));
|
|
150
|
+
redis.ZRANGE("myzset", 1, -2, test("ZRANGE pos=neg", null, [ "two" ]));
|
|
151
|
+
redis.ZRANGE("myzset", -1, 1, test("ZRANGE null", null, []));
|
|
152
|
+
redis.ZRANGE("myzset", "-inf", "+inf", test("ZRANGE int", BAD_INT, null));
|
|
153
|
+
redis.ZREVRANGEBYSCORE("myzset", "+inf", "-inf", test("ZREVRANGEBYSCORE all", null, [ "three", "two", "one" ]));
|
|
154
|
+
redis.ZREVRANGEBYSCORE("myzset", 2, 1, test("ZREVRANGEBYSCORE incl", null, [ "two", "one" ]));
|
|
155
|
+
redis.ZREVRANGEBYSCORE("myzset", 2, "(1", test("ZREVRANGEBYSCORE soso", null, [ "two" ]));
|
|
156
|
+
redis.ZREVRANGEBYSCORE("myzset", "(2", "(1", test("ZREVRANGEBYSCORE excl", null, []));
|
|
157
|
+
redis.ZADD("myzset", 1.5, "one.five");
|
|
158
|
+
redis.ZRANGEBYSCORE("myzset", "-inf", "+inf", "WITHSCORES", "LIMIT", 1, 2, test("ZREVRANGEBYSCORE limit", null, [ "one.five", "1.5", "two", "2" ]));
|
|
159
|
+
|
|
160
|
+
// Negative offset behaves differently here and in SORT
|
|
161
|
+
|
|
162
|
+
redis.ZRANGEBYSCORE("myzset", "-inf", "+inf", "WITHSCORES", "LIMIT", -1, 2, test("ZREVRANGEBYSCORE limit +negoffset", null, []));
|
|
163
|
+
redis.ZRANGEBYSCORE("myzset", "-inf", "+inf", "WITHSCORES", "LIMIT", 1, -11, test("ZREVRANGEBYSCORE limit +negcount", null, [ "one.five", "1.5", "two", "2", "three", "3" ]));
|
|
164
|
+
|
|
165
|
+
redis.ZCOUNT("myzset", "(1", 2, test("ZCOUNT", null, 2));
|
|
166
|
+
redis.SET("wrong", "indeed");
|
|
167
|
+
redis.ZREMRANGEBYRANK("wrong", 0, -1, test("ZREMRANGEBYRANK badkey", BAD_TYPE, null));
|
|
168
|
+
redis.ZREMRANGEBYSCORE("myzset", "(1", "2", test("ZREMRANGEBYSCORE", null, 2));
|
|
169
|
+
redis.ZRANGE("myzset", "0", "-1", test("ZREMRANGEBYSCORE / ZRANGE", null, [ "one", "three" ]));
|
|
170
|
+
redis.ZADD("myzset", 1.9, "goner1", 2.1, "goner2");
|
|
171
|
+
redis.ZREMRANGEBYRANK("myzset", 1, 2, test("ZREMRANGEBYRANK", null, 2));
|
|
172
|
+
redis.ZRANGE("myzset", "0", "-1", test("ZREMRANGEBYRANK / ZRANGE", null, [ "one", "three" ]));
|
|
173
|
+
redis.ZADD("myzset", "2", "one", test("ZADD not adding", null, 0));
|
|
174
|
+
redis.ZADD("myzset", "", "one", test("ZADD bad score", BAD_FLOAT, null));
|
|
175
|
+
redis.ZADD("myzset", "2", "two");
|
|
176
|
+
redis.ZINCRBY("myzset", 2, "one", test("ZINCRBY", null, 4));
|
|
177
|
+
redis.ZREVRANGE("myzset", 0, -1, "WITHSCORES", test("ZREVRANGE", null, [ "one", "4", "three", "3", "two", "2" ]));
|
|
178
|
+
redis.ZSCORE("myzset", "three", test("ZSCORE", null, 3));
|
|
179
|
+
redis.ZADD("myzset", 1.5, "one.five");
|
|
180
|
+
redis.ZRANK("myzset", "three", test("ZRANK", null, 2));
|
|
181
|
+
redis.ZREVRANK("myzset", "three", test("ZREVRANK", null, 1));
|
|
182
|
+
|
|
183
|
+
redis.ZADD("zset1", 1, "one", 2, "two");
|
|
184
|
+
redis.ZADD("zset2", 1, "one", 2, "two", 3, "three");
|
|
185
|
+
redis.ZINTERSTORE("out", 2, "zset1", "zset2", "weights", 2, 3, test("ZINTERSTORE no aggregate", null, 2));
|
|
186
|
+
redis.ZRANGE("out", 0, -1, "WITHSCORES", test("ZINTERSTORE / ZRANGE", null, [ "one", "5", "two", "10" ]));
|
|
187
|
+
|
|
188
|
+
redis.ZUNIONSTORE(
|
|
189
|
+
"out", /* 4, */ "nonex", "zset1", "zset2", "out", "weights", 10, 1, 2, 0.5, "aggregate", "max",
|
|
190
|
+
test("ZUNIONSTORE missing keycount", BAD_INT, null)
|
|
191
|
+
);
|
|
192
|
+
redis.ZUNIONSTORE(
|
|
193
|
+
"out", 4, "nonex", "zset1", "zset2", "out", "weights", 10, 1, 2, /* .5, */ "aggregate", "max",
|
|
194
|
+
test("ZUNIONSTORE bad weight count (less)", BAD_FLOAT, null)
|
|
195
|
+
);
|
|
196
|
+
redis.ZUNIONSTORE(
|
|
197
|
+
"out", 4, "nonex", "zset1", "zset2", "out", "weights", 10, 1, 2, 0.5, 10, "aggregate", "max",
|
|
198
|
+
test("ZUNIONSTORE bad weight count (more)", BAD_ARGS, null)
|
|
199
|
+
);
|
|
200
|
+
redis.ZUNIONSTORE(
|
|
201
|
+
"out", 4, "nonex", "zset1", "zset2", "out", "weights", 10, 1, 2, 0.5, "aggregate", /* "max", */
|
|
202
|
+
test("ZUNIONSTORE missing aggregate", BAD_ARGS, null)
|
|
203
|
+
);
|
|
204
|
+
redis.ZUNIONSTORE(
|
|
205
|
+
"out", 4, "nonex", "zset1", "zset2", "out", /* "weights", */ 10, 1, 2, 0.5, "aggregate", "max",
|
|
206
|
+
test("ZUNIONSTORE missing weight keyword", BAD_ARGS, null)
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
redis.ZUNIONSTORE(
|
|
210
|
+
"out2", 2, "zset1", "zset2",
|
|
211
|
+
test("ZUNIONSTORE naked", null, 3 )
|
|
212
|
+
);
|
|
213
|
+
redis.ZRANGE("out2", 0, -1, "WITHSCORES", test("ZUNIONSTORE naked / ZRANGE", null, [ "one", "2", "three", "3", "two", "4" ]));
|
|
214
|
+
|
|
215
|
+
redis.ZUNIONSTORE(
|
|
216
|
+
"out2", 2, "zset1", "zset2", "aggregate", "min",
|
|
217
|
+
test("ZUNIONSTORE with aggregate", null, 3 )
|
|
218
|
+
);
|
|
219
|
+
redis.ZRANGE("out2", 0, -1, "WITHSCORES", test("ZUNIONSTORE with aggregate / ZRANGE", null, [ "one", "1", "two", "2", "three", "3" ]));
|
|
220
|
+
|
|
221
|
+
redis.ZUNIONSTORE(
|
|
222
|
+
"out", 4, "nonex", "zset1", "zset2", "out", "weights", 10, 1, 2, 0.5, "aggregate", "max",
|
|
223
|
+
test("ZUNIONSTORE with weights + aggregate", null, 3 )
|
|
224
|
+
);
|
|
225
|
+
redis.ZRANGE("out", 0, -1, "WITHSCORES", test("ZUNIONSTORE / ZRANGE", null, [ "one", "2.5", "two", "5", "three", "6" ]));
|
|
226
|
+
|
|
227
|
+
redis.KEYS("*z?et*", test("KEYS with ? and *", null, [ "myzset", "zset1", "zset2" ]));
|
|
228
|
+
redis.KEYS("my[sz]*et", test("KEYS with [] and *", null, [ "myset", "myzset" ]));
|
|
229
|
+
redis.KEYS("my[sz]{2}et", test("REGEXP escaping", null, []));
|
|
230
|
+
redis.TYPE("myset", test("TYPE", null, "set"));
|
|
231
|
+
|
|
232
|
+
redis.EXPIRE("out", 60);
|
|
233
|
+
redis.RENAME("out", "outandabout", test("RENAME", null, OK));
|
|
234
|
+
redis.ZADD("outandabout", 0, "zero", test("ZADD zero", null, 1));
|
|
235
|
+
redis.TTL("outandabout", test("RENAME / ZADD / TTL", null, 60));
|
|
236
|
+
redis.EXISTS("out", test("EXISTS no", null, 0));
|
|
237
|
+
redis.EXISTS("outandabout", test("EXISTS yes", null, 1));
|
|
238
|
+
|
|
239
|
+
redis.ZADD("lexi", 1, "AAA", 1, "BBB", 1, "ZZZ", 1, "XXX", 1, "YYY", 2, "FFF");
|
|
240
|
+
redis.ZRANGE("lexi", 0, -1, test("lexicographic zset member sort", null, [ "AAA", "BBB", "XXX", "YYY", "ZZZ", "FFF" ]));
|
|
241
|
+
redis.ZREVRANGE("lexi", 0, -1, test("lexicographic zset member sort", null, [ "FFF", "ZZZ", "YYY", "XXX", "BBB", "AAA" ]));
|
|
242
|
+
|
|
243
|
+
redis.ZADD("otherzset", 100, "whatever");
|
|
244
|
+
redis.ZINTERSTORE("nothing", 2, "lexi", "otherzset", test("ZINTERSTORE empty out", null, 0));
|
|
245
|
+
redis.TYPE("nothing", test("ZINTERSTORE empty out / TYPE", null, "none"));
|
|
246
|
+
|
|
247
|
+
redis.SADD("newset", "v1", "v2");
|
|
248
|
+
redis.ZADD("newzset", 1, "v1", 2, "v2", 3, "v3");
|
|
249
|
+
redis.ZINTERSTORE("out", 2, "newzset", "newset");
|
|
250
|
+
redis.ZRANGE("out", 0, -1, test("ZINTERSTORE with sets", null, ["v1", "v2"]));
|
|
251
|
+
// switch set and zset key order
|
|
252
|
+
redis.ZINTERSTORE("out2", 2, "newset", "newzset");
|
|
253
|
+
redis.ZRANGE("out2", 0, -1, test("ZINTERSTORE with sets", null, ["v1", "v2"]));
|
|
254
|
+
redis.ZREVRANGE("out2", 0, -1, "withscores", test("ZINTERSTORE with sets withscores", null, ["v2", "3", "v1", "2"]));
|
|
255
|
+
redis.ZUNIONSTORE("out3", 2, "newset", "newzset");
|
|
256
|
+
redis.ZRANGE("out3", 0, -1, "withscores", test("ZUNIONSTORE with sets withscores", null, ["v1", "2", "v2", "3", "v3", "3"]));
|
|
257
|
+
|
|
258
|
+
// Hashes.
|
|
259
|
+
|
|
260
|
+
redis.HGETALL("nonex", test("HGETALL nonex", null, null));
|
|
261
|
+
|
|
262
|
+
redis.HMSET("h", { "f1" : "v1", "field-3" : "3" }, test("HMSET {} ok", null, OK));
|
|
263
|
+
redis.HMSET("h", "f2", "v2", "field-4", 4, test("HMSET ... ok", null, OK));
|
|
264
|
+
|
|
265
|
+
redis.HSETNX("h", "f1", "V1", test("HSETNX safe", null, 0));
|
|
266
|
+
redis.HSETNX("h", "F1", "V1", test("HSETNX", null, 1));
|
|
267
|
+
redis.HGETALL("h", test("HGETALL", null, { "F1": "V1", "f1": "v1", "f2": "v2", "field-3": "3", "field-4": "4" }));
|
|
268
|
+
|
|
269
|
+
redis.getKeyspace("*h", test("getKeyspace() with pattern", null, [ "h", "-1", "hash", [ "F1", "V1", "f1", "v1", "f2", "v2", "field-3", "3", "field-4", "4" ] ]));
|
|
270
|
+
|
|
271
|
+
redis.HKEYS("h", test("HKEYS", null, [ "F1", "f1", "f2", "field-3", "field-4" ]));
|
|
272
|
+
redis.send_command("HINCRBYFLOAT", [ "h", "f1", 3.5 ], test("HINCRBYFLOAT fail", BAD_FLOAT, null));
|
|
273
|
+
redis.HINCRBY("h", "field-3", 3, test("HINCRBYFLOAT success", null, 6));
|
|
274
|
+
redis.HVALS("h", test("HVALS", null, [ "4", "6", "V1", "v1", "v2" ]));
|
|
275
|
+
redis.HMGET("h", "F1", "f1", "f2", test("HMGET", null, [ "V1", "v1", "v2" ]));
|
|
276
|
+
redis.HGETALL("h", function (err, data) {
|
|
277
|
+
redis.multi()
|
|
278
|
+
.HGETALL("h", test("HGETALL multi/exec sugar", err, data))
|
|
279
|
+
.exec(test("HGETALL multi/exec replies sugar", err, [ data ]));
|
|
280
|
+
|
|
281
|
+
redis.HDEL("h", "field-3", "F1", "F2", test("HDEL", null, 2));
|
|
282
|
+
redis.TYPE("h", test("TYPE hash", null, "hash"));
|
|
283
|
+
redis.HDEL("h", "field-4", "f1", "f2");
|
|
284
|
+
redis.TYPE("h", test("TYPE none", null, "none"));
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
redis.HDEL('hnonex', 'moot', test("HDEL nonex", null, 0));
|
|
288
|
+
redis.HSET('w00t', 'field', 'value', function () {
|
|
289
|
+
redis.HDEL('w00t', 'moot', test("HDEL nonex field", null, 0));
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
// Lists, non-blocking.
|
|
294
|
+
|
|
295
|
+
redis.LPUSH("list", [ "one", "two", "three" ], test("LPUSH", null, 3));
|
|
296
|
+
redis.LPOP("list", test("RPOP", null, "three"));
|
|
297
|
+
redis.LRANGE("list", 0, -1, test("LRANGE all posneg", null, [ "two", "one" ]));
|
|
298
|
+
redis.LSET("list", 1, "what", test("LSET", null, OK));
|
|
299
|
+
redis.LSET("list", 4, "what", test("LSET out of range", BAD_INDEX, null));
|
|
300
|
+
redis.LTRIM("list", 1, -1, test("LTRIM posneg", null, OK));
|
|
301
|
+
redis.RPOPLPUSH("nonexl", "newlist", test("RPOPLPUSH nonex", null, null));
|
|
302
|
+
redis.TYPE("newlist", test("RPOPLPUSH nonex safe", null, "none"));
|
|
303
|
+
redis.RPOPLPUSH("list", "newlist", test("RPOPLPUSH", null, "what"));
|
|
304
|
+
redis.LPUSHX("nonex", "where", "why", test("LPUSHX nonex", null, 0));
|
|
305
|
+
redis.RPUSHX("newlist", "where", "why", test("RPUSHX", null, 3));
|
|
306
|
+
redis.RPUSH("list3", "one", "two", "three", test("RPUSH", null, 3));
|
|
307
|
+
redis.LTRIM("list3", -3, -1, test("LTRIM negneg", null, OK));
|
|
308
|
+
redis.LLEN("list3", test("LLEN", null, 3));
|
|
309
|
+
redis.LINDEX("list3", 2, test("LINDEX posyes", null, "three"));
|
|
310
|
+
redis.LINDEX("list3", -3, test("LINDEX negyes", null, "one"));
|
|
311
|
+
redis.LINDEX("list3", 3, test("LINDEX negno", null, null));
|
|
312
|
+
redis.LINDEX("list3", -4, test("LINDEX negno", null, null));
|
|
313
|
+
redis.LINDEX("nonex", 0, test("LINDEX badkey", null, null));
|
|
314
|
+
redis.LINDEX("hello", 0, test("LINDEX badkey", BAD_TYPE, null));
|
|
315
|
+
redis.LRANGE("list3", -3, 2, test("LRANGE all negpos", null, [ "one", "two", "three" ]));
|
|
316
|
+
redis.LRANGE("list3", -5, 0, test("LRANGE lo2lo", null, [ "one" ]));
|
|
317
|
+
redis.LRANGE("list3", 2, 10, test("LRANGE hi2hi", null, [ "three" ]));
|
|
318
|
+
redis.LPUSH("list3", "three", "what", "what");
|
|
319
|
+
redis.LREM("list3", 1, "one", test("LREM left", null, 1));
|
|
320
|
+
redis.LREM("list3", -1, "three", test("LREM right", null, 1));
|
|
321
|
+
redis.LREM("list3", -2, "what", test("LREM 2right", null, 2));
|
|
322
|
+
|
|
323
|
+
redis.getKeyspace("*list*", test("lists outcome", null, [ "list3", "-1", "list", [ "three", "two" ], "newlist", "-1", "list", [ "what", "where", "why" ] ]));
|
|
324
|
+
|
|
325
|
+
redis.LREM("lnonex", 1, "what", test("LREM nonex", null, 0));
|
|
326
|
+
|
|
327
|
+
redis.LPUSH("lremlist", "a", "b", "b", "a", "b", "b", test("LPUSH", null, 6));
|
|
328
|
+
redis.LREM("lremlist", 0, "a", test("LREM 0", null, 2));
|
|
329
|
+
redis.LLEN("lremlist", test("LLEN", null, 4));
|
|
330
|
+
redis.LREM("lremlist", 0, "b", test("LREM 0", null, 4));
|
|
331
|
+
redis.LLEN("lremlist", test("LLEN empty", null, 0));
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
// Blocking list commands !
|
|
335
|
+
|
|
336
|
+
redis.BLPOP("BL-a", "BL-b", "BL-c", 0, test("BLPOP", null, [ "BL-a", "AAA" ]));
|
|
337
|
+
|
|
338
|
+
redis2.LPUSH("BL-a", "AAA", test("LPUSH + BLPOP", null, 1));
|
|
339
|
+
redis2.BRPOP("BL-b", "BL-c", 0, test("BRPOP", null, [ "BL-b", "BB3" ]));
|
|
340
|
+
|
|
341
|
+
redis.RPUSH("BL-b", "BB1", "BB2", "BB3", test("RPUSH + BRPOP", null, 3));
|
|
342
|
+
redis.BLPOP("BL-a", "BL-c", 0, test("BLPOP", null, [ "BL-c", "CC1" ]));
|
|
343
|
+
|
|
344
|
+
redis2.RPUSH("BL-c", "CC1", "CC2", "CC3", test("RPUSH + BLPOP", null, 3));
|
|
345
|
+
|
|
346
|
+
redis.getKeyspace("BL-?", test("blocking lists outcome", null, [ "BL-b", "-1", "list", [ "BB1", "BB2" ], "BL-c", "-1", "list", [ "CC2", "CC3" ] ]));
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
// Misc stuff.
|
|
350
|
+
|
|
351
|
+
redis.ECHO("hello world!", test("ECHO", null, "hello world!"));
|
|
352
|
+
redis.PING(test("PING", null, "PONG"));
|
|
353
|
+
|
|
354
|
+
redis.SAVE(test("SAVE", null, "OK"));
|
|
355
|
+
redis.BGSAVE(test("BGSAVE", null, "OK"));
|
|
356
|
+
redis.BGREWRITEAOF(test("BGREWRITEAOF", null, "OK"));
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
// Expiry and flush.
|
|
360
|
+
|
|
361
|
+
setTimeout(
|
|
362
|
+
function () {
|
|
363
|
+
redis.GET("hello", test("GET expired", null, null));
|
|
364
|
+
|
|
365
|
+
// redis.pretty ();
|
|
366
|
+
|
|
367
|
+
redis.FLUSHDB ();
|
|
368
|
+
redis.GETSET("hello", "world", test("GETSET null", null, null));
|
|
369
|
+
redis.getKeyspace(test("getKeyspace() flushed, nopat", null, [ "hello", "-1", "string", "world" ]));
|
|
370
|
+
},
|
|
371
|
+
1000
|
|
372
|
+
);
|
|
373
|
+
} ());
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
// Transactions.
|
|
377
|
+
|
|
378
|
+
(function () {
|
|
379
|
+
var multi,
|
|
380
|
+
redis = fake.createClient("transactions-1"),
|
|
381
|
+
redis2 = fake.createClient("transactions-1");
|
|
382
|
+
|
|
383
|
+
redis.SET("abc", "dfg");
|
|
384
|
+
redis.SET("what", "who");
|
|
385
|
+
redis.WATCH("why", "what", "abc");
|
|
386
|
+
multi = redis.MULTI();
|
|
387
|
+
redis.GET("abc", function () {
|
|
388
|
+
redis2.SET("abc", "dfgdfg", function () {
|
|
389
|
+
multi.SET("abc", "dfggfd", test("SET discarded", null, null));
|
|
390
|
+
multi.exec ();
|
|
391
|
+
|
|
392
|
+
redis.GET("abc", test("invalidated transaction", null, "dfgdfg"));
|
|
393
|
+
});
|
|
394
|
+
});
|
|
395
|
+
} ());
|
|
396
|
+
|
|
397
|
+
(function () {
|
|
398
|
+
var multi,
|
|
399
|
+
redis = fake.createClient("transactions-1"),
|
|
400
|
+
redis2 = fake.createClient("transactions-1");
|
|
401
|
+
|
|
402
|
+
redis.SET("abc", "dfg");
|
|
403
|
+
redis.SET("what", "who");
|
|
404
|
+
redis.WATCH("why", "what", "abc");
|
|
405
|
+
multi = redis.MULTI();
|
|
406
|
+
redis.GET("abc", function () {
|
|
407
|
+
redis2.SET("abc", "dfgdfg", function () {
|
|
408
|
+
multi.SET("abc", "dfggfd", test("SET discarded", null, null));
|
|
409
|
+
multi.exec ();
|
|
410
|
+
|
|
411
|
+
redis.GET("abc", test("invalidated transaction", null, "dfgdfg"));
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
} ());
|
|
415
|
+
|
|
416
|
+
(function () {
|
|
417
|
+
var multi,
|
|
418
|
+
redis = fake.createClient("transactions-2"),
|
|
419
|
+
redis2 = fake.createClient("transactions-2");
|
|
420
|
+
|
|
421
|
+
redis.SET("abc", "dfg");
|
|
422
|
+
redis.SET("what", "who");
|
|
423
|
+
redis.WATCH("why", "what", "abc");
|
|
424
|
+
multi = redis.MULTI();
|
|
425
|
+
redis.GET("abc", function () {
|
|
426
|
+
redis2.SET("abc", "dfgdfg", function () {
|
|
427
|
+
redis.UNWATCH ();
|
|
428
|
+
multi.SET("abc", "dfggfd", test("SET discarded", null, OK));
|
|
429
|
+
multi.STRLEN("abc", test("STRLEN", null, 6));
|
|
430
|
+
multi.exec ();
|
|
431
|
+
|
|
432
|
+
redis.GET("abc", test("unwatched succeeds", null, "dfggfd"));
|
|
433
|
+
});
|
|
434
|
+
});
|
|
435
|
+
} ());
|
|
436
|
+
|
|
437
|
+
(function () {
|
|
438
|
+
var multi,
|
|
439
|
+
redis = fake.createClient("transactions-3");
|
|
440
|
+
|
|
441
|
+
redis.WATCH("abc");
|
|
442
|
+
redis.GET("abc");
|
|
443
|
+
multi = redis.MULTI();
|
|
444
|
+
multi.SET("abc", "dfgdfg");
|
|
445
|
+
multi.exec(test("WATCH NONEX EXEC succeeds", null, ['OK']));
|
|
446
|
+
redis.GET("abc", test("WATCH NONEX GET succeeds", null, "dfgdfg"));
|
|
447
|
+
} ());
|
|
448
|
+
|
|
449
|
+
(function () {
|
|
450
|
+
var multi,
|
|
451
|
+
redis = fake.createClient("transactions-4");
|
|
452
|
+
|
|
453
|
+
redis.SET("fail-a", "hello");
|
|
454
|
+
multi = redis.MULTI();
|
|
455
|
+
multi.SADD("fail-a", "woot", test("EXEC reply error", BAD_TYPE));
|
|
456
|
+
multi.exec();
|
|
457
|
+
} ());
|
|
458
|
+
|
|
459
|
+
(function () {
|
|
460
|
+
var client = fake.createClient(), set_size = 1000;
|
|
461
|
+
|
|
462
|
+
client.sadd("bigset", "a member");
|
|
463
|
+
client.sadd("bigset", "another member");
|
|
464
|
+
|
|
465
|
+
while (set_size > 0) {
|
|
466
|
+
client.sadd("bigset", "member " + set_size);
|
|
467
|
+
set_size -= 1;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
client.multi()
|
|
471
|
+
.scard("bigset")
|
|
472
|
+
.sadd("set2","m1","m2")
|
|
473
|
+
.keys("*")
|
|
474
|
+
.smembers("set2")
|
|
475
|
+
.srem("set2","m3","m2","m1")
|
|
476
|
+
.dbsize(test("DBSIZE", null, 1))
|
|
477
|
+
.exec(test("multi chain with an individual callback", null, [ 1002, 2, [ "bigset", "set2" ], [ "m1", "m2" ], 2, 1 ]));
|
|
478
|
+
} ());
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
// Pub / Sub.
|
|
482
|
+
|
|
483
|
+
(function () {
|
|
484
|
+
var pub = fake.createClient("pubsub-1"),
|
|
485
|
+
sub1 = fake.createClient("pubsub-1"),
|
|
486
|
+
sub2 = fake.createClient("pubsub-1"),
|
|
487
|
+
sub3 = fake.createClient("pubsub-1"),
|
|
488
|
+
|
|
489
|
+
data = [ 0, [], [], [] ],
|
|
490
|
+
tcb1 = test("PUBSUB basics", null, [ 4, [ 'my.ch-alpha', 'my.ch-beta', 'my.ch-omega' ], [ 'my.ch-alpha', 'my.ch-beta' ], [ 'my.ch-alpha', 'my.ch-beta', 'what-what', 'my.ch-omega' ] ]),
|
|
491
|
+
|
|
492
|
+
ord = [],
|
|
493
|
+
tcb2 = test("PUBSUB normal / sequence", null, [ 1, '*ch', 'pun', 1 ]),
|
|
494
|
+
|
|
495
|
+
thr = test("Pubsub mode", null, true),
|
|
496
|
+
pun = test("PUNSUBSCRIBE", null, "*ch");
|
|
497
|
+
|
|
498
|
+
sub2.SADD("testset", "testmem", function (err, data) {
|
|
499
|
+
ord.push(data);
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
sub1.SUBSCRIBE("my.ch");
|
|
503
|
+
sub2.PSUBSCRIBE("*ch");
|
|
504
|
+
sub3.PSUBSCRIBE("my.*", "what");
|
|
505
|
+
|
|
506
|
+
try {
|
|
507
|
+
sub3.PUBLISH('fail', 'fail');
|
|
508
|
+
thr(null, false);
|
|
509
|
+
}
|
|
510
|
+
catch (e) {
|
|
511
|
+
thr(null, true);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
sub1.on('message', function (channel, message) {
|
|
515
|
+
data[1].push(channel + '-' + message);
|
|
516
|
+
|
|
517
|
+
if (message === 'alpha')
|
|
518
|
+
pub.PUBLISH('my.ch', 'beta', test('PUB2', null, 3));
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
sub2.on('pmessage', function (pattern, channel, message) {
|
|
522
|
+
data[2].push(channel + '-' + message);
|
|
523
|
+
|
|
524
|
+
if (message === 'beta') {
|
|
525
|
+
pub.PUBLISH('ignore', 'ignored', test('PUB3 ignored', null, 0));
|
|
526
|
+
pub.PUBLISH('what', 'what', test('PUB3 delivered', null, 1));
|
|
527
|
+
sub2.PUNSUBSCRIBE('hello', 'world', '*ch');
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
sub2.on('punsubscribe', function (pattern) {
|
|
532
|
+
pun(null, pattern);
|
|
533
|
+
|
|
534
|
+
ord.push('pun');
|
|
535
|
+
|
|
536
|
+
sub2.SREM('testset', 'testmem', function (err, data) {
|
|
537
|
+
ord.push(data);
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
sub2.PUBLISH('hello', 'world', test('PUB4 ignored', null, 0));
|
|
541
|
+
sub2.PUBLISH('my.ch', 'omega', test('PUB5 unsubed', null, 2));
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
sub3.on('pmessage', function (pattern, channel, message) {
|
|
545
|
+
data [ 3 ].push(channel + '-' + message);
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
var start = function (ch) {
|
|
549
|
+
data [ 0 ] ++;
|
|
550
|
+
if (data [ 0 ] === 4) {
|
|
551
|
+
pub.PUBLISH('my.ch', 'alpha', test('PUB1', null, 3));
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (ch === '*ch')
|
|
555
|
+
ord.push(ch);
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
sub1.on('subscribe', start);
|
|
559
|
+
sub2.on('psubscribe', start);
|
|
560
|
+
sub3.on('psubscribe', start);
|
|
561
|
+
|
|
562
|
+
// Test the state a bit later.
|
|
563
|
+
|
|
564
|
+
setTimeout(
|
|
565
|
+
function () {
|
|
566
|
+
tcb1(null, data);
|
|
567
|
+
tcb2(null, ord);
|
|
568
|
+
},
|
|
569
|
+
1000
|
|
570
|
+
);
|
|
571
|
+
} ());
|
|
572
|
+
|
|
573
|
+
(function () {
|
|
574
|
+
var pub = fake.createClient("pubsub-2"),
|
|
575
|
+
sub1 = fake.createClient("pubsub-2"),
|
|
576
|
+
sub2 = fake.createClient("pubsub-2"),
|
|
577
|
+
|
|
578
|
+
un1 = [],
|
|
579
|
+
tcb1 = test("PUBSUB UNSUBSCRIBE from all", null, [ "one", 3, "two", 2, "three", 1 ]),
|
|
580
|
+
|
|
581
|
+
un2 = [],
|
|
582
|
+
tcb2 = test("PUBSUB PUNSUBSCRIBE from all", null, [ "on?", 3, "tw?", 2, "thre?", 1 ]),
|
|
583
|
+
|
|
584
|
+
good = [],
|
|
585
|
+
tcb3 = test("subscribed correctly", null, [ "A", "B", "C", "A", "B", "C" ]),
|
|
586
|
+
|
|
587
|
+
bad = [],
|
|
588
|
+
tcb4 = test("unsubscribed correctly", null, []),
|
|
589
|
+
|
|
590
|
+
msg = [ 'A', 'B', 'C' ],
|
|
591
|
+
|
|
592
|
+
x = 0,
|
|
593
|
+
y = 0,
|
|
594
|
+
tcb5 = test("sub / unsub counters", null, [ 8, 6 ]);
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
sub1.SUBSCRIBE('one');
|
|
598
|
+
sub1.SUBSCRIBE('two', 'three');
|
|
599
|
+
sub2.PSUBSCRIBE('on?');
|
|
600
|
+
sub2.PSUBSCRIBE('tw?', 'thre?');
|
|
601
|
+
|
|
602
|
+
sub1.PSUBSCRIBE('t?st');
|
|
603
|
+
sub2.SUBSCRIBE('test');
|
|
604
|
+
|
|
605
|
+
sub1.on('message', function (pat, channel, message) {
|
|
606
|
+
bad.push(message);
|
|
607
|
+
});
|
|
608
|
+
sub2.on('pmessage', function (channel, message) {
|
|
609
|
+
bad.push(message);
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
sub1.on('pmessage', function (pat, channel, message) {
|
|
613
|
+
good.push(message);
|
|
614
|
+
});
|
|
615
|
+
sub2.on('message', function (channel, message) {
|
|
616
|
+
good.push(message);
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
sub1.on('subscribe', function () {
|
|
621
|
+
start ();
|
|
622
|
+
});
|
|
623
|
+
sub1.on('psubscribe', function () {
|
|
624
|
+
start ();
|
|
625
|
+
});
|
|
626
|
+
sub2.on('subscribe', function () {
|
|
627
|
+
start ();
|
|
628
|
+
});
|
|
629
|
+
sub2.on('psubscribe', function () {
|
|
630
|
+
start ();
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
function start() {
|
|
634
|
+
x ++;
|
|
635
|
+
if (x < 8)
|
|
636
|
+
return;
|
|
637
|
+
|
|
638
|
+
sub1.UNSUBSCRIBE ();
|
|
639
|
+
sub2.PUNSUBSCRIBE ();
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
sub1.on('unsubscribe', function (channel, count) {
|
|
644
|
+
un1.push(channel, count);
|
|
645
|
+
end ();
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
sub2.on('punsubscribe', function (pattern, count) {
|
|
649
|
+
un2.push(pattern, count);
|
|
650
|
+
end ();
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
function end() {
|
|
654
|
+
y ++;
|
|
655
|
+
if (y < 4 )
|
|
656
|
+
return;
|
|
657
|
+
|
|
658
|
+
pub.PUBLISH('test', msg.shift());
|
|
659
|
+
if (y === 4 )
|
|
660
|
+
pub.PUBLISH('three', 'ignored', test("PUB ignored", null, 0));
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
// Test the state a bit later.
|
|
665
|
+
|
|
666
|
+
setTimeout(
|
|
667
|
+
function () {
|
|
668
|
+
tcb1(null, un1);
|
|
669
|
+
tcb2(null, un2);
|
|
670
|
+
tcb3(null, good);
|
|
671
|
+
tcb4(null, bad);
|
|
672
|
+
tcb5(null, [ x, y ]);
|
|
673
|
+
},
|
|
674
|
+
1000
|
|
675
|
+
);
|
|
676
|
+
} ());
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
// More blocking list stuff.
|
|
680
|
+
|
|
681
|
+
(function () {
|
|
682
|
+
fake.createClient().BLPOP("list", "mylist", "BL-a", 1, test("BLPOP timeout", null, null));
|
|
683
|
+
fake.createClient().BRPOP("list", "mylist", "BL-a", 1, test("BRPOP timeout", null, null));
|
|
684
|
+
fake.createClient().BRPOPLPUSH("list", "mylist", "BL-a", 1, test("BRPOPLPUSH timeout", null, null));
|
|
685
|
+
} ());
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
// Connection state changes and other weirdness.
|
|
689
|
+
|
|
690
|
+
(function () {
|
|
691
|
+
var redis1 = fake.createClient("weird"),
|
|
692
|
+
redis2 = fake.createClient("weird"),
|
|
693
|
+
redis3 = fake.createClient("weird");
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
redis1.multi()
|
|
697
|
+
.SET("hello", "world" )
|
|
698
|
+
.BLPOP("nonex", 0, test("BLPOP in transaction", null, null))
|
|
699
|
+
.LPUSH("step-1", "", test("LPUSH empty string", null, 1))
|
|
700
|
+
.exec ();
|
|
701
|
+
|
|
702
|
+
redis1.BRPOP("step-3", 0, test("BRPOPLPUSH step 3, chain worked.", null, [ "step-3", "" ]));
|
|
703
|
+
|
|
704
|
+
redis1.MULTI()
|
|
705
|
+
.get("hello", test("GET transblocktrans", null, "redis"))
|
|
706
|
+
.blpop("nonex", 0, test("BLPOP in postblock transaction", null, null))
|
|
707
|
+
.publish("hello", "world", test("PUBLISH in postblock transaction", null, 1))
|
|
708
|
+
.exec ();
|
|
709
|
+
|
|
710
|
+
redis2.BRPOPLPUSH("step-2", "step-3", 0, test("BRPOPLPUSH step 2", null, ""));
|
|
711
|
+
redis2.SET("hello", "redis");
|
|
712
|
+
|
|
713
|
+
redis3.BRPOPLPUSH("step-1", "step-2", 0, test("BRPOPLPUSH step 1", null, ""));
|
|
714
|
+
redis3.SUBSCRIBE("hello");
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
redis3.on('message', function (channel, message) {
|
|
718
|
+
if (channel === 'hello' && message === 'world')
|
|
719
|
+
redis3.UNSUBSCRIBE ();
|
|
720
|
+
});
|
|
721
|
+
|
|
722
|
+
redis3.on('unsubscribe', function (channel) {
|
|
723
|
+
if (channel === 'hello')
|
|
724
|
+
redis3.LPUSH("end-message", "Hello World!");
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
redis1.BLPOP("end-message", 0, test("Multi + Blocking + Pubsub, end result", null, [ "end-message", "Hello World!" ]));
|
|
729
|
+
} ());
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
// Sort.
|
|
733
|
+
|
|
734
|
+
(function () {
|
|
735
|
+
var redis = fake.createClient(),
|
|
736
|
+
result;
|
|
737
|
+
|
|
738
|
+
// Simple num and alpha sort.
|
|
739
|
+
|
|
740
|
+
redis.LPUSH("list", "2", "11", 3, 1);
|
|
741
|
+
redis.SORT("list", test("SORT num", null, [ "1", "2", "3", "11" ]));
|
|
742
|
+
redis.DEL("list");
|
|
743
|
+
|
|
744
|
+
redis.LPUSH("list", "2", "a", "11", 3, 1, "A", "-", "_", ".", "~", "*");
|
|
745
|
+
redis.SORT("list", test("SORT scorefail", BAD_SORT, null));
|
|
746
|
+
redis.SORT("list", "alpha", test("SORT alpha", null, [ "*", "-", ".", "1", "11", "2", "3", "A", "_", "a", "~" ]));
|
|
747
|
+
redis.DEL("list");
|
|
748
|
+
|
|
749
|
+
// By clause.
|
|
750
|
+
|
|
751
|
+
redis.LPUSH("list", 11, 22, "hello", "abra", "opa");
|
|
752
|
+
redis.SET("w11w", -1);
|
|
753
|
+
redis.SET("w22w", 1);
|
|
754
|
+
redis.SORT("list", "by", "w*w", test("SORT num by +MVs, str*", null, [ "11", "abra", "hello", "opa", "22" ]));
|
|
755
|
+
redis.DEL("list", "w11w", "w22w");
|
|
756
|
+
|
|
757
|
+
// Test BY and GET clauses.
|
|
758
|
+
|
|
759
|
+
redis.LPUSH("list", 11, 22, 33, 44, 55);
|
|
760
|
+
redis.SADD ("set", 11, 22, 33, 44, 55);
|
|
761
|
+
redis.ZADD ("zset", 0, 11, 0, 22, 0, 33, 0, 44, 0, 55);
|
|
762
|
+
|
|
763
|
+
redis.HMSET("o11", "name", "tuti", "age", 25);
|
|
764
|
+
redis.HMSET("o22", "name", "ivo", "age", 26);
|
|
765
|
+
redis.HMSET("o33", "name", "lino", "age", 27);
|
|
766
|
+
redis.HMSET("o44", "name", "mina", "age", 20);
|
|
767
|
+
redis.HMSET("o55", "name", "kemi", "age", 18);
|
|
768
|
+
|
|
769
|
+
result = [ "55", "kemi", "44", "mina", "11", "tuti", "22", "ivo", "33", "lino" ];
|
|
770
|
+
|
|
771
|
+
redis.SORT("list", "by", "o*->age", "get", "#", "get", "o*->name", test("SORT list by+get, h*->f", null, result));
|
|
772
|
+
redis.SORT("set", "by", "o*->age", "get", "#", "get", "o*->name", test("SORT set by+get, h*->f", null, result));
|
|
773
|
+
redis.SORT("zset", "by", "o*->age", "get", "#", "get", "o*->name", test("SORT zset by+get, h*->f", null, result));
|
|
774
|
+
|
|
775
|
+
redis.SORT("zset", "by", "o*->age", "get", "#", "get", "o*->name", "store", "storekey", test("SORT zset by+get, h*->f, STORE", null, result.length));
|
|
776
|
+
redis.LRANGE("storekey", 0, -1, test("SORT zset by+get, h*->f, STORE / LRANGE", null, result));
|
|
777
|
+
|
|
778
|
+
// Negative offset behaves differently here and in ZRANGEBYSCORE
|
|
779
|
+
|
|
780
|
+
redis.SORT("list", "by", "o*->age", "limit", 0, 2, "get", "#", "get", "o*->name", test("SORT limit", null, result.slice(0, 4 )));
|
|
781
|
+
redis.SORT("list", "by", "o*->age", "limit", 2, 4, "get", "#", "get", "o*->name", test("SORT limit +offset", null, result.slice(4 )));
|
|
782
|
+
redis.SORT("list", "by", "o*->age", "limit", 2, -10, "get", "#", "get", "o*->name", test("SORT limit +negcount", null, result.slice(4 )));
|
|
783
|
+
redis.SORT("list", "by", "o*->age", "limit", -2, 2, "get", "#", "get", "o*->name", test("SORT limit +negoffset+negcount", null, result.slice(0, 4 )));
|
|
784
|
+
|
|
785
|
+
redis.HSET("o11", "age", "not-a-number");
|
|
786
|
+
redis.SORT("list", "by", "o*->age", "get", "#", "get", "o*->name", test("SORT by+scorefail", BAD_SORT, null));
|
|
787
|
+
|
|
788
|
+
// Edge cases.
|
|
789
|
+
|
|
790
|
+
redis.SORT("nonex", test("SORT nonex", null, []));
|
|
791
|
+
redis.SORT("nonex", "by", "o*->age", test("SORT nonex+by", null, []));
|
|
792
|
+
redis.SORT("nonex", "by", "o*->age", "get", "#", "get", "o*->name", test("SORT nonex+by+get", null, []));
|
|
793
|
+
redis.SET("hello", "world");
|
|
794
|
+
redis.SORT("hello", test("SORT bad type", BAD_TYPE, null));
|
|
795
|
+
} ());
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
// Keyspace dump.
|
|
799
|
+
|
|
800
|
+
(function () {
|
|
801
|
+
var redis = fake.createClient();
|
|
802
|
+
|
|
803
|
+
redis.SET("hello", "redis");
|
|
804
|
+
redis.SET("mykey", "some string");
|
|
805
|
+
redis.SADD("myset", "m3", "m2", "m1");
|
|
806
|
+
redis.ZADD("myzset", 10, "zm1", 5, "zm2", -5, "zm3");
|
|
807
|
+
redis.HMSET("myhash", "field1", "value1", "field2", "value2");
|
|
808
|
+
redis.LPUSH("mylist", "e1", "e2", "e3");
|
|
809
|
+
|
|
810
|
+
redis.getKeyspace("my*", test(
|
|
811
|
+
"keyspace dump, all types", null,
|
|
812
|
+
[
|
|
813
|
+
"myhash", "-1", "hash", [ "field1", "value1", "field2", "value2" ],
|
|
814
|
+
"mykey", "-1", "string", "some string",
|
|
815
|
+
"mylist", "-1", "list", [ "e3", "e2", "e1" ],
|
|
816
|
+
"myset", "-1", "set", [ "m1", "m2", "m3" ],
|
|
817
|
+
"myzset", "-1", "zset", [ "zm3", "-5", "zm2", "5", "zm1", "10" ]
|
|
818
|
+
]
|
|
819
|
+
));
|
|
820
|
+
|
|
821
|
+
//
|
|
822
|
+
redis.end();
|
|
823
|
+
} ());
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
// Select.
|
|
827
|
+
|
|
828
|
+
(function () {
|
|
829
|
+
var redis1 = fake.createClient("select-test");
|
|
830
|
+
var redis2 = fake.createClient("select-test");
|
|
831
|
+
var redis3 = fake.createClient("select-test");
|
|
832
|
+
|
|
833
|
+
var finish = test("SELECT, cross-database pubsub", null, "Hey you!");
|
|
834
|
+
|
|
835
|
+
redis2.SUBSCRIBE("PASS");
|
|
836
|
+
redis2.on('message', function (channel, message) {
|
|
837
|
+
finish(null, message);
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
redis1.SET("A", "Hola");
|
|
841
|
+
redis1.SELECT(1, test("SELECT 1", null, OK));
|
|
842
|
+
|
|
843
|
+
redis1.GET("A", test("SELECT, keyspace isolation", null, null));
|
|
844
|
+
redis1.SET("A", "Hello", function () {
|
|
845
|
+
|
|
846
|
+
redis3.GET("A", test("SELECT, connection selection isolation", null, "Hola"));
|
|
847
|
+
redis3.SET("A", "Hola!!!", function () {
|
|
848
|
+
|
|
849
|
+
redis1.SELECT(0, test("SELECT 0", null, OK));
|
|
850
|
+
redis1.GET("A", test("SELECT, keyspace switching", null, "Hola!!!"));
|
|
851
|
+
|
|
852
|
+
redis1.SELECT(-1, test("SELECT BAD_DB neg", BAD_DB, null));
|
|
853
|
+
redis1.SELECT("X", test("SELECT BAD_DB X", BAD_DB, null));
|
|
854
|
+
redis1.SELECT(111.4, test("SELECT BAD_DB float", BAD_DB, null));
|
|
855
|
+
|
|
856
|
+
redis1.SELECT(2000, test("SELECT 2000", null, OK));
|
|
857
|
+
redis1.PUBLISH("PASS", "Hey you!");
|
|
858
|
+
});
|
|
859
|
+
});
|
|
860
|
+
} ());
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
// Select with blocking.
|
|
864
|
+
|
|
865
|
+
(function () {
|
|
866
|
+
var redis1 = fake.createClient("select-test2");
|
|
867
|
+
var redis2 = fake.createClient("select-test2");
|
|
868
|
+
var redis3 = fake.createClient("select-test2");
|
|
869
|
+
|
|
870
|
+
redis1.BLPOP("list", "other", 1, test("SELECT 0 + BLPOP", null, ["list", "hello list in 0"]));
|
|
871
|
+
|
|
872
|
+
redis2.SELECT(1);
|
|
873
|
+
redis2.BRPOP("other", "list", 1, test("SELECT 1 + BRPOP", null, ["list", "hello list in 1"]));
|
|
874
|
+
|
|
875
|
+
redis3.SELECT(2);
|
|
876
|
+
redis3.LPUSH("list", "wrong!");
|
|
877
|
+
redis3.SELECT(1);
|
|
878
|
+
redis3.LPUSH("list", "hello list in 1");
|
|
879
|
+
redis3.SELECT(0);
|
|
880
|
+
redis3.RPUSH("list", "hello list in 0");
|
|
881
|
+
} ());
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+
// Buffers.
|
|
885
|
+
|
|
886
|
+
(function () {
|
|
887
|
+
var redis = fake.createClient(null, null, { return_buffers: true });
|
|
888
|
+
|
|
889
|
+
function randBuf() {
|
|
890
|
+
var n = Math.ceil(Math.random() * 1024);
|
|
891
|
+
var buf = new Buffer(n);
|
|
892
|
+
while (n --)
|
|
893
|
+
buf[n] = Math.round(Math.random() * 256);
|
|
894
|
+
|
|
895
|
+
return buf;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
var k1 = randBuf();
|
|
899
|
+
var v1 = randBuf();
|
|
900
|
+
|
|
901
|
+
redis.SET(k1, v1, test("SET bufbuf", null, new Buffer(OK)));
|
|
902
|
+
redis.GET(k1, test("GET bufbuf", null, v1));
|
|
903
|
+
} ());
|
|
904
|
+
|
|
905
|
+
|
|
906
|
+
// Scan & co.
|
|
907
|
+
|
|
908
|
+
(function () {
|
|
909
|
+
var redis = fake.createClient();
|
|
910
|
+
|
|
911
|
+
redis.SADD('myset', 'what', 'woo', 'woot', 'www');
|
|
912
|
+
redis.ZADD('myzset', 1, 'what', 4, 'woo', 3, 'woot', 2, 'www');
|
|
913
|
+
redis.HMSET('myhash', 'key1', 'val1', 'key2', 'val2');
|
|
914
|
+
|
|
915
|
+
redis.SCAN(0, test('SCAN 0 all', null, ['0', ['myset', 'myzset', 'myhash']]));
|
|
916
|
+
redis.SCAN(0, 'COUNT', 2, test('SCAN 0 COUNT 2', null, ['2', ['myset', 'myzset']]));
|
|
917
|
+
redis.SCAN(2, 'COUNT', 2, test('SCAN COUNT 2 rest', null, ['0', ['myhash']]));
|
|
918
|
+
redis.SCAN(0, 'MATCH', '*z*', test('SCAN MATCH 1', null, ['0', ['myzset']]));
|
|
919
|
+
redis.SCAN(0, 'MATCH', 'none', test('SCAN MATCH none', null, ['0', []]));
|
|
920
|
+
redis.SCAN(0, 'MATCH', '*set', 'COUNT', 1, test('SCAN MATCH COUNT', null, ['1', ['myset']]));
|
|
921
|
+
redis.SCAN(0, 'MATCH', '*zset', 'COUNT', 1, test('SCAN MATCH COUNT empty', null, ['1', []]));
|
|
922
|
+
redis.SCAN(1, 'MATCH', '*zset', 'COUNT', 1, test('SCAN MATCH COUNT mid', null, ['2', ['myzset']]));
|
|
923
|
+
redis.SCAN(0, 'MATCH', '*set', 'COUNT', 0, test('SCAN MATCH COUNT 0', null, ['0', []]));
|
|
924
|
+
|
|
925
|
+
redis.SSCAN('myset', 0, test('SSCAN 0 all', null, ['0', ['what', 'woo', 'woot', 'www']]));
|
|
926
|
+
redis.SSCAN('myset', 0, 'COUNT', 2, test('SSCAN 0 COUNT 2', null, ['2', ['what', 'woo']]));
|
|
927
|
+
redis.SSCAN('myset', 2, 'COUNT', 2, test('SSCAN COUNT 2 rest', null, ['0', ['woot', 'www']]));
|
|
928
|
+
redis.SSCAN('myset', 0, 'MATCH', '*o', test('SSCAN MATCH 1', null, ['0', ['woo']]));
|
|
929
|
+
|
|
930
|
+
redis.HSCAN('myhash', 0, test('HSCAN', null, ['0', ['key1', 'val1', 'key2', 'val2']]));
|
|
931
|
+
redis.HSCAN('myhash', 0, 'MATCH', '*y2', test('HSCAN MATCH', null, ['0', ['key2', 'val2']]));
|
|
932
|
+
|
|
933
|
+
redis.ZSCAN('myzset', 0, test('ZSCAN', null, ['0', ['what', '1', 'www', '2', 'woot', '3', 'woo', '4']]));
|
|
934
|
+
redis.ZSCAN('myzset', 0, 'MATCH', 'wo*', test('ZSCAN MATCH', null, ['0', ['woot', '3', 'woo', '4']]));
|
|
935
|
+
|
|
936
|
+
} ());
|
|
937
|
+
|
|
938
|
+
|
|
939
|
+
// Test shorthand.
|
|
940
|
+
|
|
941
|
+
var TEST_COUNT, numErrors, numOk;
|
|
942
|
+
|
|
943
|
+
function areEqualBuffers(b1, b2) {
|
|
944
|
+
if (!Buffer.isBuffer(b1))
|
|
945
|
+
return false;
|
|
946
|
+
if (!Buffer.isBuffer(b2))
|
|
947
|
+
return false;
|
|
948
|
+
|
|
949
|
+
if (b1.length !== b2.length)
|
|
950
|
+
return false;
|
|
951
|
+
|
|
952
|
+
var n = b1.length;
|
|
953
|
+
while (n--)
|
|
954
|
+
if (b1[n] !== b2[n])
|
|
955
|
+
return false;
|
|
956
|
+
|
|
957
|
+
return true;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
function test(name, xErr, xData) {
|
|
961
|
+
var timeout,
|
|
962
|
+
c = (TEST_COUNT = (TEST_COUNT || 0) + 1);
|
|
963
|
+
|
|
964
|
+
xErr = JSON.stringify(xErr);
|
|
965
|
+
if (!Buffer.isBuffer(xData))
|
|
966
|
+
xData = JSON.stringify(xData);
|
|
967
|
+
|
|
968
|
+
timeout = setTimeout(
|
|
969
|
+
function () {
|
|
970
|
+
numErrors = (numErrors || 0 ) + 1;
|
|
971
|
+
process.stdout.write('\x1B[1;31m\n ✗ #' + c + ' ' + name + '\x1B[0m:\n\tDidn\'t call back.\n\txErr = ' + xErr + '\t\txData = ' + xData + '\n\n');
|
|
972
|
+
},
|
|
973
|
+
5000
|
|
974
|
+
);
|
|
975
|
+
|
|
976
|
+
return function (err, data) {
|
|
977
|
+
clearTimeout(timeout);
|
|
978
|
+
if (err)
|
|
979
|
+
err = err.message;
|
|
980
|
+
|
|
981
|
+
err = JSON.stringify(err);
|
|
982
|
+
if (!Buffer.isBuffer(data))
|
|
983
|
+
data = JSON.stringify(data);
|
|
984
|
+
|
|
985
|
+
if (err === xErr && (Buffer.isBuffer(xData) ? areEqualBuffers(data, xData) : data === xData)) {
|
|
986
|
+
numOk = (numOk || 0) + 1;
|
|
987
|
+
process.stdout.write('\x1B[1;32m ✓ #' + c + ' ' + name + '\x1B[0m\n');
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
else {
|
|
991
|
+
numErrors = (numErrors || 0 ) + 1;
|
|
992
|
+
process.stdout.write('\x1B[1;31m\n ✗ #' + c + ' ' + name + '\x1B[0m:\n\terr = ' + err + '\t\tdata = ' + data + '\n\txErr = ' + xErr + '\t\txData = ' + xData + '\n\n');
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
|
|
998
|
+
// Suite self-validate and known test count check.
|
|
999
|
+
|
|
1000
|
+
function countTests() {
|
|
1001
|
+
|
|
1002
|
+
// Counts the number of tests in tests.js.
|
|
1003
|
+
// -1 because this matches the function defition too.
|
|
1004
|
+
var tests = require('fs').readFileSync('./test.js', 'utf8');
|
|
1005
|
+
return tests.match(/[^a-z0-9_$]test\s*\(/g).length - 1;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
var NUM_TESTS = countTests();
|
|
1009
|
+
if (NUM_TESTS !== 286)
|
|
1010
|
+
throw new Error("Test count is off: " + NUM_TESTS);
|
|
1011
|
+
|
|
1012
|
+
process.on('exit', function () {
|
|
1013
|
+
if (TEST_COUNT > NUM_TESTS)
|
|
1014
|
+
throw new Error("Update NUM_TESTS when adding stuff to the test suite.");
|
|
1015
|
+
|
|
1016
|
+
if (!numErrors && numOk === TEST_COUNT && numOk === NUM_TESTS) {
|
|
1017
|
+
process.stdout.write('\n\x1B[1;32m ✓ All good (' + numOk + ').\x1B[0m\n');
|
|
1018
|
+
process.exit(0);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
else {
|
|
1022
|
+
process.stdout.write('\x1B[1;31m\n ✗ ' + numErrors + ' broken.\x1B[0m\n');
|
|
1023
|
+
process.exit(1);
|
|
1024
|
+
}
|
|
1025
|
+
});
|