]>
Commit | Line | Data |
---|---|---|
24f753a8 PN |
1 | #include <stdio.h> |
2 | #include <stdlib.h> | |
3 | #include <string.h> | |
4 | #include <strings.h> | |
5 | #include <sys/time.h> | |
6 | #include <assert.h> | |
7 | #include <unistd.h> | |
57c9babd | 8 | #include <signal.h> |
9703b1b3 | 9 | #include <errno.h> |
24f753a8 PN |
10 | |
11 | #include "hiredis.h" | |
12 | ||
13 | /* The following lines make up our testing "framework" :) */ | |
14 | static int tests = 0, fails = 0; | |
15 | #define test(_s) { printf("#%02d ", ++tests); printf(_s); } | |
16 | #define test_cond(_c) if(_c) printf("PASSED\n"); else {printf("FAILED\n"); fails++;} | |
17 | ||
18 | static long long usec(void) { | |
19 | struct timeval tv; | |
20 | gettimeofday(&tv,NULL); | |
21 | return (((long long)tv.tv_sec)*1000000)+tv.tv_usec; | |
22 | } | |
23 | ||
24 | static int use_unix = 0; | |
25 | static redisContext *blocking_context = NULL; | |
26 | static void __connect(redisContext **target) { | |
27 | *target = blocking_context = (use_unix ? | |
28 | redisConnectUnix("/tmp/redis.sock") : redisConnect((char*)"127.0.0.1", 6379)); | |
29 | if (blocking_context->err) { | |
30 | printf("Connection error: %s\n", blocking_context->errstr); | |
31 | exit(1); | |
32 | } | |
33 | } | |
34 | ||
9703b1b3 | 35 | static void test_format_commands(void) { |
24f753a8 PN |
36 | char *cmd; |
37 | int len; | |
38 | ||
39 | test("Format command without interpolation: "); | |
40 | len = redisFormatCommand(&cmd,"SET foo bar"); | |
41 | test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && | |
42 | len == 4+4+(3+2)+4+(3+2)+4+(3+2)); | |
43 | free(cmd); | |
44 | ||
45 | test("Format command with %%s string interpolation: "); | |
46 | len = redisFormatCommand(&cmd,"SET %s %s","foo","bar"); | |
47 | test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && | |
48 | len == 4+4+(3+2)+4+(3+2)+4+(3+2)); | |
49 | free(cmd); | |
50 | ||
a1e97d69 PN |
51 | test("Format command with %%s and an empty string: "); |
52 | len = redisFormatCommand(&cmd,"SET %s %s","foo",""); | |
53 | test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && | |
54 | len == 4+4+(3+2)+4+(3+2)+4+(0+2)); | |
55 | free(cmd); | |
56 | ||
9703b1b3 PN |
57 | test("Format command with an empty string in between proper interpolations: "); |
58 | len = redisFormatCommand(&cmd,"SET %s %s","","foo"); | |
59 | test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$0\r\n\r\n$3\r\nfoo\r\n",len) == 0 && | |
60 | len == 4+4+(3+2)+4+(0+2)+4+(3+2)); | |
61 | free(cmd); | |
62 | ||
24f753a8 PN |
63 | test("Format command with %%b string interpolation: "); |
64 | len = redisFormatCommand(&cmd,"SET %b %b","foo",3,"b\0r",3); | |
65 | test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nb\0r\r\n",len) == 0 && | |
66 | len == 4+4+(3+2)+4+(3+2)+4+(3+2)); | |
67 | free(cmd); | |
68 | ||
a1e97d69 PN |
69 | test("Format command with %%b and an empty string: "); |
70 | len = redisFormatCommand(&cmd,"SET %b %b","foo",3,"",0); | |
71 | test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && | |
72 | len == 4+4+(3+2)+4+(3+2)+4+(0+2)); | |
73 | free(cmd); | |
74 | ||
75 | test("Format command with literal %%: "); | |
76 | len = redisFormatCommand(&cmd,"SET %% %%"); | |
77 | test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$1\r\n%\r\n$1\r\n%\r\n",len) == 0 && | |
78 | len == 4+4+(3+2)+4+(1+2)+4+(1+2)); | |
79 | free(cmd); | |
80 | ||
81 | test("Format command with printf-delegation (long long): "); | |
82 | len = redisFormatCommand(&cmd,"key:%08lld",1234ll); | |
83 | test_cond(strncmp(cmd,"*1\r\n$12\r\nkey:00001234\r\n",len) == 0 && | |
84 | len == 4+5+(12+2)); | |
85 | free(cmd); | |
86 | ||
87 | test("Format command with printf-delegation (float): "); | |
88 | len = redisFormatCommand(&cmd,"v:%06.1f",12.34f); | |
89 | test_cond(strncmp(cmd,"*1\r\n$8\r\nv:0012.3\r\n",len) == 0 && | |
90 | len == 4+4+(8+2)); | |
91 | free(cmd); | |
92 | ||
93 | test("Format command with printf-delegation and extra interpolation: "); | |
94 | len = redisFormatCommand(&cmd,"key:%d %b",1234,"foo",3); | |
95 | test_cond(strncmp(cmd,"*2\r\n$8\r\nkey:1234\r\n$3\r\nfoo\r\n",len) == 0 && | |
96 | len == 4+4+(8+2)+4+(3+2)); | |
97 | free(cmd); | |
98 | ||
99 | test("Format command with wrong printf format and extra interpolation: "); | |
100 | len = redisFormatCommand(&cmd,"key:%08p %b",1234,"foo",3); | |
101 | test_cond(strncmp(cmd,"*2\r\n$6\r\nkey:8p\r\n$3\r\nfoo\r\n",len) == 0 && | |
102 | len == 4+4+(6+2)+4+(3+2)); | |
103 | free(cmd); | |
104 | ||
24f753a8 PN |
105 | const char *argv[3]; |
106 | argv[0] = "SET"; | |
a1e97d69 | 107 | argv[1] = "foo\0xxx"; |
24f753a8 | 108 | argv[2] = "bar"; |
a1e97d69 | 109 | size_t lens[3] = { 3, 7, 3 }; |
24f753a8 PN |
110 | int argc = 3; |
111 | ||
112 | test("Format command by passing argc/argv without lengths: "); | |
113 | len = redisFormatCommandArgv(&cmd,argc,argv,NULL); | |
114 | test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && | |
115 | len == 4+4+(3+2)+4+(3+2)+4+(3+2)); | |
116 | free(cmd); | |
117 | ||
118 | test("Format command by passing argc/argv with lengths: "); | |
119 | len = redisFormatCommandArgv(&cmd,argc,argv,lens); | |
a1e97d69 PN |
120 | test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 && |
121 | len == 4+4+(3+2)+4+(7+2)+4+(3+2)); | |
24f753a8 PN |
122 | free(cmd); |
123 | } | |
124 | ||
9703b1b3 | 125 | static void test_blocking_connection(void) { |
24f753a8 PN |
126 | redisContext *c; |
127 | redisReply *reply; | |
a1e97d69 | 128 | int major, minor; |
24f753a8 | 129 | |
a1e97d69 PN |
130 | test("Returns error when host cannot be resolved: "); |
131 | c = redisConnect((char*)"idontexist.local", 6379); | |
132 | test_cond(c->err == REDIS_ERR_OTHER && | |
133 | strcmp(c->errstr,"Can't resolve: idontexist.local") == 0); | |
24f753a8 PN |
134 | redisFree(c); |
135 | ||
a1e97d69 PN |
136 | test("Returns error when the port is not open: "); |
137 | c = redisConnect((char*)"localhost", 56380); | |
138 | test_cond(c->err == REDIS_ERR_IO && | |
139 | strcmp(c->errstr,"Connection refused") == 0); | |
140 | redisFree(c); | |
141 | ||
142 | __connect(&c); | |
24f753a8 PN |
143 | test("Is able to deliver commands: "); |
144 | reply = redisCommand(c,"PING"); | |
145 | test_cond(reply->type == REDIS_REPLY_STATUS && | |
146 | strcasecmp(reply->str,"pong") == 0) | |
147 | freeReplyObject(reply); | |
148 | ||
149 | /* Switch to DB 9 for testing, now that we know we can chat. */ | |
150 | reply = redisCommand(c,"SELECT 9"); | |
151 | freeReplyObject(reply); | |
152 | ||
153 | /* Make sure the DB is emtpy */ | |
154 | reply = redisCommand(c,"DBSIZE"); | |
a1e97d69 PN |
155 | if (reply->type != REDIS_REPLY_INTEGER || reply->integer != 0) { |
156 | printf("Database #9 is not empty, test can not continue\n"); | |
24f753a8 | 157 | exit(1); |
24f753a8 PN |
158 | } |
159 | freeReplyObject(reply); | |
160 | ||
161 | test("Is a able to send commands verbatim: "); | |
162 | reply = redisCommand(c,"SET foo bar"); | |
163 | test_cond (reply->type == REDIS_REPLY_STATUS && | |
164 | strcasecmp(reply->str,"ok") == 0) | |
165 | freeReplyObject(reply); | |
166 | ||
167 | test("%%s String interpolation works: "); | |
168 | reply = redisCommand(c,"SET %s %s","foo","hello world"); | |
169 | freeReplyObject(reply); | |
170 | reply = redisCommand(c,"GET foo"); | |
171 | test_cond(reply->type == REDIS_REPLY_STRING && | |
172 | strcmp(reply->str,"hello world") == 0); | |
173 | freeReplyObject(reply); | |
174 | ||
175 | test("%%b String interpolation works: "); | |
176 | reply = redisCommand(c,"SET %b %b","foo",3,"hello\x00world",11); | |
177 | freeReplyObject(reply); | |
178 | reply = redisCommand(c,"GET foo"); | |
179 | test_cond(reply->type == REDIS_REPLY_STRING && | |
180 | memcmp(reply->str,"hello\x00world",11) == 0) | |
181 | ||
182 | test("Binary reply length is correct: "); | |
183 | test_cond(reply->len == 11) | |
184 | freeReplyObject(reply); | |
185 | ||
186 | test("Can parse nil replies: "); | |
187 | reply = redisCommand(c,"GET nokey"); | |
188 | test_cond(reply->type == REDIS_REPLY_NIL) | |
189 | freeReplyObject(reply); | |
190 | ||
191 | /* test 7 */ | |
192 | test("Can parse integer replies: "); | |
193 | reply = redisCommand(c,"INCR mycounter"); | |
194 | test_cond(reply->type == REDIS_REPLY_INTEGER && reply->integer == 1) | |
195 | freeReplyObject(reply); | |
196 | ||
197 | test("Can parse multi bulk replies: "); | |
198 | freeReplyObject(redisCommand(c,"LPUSH mylist foo")); | |
199 | freeReplyObject(redisCommand(c,"LPUSH mylist bar")); | |
200 | reply = redisCommand(c,"LRANGE mylist 0 -1"); | |
201 | test_cond(reply->type == REDIS_REPLY_ARRAY && | |
202 | reply->elements == 2 && | |
203 | !memcmp(reply->element[0]->str,"bar",3) && | |
204 | !memcmp(reply->element[1]->str,"foo",3)) | |
205 | freeReplyObject(reply); | |
206 | ||
207 | /* m/e with multi bulk reply *before* other reply. | |
208 | * specifically test ordering of reply items to parse. */ | |
209 | test("Can handle nested multi bulk replies: "); | |
210 | freeReplyObject(redisCommand(c,"MULTI")); | |
211 | freeReplyObject(redisCommand(c,"LRANGE mylist 0 -1")); | |
212 | freeReplyObject(redisCommand(c,"PING")); | |
213 | reply = (redisCommand(c,"EXEC")); | |
214 | test_cond(reply->type == REDIS_REPLY_ARRAY && | |
215 | reply->elements == 2 && | |
216 | reply->element[0]->type == REDIS_REPLY_ARRAY && | |
217 | reply->element[0]->elements == 2 && | |
218 | !memcmp(reply->element[0]->element[0]->str,"bar",3) && | |
219 | !memcmp(reply->element[0]->element[1]->str,"foo",3) && | |
220 | reply->element[1]->type == REDIS_REPLY_STATUS && | |
221 | strcasecmp(reply->element[1]->str,"pong") == 0); | |
222 | freeReplyObject(reply); | |
a1e97d69 PN |
223 | |
224 | { | |
225 | /* Find out Redis version to determine the path for the next test */ | |
226 | const char *field = "redis_version:"; | |
227 | char *p, *eptr; | |
228 | ||
229 | reply = redisCommand(c,"INFO"); | |
230 | p = strstr(reply->str,field); | |
231 | major = strtol(p+strlen(field),&eptr,10); | |
232 | p = eptr+1; /* char next to the first "." */ | |
233 | minor = strtol(p,&eptr,10); | |
234 | freeReplyObject(reply); | |
235 | } | |
236 | ||
237 | test("Returns I/O error when the connection is lost: "); | |
238 | reply = redisCommand(c,"QUIT"); | |
239 | if (major >= 2 && minor > 0) { | |
240 | /* > 2.0 returns OK on QUIT and read() should be issued once more | |
241 | * to know the descriptor is at EOF. */ | |
242 | test_cond(strcasecmp(reply->str,"OK") == 0 && | |
243 | redisGetReply(c,(void**)&reply) == REDIS_ERR); | |
244 | freeReplyObject(reply); | |
245 | } else { | |
246 | test_cond(reply == NULL); | |
247 | } | |
248 | ||
249 | /* On 2.0, QUIT will cause the connection to be closed immediately and | |
250 | * the read(2) for the reply on QUIT will set the error to EOF. | |
251 | * On >2.0, QUIT will return with OK and another read(2) needed to be | |
252 | * issued to find out the socket was closed by the server. In both | |
253 | * conditions, the error will be set to EOF. */ | |
254 | assert(c->err == REDIS_ERR_EOF && | |
255 | strcmp(c->errstr,"Server closed the connection") == 0); | |
9703b1b3 | 256 | redisFree(c); |
a1e97d69 | 257 | |
9703b1b3 PN |
258 | __connect(&c); |
259 | test("Returns I/O error on socket timeout: "); | |
260 | struct timeval tv = { 0, 1000 }; | |
261 | assert(redisSetTimeout(c,tv) == REDIS_OK); | |
262 | test_cond(redisGetReply(c,(void**)&reply) == REDIS_ERR && | |
263 | c->err == REDIS_ERR_IO && errno == EAGAIN); | |
a1e97d69 | 264 | redisFree(c); |
9703b1b3 PN |
265 | |
266 | /* Context should be connected */ | |
a1e97d69 | 267 | __connect(&c); |
24f753a8 PN |
268 | } |
269 | ||
9703b1b3 | 270 | static void test_reply_reader(void) { |
24f753a8 | 271 | void *reader; |
afc156c2 | 272 | void *reply; |
24f753a8 PN |
273 | char *err; |
274 | int ret; | |
275 | ||
276 | test("Error handling in reply parser: "); | |
afc156c2 | 277 | reader = redisReplyReaderCreate(); |
24f753a8 PN |
278 | redisReplyReaderFeed(reader,(char*)"@foo\r\n",6); |
279 | ret = redisReplyReaderGetReply(reader,NULL); | |
280 | err = redisReplyReaderGetError(reader); | |
281 | test_cond(ret == REDIS_ERR && | |
a1e97d69 | 282 | strcasecmp(err,"Protocol error, got \"@\" as reply type byte") == 0); |
24f753a8 PN |
283 | redisReplyReaderFree(reader); |
284 | ||
285 | /* when the reply already contains multiple items, they must be free'd | |
286 | * on an error. valgrind will bark when this doesn't happen. */ | |
287 | test("Memory cleanup in reply parser: "); | |
afc156c2 | 288 | reader = redisReplyReaderCreate(); |
24f753a8 PN |
289 | redisReplyReaderFeed(reader,(char*)"*2\r\n",4); |
290 | redisReplyReaderFeed(reader,(char*)"$5\r\nhello\r\n",11); | |
291 | redisReplyReaderFeed(reader,(char*)"@foo\r\n",6); | |
292 | ret = redisReplyReaderGetReply(reader,NULL); | |
293 | err = redisReplyReaderGetError(reader); | |
294 | test_cond(ret == REDIS_ERR && | |
a1e97d69 PN |
295 | strcasecmp(err,"Protocol error, got \"@\" as reply type byte") == 0); |
296 | redisReplyReaderFree(reader); | |
297 | ||
298 | test("Set error on nested multi bulks with depth > 1: "); | |
299 | reader = redisReplyReaderCreate(); | |
300 | redisReplyReaderFeed(reader,(char*)"*1\r\n",4); | |
301 | redisReplyReaderFeed(reader,(char*)"*1\r\n",4); | |
302 | redisReplyReaderFeed(reader,(char*)"*1\r\n",4); | |
303 | ret = redisReplyReaderGetReply(reader,NULL); | |
304 | err = redisReplyReaderGetError(reader); | |
305 | test_cond(ret == REDIS_ERR && | |
306 | strncasecmp(err,"No support for",14) == 0); | |
24f753a8 | 307 | redisReplyReaderFree(reader); |
afc156c2 PN |
308 | |
309 | test("Works with NULL functions for reply: "); | |
310 | reader = redisReplyReaderCreate(); | |
311 | redisReplyReaderSetReplyObjectFunctions(reader,NULL); | |
312 | redisReplyReaderFeed(reader,(char*)"+OK\r\n",5); | |
313 | ret = redisReplyReaderGetReply(reader,&reply); | |
314 | test_cond(ret == REDIS_OK && reply == (void*)REDIS_REPLY_STATUS); | |
315 | redisReplyReaderFree(reader); | |
57c9babd PN |
316 | |
317 | test("Works when a single newline (\\r\\n) covers two calls to feed: "); | |
318 | reader = redisReplyReaderCreate(); | |
319 | redisReplyReaderSetReplyObjectFunctions(reader,NULL); | |
320 | redisReplyReaderFeed(reader,(char*)"+OK\r",4); | |
321 | ret = redisReplyReaderGetReply(reader,&reply); | |
322 | assert(ret == REDIS_OK && reply == NULL); | |
323 | redisReplyReaderFeed(reader,(char*)"\n",1); | |
324 | ret = redisReplyReaderGetReply(reader,&reply); | |
325 | test_cond(ret == REDIS_OK && reply == (void*)REDIS_REPLY_STATUS); | |
326 | redisReplyReaderFree(reader); | |
9703b1b3 PN |
327 | |
328 | test("Properly reset state after protocol error: "); | |
329 | reader = redisReplyReaderCreate(); | |
330 | redisReplyReaderSetReplyObjectFunctions(reader,NULL); | |
331 | redisReplyReaderFeed(reader,(char*)"x",1); | |
332 | ret = redisReplyReaderGetReply(reader,&reply); | |
333 | assert(ret == REDIS_ERR); | |
334 | ret = redisReplyReaderGetReply(reader,&reply); | |
335 | test_cond(ret == REDIS_OK && reply == NULL) | |
24f753a8 PN |
336 | } |
337 | ||
9703b1b3 PN |
338 | static void test_throughput(void) { |
339 | int i, num; | |
24f753a8 PN |
340 | long long t1, t2; |
341 | redisContext *c = blocking_context; | |
342 | redisReply **replies; | |
343 | ||
344 | test("Throughput:\n"); | |
345 | for (i = 0; i < 500; i++) | |
346 | freeReplyObject(redisCommand(c,"LPUSH mylist foo")); | |
347 | ||
9703b1b3 PN |
348 | num = 1000; |
349 | replies = malloc(sizeof(redisReply*)*num); | |
24f753a8 | 350 | t1 = usec(); |
9703b1b3 | 351 | for (i = 0; i < num; i++) { |
24f753a8 PN |
352 | replies[i] = redisCommand(c,"PING"); |
353 | assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_STATUS); | |
354 | } | |
355 | t2 = usec(); | |
9703b1b3 | 356 | for (i = 0; i < num; i++) freeReplyObject(replies[i]); |
24f753a8 | 357 | free(replies); |
9703b1b3 | 358 | printf("\t(%dx PING: %.3fs)\n", num, (t2-t1)/1000000.0); |
24f753a8 | 359 | |
9703b1b3 | 360 | replies = malloc(sizeof(redisReply*)*num); |
24f753a8 | 361 | t1 = usec(); |
9703b1b3 | 362 | for (i = 0; i < num; i++) { |
24f753a8 PN |
363 | replies[i] = redisCommand(c,"LRANGE mylist 0 499"); |
364 | assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_ARRAY); | |
365 | assert(replies[i] != NULL && replies[i]->elements == 500); | |
366 | } | |
367 | t2 = usec(); | |
9703b1b3 PN |
368 | for (i = 0; i < num; i++) freeReplyObject(replies[i]); |
369 | free(replies); | |
370 | printf("\t(%dx LRANGE with 500 elements: %.3fs)\n", num, (t2-t1)/1000000.0); | |
371 | ||
372 | num = 10000; | |
373 | replies = malloc(sizeof(redisReply*)*num); | |
374 | for (i = 0; i < num; i++) | |
375 | redisAppendCommand(c,"PING"); | |
376 | t1 = usec(); | |
377 | for (i = 0; i < num; i++) { | |
378 | assert(redisGetReply(c, (void*)&replies[i]) == REDIS_OK); | |
379 | assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_STATUS); | |
380 | } | |
381 | t2 = usec(); | |
382 | for (i = 0; i < num; i++) freeReplyObject(replies[i]); | |
383 | free(replies); | |
384 | printf("\t(%dx PING (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); | |
385 | ||
386 | replies = malloc(sizeof(redisReply*)*num); | |
387 | for (i = 0; i < num; i++) | |
388 | redisAppendCommand(c,"LRANGE mylist 0 499"); | |
389 | t1 = usec(); | |
390 | for (i = 0; i < num; i++) { | |
391 | assert(redisGetReply(c, (void*)&replies[i]) == REDIS_OK); | |
392 | assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_ARRAY); | |
393 | assert(replies[i] != NULL && replies[i]->elements == 500); | |
394 | } | |
395 | t2 = usec(); | |
396 | for (i = 0; i < num; i++) freeReplyObject(replies[i]); | |
24f753a8 | 397 | free(replies); |
9703b1b3 | 398 | printf("\t(%dx LRANGE with 500 elements (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); |
24f753a8 PN |
399 | } |
400 | ||
9703b1b3 | 401 | static void cleanup(void) { |
24f753a8 PN |
402 | redisContext *c = blocking_context; |
403 | redisReply *reply; | |
404 | ||
405 | /* Make sure we're on DB 9 */ | |
406 | reply = redisCommand(c,"SELECT 9"); | |
407 | assert(reply != NULL); freeReplyObject(reply); | |
408 | reply = redisCommand(c,"FLUSHDB"); | |
409 | assert(reply != NULL); freeReplyObject(reply); | |
410 | redisFree(c); | |
411 | } | |
412 | ||
413 | // static long __test_callback_flags = 0; | |
414 | // static void __test_callback(redisContext *c, void *privdata) { | |
415 | // ((void)c); | |
416 | // /* Shift to detect execution order */ | |
417 | // __test_callback_flags <<= 8; | |
418 | // __test_callback_flags |= (long)privdata; | |
419 | // } | |
420 | // | |
421 | // static void __test_reply_callback(redisContext *c, redisReply *reply, void *privdata) { | |
422 | // ((void)c); | |
423 | // /* Shift to detect execution order */ | |
424 | // __test_callback_flags <<= 8; | |
425 | // __test_callback_flags |= (long)privdata; | |
426 | // if (reply) freeReplyObject(reply); | |
427 | // } | |
428 | // | |
429 | // static redisContext *__connect_nonblock() { | |
430 | // /* Reset callback flags */ | |
431 | // __test_callback_flags = 0; | |
432 | // return redisConnectNonBlock("127.0.0.1", 6379, NULL); | |
433 | // } | |
434 | // | |
435 | // static void test_nonblocking_connection() { | |
436 | // redisContext *c; | |
437 | // int wdone = 0; | |
438 | // | |
439 | // test("Calls command callback when command is issued: "); | |
440 | // c = __connect_nonblock(); | |
441 | // redisSetCommandCallback(c,__test_callback,(void*)1); | |
442 | // redisCommand(c,"PING"); | |
443 | // test_cond(__test_callback_flags == 1); | |
444 | // redisFree(c); | |
445 | // | |
446 | // test("Calls disconnect callback on redisDisconnect: "); | |
447 | // c = __connect_nonblock(); | |
448 | // redisSetDisconnectCallback(c,__test_callback,(void*)2); | |
449 | // redisDisconnect(c); | |
450 | // test_cond(__test_callback_flags == 2); | |
451 | // redisFree(c); | |
452 | // | |
453 | // test("Calls disconnect callback and free callback on redisFree: "); | |
454 | // c = __connect_nonblock(); | |
455 | // redisSetDisconnectCallback(c,__test_callback,(void*)2); | |
456 | // redisSetFreeCallback(c,__test_callback,(void*)4); | |
457 | // redisFree(c); | |
458 | // test_cond(__test_callback_flags == ((2 << 8) | 4)); | |
459 | // | |
460 | // test("redisBufferWrite against empty write buffer: "); | |
461 | // c = __connect_nonblock(); | |
462 | // test_cond(redisBufferWrite(c,&wdone) == REDIS_OK && wdone == 1); | |
463 | // redisFree(c); | |
464 | // | |
465 | // test("redisBufferWrite against not yet connected fd: "); | |
466 | // c = __connect_nonblock(); | |
467 | // redisCommand(c,"PING"); | |
468 | // test_cond(redisBufferWrite(c,NULL) == REDIS_ERR && | |
469 | // strncmp(c->error,"write:",6) == 0); | |
470 | // redisFree(c); | |
471 | // | |
472 | // test("redisBufferWrite against closed fd: "); | |
473 | // c = __connect_nonblock(); | |
474 | // redisCommand(c,"PING"); | |
475 | // redisDisconnect(c); | |
476 | // test_cond(redisBufferWrite(c,NULL) == REDIS_ERR && | |
477 | // strncmp(c->error,"write:",6) == 0); | |
478 | // redisFree(c); | |
479 | // | |
480 | // test("Process callbacks in the right sequence: "); | |
481 | // c = __connect_nonblock(); | |
482 | // redisCommandWithCallback(c,__test_reply_callback,(void*)1,"PING"); | |
483 | // redisCommandWithCallback(c,__test_reply_callback,(void*)2,"PING"); | |
484 | // redisCommandWithCallback(c,__test_reply_callback,(void*)3,"PING"); | |
485 | // | |
486 | // /* Write output buffer */ | |
487 | // wdone = 0; | |
488 | // while(!wdone) { | |
489 | // usleep(500); | |
490 | // redisBufferWrite(c,&wdone); | |
491 | // } | |
492 | // | |
493 | // /* Read until at least one callback is executed (the 3 replies will | |
494 | // * arrive in a single packet, causing all callbacks to be executed in | |
495 | // * a single pass). */ | |
496 | // while(__test_callback_flags == 0) { | |
497 | // assert(redisBufferRead(c) == REDIS_OK); | |
498 | // redisProcessCallbacks(c); | |
499 | // } | |
500 | // test_cond(__test_callback_flags == 0x010203); | |
501 | // redisFree(c); | |
502 | // | |
503 | // test("redisDisconnect executes pending callbacks with NULL reply: "); | |
504 | // c = __connect_nonblock(); | |
505 | // redisSetDisconnectCallback(c,__test_callback,(void*)1); | |
506 | // redisCommandWithCallback(c,__test_reply_callback,(void*)2,"PING"); | |
507 | // redisDisconnect(c); | |
508 | // test_cond(__test_callback_flags == 0x0201); | |
509 | // redisFree(c); | |
510 | // } | |
511 | ||
512 | int main(int argc, char **argv) { | |
513 | if (argc > 1) { | |
514 | if (strcmp(argv[1],"-s") == 0) | |
515 | use_unix = 1; | |
516 | } | |
517 | ||
518 | signal(SIGPIPE, SIG_IGN); | |
519 | test_format_commands(); | |
520 | test_blocking_connection(); | |
521 | test_reply_reader(); | |
522 | // test_nonblocking_connection(); | |
523 | test_throughput(); | |
524 | cleanup(); | |
525 | ||
526 | if (fails == 0) { | |
527 | printf("ALL TESTS PASSED\n"); | |
528 | } else { | |
529 | printf("*** %d TESTS FAILED ***\n", fails); | |
530 | } | |
531 | return 0; | |
532 | } |