UNPKG

9.58 kBMarkdownView Raw
1
2
3# fakeredis - a fake redis for node.js
4
5
6This module provides easy-to-use simulated instances of Redis
7to which you appear to be connected via the
8[redis](https://github.com/mranney/node_redis) client by [Matt Ranney](https://github.com/mranney).
9**It helps with writing tests** in two ways:
10your tests won't require an actual redis instance
11and you'll be able to safely run as many tests in parallel as you want.
12
13[![NPM Version](https://nodei.co/npm/fakeredis.png?downloads=true)](https://npmjs.org/package/fakeredis)
14[![Build Status](https://secure.travis-ci.org/hdachev/fakeredis.png?branch=master)](http://travis-ci.org/hdachev/fakeredis)
15
16
17## Usage
18
19Install:
20
21 npm install fakeredis
22
23You can use fakeredis as you would use node_redis,
24just changing the module name from `redis` to `fakeredis`:
25
26```javascript
27var client = require("fakeredis").createClient(port, host);
28```
29
30Both parameters are optional,
31and only serve to determine if you want to reuse a an existing fakeredis instance or not.
32You can also just name your backends arbitrarily:
33
34```javascript
35
36// Create a connection to a fresh fakeredis instance:
37var client = fakeredis.createClient("social stuff");
38
39// Connect to the same backend via another simulated connection:
40var concurrentClient = fakeredis.createClient("social stuff");
41```
42
43By omitting both parameters,
44you simply create a new blank slate fakeredis instance:
45
46```javascript
47var client = require("fakeredis").createClient();
48```
49
50
51In other words,
52every time you create a client specifying the same port and/or name
53you reuse the same simulated backend.
54This makes most sense when you need a concurrent client setup for some test,
55say because you need to publish / subscribe,
56or because you want to test something that's based on `MULTI`/`EXEC`
57and uses optimistic locking with `WATCH`/`UNWATCH`.
58
59In any case, fakeredis is great for testing
60because you can run as many tests in parallel as you wish,
61and that's also why you'll generally be naming your clients
62in a way that ensures tests don't collide.
63
64
65
66## Intended differences from a true Redis
67
68One key difference is that the output of some commands,
69such as `SMEMBERS`, `HKEYS`, `HVALS`,
70comes out sorted lexicographically to provide for simpler testing.
71This means that some tests that make use of undocumented Redis behaviours
72such as the chronological order of retrieval for members in a set
73may fail when attempted with fakeredis.
74To solve this,
75whenever there is no documented sort order for a given Redis command's multi-bulk reply,
76sort the output before asserting equality to ensure your tests run everywhere.
77
78Another major difference is that commands that accept modifier parameters, such as
79`SORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]`
80currently only accept these parameters in the order that is stated in the documentation.
81For example,
82in Redis it appears to be perfectly legitimate to have `SORT myset ALPHA LIMIT 0 5`,
83but in fakeredis this will currently return a syntax error.
84
85I'm totally open to discussion on both points.
86
87
88### Implemented subset:
89
90All string, list, hash, set and sorted set commands,
91most keyspace commands, and some connection and server commands.
92Pubsub, transactions with optimistic locking are also fully implemented.
93
94List of **available** commands:
95
96Keyspace:
97
98 DBSIZE
99 EXISTS
100 EXPIRE
101 EXPIREAT
102 FLUSHDB
103 KEYS
104 PERSIST
105 DEL
106 RANDOMKEY
107 RENAME
108 RENAMENX
109 SORT
110 TTL
111 TYPE
112
113Strings:
114
115 APPEND
116 DECR
117 DECRBY
118 GET
119 GETBIT
120 GETRANGE
121 GETSET
122 INCR
123 INCRBY
124 MGET
125 MSET
126 MSETNX
127 SET
128 SETBIT
129 SETEX
130 SETNX
131 SETRANGE
132
133Hashes:
134
135 HDEL
136 HEXISTS
137 HGET
138 HGETALL
139 HINCRBY
140 HKEYS
141 HLEN
142 HMGET
143 HMSET
144 HSET
145 HSETNX
146 HVALS
147
148Lists:
149
150 BLPOP
151 BRPOP
152 BRPOPLPUSH
153 LINDEX
154 LINSERT
155 LLEN
156 LPOP
157 LPUSH
158 LPUSHX
159 LRANGE
160 LREM
161 LSET
162 LTRIM
163 RPOP
164 RPOPLPUSH
165 RPUSH
166 RPUSHX
167
168Sets:
169
170 SADD
171 SCARD
172 SDIFF
173 SDIFFSTORE
174 SINTER
175 SINTERSTORE
176 SISMEMBER
177 SMEMBERS
178 SMOVE
179 SPOP
180 SRANDMEMBER
181 SREM
182 STRLEN
183 SUNION
184 SUNIONSTORE
185
186Sorted Sets:
187
188 ZADD
189 ZCARD
190 ZCOUNT
191 ZINCRBY
192 ZINTERSTORE
193 ZRANGE
194 ZRANGEBYSCORE
195 ZRANK
196 ZREM
197 ZREMRANGEBYRANK
198 ZREMRANGEBYSCORE
199 ZREVRANGE
200 ZREVRANGEBYSCORE
201 ZREVRANK
202 ZSCORE
203 ZUNIONSTORE
204
205Pub/Sub:
206
207 PSUBSCRIBE
208 PUBLISH
209 PUNSUBSCRIBE
210 SUBSCRIBE
211 UNSUBSCRIBE
212
213Transactions:
214
215 DISCARD
216 EXEC
217 MULTI
218 UNWATCH
219 WATCH
220
221Connection and Server:
222
223 ECHO
224 PING
225 QUIT
226 SELECT
227
228These do nothing but return `OK`:
229
230 AUTH
231 BGREWRITEAOF
232 BGSAVE
233 SAVE
234
235
236### What's missing:
237
238Most notably, `MONITOR` is still missing.
239
240Also note that **none of the node_redis client constructor options are available**,
241which means no `detect_buffers` and `return_buffers`.
242Command arguments are always stringified at the fake connection level,
243and replies are always returned as `null`, `String`, `Number` or `Array`.
244
245Finally,
246none of the `ready`, `connect`, `error`, `end`, `drain` and `idle`
247client events are currently implemented.
248
249List of **missing** commands (will throw upon attempt to use):
250
251Connection and Server:
252
253 CONFIG GET
254 CONFIG SET
255 CONFIG RESETSTAT
256 DEBUG OBJECT
257 DEBUG SEGFAULT
258 FLUSHALL
259 INFO
260 LASTSAVE
261 MONITOR
262 MOVE
263 OBJECT
264 SHUTDOWN
265 SLAVEOF
266 SYNC
267
268
269
270## Helpers
271
272To facilitate development and testing,
273fakeredis provides some additional methods on the client object.
274
275
276### Prettyprinting:
277
278```javascript
279fakeredisClient.pretty();
280fakeredisClient.pretty("p*tte?n");
281fakeredisClient.pretty(options);
282```
283
284`.pretty()` will prettyprint to stdout the entire keyspace
285or a subset of keys specificed with a redis pattern
286of the same kind that's used for `KEYS` and `PSUBSCRIBE`.
287Keep in mind .pretty() is async,
288because it works as a normal client command
289and hence needs to respect the command order,
290fake pipelining and latency and all,
291so that you can do stuff like:
292
293```javascript
294var client = require("fakeredis").createClient();
295
296client.SADD('hello', 'world', 'Jenny', 'Sam');
297client.LPUSH('mylist', 'hey', 'ho', 'letsgo');
298client.pretty({label: "my stuff", pattern: "*"});
299```
300
301Which would print *(in color!)*
302
303 my stuff:
304
305 set hello
306 -1 Jenny, Sam, world
307
308 list mylist
309 -1 letsgo, ho, hey
310
311
312### Keyspace dumps:
313
314```javascript
315fakeredisClient.getKeypsace(callback);
316fakeredisClient.getKeypsace("p*tte?n", callback);
317fakeredisClient.getKeyspace(options, callback);
318```
319
320Will `callback(err, data)` with an array
321that enumerates the whole keyspace,
322or the requested subset, in the following manner:
323
324```javascript
325[ key1, ttl1, type1, value1
326, key2, ttl2, type2, value2
327, ... ]
328```
329
330The keyspace is sorted lexicographically by key,
331string values are strings,
332list values are the output of `LRANGE 0 -1`,
333hashes come out as the output of `HGETALL` for hashes
334(no syntactic sugar though, so an Array of `[field, value, field, value, ...]`),
335`SMEMBERS` output is used for sets,
336and `ZRANGE 0 -1 WITHSCORES` for sorted sets,
337each of which is sorted lexicographically in a way that makes sense,
338so that the final result is simple enough to assert deep equality against.
339
340In any case, you'll probably need to reformat these keyspace dumps
341to a format that makes more sense for your testing needs.
342There are a couple of transforms that are included out of the box:
343
344```javascript
345fakeredisClient.getKeypsace({pattern: "myz*", map: true}, callback);
346```
347
348If you only care about the key and value of each entry,
349you can set the **map** option to a truthy value,
350you will instead receive the keyspace dump as a key-value map of the kind:
351
352```javascript
353{ key1: value1, key2: value2, ... }
354```
355
356This means you're skipping ttl and key type info though. You can also do:
357
358```javascript
359fakeredisClient.getKeypsace({pattern: "myz*", group: true}, callback);
360```
361
362Which will return an `Array` of `Array`s,
363one for each keyspace entry, so that you end up with:
364
365```javascript
366[ [ key1, ttl1, type1, value1 ]
367, [ key2, ttl2, type2, value2 ]
368, ... ]
369```
370
371The benefit of this option is that you can sort the outer array as you like more easily.
372
373
374
375## Similar projects
376
377You might also want to check out these similar implementations in
378[python](https://github.com/jamesls/fakeredis) and
379[ruby](https://github.com/guilleiguaran/fakeredis).
380
381
382
383## MIT License
384
385Copyright (c) 2012 Hristo Dachev
386
387Permission is hereby granted, free of charge, to any person
388obtaining a copy of this software and associated documentation
389files (the "Software"), to deal in the Software without
390restriction, including without limitation the rights to use,
391copy, modify, merge, publish, distribute, sublicense, and/or sell
392copies of the Software, and to permit persons to whom the
393Software is furnished to do so, subject to the following
394conditions:
395
396The above copyright notice and this permission notice shall be
397included in all copies or substantial portions of the Software.
398
399THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
400EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
401OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
402NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
403HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
404WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
405FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
406OTHER DEALINGS IN THE SOFTWARE.
407