UNPKG

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