1 /*
2  * ProFTPD - FTP server testsuite
3  * Copyright (c) 2017-2021 The ProFTPD Project team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  *
19  * As a special exemption, The ProFTPD Project team and other respective
20  * copyright holders give permission to link this program with OpenSSL, and
21  * distribute the resulting executable, without including the source code for
22  * OpenSSL in the source distribution.
23  */
24 
25 /* Redis API tests. */
26 
27 #include "tests.h"
28 
29 #ifdef PR_USE_REDIS
30 
31 static pool *p = NULL;
32 static const char *redis_server = "127.0.0.1";
33 static int redis_port = 6379;
34 
35 /* Fixtures */
36 
set_up(void)37 static void set_up(void) {
38   char *redis_host = NULL;
39 
40   if (p == NULL) {
41     p = permanent_pool = make_sub_pool(NULL);
42   }
43 
44   redis_init();
45   redis_set_server(redis_server, redis_port, 0UL, NULL, NULL);
46 
47   if (getenv("TEST_VERBOSE") != NULL) {
48     pr_trace_set_levels("redis", 1, 20);
49   }
50 }
51 
tear_down(void)52 static void tear_down(void) {
53   if (getenv("TEST_VERBOSE") != NULL) {
54     pr_trace_set_levels("redis", 0, 0);
55   }
56 
57   redis_clear();
58 
59   if (p) {
60     destroy_pool(p);
61     p = permanent_pool = NULL;
62   }
63 }
64 
65 /* Tests */
66 
START_TEST(redis_conn_destroy_test)67 START_TEST (redis_conn_destroy_test) {
68   int res;
69 
70   mark_point();
71   res = pr_redis_conn_destroy(NULL);
72   fail_unless(res < 0, "Failed to handle null redis");
73   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
74     strerror(errno), errno);
75 }
76 END_TEST
77 
START_TEST(redis_conn_close_test)78 START_TEST (redis_conn_close_test) {
79   int res;
80 
81   mark_point();
82   res = pr_redis_conn_close(NULL);
83   fail_unless(res < 0, "Failed to handle null redis");
84   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
85     strerror(errno), errno);
86 }
87 END_TEST
88 
START_TEST(redis_conn_new_test)89 START_TEST (redis_conn_new_test) {
90   int res;
91   pr_redis_t *redis;
92 
93   mark_point();
94   redis = pr_redis_conn_new(NULL, NULL, 0);
95   fail_unless(redis == NULL, "Failed to handle null pool");
96   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
97     strerror(errno), errno);
98 
99   mark_point();
100   redis = pr_redis_conn_new(p, NULL, 0);
101   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
102     strerror(errno));
103 
104   mark_point();
105   res = pr_redis_conn_destroy(redis);
106   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
107 
108   if (getenv("CI") == NULL &&
109       getenv("CIRRUS_CLONE_DEPTH") == NULL &&
110       getenv("TRAVIS") == NULL) {
111     /* Now deliberately set the wrong server and port. */
112     redis_set_server("127.1.2.3", redis_port, 0UL, NULL, NULL);
113 
114     mark_point();
115     redis = pr_redis_conn_new(p, NULL, 0);
116     fail_unless(redis == NULL, "Failed to handle invalid address");
117     fail_unless(errno == EIO, "Expected EIO (%d), got %s (%d)", EIO,
118       strerror(errno), errno);
119   }
120 
121   redis_set_server(redis_server, 1020, 0UL, NULL, NULL);
122 
123   mark_point();
124   redis = pr_redis_conn_new(p, NULL, 0);
125   fail_unless(redis == NULL, "Failed to handle invalid port");
126   fail_unless(errno == EIO, "Expected EIO (%d), got %s (%d)", EIO,
127     strerror(errno), errno);
128 
129   /* Restore our testing server/port. */
130   redis_set_server(redis_server, redis_port, 0UL, NULL, NULL);
131 }
132 END_TEST
133 
START_TEST(redis_conn_get_test)134 START_TEST (redis_conn_get_test) {
135   int res;
136   pr_redis_t *redis, *redis2;
137 
138   mark_point();
139   redis = pr_redis_conn_get(NULL, 0UL);
140   fail_unless(redis == NULL, "Failed to handle null pool");
141   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
142     strerror(errno), errno);
143 
144   mark_point();
145   redis = pr_redis_conn_get(p, 0UL);
146   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
147     strerror(errno));
148 
149   mark_point();
150   res = pr_redis_conn_destroy(redis);
151   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
152 
153   mark_point();
154   redis = pr_redis_conn_get(p, 0UL);
155   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
156     strerror(errno));
157 
158   mark_point();
159   redis2 = pr_redis_conn_get(p, 0UL);
160   fail_unless(redis2 != NULL, "Failed to open connection to Redis: %s",
161     strerror(errno));
162   fail_unless(redis == redis2, "Expected %p, got %p", redis, redis2);
163 
164   mark_point();
165   res = pr_redis_conn_destroy(redis);
166   fail_unless(res == FALSE, "Expected FALSE, got TRUE");
167 
168   mark_point();
169   res = pr_redis_conn_destroy(redis);
170   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
171 }
172 END_TEST
173 
START_TEST(redis_conn_set_namespace_test)174 START_TEST (redis_conn_set_namespace_test) {
175   int res;
176   pr_redis_t *redis;
177   module m;
178   const char *prefix;
179   size_t prefixsz;
180 
181   mark_point();
182   res = pr_redis_conn_set_namespace(NULL, NULL, NULL, 0);
183   fail_unless(res < 0, "Failed to handle null redis");
184   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
185     strerror(errno), errno);
186 
187   mark_point();
188   redis = pr_redis_conn_new(p, NULL, 0);
189   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
190     strerror(errno));
191 
192   mark_point();
193   res = pr_redis_conn_set_namespace(redis, NULL, NULL, 0);
194   fail_unless(res < 0, "Failed to handle null module");
195   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
196     strerror(errno), errno);
197 
198   mark_point();
199   res = pr_redis_conn_set_namespace(redis, &m, NULL, 0);
200   fail_unless(res == 0, "Failed to set null namespace prefix: %s",
201     strerror(errno));
202 
203   prefix = "test.";
204   prefixsz = strlen(prefix);
205 
206   mark_point();
207   res = pr_redis_conn_set_namespace(redis, &m, prefix, 0);
208   fail_unless(res < 0, "Failed to handle empty namespace prefix");
209   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
210     strerror(errno), errno);
211 
212   mark_point();
213   res = pr_redis_conn_set_namespace(redis, &m, prefix, prefixsz);
214   fail_unless(res == 0, "Failed to set namespace prefix '%s': %s", prefix,
215     strerror(errno));
216 
217   mark_point();
218   res = pr_redis_conn_set_namespace(redis, &m, NULL, 0);
219   fail_unless(res == 0, "Failed to set null namespace prefix: %s",
220     strerror(errno));
221 
222   mark_point();
223   res = pr_redis_conn_destroy(redis);
224   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
225 }
226 END_TEST
227 
START_TEST(redis_conn_get_version_test)228 START_TEST (redis_conn_get_version_test) {
229   int res;
230   pr_redis_t *redis;
231   unsigned int major = 0, minor = 0, patch = 0;
232 
233   mark_point();
234   res = pr_redis_conn_get_version(NULL, NULL, NULL, NULL);
235   fail_unless(res < 0, "Failed to handle null redis");
236   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
237     strerror(errno), errno);
238 
239   mark_point();
240   redis = pr_redis_conn_new(p, NULL, 0);
241   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
242     strerror(errno));
243 
244   mark_point();
245   res = pr_redis_conn_get_version(redis, NULL, NULL, NULL);
246   fail_unless(res < 0, "Failed to handle null version arguments");
247   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
248     strerror(errno), errno);
249 
250   mark_point();
251   res = pr_redis_conn_get_version(redis, &major, &minor, &patch);
252   fail_unless(res == 0, "Failed to get Redis version: %s", strerror(errno));
253 
254   mark_point();
255   res = pr_redis_conn_destroy(redis);
256   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
257 }
258 END_TEST
259 
START_TEST(redis_conn_auth_test)260 START_TEST (redis_conn_auth_test) {
261   int res;
262   pr_redis_t *redis;
263   const char *text;
264   array_header *args;
265   unsigned int major_version = 0;
266 
267   mark_point();
268   res = pr_redis_auth(NULL, NULL);
269   fail_unless(res < 0, "Failed to handle null redis");
270   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
271     strerror(errno), errno);
272 
273   mark_point();
274   redis = pr_redis_conn_new(p, NULL, 0);
275   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
276     strerror(errno));
277 
278   mark_point();
279   res = pr_redis_auth(redis, NULL);
280   fail_unless(res < 0, "Failed to handle null password");
281   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
282     strerror(errno), errno);
283 
284   /* What happens if we try to AUTH to a non-password-protected Redis?
285    * Answer: Redis returns an error indicating that no password is required.
286    *
287    * Note that this behavior changed with Redis 6.x.  In particular, any
288    * "AUTH default ..." command automatically succeeds with Redis 6.x,
289    * regardless of the actual password given.  Sigh.
290    */
291 
292   mark_point();
293   res = pr_redis_conn_get_version(redis, &major_version, NULL, NULL);
294   fail_unless(res == 0, "Failed to get Redis version: %s", strerror(errno));
295 
296   mark_point();
297   text = "password";
298   res = pr_redis_auth(redis, text);
299 
300   if (major_version < 6) {
301     fail_unless(res < 0, "Failed to handle lack of need for authentication");
302     fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
303       strerror(errno), errno);
304 
305     /* Use CONFIG SET to require a password. */
306     args = make_array(p, 0, sizeof(char *));
307     *((char **) push_array(args)) = pstrdup(p, "CONFIG");
308     *((char **) push_array(args)) = pstrdup(p, "SET");
309     *((char **) push_array(args)) = pstrdup(p, "requirepass");
310     *((char **) push_array(args)) = pstrdup(p, text);
311 
312     mark_point();
313     res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
314     fail_unless(res == 0, "Failed to enable authentication: %s",
315       strerror(errno));
316 
317     args = make_array(p, 0, sizeof(char *));
318     *((char **) push_array(args)) = pstrdup(p, "TIME");
319 
320     mark_point();
321     res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_ARRAY);
322     fail_unless(res < 0, "Failed to handle required authentication");
323     fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
324       strerror(errno), errno);
325 
326     mark_point();
327     res = pr_redis_auth(redis, text);
328     fail_unless(res == 0, "Failed to authenticate client: %s", strerror(errno));
329 
330     /* Don't forget to remove the password. */
331     args = make_array(p, 0, sizeof(char *));
332     *((char **) push_array(args)) = pstrdup(p, "CONFIG");
333     *((char **) push_array(args)) = pstrdup(p, "SET");
334     *((char **) push_array(args)) = pstrdup(p, "requirepass");
335     *((char **) push_array(args)) = pstrdup(p, "");
336 
337     mark_point();
338     res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
339     fail_unless(res == 0, "Failed to remove password authentication: %s",
340       strerror(errno));
341 
342   } else {
343     fail_unless(res == 0, "Failed to handle AUTH command: %s",
344       strerror(errno));
345   }
346 
347   mark_point();
348   res = pr_redis_conn_destroy(redis);
349   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
350 }
351 END_TEST
352 
START_TEST(redis_conn_auth2_test)353 START_TEST (redis_conn_auth2_test) {
354   int res;
355   pr_redis_t *redis;
356   const char *username, *password;
357   array_header *args;
358   unsigned int major_version = 0;
359 
360   mark_point();
361   res = pr_redis_auth2(NULL, NULL, NULL);
362   fail_unless(res < 0, "Failed to handle null redis");
363   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
364     strerror(errno), errno);
365 
366   mark_point();
367   redis = pr_redis_conn_new(p, NULL, 0);
368   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
369     strerror(errno));
370 
371   mark_point();
372   res = pr_redis_auth2(redis, NULL, NULL);
373   fail_unless(res < 0, "Failed to handle null username");
374   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
375     strerror(errno), errno);
376 
377   /* Note: Do NOT use "default" as the initial username; that name has
378    * specific semantics for Redis 6.x and later.
379    */
380   username = "foobar";
381 
382   mark_point();
383   res = pr_redis_auth2(redis, username, NULL);
384   fail_unless(res < 0, "Failed to handle null password");
385   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
386     strerror(errno), errno);
387 
388   /* What happens if we try to AUTH to a non-password-protected Redis?
389    * Answer: Redis returns an error indicating that no password is required.
390    *
391    * Note that this behavior changed with Redis 6.x.  In particular, any
392    * "AUTH default ..." command automatically succeeds with Redis 6.x,
393    * regardless of the actual password given.  Sigh.
394    */
395 
396   mark_point();
397   res = pr_redis_conn_get_version(redis, &major_version, NULL, NULL);
398   fail_unless(res == 0, "Failed to get Redis version: %s", strerror(errno));
399 
400   mark_point();
401   password = "password";
402   res = pr_redis_auth2(redis, username, password);
403   fail_unless(res < 0, "Failed to handle lack of need for authentication");
404   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
405     strerror(errno), errno);
406 
407   if (major_version < 6) {
408     /* Use CONFIG SET to require a password. */
409     args = make_array(p, 0, sizeof(char *));
410     *((char **) push_array(args)) = pstrdup(p, "CONFIG");
411     *((char **) push_array(args)) = pstrdup(p, "SET");
412     *((char **) push_array(args)) = pstrdup(p, "requirepass");
413     *((char **) push_array(args)) = pstrdup(p, password);
414 
415     mark_point();
416     res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
417     fail_unless(res == 0, "Failed to enable authentication: %s",
418       strerror(errno));
419 
420     args = make_array(p, 0, sizeof(char *));
421     *((char **) push_array(args)) = pstrdup(p, "TIME");
422 
423     mark_point();
424     res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_ARRAY);
425     fail_unless(res < 0, "Failed to handle required authentication");
426     fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
427       strerror(errno), errno);
428 
429     mark_point();
430     res = pr_redis_auth2(redis, username, password);
431     fail_unless(res == 0, "Failed to authenticate client: %s", strerror(errno));
432 
433     /* Don't forget to remove the password. */
434     args = make_array(p, 0, sizeof(char *));
435     *((char **) push_array(args)) = pstrdup(p, "CONFIG");
436     *((char **) push_array(args)) = pstrdup(p, "SET");
437     *((char **) push_array(args)) = pstrdup(p, "requirepass");
438     *((char **) push_array(args)) = pstrdup(p, "");
439 
440     mark_point();
441     res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STATUS);
442     fail_unless(res == 0, "Failed to remove password authentication: %s",
443       strerror(errno));
444   }
445 
446   mark_point();
447   res = pr_redis_conn_destroy(redis);
448   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
449 }
450 END_TEST
451 
START_TEST(redis_conn_select_test)452 START_TEST (redis_conn_select_test) {
453   int res;
454   pr_redis_t *redis;
455   const char *text;
456 
457   mark_point();
458   res = pr_redis_select(NULL, NULL);
459   fail_unless(res < 0, "Failed to handle null redis");
460   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
461     strerror(errno), errno);
462 
463   mark_point();
464   redis = pr_redis_conn_new(p, NULL, 0);
465   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
466     strerror(errno));
467 
468   mark_point();
469   res = pr_redis_select(redis, NULL);
470   fail_unless(res < 0, "Failed to handle null db_idx");
471   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
472     strerror(errno), errno);
473 
474   mark_point();
475   text = "-1";
476   res = pr_redis_select(redis, text);
477   fail_unless(res < 0, "Failed to handle invalid index %s", text);
478   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
479     strerror(errno), errno);
480 
481   mark_point();
482   text = "100";
483   res = pr_redis_select(redis, text);
484   fail_unless(res < 0, "Failed to handle invalid index %s", text);
485   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
486     strerror(errno), errno);
487 
488   mark_point();
489   text = "someotherlabel";
490   res = pr_redis_select(redis, text);
491   fail_unless(res < 0, "Failed to handle invalid index %s", text);
492   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
493     strerror(errno), errno);
494 
495   mark_point();
496   text = "0";
497   res = pr_redis_select(redis, text);
498   fail_unless(res == 0, "Failed to select database %s: %s", text,
499     strerror(errno));
500 
501   mark_point();
502   text = "1";
503   res = pr_redis_select(redis, text);
504   fail_unless(res == 0, "Failed to select database %s: %s", text,
505     strerror(errno));
506 
507   mark_point();
508   res = pr_redis_conn_destroy(redis);
509   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
510 }
511 END_TEST
512 
START_TEST(redis_conn_reconnect_test)513 START_TEST (redis_conn_reconnect_test) {
514   int res;
515   pr_redis_t *redis;
516   array_header *args;
517 
518   /* Note: This test is intended to be run manually, locally. */
519 
520   if (getenv("REDIS_RECONNECT") == NULL) {
521     return;
522   }
523 
524   mark_point();
525   redis = pr_redis_conn_new(p, NULL, 0);
526   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
527     strerror(errno));
528 
529   /* Now we PAUSE, and elsewhere, stop/start the Redis server, breaking the
530    * connection.
531    */
532   pr_trace_msg("redis", 1, "PAUSING test while admin restarts Redis server");
533   pr_timer_sleep(15);
534   pr_trace_msg("redis", 1, "RESUMING test");
535 
536   args = make_array(p, 0, sizeof(char *));
537   *((char **) push_array(args)) = pstrdup(p, "INFO");
538 
539   /* This first one should fail, due to the reconnect. */
540   mark_point();
541   res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STRING);
542   fail_unless(res < 0, "Failed to handle reconnect");
543   fail_unless(errno == EIO, "Expected EIO (%d), got %s (%d)", EIO,
544     strerror(errno), errno);
545 
546   mark_point();
547   res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STRING);
548   fail_unless(res == 0, "Failed to handle valid command with array: %s",
549     strerror(errno));
550 
551 
552   mark_point();
553   res = pr_redis_conn_destroy(redis);
554   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
555 }
556 END_TEST
557 
START_TEST(redis_command_test)558 START_TEST (redis_command_test) {
559   int res;
560   pr_redis_t *redis;
561   array_header *args;
562 
563   mark_point();
564   res = pr_redis_command(NULL, NULL, 0);
565   fail_unless(res < 0, "Failed to handle null redis");
566   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
567     strerror(errno), errno);
568 
569   mark_point();
570   redis = pr_redis_conn_new(p, NULL, 0);
571   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
572     strerror(errno));
573 
574   mark_point();
575   res = pr_redis_command(redis, NULL, 0);
576   fail_unless(res < 0, "Failed to handle null args");
577   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
578     strerror(errno), errno);
579 
580   args = make_array(p, 0, sizeof(char *));
581 
582   mark_point();
583   res = pr_redis_command(redis, args, 0);
584   fail_unless(res < 0, "Failed to handle empty args");
585   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
586     strerror(errno), errno);
587 
588   *((char **) push_array(args)) = pstrdup(p, "FOO");
589 
590   mark_point();
591   res = pr_redis_command(redis, args, -1);
592   fail_unless(res < 0, "Failed to handle invalid reply type");
593   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
594     strerror(errno), errno);
595 
596   mark_point();
597   res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_ERROR);
598   fail_unless(res == 0, "Failed to handle invalid command with error: %s",
599     strerror(errno));
600 
601   args = make_array(p, 0, sizeof(char *));
602   *((char **) push_array(args)) = pstrdup(p, "COMMAND");
603   *((char **) push_array(args)) = pstrdup(p, "COUNT");
604 
605   mark_point();
606   res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_INTEGER);
607   fail_unless(res == 0, "Failed to handle valid command with integer: %s",
608     strerror(errno));
609 
610   args = make_array(p, 0, sizeof(char *));
611   *((char **) push_array(args)) = pstrdup(p, "INFO");
612 
613   mark_point();
614   res = pr_redis_command(redis, args, PR_REDIS_REPLY_TYPE_STRING);
615   fail_unless(res == 0, "Failed to handle valid command with array: %s",
616     strerror(errno));
617 
618   mark_point();
619   res = pr_redis_conn_destroy(redis);
620   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
621 }
622 END_TEST
623 
START_TEST(redis_sentinel_get_master_addr_test)624 START_TEST (redis_sentinel_get_master_addr_test) {
625   int res;
626   pr_redis_t *redis;
627   pr_netaddr_t *addr = NULL;
628   const char *name;
629 
630   mark_point();
631   res = pr_redis_sentinel_get_master_addr(NULL, NULL, NULL, NULL);
632   fail_unless(res < 0, "Failed to handle null pool");
633   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
634     strerror(errno), errno);
635 
636   mark_point();
637   res = pr_redis_sentinel_get_master_addr(p, NULL, NULL, NULL);
638   fail_unless(res < 0, "Failed to handle null redis");
639   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
640     strerror(errno), errno);
641 
642   mark_point();
643   redis = pr_redis_conn_new(p, NULL, 0);
644   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
645     strerror(errno));
646 
647   mark_point();
648   res = pr_redis_sentinel_get_master_addr(p, redis, NULL, NULL);
649   fail_unless(res < 0, "Failed to handle null name");
650   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
651     strerror(errno), errno);
652 
653   mark_point();
654   name = "foobar";
655   res = pr_redis_sentinel_get_master_addr(p, redis, name, NULL);
656   fail_unless(res < 0, "Failed to handle null addr");
657   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
658     strerror(errno), errno);
659 
660   mark_point();
661   name = "foobar";
662   res = pr_redis_sentinel_get_master_addr(p, redis, name, &addr);
663   fail_unless(res < 0, "Failed to handle invalid sentinel");
664   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
665     strerror(errno), errno);
666 
667   mark_point();
668   res = pr_redis_conn_destroy(redis);
669   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
670 }
671 END_TEST
672 
START_TEST(redis_sentinel_get_masters_test)673 START_TEST (redis_sentinel_get_masters_test) {
674   int res;
675   pr_redis_t *redis;
676   array_header *masters = NULL;
677 
678   mark_point();
679   res = pr_redis_sentinel_get_masters(NULL, NULL, NULL);
680   fail_unless(res < 0, "Failed to handle null pool");
681   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
682     strerror(errno), errno);
683 
684   mark_point();
685   res = pr_redis_sentinel_get_masters(p, NULL, NULL);
686   fail_unless(res < 0, "Failed to handle null redis");
687   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
688     strerror(errno), errno);
689 
690   mark_point();
691   redis = pr_redis_conn_new(p, NULL, 0);
692   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
693     strerror(errno));
694 
695   mark_point();
696   res = pr_redis_sentinel_get_masters(p, redis, NULL);
697   fail_unless(res < 0, "Failed to handle null masters");
698   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
699     strerror(errno), errno);
700 
701   mark_point();
702   res = pr_redis_sentinel_get_masters(p, redis, &masters);
703   fail_unless(res < 0, "Failed to handle invalid sentinel");
704   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
705     strerror(errno), errno);
706 
707   mark_point();
708   res = pr_redis_conn_destroy(redis);
709   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
710 }
711 END_TEST
712 
START_TEST(redis_sentinel_conn_new_test)713 START_TEST (redis_sentinel_conn_new_test) {
714   int res;
715   pr_redis_t *redis;
716   array_header *sentinels = NULL;
717   const char *master = NULL;
718   const pr_netaddr_t *addr;
719 
720   /* Deliberately set the wrong server and port; we want to discover the
721    * correct host/port via the Sentinels.
722    */
723   redis_set_server(NULL, -2, 0UL, NULL, NULL);
724 
725   sentinels = make_array(p, 0, sizeof(pr_netaddr_t *));
726 
727   if (getenv("CI") != NULL ||
728       getenv("CIRRUS_CLONE_DEPTH") != NULL ||
729       getenv("TRAVIS") != NULL) {
730     /* Treat the local Redis server as a Sentinel. */
731     addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL);
732     pr_netaddr_set_port2((pr_netaddr_t *) addr, 6379);
733     *((pr_netaddr_t **) push_array(sentinels)) = (pr_netaddr_t *) addr;
734 
735     mark_point();
736     res = redis_set_sentinels(sentinels, NULL);
737     fail_unless(res == 0, "Failed to set sentinel list: %s", strerror(errno));
738 
739     mark_point();
740     redis = pr_redis_conn_new(p, NULL, 0);
741     fail_unless(redis == NULL, "Failed to handle invald sentinels");
742     fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
743       strerror(errno), errno);
744 
745     /* Restore our testing server/port. */
746     redis_set_server(redis_server, redis_port, 0UL, NULL, NULL);
747     redis_set_sentinels(NULL, NULL);
748 
749     return;
750   }
751 
752   mark_point();
753   res = redis_set_sentinels(sentinels, NULL);
754   fail_unless(res < 0, "Failed to handle empty sentinel list");
755   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
756     strerror(errno), errno);
757 
758   /* Set a list of bad sentinels */
759   addr = pr_netaddr_get_addr(p, "127.1.2.3", NULL);
760   pr_netaddr_set_port2((pr_netaddr_t *) addr, 26379);
761   *((pr_netaddr_t **) push_array(sentinels)) = (pr_netaddr_t *) addr;
762 
763   addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL);
764   pr_netaddr_set_port2((pr_netaddr_t *) addr, 16379);
765   *((pr_netaddr_t **) push_array(sentinels)) = (pr_netaddr_t *) addr;
766 
767   mark_point();
768   res = redis_set_sentinels(sentinels, NULL);
769   fail_unless(res == 0, "Failed to set sentinels: %s", strerror(errno));
770 
771   mark_point();
772   redis = pr_redis_conn_new(p, NULL, 0);
773   fail_unless(redis == NULL, "Failed to handle invalid sentinels");
774   fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
775     strerror(errno), errno);
776 
777   /* Set a list of one bad, one good sentinel -- use "bad" master" */
778   sentinels = make_array(p, 0, sizeof(pr_netaddr_t *));
779   master = "foobar";
780 
781   addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL);
782   pr_netaddr_set_port2((pr_netaddr_t *) addr, 16379);
783   *((pr_netaddr_t **) push_array(sentinels)) = (pr_netaddr_t *) addr;
784 
785   addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL);
786   pr_netaddr_set_port2((pr_netaddr_t *) addr, 26379);
787   *((pr_netaddr_t **) push_array(sentinels)) = (pr_netaddr_t *) addr;
788 
789   mark_point();
790   res = redis_set_sentinels(sentinels, master);
791   fail_unless(res == 0, "Failed to set sentinels: %s", strerror(errno));
792 
793   mark_point();
794   redis = pr_redis_conn_new(p, NULL, 0);
795   fail_unless(redis == NULL, "Failed to handle invalid master");
796   fail_unless(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
797     strerror(errno), errno);
798 
799   /* Set a list of one bad, one good sentinel -- use "good" master */
800   sentinels = make_array(p, 0, sizeof(pr_netaddr_t *));
801   master = "proftpd";
802 
803   addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL);
804   pr_netaddr_set_port2((pr_netaddr_t *) addr, 16379);
805   *((pr_netaddr_t **) push_array(sentinels)) = (pr_netaddr_t *) addr;
806 
807   addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL);
808   pr_netaddr_set_port2((pr_netaddr_t *) addr, 26379);
809   *((pr_netaddr_t **) push_array(sentinels)) = (pr_netaddr_t *) addr;
810 
811   mark_point();
812   res = redis_set_sentinels(sentinels, master);
813   fail_unless(res == 0, "Failed to set sentinels: %s", strerror(errno));
814 
815   mark_point();
816   redis = pr_redis_conn_new(p, NULL, 0);
817   fail_unless(redis != NULL, "Failed to discover valid master: %s",
818     strerror(errno));
819 
820   mark_point();
821   res = pr_redis_conn_destroy(redis);
822   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
823 
824   /* Set a list of one bad, one good sentinel -- use no master */
825   sentinels = make_array(p, 0, sizeof(pr_netaddr_t *));
826   master = NULL;
827 
828   addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL);
829   pr_netaddr_set_port2((pr_netaddr_t *) addr, 16379);
830   *((pr_netaddr_t **) push_array(sentinels)) = (pr_netaddr_t *) addr;
831 
832   addr = pr_netaddr_get_addr(p, "127.0.0.1", NULL);
833   pr_netaddr_set_port2((pr_netaddr_t *) addr, 26379);
834   *((pr_netaddr_t **) push_array(sentinels)) = (pr_netaddr_t *) addr;
835 
836   mark_point();
837   res = redis_set_sentinels(sentinels, master);
838   fail_unless(res == 0, "Failed to set sentinels: %s", strerror(errno));
839 
840   mark_point();
841   redis = pr_redis_conn_new(p, NULL, 0);
842   fail_unless(redis != NULL, "Failed to discover valid master: %s",
843     strerror(errno));
844 
845   mark_point();
846   res = pr_redis_conn_destroy(redis);
847   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
848 
849   /* Restore our testing server/port. */
850   redis_set_server(redis_server, redis_port, 0UL, NULL, NULL);
851   redis_set_sentinels(NULL, NULL);
852 }
853 END_TEST
854 
START_TEST(redis_remove_test)855 START_TEST (redis_remove_test) {
856   int res;
857   pr_redis_t *redis;
858   module m;
859   const char *key;
860 
861   mark_point();
862   res = pr_redis_remove(NULL, NULL, NULL);
863   fail_unless(res < 0, "Failed to handle null redis");
864   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
865     strerror(errno), errno);
866 
867   mark_point();
868   redis = pr_redis_conn_new(p, NULL, 0);
869   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
870     strerror(errno));
871 
872   mark_point();
873   res = pr_redis_remove(redis, NULL, NULL);
874   fail_unless(res < 0, "Failed to handle null module");
875   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
876     strerror(errno), errno);
877 
878   mark_point();
879   res = pr_redis_remove(redis, &m, NULL);
880   fail_unless(res < 0, "Failed to handle null key");
881   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
882     strerror(errno), errno);
883 
884   key = "testkey";
885 
886   mark_point();
887   res = pr_redis_remove(redis, &m, key);
888   fail_unless(res < 0, "Unexpectedly removed key '%s'", key);
889   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
890     strerror(errno), errno);
891 
892   mark_point();
893   res = pr_redis_conn_destroy(redis);
894   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
895 }
896 END_TEST
897 
START_TEST(redis_add_test)898 START_TEST (redis_add_test) {
899   int res;
900   pr_redis_t *redis;
901   module m;
902   const char *key;
903   char *val;
904   size_t valsz;
905   time_t expires;
906 
907   mark_point();
908   res = pr_redis_add(NULL, NULL, NULL, NULL, 0, 0);
909   fail_unless(res < 0, "Failed to handle null redis");
910   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
911     strerror(errno), errno);
912 
913   mark_point();
914   redis = pr_redis_conn_new(p, NULL, 0);
915   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
916     strerror(errno));
917 
918   mark_point();
919   res = pr_redis_add(redis, NULL, NULL, NULL, 0, 0);
920   fail_unless(res < 0, "Failed to handle null module");
921   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
922     strerror(errno), errno);
923 
924   mark_point();
925   res = pr_redis_add(redis, &m, NULL, NULL, 0, 0);
926   fail_unless(res < 0, "Failed to handle null key");
927   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
928     strerror(errno), errno);
929 
930   key = "testkey";
931 
932   mark_point();
933   res = pr_redis_add(redis, &m, key, NULL, 0, 0);
934   fail_unless(res < 0, "Failed to handle null value");
935   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
936     strerror(errno), errno);
937 
938   val = "testval";
939   valsz = strlen(val);
940   expires = 0;
941 
942   mark_point();
943   res = pr_redis_add(redis, &m, key, val, valsz, expires);
944   fail_unless(res == 0, "Failed to add key '%s', val '%s': %s", key, val,
945     strerror(errno));
946 
947   mark_point();
948   res = pr_redis_remove(redis, &m, key);
949   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
950 
951   expires = 3;
952 
953   mark_point();
954   res = pr_redis_add(redis, &m, key, val, valsz, expires);
955   fail_unless(res == 0, "Failed to add key '%s', val '%s': %s", key, val,
956     strerror(errno));
957 
958   mark_point();
959   res = pr_redis_remove(redis, &m, key);
960   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
961 
962   mark_point();
963   res = pr_redis_conn_destroy(redis);
964   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
965 }
966 END_TEST
967 
START_TEST(redis_add_with_namespace_test)968 START_TEST (redis_add_with_namespace_test) {
969   int res;
970   pr_redis_t *redis;
971   module m;
972   const char *prefix, *key;
973   char *val;
974   size_t prefixsz, valsz;
975   time_t expires;
976 
977   mark_point();
978   redis = pr_redis_conn_new(p, NULL, 0);
979   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
980     strerror(errno));
981 
982   prefix = "test.";
983   prefixsz = strlen(prefix);
984 
985   mark_point();
986   res = pr_redis_conn_set_namespace(redis, &m, prefix, prefixsz);
987   fail_unless(res == 0, "Failed to set namespace prefix '%s': %s", prefix,
988     strerror(errno));
989 
990   key = "key";
991   val = "val";
992   valsz = strlen(val);
993   expires = 0;
994 
995   mark_point();
996   res = pr_redis_add(redis, &m, key, val, valsz, expires);
997   fail_unless(res == 0, "Failed to add key '%s', val '%s': %s", key, val,
998     strerror(errno));
999 
1000   mark_point();
1001   res = pr_redis_remove(redis, &m, key);
1002   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
1003 
1004   mark_point();
1005   res = pr_redis_conn_set_namespace(redis, &m, NULL, 0);
1006   fail_unless(res == 0, "Failed to set null namespace prefix: %s",
1007     strerror(errno));
1008 
1009   mark_point();
1010   res = pr_redis_conn_destroy(redis);
1011   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
1012 }
1013 END_TEST
1014 
START_TEST(redis_get_test)1015 START_TEST (redis_get_test) {
1016   int res;
1017   pr_redis_t *redis;
1018   module m;
1019   const char *key;
1020   char *val;
1021   size_t valsz;
1022   time_t expires;
1023   void *data;
1024 
1025   mark_point();
1026   data = pr_redis_get(NULL, NULL, NULL, NULL, NULL);
1027   fail_unless(data == NULL, "Failed to handle null pool");
1028   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1029     strerror(errno), errno);
1030 
1031   mark_point();
1032   data = pr_redis_get(p, NULL, NULL, NULL, NULL);
1033   fail_unless(data == NULL, "Failed to handle null redis");
1034   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1035     strerror(errno), errno);
1036 
1037   mark_point();
1038   redis = pr_redis_conn_new(p, NULL, 0);
1039   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
1040     strerror(errno));
1041 
1042   mark_point();
1043   data = pr_redis_get(p, redis, NULL, NULL, NULL);
1044   fail_unless(data == NULL, "Failed to handle null module");
1045   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1046     strerror(errno), errno);
1047 
1048   mark_point();
1049   data = pr_redis_get(p, redis, &m, NULL, NULL);
1050   fail_unless(data == NULL, "Failed to handle null key");
1051   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1052     strerror(errno), errno);
1053 
1054   key = "testkey";
1055   (void) pr_redis_remove(redis, &m, key);
1056 
1057   mark_point();
1058   data = pr_redis_get(p, redis, &m, key, NULL);
1059   fail_unless(data == NULL, "Failed to handle null valuesz");
1060   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1061     strerror(errno), errno);
1062 
1063   mark_point();
1064   data = pr_redis_get(p, redis, &m, key, &valsz);
1065   fail_unless(data == NULL, "Failed to handle nonexistent key");
1066   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1067     strerror(errno), errno);
1068 
1069   val = "Hello, World!";
1070   valsz = strlen(val);
1071   expires = 0;
1072 
1073   mark_point();
1074   res = pr_redis_set(redis, &m, key, val, valsz, expires);
1075   fail_unless(res == 0, "Failed to set key '%s', val '%s': %s", key, val,
1076     strerror(errno));
1077 
1078   valsz = 0;
1079 
1080   mark_point();
1081   data = pr_redis_get(p, redis, &m, key, &valsz);
1082   fail_unless(data != NULL, "Failed to get data for key '%s': %s", key,
1083     strerror(errno));
1084   fail_unless(valsz == strlen(val), "Expected %lu, got %lu",
1085     (unsigned long) strlen(val), (unsigned long) valsz);
1086 
1087   mark_point();
1088   res = pr_redis_remove(redis, &m, key);
1089   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
1090 
1091   mark_point();
1092   data = pr_redis_get(p, redis, &m, key, &valsz);
1093   fail_unless(data == NULL, "Failed to handle nonexistent key");
1094   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1095     strerror(errno), errno);
1096 
1097   mark_point();
1098   res = pr_redis_conn_destroy(redis);
1099   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
1100 }
1101 END_TEST
1102 
START_TEST(redis_get_with_namespace_test)1103 START_TEST (redis_get_with_namespace_test) {
1104   int res;
1105   pr_redis_t *redis;
1106   module m;
1107   const char *prefix, *key;
1108   char *val;
1109   size_t prefixsz, valsz;
1110   time_t expires;
1111   void *data;
1112 
1113   /* set a value, set the namespace, get it. */
1114 
1115   mark_point();
1116   redis = pr_redis_conn_new(p, NULL, 0);
1117   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
1118     strerror(errno));
1119 
1120   prefix = "prefix.";
1121   prefixsz = strlen(prefix);
1122 
1123   key = "prefix.testkey";
1124   (void) pr_redis_remove(redis, &m, key);
1125 
1126   val = "Hello, World!";
1127   valsz = strlen(val);
1128   expires = 0;
1129 
1130   mark_point();
1131   res = pr_redis_set(redis, &m, key, val, valsz, expires);
1132   fail_unless(res == 0, "Failed to set key '%s', val '%s': %s", key, val,
1133     strerror(errno));
1134 
1135   mark_point();
1136   res = pr_redis_conn_set_namespace(redis, &m, prefix, prefixsz);
1137   fail_unless(res == 0, "Failed to set namespace prefix '%s': %s", prefix,
1138     strerror(errno));
1139 
1140   key = "testkey";
1141   valsz = 0;
1142 
1143   mark_point();
1144   data = pr_redis_get(p, redis, &m, key, &valsz);
1145   fail_unless(data != NULL, "Failed to get data for key '%s': %s", key,
1146     strerror(errno));
1147   fail_unless(valsz == strlen(val), "Expected %lu, got %lu",
1148     (unsigned long) strlen(val), (unsigned long) valsz);
1149   fail_unless(strncmp(data, val, valsz) == 0, "Expected '%s', got '%.*s'",
1150     val, (int) valsz, data);
1151 
1152   mark_point();
1153   res = pr_redis_conn_destroy(redis);
1154   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
1155 }
1156 END_TEST
1157 
START_TEST(redis_get_str_test)1158 START_TEST (redis_get_str_test) {
1159   int res;
1160   pr_redis_t *redis;
1161   module m;
1162   const char *key;
1163   size_t valsz;
1164   time_t expires;
1165   char *val, *str;
1166 
1167   mark_point();
1168   str = pr_redis_get_str(NULL, NULL, NULL, NULL);
1169   fail_unless(str == NULL, "Failed to handle null pool");
1170   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1171     strerror(errno), errno);
1172 
1173   mark_point();
1174   str = pr_redis_get_str(p, NULL, NULL, NULL);
1175   fail_unless(str == NULL, "Failed to handle null redis");
1176   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1177     strerror(errno), errno);
1178 
1179   mark_point();
1180   redis = pr_redis_conn_new(p, NULL, 0);
1181   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
1182     strerror(errno));
1183 
1184   mark_point();
1185   str = pr_redis_get_str(p, redis, NULL, NULL);
1186   fail_unless(str == NULL, "Failed to handle null module");
1187   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1188     strerror(errno), errno);
1189 
1190   mark_point();
1191   str = pr_redis_get_str(p, redis, &m, NULL);
1192   fail_unless(str == NULL, "Failed to handle null key");
1193   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1194     strerror(errno), errno);
1195 
1196   key = "test_string";
1197   (void) pr_redis_remove(redis, &m, key);
1198 
1199   mark_point();
1200   str = pr_redis_get_str(p, redis, &m, key);
1201   fail_unless(str == NULL, "Failed to handle nonexistent key");
1202   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1203     strerror(errno), errno);
1204 
1205   val = "Hello, World!";
1206   valsz = strlen(val);
1207   expires = 0;
1208 
1209   mark_point();
1210   res = pr_redis_set(redis, &m, key, val, valsz, expires);
1211   fail_unless(res == 0, "Failed to set key '%s', val '%s': %s", key, val,
1212     strerror(errno));
1213 
1214   mark_point();
1215   str = pr_redis_get_str(p, redis, &m, key);
1216   fail_unless(str != NULL, "Failed to get string for key '%s': %s", key,
1217     strerror(errno));
1218   fail_unless(strlen(str) == strlen(val), "Expected %lu, got %lu",
1219     (unsigned long) strlen(val), (unsigned long) strlen(str));
1220 
1221   mark_point();
1222   res = pr_redis_remove(redis, &m, key);
1223   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
1224 
1225   mark_point();
1226   str = pr_redis_get_str(p, redis, &m, key);
1227   fail_unless(str == NULL, "Failed to handle nonexistent key");
1228   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1229     strerror(errno), errno);
1230 
1231   mark_point();
1232   res = pr_redis_conn_destroy(redis);
1233   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
1234 }
1235 END_TEST
1236 
START_TEST(redis_incr_test)1237 START_TEST (redis_incr_test) {
1238   int res;
1239   pr_redis_t *redis;
1240   module m;
1241   const char *key;
1242   char *value;
1243   uint32_t incr;
1244   uint64_t val = 0;
1245   size_t valsz;
1246   time_t expires;
1247 
1248   mark_point();
1249   res = pr_redis_incr(NULL, NULL, NULL, 0, NULL);
1250   fail_unless(res < 0, "Failed to handle null redis");
1251   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1252     strerror(errno), errno);
1253 
1254   mark_point();
1255   redis = pr_redis_conn_new(p, NULL, 0);
1256   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
1257     strerror(errno));
1258 
1259   mark_point();
1260   res = pr_redis_incr(redis, NULL, NULL, 0, NULL);
1261   fail_unless(res < 0, "Failed to handle null module");
1262   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1263     strerror(errno), errno);
1264 
1265   mark_point();
1266   res = pr_redis_incr(redis, &m, NULL, 0, NULL);
1267   fail_unless(res < 0, "Failed to handle null key");
1268   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1269     strerror(errno), errno);
1270 
1271   key = "testval";
1272   (void) pr_redis_remove(redis, &m, key);
1273 
1274   mark_point();
1275   res = pr_redis_incr(redis, &m, key, 0, NULL);
1276   fail_unless(res < 0, "Failed to handle zero incr");
1277   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1278     strerror(errno), errno);
1279 
1280   incr = 2;
1281 
1282   mark_point();
1283   res = pr_redis_incr(redis, &m, key, incr, NULL);
1284   fail_unless(res < 0, "Failed to handle nonexistent key");
1285   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1286     strerror(errno), errno);
1287 
1288   /* Note: Yes, Redis wants a string, NOT the actual bytes.  Makes sense,
1289    * I guess, given its text-based protocol.
1290    */
1291   value = "31";
1292   valsz = strlen(value);
1293   expires = 0;
1294 
1295   mark_point();
1296   res = pr_redis_set(redis, &m, key, value, valsz, expires);
1297   fail_unless(res == 0, "Failed to set key '%s', val '%s': %s", key, val,
1298     strerror(errno));
1299 
1300   mark_point();
1301   res = pr_redis_incr(redis, &m, key, incr, NULL);
1302   fail_unless(res == 0, "Failed to increment key '%s' by %lu: %s", key,
1303     (unsigned long) incr, strerror(errno));
1304 
1305   val = 0;
1306 
1307   mark_point();
1308   res = pr_redis_incr(redis, &m, key, incr, &val);
1309   fail_unless(res == 0, "Failed to increment key '%s' by %lu: %s", key,
1310     (unsigned long) incr, strerror(errno));
1311   fail_unless(val == 35, "Expected %lu, got %lu", 35, (unsigned long) val);
1312 
1313   mark_point();
1314   res = pr_redis_remove(redis, &m, key);
1315   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
1316 
1317   /* Now, let's try incrementing a non-numeric value. */
1318   value = "Hello, World!";
1319   valsz = strlen(value);
1320   expires = 0;
1321 
1322   mark_point();
1323   res = pr_redis_set(redis, &m, key, value, valsz, expires);
1324   fail_unless(res == 0, "Failed to set key '%s', val '%s': %s", key, val,
1325     strerror(errno));
1326 
1327   mark_point();
1328   res = pr_redis_incr(redis, &m, key, incr, &val);
1329   fail_unless(res < 0, "Failed to handle non-numeric key value");
1330   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1331     strerror(errno), errno);
1332 
1333   (void) pr_redis_remove(redis, &m, key);
1334 
1335   mark_point();
1336   res = pr_redis_conn_destroy(redis);
1337   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
1338 }
1339 END_TEST
1340 
START_TEST(redis_decr_test)1341 START_TEST (redis_decr_test) {
1342   int res;
1343   pr_redis_t *redis;
1344   module m;
1345   const char *key;
1346   char *value;
1347   uint32_t decr;
1348   uint64_t val = 0;
1349   size_t valsz;
1350   time_t expires;
1351 
1352   mark_point();
1353   res = pr_redis_decr(NULL, NULL, NULL, 0, NULL);
1354   fail_unless(res < 0, "Failed to handle null redis");
1355   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1356     strerror(errno), errno);
1357 
1358   mark_point();
1359   redis = pr_redis_conn_new(p, NULL, 0);
1360   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
1361     strerror(errno));
1362 
1363   mark_point();
1364   res = pr_redis_decr(redis, NULL, NULL, 0, NULL);
1365   fail_unless(res < 0, "Failed to handle null module");
1366   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1367     strerror(errno), errno);
1368 
1369   mark_point();
1370   res = pr_redis_decr(redis, &m, NULL, 0, NULL);
1371   fail_unless(res < 0, "Failed to handle null key");
1372   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1373     strerror(errno), errno);
1374 
1375   key = "testval";
1376   (void) pr_redis_remove(redis, &m, key);
1377 
1378   mark_point();
1379   res = pr_redis_decr(redis, &m, key, 0, NULL);
1380   fail_unless(res < 0, "Failed to handle zero decr");
1381   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1382     strerror(errno), errno);
1383 
1384   decr = 5;
1385 
1386   mark_point();
1387   res = pr_redis_decr(redis, &m, key, decr, NULL);
1388   fail_unless(res < 0, "Failed to handle nonexistent key");
1389   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1390     strerror(errno), errno);
1391 
1392   /* Note: Yes, Redis wants a string, NOT the actual bytes.  Makes sense,
1393    * I guess, given its text-based protocol.
1394    */
1395   value = "31";
1396   valsz = strlen(value);
1397   expires = 0;
1398 
1399   mark_point();
1400   res = pr_redis_set(redis, &m, key, value, valsz, expires);
1401   fail_unless(res == 0, "Failed to set key '%s', val '%s': %s", key, val,
1402     strerror(errno));
1403 
1404   mark_point();
1405   res = pr_redis_decr(redis, &m, key, decr, NULL);
1406   fail_unless(res == 0, "Failed to decrement key '%s' by %lu: %s", key,
1407     (unsigned long) decr, strerror(errno));
1408 
1409   val = 0;
1410 
1411   mark_point();
1412   res = pr_redis_decr(redis, &m, key, decr, &val);
1413   fail_unless(res == 0, "Failed to decrement key '%s' by %lu: %s", key,
1414     (unsigned long) decr, strerror(errno));
1415   fail_unless(val == 21, "Expected %lu, got %lu", 21, (unsigned long) val);
1416 
1417   mark_point();
1418   res = pr_redis_remove(redis, &m, key);
1419   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
1420 
1421   /* Now, let's try decrementing a non-numeric value. */
1422   value = "Hello, World!";
1423   valsz = strlen(value);
1424   expires = 0;
1425 
1426   mark_point();
1427   res = pr_redis_set(redis, &m, key, value, valsz, expires);
1428   fail_unless(res == 0, "Failed to set key '%s', val '%s': %s", key, val,
1429     strerror(errno));
1430 
1431   mark_point();
1432   res = pr_redis_decr(redis, &m, key, decr, &val);
1433   fail_unless(res < 0, "Failed to handle non-numeric key value");
1434   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1435     strerror(errno), errno);
1436 
1437   (void) pr_redis_remove(redis, &m, key);
1438 
1439   mark_point();
1440   res = pr_redis_conn_destroy(redis);
1441   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
1442 }
1443 END_TEST
1444 
START_TEST(redis_rename_test)1445 START_TEST (redis_rename_test) {
1446   int res;
1447   pr_redis_t *redis;
1448   module m;
1449   const char *from, *to;
1450   char *val;
1451   size_t valsz;
1452   time_t expires;
1453 
1454   mark_point();
1455   res = pr_redis_rename(NULL, NULL, NULL, NULL);
1456   fail_unless(res < 0, "Failed to handle null redis");
1457   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1458     strerror(errno), errno);
1459 
1460   mark_point();
1461   redis = pr_redis_conn_new(p, NULL, 0);
1462   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
1463     strerror(errno));
1464 
1465   mark_point();
1466   res = pr_redis_rename(redis, NULL, NULL, NULL);
1467   fail_unless(res < 0, "Failed to handle null module");
1468   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1469     strerror(errno), errno);
1470 
1471   mark_point();
1472   res = pr_redis_rename(redis, &m, NULL, NULL);
1473   fail_unless(res < 0, "Failed to handle null from");
1474   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1475     strerror(errno), errno);
1476 
1477   from = "fromkey";
1478 
1479   mark_point();
1480   res = pr_redis_rename(redis, &m, from, NULL);
1481   fail_unless(res < 0, "Failed to handle null to");
1482   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1483     strerror(errno), errno);
1484 
1485   to = "tokey";
1486 
1487   mark_point();
1488   res = pr_redis_rename(redis, &m, from, to);
1489   fail_unless(res < 0, "Failed to handle nonexistent from key");
1490   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1491     strerror(errno), errno);
1492 
1493   val = "testval";
1494   valsz = strlen(val);
1495   expires = 0;
1496 
1497   mark_point();
1498   res = pr_redis_set(redis, &m, from, val, valsz, expires);
1499   fail_unless(res == 0, "Failed to set key '%s', val '%s': %s", from, val,
1500     strerror(errno));
1501 
1502   mark_point();
1503   res = pr_redis_rename(redis, &m, from, to);
1504   fail_unless(res == 0, "Failed to rename '%s' to '%s': %s", from, to,
1505     strerror(errno));
1506 
1507   mark_point();
1508   res = pr_redis_remove(redis, &m, to);
1509   fail_unless(res == 0, "Failed to remove key '%s': %s", to, strerror(errno));
1510 
1511   mark_point();
1512   res = pr_redis_conn_destroy(redis);
1513   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
1514 }
1515 END_TEST
1516 
START_TEST(redis_set_test)1517 START_TEST (redis_set_test) {
1518   int res;
1519   pr_redis_t *redis;
1520   module m;
1521   const char *key;
1522   char *val;
1523   size_t valsz;
1524   time_t expires;
1525 
1526   mark_point();
1527   res = pr_redis_set(NULL, NULL, NULL, NULL, 0, 0);
1528   fail_unless(res < 0, "Failed to handle null redis");
1529   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1530     strerror(errno), errno);
1531 
1532   mark_point();
1533   redis = pr_redis_conn_new(p, NULL, 0);
1534   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
1535     strerror(errno));
1536 
1537   mark_point();
1538   res = pr_redis_set(redis, NULL, NULL, NULL, 0, 0);
1539   fail_unless(res < 0, "Failed to handle null module");
1540   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1541     strerror(errno), errno);
1542 
1543   mark_point();
1544   res = pr_redis_set(redis, &m, NULL, NULL, 0, 0);
1545   fail_unless(res < 0, "Failed to handle null key");
1546   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1547     strerror(errno), errno);
1548 
1549   key = "testkey";
1550 
1551   mark_point();
1552   res = pr_redis_set(redis, &m, key, NULL, 0, 0);
1553   fail_unless(res < 0, "Failed to handle null value");
1554   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1555     strerror(errno), errno);
1556 
1557   val = "testval";
1558   valsz = strlen(val);
1559   expires = 0;
1560 
1561   mark_point();
1562   res = pr_redis_set(redis, &m, key, val, valsz, expires);
1563   fail_unless(res == 0, "Failed to set key '%s', val '%s': %s", key, val,
1564     strerror(errno));
1565 
1566   mark_point();
1567   res = pr_redis_remove(redis, &m, key);
1568   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
1569 
1570   expires = 3;
1571 
1572   mark_point();
1573   res = pr_redis_set(redis, &m, key, val, valsz, expires);
1574   fail_unless(res == 0, "Failed to set key '%s', val '%s': %s", key, val,
1575     strerror(errno));
1576 
1577   mark_point();
1578   res = pr_redis_remove(redis, &m, key);
1579   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
1580 
1581   mark_point();
1582   res = pr_redis_conn_destroy(redis);
1583   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
1584 }
1585 END_TEST
1586 
START_TEST(redis_hash_remove_test)1587 START_TEST (redis_hash_remove_test) {
1588   int res;
1589   pr_redis_t *redis;
1590   module m;
1591   const char *key;
1592 
1593   mark_point();
1594   res = pr_redis_hash_remove(NULL, NULL, NULL);
1595   fail_unless(res < 0, "Failed to handle null redis");
1596   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1597     strerror(errno), errno);
1598 
1599   mark_point();
1600   redis = pr_redis_conn_new(p, NULL, 0);
1601   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
1602     strerror(errno));
1603 
1604   mark_point();
1605   res = pr_redis_hash_remove(redis, NULL, NULL);
1606   fail_unless(res < 0, "Failed to handle null module");
1607   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1608     strerror(errno), errno);
1609 
1610   mark_point();
1611   res = pr_redis_hash_remove(redis, &m, NULL);
1612   fail_unless(res < 0, "Failed to handle null key");
1613   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1614     strerror(errno), errno);
1615 
1616   key = "testkey";
1617 
1618   mark_point();
1619   res = pr_redis_hash_remove(redis, &m, key);
1620   fail_unless(res < 0, "Unexpectedly removed key '%s'", key);
1621   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1622     strerror(errno), errno);
1623 
1624   mark_point();
1625   res = pr_redis_conn_destroy(redis);
1626   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
1627 }
1628 END_TEST
1629 
START_TEST(redis_hash_get_test)1630 START_TEST (redis_hash_get_test) {
1631   int res;
1632   pr_redis_t *redis;
1633   module m;
1634   const char *key, *field;
1635   char *val;
1636   size_t valsz;
1637 
1638   mark_point();
1639   res = pr_redis_hash_get(NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1640   fail_unless(res < 0, "Failed to handle null pool");
1641   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1642     strerror(errno), errno);
1643 
1644   mark_point();
1645   res = pr_redis_hash_get(p, NULL, NULL, NULL, NULL, NULL, NULL);
1646   fail_unless(res < 0, "Failed to handle null redis");
1647   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1648     strerror(errno), errno);
1649 
1650   mark_point();
1651   redis = pr_redis_conn_new(p, NULL, 0);
1652   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
1653     strerror(errno));
1654 
1655   mark_point();
1656   res = pr_redis_hash_get(p, redis, NULL, NULL, NULL, NULL, NULL);
1657   fail_unless(res < 0, "Failed to handle null module");
1658   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1659     strerror(errno), errno);
1660 
1661   mark_point();
1662   res = pr_redis_hash_get(p, redis, &m, NULL, NULL, NULL, NULL);
1663   fail_unless(res < 0, "Failed to handle null key");
1664   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1665     strerror(errno), errno);
1666 
1667   key = "testhashkey";
1668   (void) pr_redis_remove(redis, &m, key);
1669 
1670   mark_point();
1671   res = pr_redis_hash_get(p, redis, &m, key, NULL, NULL, NULL);
1672   fail_unless(res < 0, "Failed to handle null field");
1673   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1674     strerror(errno), errno);
1675 
1676   field = "hashfield";
1677 
1678   mark_point();
1679   res = pr_redis_hash_get(p, redis, &m, key, field, NULL, NULL);
1680   fail_unless(res < 0, "Failed to handle null value");
1681   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1682     strerror(errno), errno);
1683 
1684   mark_point();
1685   res = pr_redis_hash_get(p, redis, &m, key, field, (void **) &val, &valsz);
1686   fail_unless(res < 0, "Failed to handle nonexistent item");
1687   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1688     strerror(errno), errno);
1689 
1690   (void) pr_redis_remove(redis, &m, key);
1691 
1692   mark_point();
1693   res = pr_redis_conn_destroy(redis);
1694   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
1695 }
1696 END_TEST
1697 
START_TEST(redis_hash_set_test)1698 START_TEST (redis_hash_set_test) {
1699   int res;
1700   pr_redis_t *redis;
1701   module m;
1702   const char *key, *field;
1703   char *val;
1704   size_t valsz;
1705 
1706   mark_point();
1707   res = pr_redis_hash_set(NULL, NULL, NULL, NULL, NULL, 0);
1708   fail_unless(res < 0, "Failed to handle null redis");
1709   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1710     strerror(errno), errno);
1711 
1712   mark_point();
1713   redis = pr_redis_conn_new(p, NULL, 0);
1714   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
1715     strerror(errno));
1716 
1717   mark_point();
1718   res = pr_redis_hash_set(redis, NULL, NULL, NULL, NULL, 0);
1719   fail_unless(res < 0, "Failed to handle null module");
1720   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1721     strerror(errno), errno);
1722 
1723   mark_point();
1724   res = pr_redis_hash_set(redis, &m, NULL, NULL, NULL, 0);
1725   fail_unless(res < 0, "Failed to handle null key");
1726   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1727     strerror(errno), errno);
1728 
1729   key = "testhashkey";
1730   (void) pr_redis_remove(redis, &m, key);
1731 
1732   mark_point();
1733   res = pr_redis_hash_set(redis, &m, key, NULL, NULL, 0);
1734   fail_unless(res < 0, "Failed to handle null field");
1735   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1736     strerror(errno), errno);
1737 
1738   field = "hashfield";
1739 
1740   mark_point();
1741   res = pr_redis_hash_set(redis, &m, key, field, NULL, 0);
1742   fail_unless(res < 0, "Failed to handle null value");
1743   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1744     strerror(errno), errno);
1745 
1746   val = "hashval";
1747   valsz = strlen(val);
1748 
1749   mark_point();
1750   res = pr_redis_hash_set(redis, &m, key, field, val, 0);
1751   fail_unless(res < 0, "Failed to handle zero valuesz");
1752   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1753     strerror(errno), errno);
1754 
1755   mark_point();
1756   res = pr_redis_hash_set(redis, &m, key, field, val, valsz);
1757   fail_unless(res == 0, "Failed to set item: %s", strerror(errno));
1758 
1759   val = NULL;
1760   valsz = 0;
1761 
1762   mark_point();
1763   res = pr_redis_hash_get(p, redis, &m, key, field, (void **) &val, &valsz);
1764   fail_unless(res == 0, "Failed to get item: %s", strerror(errno));
1765   fail_unless(valsz == 7, "Expected item length 7, got %lu",
1766     (unsigned long) valsz);
1767   fail_unless(val != NULL, "Failed to get value from hash");
1768   fail_unless(strncmp(val, "hashval", valsz) == 0,
1769     "Expected 'hashval', got '%.*s'", (int) valsz, val);
1770 
1771   mark_point();
1772   res = pr_redis_hash_remove(redis, &m, key);
1773   fail_unless(res == 0, "Failed to remove hash: %s", strerror(errno));
1774 
1775   mark_point();
1776   res = pr_redis_conn_destroy(redis);
1777   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
1778 }
1779 END_TEST
1780 
START_TEST(redis_hash_delete_test)1781 START_TEST (redis_hash_delete_test) {
1782   int res;
1783   pr_redis_t *redis;
1784   module m;
1785   const char *key, *field;
1786   char *val;
1787   size_t valsz;
1788 
1789   mark_point();
1790   res = pr_redis_hash_delete(NULL, NULL, NULL, NULL);
1791   fail_unless(res < 0, "Failed to handle null redis");
1792   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1793     strerror(errno), errno);
1794 
1795   mark_point();
1796   redis = pr_redis_conn_new(p, NULL, 0);
1797   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
1798     strerror(errno));
1799 
1800   mark_point();
1801   res = pr_redis_hash_delete(redis, NULL, NULL, NULL);
1802   fail_unless(res < 0, "Failed to handle null module");
1803   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1804     strerror(errno), errno);
1805 
1806   mark_point();
1807   res = pr_redis_hash_delete(redis, &m, NULL, NULL);
1808   fail_unless(res < 0, "Failed to handle null key");
1809   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1810     strerror(errno), errno);
1811 
1812   key = "testhashkey";
1813   (void) pr_redis_remove(redis, &m, key);
1814 
1815   mark_point();
1816   res = pr_redis_hash_delete(redis, &m, key, NULL);
1817   fail_unless(res < 0, "Failed to handle null field");
1818   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1819     strerror(errno), errno);
1820 
1821   field = "hashfield";
1822 
1823   mark_point();
1824   res = pr_redis_hash_delete(redis, &m, key, field);
1825   fail_unless(res < 0, "Failed to handle nonexistent field");
1826   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1827     strerror(errno), errno);
1828 
1829   val = "hashval";
1830   valsz = strlen(val);
1831 
1832   mark_point();
1833   res = pr_redis_hash_set(redis, &m, key, field, val, valsz);
1834   fail_unless(res == 0, "Failed to set item: %s", strerror(errno));
1835 
1836   mark_point();
1837   res = pr_redis_hash_delete(redis, &m, key, field);
1838   fail_unless(res == 0, "Failed to delete field: %s", strerror(errno));
1839 
1840   /* Note that we add this item back, just so that the hash is NOT empty when
1841    * we go to remove it entirely.
1842    */
1843 
1844   mark_point();
1845   res = pr_redis_hash_set(redis, &m, key, field, val, valsz);
1846   fail_unless(res == 0, "Failed to set item: %s", strerror(errno));
1847 
1848   (void) pr_redis_remove(redis, &m, key);
1849 
1850   mark_point();
1851   res = pr_redis_conn_destroy(redis);
1852   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
1853 }
1854 END_TEST
1855 
START_TEST(redis_hash_count_test)1856 START_TEST (redis_hash_count_test) {
1857   int res;
1858   pr_redis_t *redis;
1859   module m;
1860   const char *key, *field;
1861   uint64_t count = 0;
1862   char *val;
1863   size_t valsz;
1864 
1865   mark_point();
1866   res = pr_redis_hash_count(NULL, NULL, NULL, NULL);
1867   fail_unless(res < 0, "Failed to handle null redis");
1868   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1869     strerror(errno), errno);
1870 
1871   mark_point();
1872   redis = pr_redis_conn_new(p, NULL, 0);
1873   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
1874     strerror(errno));
1875 
1876   mark_point();
1877   res = pr_redis_hash_count(redis, NULL, NULL, NULL);
1878   fail_unless(res < 0, "Failed to handle null module");
1879   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1880     strerror(errno), errno);
1881 
1882   mark_point();
1883   res = pr_redis_hash_count(redis, &m, NULL, NULL);
1884   fail_unless(res < 0, "Failed to handle null key");
1885   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1886     strerror(errno), errno);
1887 
1888   key = "testhashkey";
1889   (void) pr_redis_remove(redis, &m, key);
1890 
1891   mark_point();
1892   res = pr_redis_hash_count(redis, &m, key, NULL);
1893   fail_unless(res < 0, "Failed to handle null count");
1894   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1895     strerror(errno), errno);
1896 
1897   mark_point();
1898   res = pr_redis_hash_count(redis, &m, key, &count);
1899   fail_unless(res == 0, "Failed to get count using key '%s': %s", key,
1900     strerror(errno));
1901 
1902   field = "hashfield";
1903   val = "hashval";
1904   valsz = strlen(val);
1905 
1906   mark_point();
1907   res = pr_redis_hash_set(redis, &m, key, field, val, valsz);
1908   fail_unless(res == 0, "Failed to set item: %s", strerror(errno));
1909 
1910   mark_point();
1911   res = pr_redis_hash_count(redis, &m, key, &count);
1912   fail_unless(res == 0, "Failed to get count: %s", strerror(errno));
1913   fail_unless(count == 1, "Expected 1, got %lu", (unsigned long) count);
1914 
1915   (void) pr_redis_remove(redis, &m, key);
1916 
1917   mark_point();
1918   res = pr_redis_conn_destroy(redis);
1919   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
1920 }
1921 END_TEST
1922 
START_TEST(redis_hash_exists_test)1923 START_TEST (redis_hash_exists_test) {
1924   int res;
1925   pr_redis_t *redis;
1926   module m;
1927   const char *key, *field;
1928   char *val;
1929   size_t valsz;
1930 
1931   mark_point();
1932   res = pr_redis_hash_exists(NULL, NULL, NULL, NULL);
1933   fail_unless(res < 0, "Failed to handle null redis");
1934   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1935     strerror(errno), errno);
1936 
1937   mark_point();
1938   redis = pr_redis_conn_new(p, NULL, 0);
1939   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
1940     strerror(errno));
1941 
1942   mark_point();
1943   res = pr_redis_hash_exists(redis, NULL, NULL, NULL);
1944   fail_unless(res < 0, "Failed to handle null module");
1945   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1946     strerror(errno), errno);
1947 
1948   mark_point();
1949   res = pr_redis_hash_exists(redis, &m, NULL, NULL);
1950   fail_unless(res < 0, "Failed to handle null key");
1951   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1952     strerror(errno), errno);
1953 
1954   key = "testhashkey";
1955   (void) pr_redis_remove(redis, &m, key);
1956 
1957   mark_point();
1958   res = pr_redis_hash_exists(redis, &m, key, NULL);
1959   fail_unless(res < 0, "Failed to handle null field");
1960   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1961     strerror(errno), errno);
1962 
1963   field = "hashfield";
1964 
1965   mark_point();
1966   res = pr_redis_hash_exists(redis, &m, key, field);
1967   fail_unless(res == FALSE, "Failed to handle nonexistent field");
1968 
1969   val = "hashval";
1970   valsz = strlen(val);
1971 
1972   mark_point();
1973   res = pr_redis_hash_set(redis, &m, key, field, val, valsz);
1974   fail_unless(res == 0, "Failed to set item: %s", strerror(errno));
1975 
1976   mark_point();
1977   res = pr_redis_hash_exists(redis, &m, key, field);
1978   fail_unless(res == TRUE, "Failed to handle existing field");
1979 
1980   (void) pr_redis_remove(redis, &m, key);
1981 
1982   mark_point();
1983   res = pr_redis_conn_destroy(redis);
1984   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
1985 }
1986 END_TEST
1987 
START_TEST(redis_hash_incr_test)1988 START_TEST (redis_hash_incr_test) {
1989   int res;
1990   pr_redis_t *redis;
1991   module m;
1992   const char *key, *field;
1993   int64_t num;
1994   char *val;
1995   size_t valsz;
1996 
1997   mark_point();
1998   res = pr_redis_hash_incr(NULL, NULL, NULL, NULL, 0, NULL);
1999   fail_unless(res < 0, "Failed to handle null redis");
2000   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2001     strerror(errno), errno);
2002 
2003   mark_point();
2004   redis = pr_redis_conn_new(p, NULL, 0);
2005   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
2006     strerror(errno));
2007 
2008   mark_point();
2009   res = pr_redis_hash_incr(redis, NULL, NULL, NULL, 0, NULL);
2010   fail_unless(res < 0, "Failed to handle null module");
2011   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2012     strerror(errno), errno);
2013 
2014   mark_point();
2015   res = pr_redis_hash_incr(redis, &m, NULL, NULL, 0, NULL);
2016   fail_unless(res < 0, "Failed to handle null key");
2017   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2018     strerror(errno), errno);
2019 
2020   key = "testhashkey";
2021   (void) pr_redis_remove(redis, &m, key);
2022 
2023   mark_point();
2024   res = pr_redis_hash_incr(redis, &m, key, NULL, 0, NULL);
2025   fail_unless(res < 0, "Failed to handle null field");
2026   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2027     strerror(errno), errno);
2028 
2029   field = "hashfield";
2030 
2031   mark_point();
2032   res = pr_redis_hash_incr(redis, &m, key, field, 0, NULL);
2033   fail_unless(res < 0, "Failed to handle nonexistent field");
2034   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
2035     strerror(errno), errno);
2036 
2037   val = "1";
2038   valsz = strlen(val);
2039 
2040   mark_point();
2041   res = pr_redis_hash_set(redis, &m, key, field, val, valsz);
2042   fail_unless(res == 0, "Failed to set item: %s", strerror(errno));
2043 
2044   mark_point();
2045   res = pr_redis_hash_incr(redis, &m, key, field, 0, NULL);
2046   fail_unless(res == 0, "Failed to handle existing field: %s", strerror(errno));
2047 
2048   mark_point();
2049   res = pr_redis_hash_incr(redis, &m, key, field, 1, &num);
2050   fail_unless(res == 0, "Failed to handle existing field: %s", strerror(errno));
2051   fail_unless(num == 2, "Expected 2, got %lu", (unsigned long) num);
2052 
2053   mark_point();
2054   res = pr_redis_hash_incr(redis, &m, key, field, -3, &num);
2055   fail_unless(res == 0, "Failed to handle existing field: %s", strerror(errno));
2056   fail_unless(num == -1, "Expected -1, got %lu", (unsigned long) num);
2057 
2058   (void) pr_redis_remove(redis, &m, key);
2059 
2060   mark_point();
2061   res = pr_redis_conn_destroy(redis);
2062   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
2063 }
2064 END_TEST
2065 
START_TEST(redis_hash_keys_test)2066 START_TEST (redis_hash_keys_test) {
2067   int res;
2068   pr_redis_t *redis;
2069   module m;
2070   const char *key, *field;
2071   char *val;
2072   size_t valsz;
2073   array_header *fields = NULL;
2074 
2075   mark_point();
2076   res = pr_redis_hash_keys(NULL, NULL, NULL, NULL, NULL);
2077   fail_unless(res < 0, "Failed to handle null pool");
2078   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2079     strerror(errno), errno);
2080 
2081   mark_point();
2082   res = pr_redis_hash_keys(p, NULL, NULL, NULL, NULL);
2083   fail_unless(res < 0, "Failed to handle null redis");
2084   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2085     strerror(errno), errno);
2086 
2087   mark_point();
2088   redis = pr_redis_conn_new(p, NULL, 0);
2089   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
2090     strerror(errno));
2091 
2092   mark_point();
2093   res = pr_redis_hash_keys(p, redis, NULL, NULL, NULL);
2094   fail_unless(res < 0, "Failed to handle null module");
2095   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2096     strerror(errno), errno);
2097 
2098   mark_point();
2099   res = pr_redis_hash_keys(p, redis, &m, NULL, NULL);
2100   fail_unless(res < 0, "Failed to handle null key");
2101   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2102     strerror(errno), errno);
2103 
2104   key = "testhashkey";
2105   (void) pr_redis_remove(redis, &m, key);
2106 
2107   mark_point();
2108   res = pr_redis_hash_keys(p, redis, &m, key, NULL);
2109   fail_unless(res < 0, "Failed to handle null fields");
2110   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2111     strerror(errno), errno);
2112 
2113   mark_point();
2114   res = pr_redis_hash_keys(p, redis, &m, key, &fields);
2115   fail_unless(res < 0, "Failed to handle nonexistent fields");
2116   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
2117     strerror(errno), errno);
2118 
2119   /* Add some fields */
2120 
2121   field = "foo";
2122   val = "1";
2123   valsz = strlen(val);
2124 
2125   mark_point();
2126   res = pr_redis_hash_set(redis, &m, key, field, val, valsz);
2127   fail_unless(res == 0, "Failed to set item: %s", strerror(errno));
2128 
2129   field = "bar";
2130   val = "baz quxx";
2131   valsz = strlen(val);
2132 
2133   mark_point();
2134   res = pr_redis_hash_set(redis, &m, key, field, val, valsz);
2135   fail_unless(res == 0, "Failed to set item: %s", strerror(errno));
2136 
2137   fields = NULL;
2138 
2139   mark_point();
2140   res = pr_redis_hash_keys(p, redis, &m, key, &fields);
2141   fail_unless(res == 0, "Failed to handle existing fields: %s", strerror(errno));
2142   fail_unless(fields != NULL, "Failed to get hash fields");
2143   fail_unless(fields->nelts == 2, "Expected 2, got %u", fields->nelts);
2144 
2145   (void) pr_redis_remove(redis, &m, key);
2146 
2147   mark_point();
2148   res = pr_redis_conn_destroy(redis);
2149   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
2150 }
2151 END_TEST
2152 
START_TEST(redis_hash_values_test)2153 START_TEST (redis_hash_values_test) {
2154   int res;
2155   pr_redis_t *redis;
2156   module m;
2157   const char *key, *field;
2158   char *val;
2159   size_t valsz;
2160   array_header *values = NULL;
2161 
2162   mark_point();
2163   res = pr_redis_hash_values(NULL, NULL, NULL, NULL, NULL);
2164   fail_unless(res < 0, "Failed to handle null pool");
2165   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2166     strerror(errno), errno);
2167 
2168   mark_point();
2169   res = pr_redis_hash_values(p, NULL, NULL, NULL, NULL);
2170   fail_unless(res < 0, "Failed to handle null redis");
2171   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2172     strerror(errno), errno);
2173 
2174   mark_point();
2175   redis = pr_redis_conn_new(p, NULL, 0);
2176   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
2177     strerror(errno));
2178 
2179   mark_point();
2180   res = pr_redis_hash_values(p, redis, NULL, NULL, NULL);
2181   fail_unless(res < 0, "Failed to handle null module");
2182   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2183     strerror(errno), errno);
2184 
2185   mark_point();
2186   res = pr_redis_hash_values(p, redis, &m, NULL, NULL);
2187   fail_unless(res < 0, "Failed to handle null key");
2188   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2189     strerror(errno), errno);
2190 
2191   key = "testhashkey";
2192   (void) pr_redis_remove(redis, &m, key);
2193 
2194   mark_point();
2195   res = pr_redis_hash_values(p, redis, &m, key, NULL);
2196   fail_unless(res < 0, "Failed to handle null values");
2197   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2198     strerror(errno), errno);
2199 
2200   mark_point();
2201   res = pr_redis_hash_values(p, redis, &m, key, &values);
2202   fail_unless(res < 0, "Failed to handle nonexistent values");
2203   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
2204     strerror(errno), errno);
2205 
2206   /* Add some fields */
2207 
2208   field = "foo";
2209   val = "1";
2210   valsz = strlen(val);
2211 
2212   mark_point();
2213   res = pr_redis_hash_set(redis, &m, key, field, val, valsz);
2214   fail_unless(res == 0, "Failed to set item: %s", strerror(errno));
2215 
2216   field = "bar";
2217   val = "baz quxx";
2218   valsz = strlen(val);
2219 
2220   mark_point();
2221   res = pr_redis_hash_set(redis, &m, key, field, val, valsz);
2222   fail_unless(res == 0, "Failed to set item: %s", strerror(errno));
2223 
2224   values = NULL;
2225 
2226   mark_point();
2227   res = pr_redis_hash_values(p, redis, &m, key, &values);
2228   fail_unless(res == 0, "Failed to handle existing values: %s", strerror(errno));
2229   fail_unless(values != NULL, "Failed to get hash values");
2230   fail_unless(values->nelts == 2, "Expected 2, got %u", values->nelts);
2231 
2232   (void) pr_redis_remove(redis, &m, key);
2233 
2234   mark_point();
2235   res = pr_redis_conn_destroy(redis);
2236   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
2237 }
2238 END_TEST
2239 
START_TEST(redis_hash_getall_test)2240 START_TEST (redis_hash_getall_test) {
2241   int res;
2242   pr_redis_t *redis;
2243   module m;
2244   const char *key, *field;
2245   char *val;
2246   size_t valsz;
2247   pr_table_t *hash = NULL;
2248 
2249   mark_point();
2250   res = pr_redis_hash_getall(NULL, NULL, NULL, NULL, NULL);
2251   fail_unless(res < 0, "Failed to handle null pool");
2252   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2253     strerror(errno), errno);
2254 
2255   mark_point();
2256   res = pr_redis_hash_getall(p, NULL, NULL, NULL, NULL);
2257   fail_unless(res < 0, "Failed to handle null redis");
2258   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2259     strerror(errno), errno);
2260 
2261   mark_point();
2262   redis = pr_redis_conn_new(p, NULL, 0);
2263   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
2264     strerror(errno));
2265 
2266   mark_point();
2267   res = pr_redis_hash_getall(p, redis, NULL, NULL, NULL);
2268   fail_unless(res < 0, "Failed to handle null module");
2269   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2270     strerror(errno), errno);
2271 
2272   mark_point();
2273   res = pr_redis_hash_getall(p, redis, &m, NULL, NULL);
2274   fail_unless(res < 0, "Failed to handle null key");
2275   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2276     strerror(errno), errno);
2277 
2278   key = "testhashkey";
2279   (void) pr_redis_remove(redis, &m, key);
2280 
2281   mark_point();
2282   res = pr_redis_hash_getall(p, redis, &m, key, NULL);
2283   fail_unless(res < 0, "Failed to handle null hash");
2284   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2285     strerror(errno), errno);
2286 
2287   mark_point();
2288   res = pr_redis_hash_getall(p, redis, &m, key, &hash);
2289   fail_unless(res < 0, "Failed to handle nonexistent hash");
2290   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
2291     strerror(errno), errno);
2292 
2293   /* Add some fields */
2294 
2295   field = "foo";
2296   val = "1";
2297   valsz = strlen(val);
2298 
2299   mark_point();
2300   res = pr_redis_hash_set(redis, &m, key, field, val, valsz);
2301   fail_unless(res == 0, "Failed to set item: %s", strerror(errno));
2302 
2303   field = "bar";
2304   val = "baz quxx";
2305   valsz = strlen(val);
2306 
2307   mark_point();
2308   res = pr_redis_hash_set(redis, &m, key, field, val, valsz);
2309   fail_unless(res == 0, "Failed to set item: %s", strerror(errno));
2310 
2311   hash = NULL;
2312 
2313   mark_point();
2314   res = pr_redis_hash_getall(p, redis, &m, key, &hash);
2315   fail_unless(res == 0, "Failed to handle existing fields: %s", strerror(errno));
2316   fail_unless(hash != NULL, "Failed to get hash");
2317   res = pr_table_count(hash);
2318   fail_unless(res == 2, "Expected 2, got %d", res);
2319 
2320   (void) pr_redis_remove(redis, &m, key);
2321 
2322   mark_point();
2323   res = pr_redis_conn_destroy(redis);
2324   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
2325 }
2326 END_TEST
2327 
START_TEST(redis_hash_setall_test)2328 START_TEST (redis_hash_setall_test) {
2329   int res;
2330   pr_redis_t *redis;
2331   module m;
2332   const char *key, *field;
2333   char *val;
2334   size_t valsz;
2335   pr_table_t *hash = NULL;
2336   uint64_t count = 0;
2337 
2338   mark_point();
2339   res = pr_redis_hash_setall(NULL, NULL, NULL, NULL);
2340   fail_unless(res < 0, "Failed to handle null redis");
2341   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2342     strerror(errno), errno);
2343 
2344   mark_point();
2345   redis = pr_redis_conn_new(p, NULL, 0);
2346   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
2347     strerror(errno));
2348 
2349   mark_point();
2350   res = pr_redis_hash_setall(redis, NULL, NULL, NULL);
2351   fail_unless(res < 0, "Failed to handle null module");
2352   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2353     strerror(errno), errno);
2354 
2355   mark_point();
2356   res = pr_redis_hash_setall(redis, &m, NULL, NULL);
2357   fail_unless(res < 0, "Failed to handle null key");
2358   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2359     strerror(errno), errno);
2360 
2361   key = "testhashkey";
2362   (void) pr_redis_remove(redis, &m, key);
2363 
2364   mark_point();
2365   res = pr_redis_hash_setall(redis, &m, key, NULL);
2366   fail_unless(res < 0, "Failed to handle null hash");
2367   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2368     strerror(errno), errno);
2369 
2370   hash = pr_table_alloc(p, 0);
2371 
2372   mark_point();
2373   res = pr_redis_hash_setall(redis, &m, key, hash);
2374   fail_unless(res < 0, "Failed to handle empty hash");
2375   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2376     strerror(errno), errno);
2377 
2378   /* Add some fields */
2379   field = "foo";
2380   val = "1";
2381   valsz = strlen(val);
2382   (void) pr_table_add_dup(hash, pstrdup(p, field), val, valsz);
2383 
2384   field = "bar";
2385   val = "baz quxx";
2386   valsz = strlen(val);
2387   (void) pr_table_add_dup(hash, pstrdup(p, field), val, valsz);
2388 
2389   mark_point();
2390   res = pr_redis_hash_setall(redis, &m, key, hash);
2391   fail_unless(res == 0, "Failed to set hash: %s", strerror(errno));
2392 
2393   mark_point();
2394   res = pr_redis_hash_count(redis, &m, key, &count);
2395   fail_unless(res == 0, "Failed to count hash: %s", strerror(errno));
2396   fail_unless(count == 2, "Expected 2, got %lu", (unsigned long) count);
2397 
2398   (void) pr_redis_remove(redis, &m, key);
2399 
2400   mark_point();
2401   res = pr_redis_conn_destroy(redis);
2402   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
2403 }
2404 END_TEST
2405 
START_TEST(redis_list_remove_test)2406 START_TEST (redis_list_remove_test) {
2407   int res;
2408   pr_redis_t *redis;
2409   module m;
2410   const char *key;
2411 
2412   mark_point();
2413   res = pr_redis_list_remove(NULL, NULL, NULL);
2414   fail_unless(res < 0, "Failed to handle null redis");
2415   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2416     strerror(errno), errno);
2417 
2418   mark_point();
2419   redis = pr_redis_conn_new(p, NULL, 0);
2420   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
2421     strerror(errno));
2422 
2423   mark_point();
2424   res = pr_redis_list_remove(redis, NULL, NULL);
2425   fail_unless(res < 0, "Failed to handle null module");
2426   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2427     strerror(errno), errno);
2428 
2429   mark_point();
2430   res = pr_redis_list_remove(redis, &m, NULL);
2431   fail_unless(res < 0, "Failed to handle null key");
2432   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2433     strerror(errno), errno);
2434 
2435   key = "testlistkey";
2436 
2437   mark_point();
2438   res = pr_redis_list_remove(redis, &m, key);
2439   fail_unless(res < 0, "Failed to handle nonexistent list");
2440   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
2441     strerror(errno), errno);
2442 
2443   mark_point();
2444   res = pr_redis_conn_destroy(redis);
2445   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
2446 }
2447 END_TEST
2448 
START_TEST(redis_list_append_test)2449 START_TEST (redis_list_append_test) {
2450   int res;
2451   pr_redis_t *redis;
2452   module m;
2453   const char *key;
2454   char *val;
2455   size_t valsz;
2456 
2457   mark_point();
2458   res = pr_redis_list_append(NULL, NULL, NULL, NULL, 0);
2459   fail_unless(res < 0, "Failed to handle null redis");
2460   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2461     strerror(errno), errno);
2462 
2463   mark_point();
2464   redis = pr_redis_conn_new(p, NULL, 0);
2465   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
2466     strerror(errno));
2467 
2468   mark_point();
2469   res = pr_redis_list_append(redis, NULL, NULL, NULL, 0);
2470   fail_unless(res < 0, "Failed to handle null module");
2471   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2472     strerror(errno), errno);
2473 
2474   mark_point();
2475   res = pr_redis_list_append(redis, &m, NULL, NULL, 0);
2476   fail_unless(res < 0, "Failed to handle null key");
2477   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2478     strerror(errno), errno);
2479 
2480   key = "testlistkey";
2481   (void) pr_redis_remove(redis, &m, key);
2482 
2483   mark_point();
2484   res = pr_redis_list_append(redis, &m, key, NULL, 0);
2485   fail_unless(res < 0, "Failed to handle null value");
2486   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2487     strerror(errno), errno);
2488 
2489   val = "Some JSON here";
2490 
2491   mark_point();
2492   res = pr_redis_list_append(redis, &m, key, val, 0);
2493   fail_unless(res < 0, "Failed to handle empty value");
2494   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2495     strerror(errno), errno);
2496 
2497   valsz = strlen(val);
2498 
2499   mark_point();
2500   (void) pr_redis_list_remove(redis, &m, key);
2501 
2502   mark_point();
2503   res = pr_redis_list_append(redis, &m, key, val, valsz);
2504   fail_unless(res == 0, "Failed to append to list '%s': %s", key,
2505     strerror(errno));
2506 
2507   mark_point();
2508   res = pr_redis_list_remove(redis, &m, key);
2509   fail_unless(res == 0, "Failed to remove list '%s': %s", key, strerror(errno));
2510 
2511   mark_point();
2512   res = pr_redis_conn_destroy(redis);
2513   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
2514 }
2515 END_TEST
2516 
START_TEST(redis_list_count_test)2517 START_TEST (redis_list_count_test) {
2518   int res;
2519   pr_redis_t *redis;
2520   module m;
2521   const char *key;
2522   uint64_t count = 0;
2523   char *val;
2524   size_t valsz;
2525 
2526   mark_point();
2527   res = pr_redis_list_count(NULL, NULL, NULL, NULL);
2528   fail_unless(res < 0, "Failed to handle null redis");
2529   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2530     strerror(errno), errno);
2531 
2532   mark_point();
2533   redis = pr_redis_conn_new(p, NULL, 0);
2534   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
2535     strerror(errno));
2536 
2537   mark_point();
2538   res = pr_redis_list_count(redis, NULL, NULL, NULL);
2539   fail_unless(res < 0, "Failed to handle null module");
2540   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2541     strerror(errno), errno);
2542 
2543   mark_point();
2544   res = pr_redis_list_count(redis, &m, NULL, NULL);
2545   fail_unless(res < 0, "Failed to handle null key");
2546   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2547     strerror(errno), errno);
2548 
2549   key = "testlistkey";
2550   (void) pr_redis_remove(redis, &m, key);
2551 
2552   mark_point();
2553   res = pr_redis_list_count(redis, &m, key, NULL);
2554   fail_unless(res < 0, "Failed to handle null count");
2555   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2556     strerror(errno), errno);
2557 
2558   mark_point();
2559   res = pr_redis_list_count(redis, &m, key, &count);
2560   fail_unless(res == 0, "Failed to get list count: %s", strerror(errno));
2561   fail_unless(count == 0, "Expected 0, got %lu", (unsigned long) count);
2562 
2563   val = "Some JSON here";
2564   valsz = strlen(val);
2565 
2566   mark_point();
2567   res = pr_redis_list_append(redis, &m, key, val, valsz);
2568   fail_unless(res == 0, "Failed to append to list '%s': %s", key,
2569     strerror(errno));
2570 
2571   mark_point();
2572   res = pr_redis_list_count(redis, &m, key, &count);
2573   fail_unless(res == 0, "Failed to get list count: %s", strerror(errno));
2574   fail_unless(count == 1, "Expected 1, got %lu", (unsigned long) count);
2575 
2576   (void) pr_redis_remove(redis, &m, key);
2577 
2578   mark_point();
2579   res = pr_redis_conn_destroy(redis);
2580   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
2581 }
2582 END_TEST
2583 
START_TEST(redis_list_delete_test)2584 START_TEST (redis_list_delete_test) {
2585   int res;
2586   pr_redis_t *redis;
2587   module m;
2588   const char *key;
2589   char *val;
2590   size_t valsz;
2591 
2592   mark_point();
2593   res = pr_redis_list_delete(NULL, NULL, NULL, NULL, 0);
2594   fail_unless(res < 0, "Failed to handle null redis");
2595   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2596     strerror(errno), errno);
2597 
2598   mark_point();
2599   redis = pr_redis_conn_new(p, NULL, 0);
2600   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
2601     strerror(errno));
2602 
2603   mark_point();
2604   res = pr_redis_list_delete(redis, NULL, NULL, NULL, 0);
2605   fail_unless(res < 0, "Failed to handle null module");
2606   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2607     strerror(errno), errno);
2608 
2609   mark_point();
2610   res = pr_redis_list_delete(redis, &m, NULL, NULL, 0);
2611   fail_unless(res < 0, "Failed to handle null key");
2612   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2613     strerror(errno), errno);
2614 
2615   key = "testlistkey";
2616   (void) pr_redis_remove(redis, &m, key);
2617 
2618   mark_point();
2619   res = pr_redis_list_delete(redis, &m, key, NULL, 0);
2620   fail_unless(res < 0, "Failed to handle null value");
2621   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2622     strerror(errno), errno);
2623 
2624   val = "Some JSON here";
2625 
2626   mark_point();
2627   res = pr_redis_list_delete(redis, &m, key, val, 0);
2628   fail_unless(res < 0, "Failed to handle empty value");
2629   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2630     strerror(errno), errno);
2631 
2632   valsz = strlen(val);
2633 
2634   mark_point();
2635   (void) pr_redis_list_remove(redis, &m, key);
2636 
2637   mark_point();
2638   res = pr_redis_list_delete(redis, &m, key, val, valsz);
2639   fail_unless(res < 0, "Failed to handle nonexistent items");
2640   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
2641     strerror(errno), errno);
2642 
2643   mark_point();
2644   res = pr_redis_list_append(redis, &m, key, val, valsz);
2645   fail_unless(res == 0, "Failed to append to list '%s': %s", key,
2646     strerror(errno));
2647 
2648   mark_point();
2649   res = pr_redis_list_delete(redis, &m, key, val, valsz);
2650   fail_unless(res == 0, "Failed to handle existing items");
2651 
2652   /* Note that we add this item back, just so that the list is NOT empty when
2653    * we go to remove it entirely.
2654    */
2655 
2656   mark_point();
2657   res = pr_redis_list_append(redis, &m, key, val, valsz);
2658   fail_unless(res == 0, "Failed to append to list '%s': %s", key,
2659     strerror(errno));
2660 
2661   mark_point();
2662   res = pr_redis_list_remove(redis, &m, key);
2663   fail_unless(res == 0, "Failed to remove list '%s': %s", key, strerror(errno));
2664 
2665   mark_point();
2666   res = pr_redis_conn_destroy(redis);
2667   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
2668 }
2669 END_TEST
2670 
START_TEST(redis_list_exists_test)2671 START_TEST (redis_list_exists_test) {
2672   int res;
2673   pr_redis_t *redis;
2674   module m;
2675   const char *key;
2676   char *val;
2677   size_t valsz;
2678 
2679   mark_point();
2680   res = pr_redis_list_exists(NULL, NULL, NULL, 0);
2681   fail_unless(res < 0, "Failed to handle null redis");
2682   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2683     strerror(errno), errno);
2684 
2685   mark_point();
2686   redis = pr_redis_conn_new(p, NULL, 0);
2687   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
2688     strerror(errno));
2689 
2690   mark_point();
2691   res = pr_redis_list_exists(redis, NULL, NULL, 0);
2692   fail_unless(res < 0, "Failed to handle null module");
2693   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2694     strerror(errno), errno);
2695 
2696   mark_point();
2697   res = pr_redis_list_exists(redis, &m, NULL, 0);
2698   fail_unless(res < 0, "Failed to handle null key");
2699   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2700     strerror(errno), errno);
2701 
2702   key = "testkey";
2703   (void) pr_redis_remove(redis, &m, key);
2704 
2705   mark_point();
2706   res = pr_redis_list_exists(redis, &m, key, 0);
2707   fail_unless(res == FALSE, "Failed to handle nonexistent item");
2708 
2709   val = "testval";
2710   valsz = strlen(val);
2711 
2712   mark_point();
2713   res = pr_redis_list_append(redis, &m, key, val, valsz);
2714   fail_unless(res == 0, "Failed to add item to key '%s': %s", key,
2715     strerror(errno));
2716 
2717   mark_point();
2718   res = pr_redis_list_exists(redis, &m, key, 0);
2719   fail_unless(res == TRUE, "Failed to handle existing item");
2720 
2721   mark_point();
2722   res = pr_redis_list_exists(redis, &m, key, 3);
2723   fail_unless(res < 0, "Failed to handle invalid index");
2724   fail_unless(errno == ERANGE, "Expected ERANGE (%d), got %s (%d)", ERANGE,
2725     strerror(errno), errno);
2726 
2727   mark_point();
2728   res = pr_redis_remove(redis, &m, key);
2729   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
2730 
2731   mark_point();
2732   res = pr_redis_conn_destroy(redis);
2733   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
2734 }
2735 END_TEST
2736 
START_TEST(redis_list_get_test)2737 START_TEST (redis_list_get_test) {
2738   int res;
2739   pr_redis_t *redis;
2740   module m;
2741   const char *key;
2742   char *val;
2743   size_t valsz;
2744 
2745   mark_point();
2746   res = pr_redis_list_get(NULL, NULL, NULL, NULL, 0, NULL, NULL);
2747   fail_unless(res < 0, "Failed to handle null pool");
2748   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2749     strerror(errno), errno);
2750 
2751   mark_point();
2752   res = pr_redis_list_get(p, NULL, NULL, NULL, 0, NULL, NULL);
2753   fail_unless(res < 0, "Failed to handle null redis");
2754   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2755     strerror(errno), errno);
2756 
2757   mark_point();
2758   redis = pr_redis_conn_new(p, NULL, 0);
2759   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
2760     strerror(errno));
2761 
2762   mark_point();
2763   res = pr_redis_list_get(p, redis, NULL, NULL, 0, NULL, NULL);
2764   fail_unless(res < 0, "Failed to handle null module");
2765   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2766     strerror(errno), errno);
2767 
2768   mark_point();
2769   res = pr_redis_list_get(p, redis, &m, NULL, 0, NULL, NULL);
2770   fail_unless(res < 0, "Failed to handle null key");
2771   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2772     strerror(errno), errno);
2773 
2774   key = "testkey";
2775   (void) pr_redis_remove(redis, &m, key);
2776 
2777   mark_point();
2778   res = pr_redis_list_get(p, redis, &m, key, 0, NULL, NULL);
2779   fail_unless(res < 0, "Failed to handle null value");
2780   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2781     strerror(errno), errno);
2782 
2783   mark_point();
2784   res = pr_redis_list_get(p, redis, &m, key, 0, (void **) &val, NULL);
2785   fail_unless(res < 0, "Failed to handle null valuesz");
2786   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2787     strerror(errno), errno);
2788 
2789   val = "foo";
2790   valsz = strlen(val);
2791 
2792   mark_point();
2793   res = pr_redis_list_append(redis, &m, key, val, valsz);
2794   fail_unless(res == 0, "Failed to append item to key '%s': %s", key,
2795     strerror(errno));
2796 
2797   val = NULL;
2798   valsz = 0;
2799 
2800   mark_point();
2801   res = pr_redis_list_get(p, redis, &m, key, 3, (void **) &val, &valsz);
2802   fail_unless(res < 0, "Failed to handle invalid index");
2803   fail_unless(errno == ERANGE, "Expected ERANGE (%d), got %s (%d)", ERANGE,
2804     strerror(errno), errno);
2805 
2806   mark_point();
2807   res = pr_redis_list_get(p, redis, &m, key, 0, (void **) &val, &valsz);
2808   fail_unless(res == 0, "Failed to get item in list: %s", strerror(errno));
2809   fail_unless(val != NULL, "Expected value, got null");
2810   fail_unless(valsz == 3, "Expected 3, got %lu", (unsigned long) valsz);
2811   fail_unless(strncmp(val, "foo", 3) == 0, "Expected 'foo', got '%.*s'",
2812     (int) valsz, val);
2813 
2814   mark_point();
2815   res = pr_redis_remove(redis, &m, key);
2816   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
2817 
2818   mark_point();
2819   res = pr_redis_conn_destroy(redis);
2820   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
2821 }
2822 END_TEST
2823 
START_TEST(redis_list_getall_test)2824 START_TEST (redis_list_getall_test) {
2825   int res;
2826   pr_redis_t *redis;
2827   module m;
2828   const char *key;
2829   char *val;
2830   size_t valsz;
2831   array_header *values = NULL, *valueszs = NULL;
2832 
2833   mark_point();
2834   res = pr_redis_list_getall(NULL, NULL, NULL, NULL, NULL, NULL);
2835   fail_unless(res < 0, "Failed to handle null pool");
2836   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2837     strerror(errno), errno);
2838 
2839   mark_point();
2840   res = pr_redis_list_getall(p, NULL, NULL, NULL, NULL, NULL);
2841   fail_unless(res < 0, "Failed to handle null redis");
2842   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2843     strerror(errno), errno);
2844 
2845   mark_point();
2846   redis = pr_redis_conn_new(p, NULL, 0);
2847   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
2848     strerror(errno));
2849 
2850   mark_point();
2851   res = pr_redis_list_getall(p, redis, NULL, NULL, NULL, NULL);
2852   fail_unless(res < 0, "Failed to handle null module");
2853   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2854     strerror(errno), errno);
2855 
2856   mark_point();
2857   res = pr_redis_list_getall(p, redis, &m, NULL, NULL, NULL);
2858   fail_unless(res < 0, "Failed to handle null key");
2859   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2860     strerror(errno), errno);
2861 
2862   key = "testkey";
2863   (void) pr_redis_remove(redis, &m, key);
2864 
2865   mark_point();
2866   res = pr_redis_list_getall(p, redis, &m, key, NULL, NULL);
2867   fail_unless(res < 0, "Failed to handle null values");
2868   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2869     strerror(errno), errno);
2870 
2871   mark_point();
2872   res = pr_redis_list_getall(p, redis, &m, key, &values, NULL);
2873   fail_unless(res < 0, "Failed to handle null valueszs");
2874   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2875     strerror(errno), errno);
2876 
2877   val = "foo";
2878   valsz = strlen(val);
2879 
2880   mark_point();
2881   res = pr_redis_list_append(redis, &m, key, val, valsz);
2882   fail_unless(res == 0, "Failed to append item to key '%s': %s", key,
2883     strerror(errno));
2884 
2885   val = "bar";
2886   valsz = strlen(val);
2887 
2888   mark_point();
2889   res = pr_redis_list_append(redis, &m, key, val, valsz);
2890   fail_unless(res == 0, "Failed to append item to key '%s': %s", key,
2891     strerror(errno));
2892 
2893   val = "baz";
2894   valsz = strlen(val);
2895 
2896   mark_point();
2897   res = pr_redis_list_append(redis, &m, key, val, valsz);
2898   fail_unless(res == 0, "Failed to append item to key '%s': %s", key,
2899     strerror(errno));
2900 
2901   mark_point();
2902   res = pr_redis_list_getall(p, redis, &m, key, &values, &valueszs);
2903   fail_unless(res == 0, "Failed to get items in list: %s", strerror(errno));
2904   fail_unless(values != NULL, "Expected values, got null");
2905   fail_unless(valueszs != NULL, "Expected valueszs, got null");
2906   fail_unless(values->nelts == 3, "Expected 3, got %u", values->nelts);
2907   fail_unless(valueszs->nelts == 3, "Expected 3, got %u", valueszs->nelts);
2908 
2909   mark_point();
2910   res = pr_redis_remove(redis, &m, key);
2911   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
2912 
2913   mark_point();
2914   res = pr_redis_conn_destroy(redis);
2915   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
2916 }
2917 END_TEST
2918 
START_TEST(redis_list_pop_params_test)2919 START_TEST (redis_list_pop_params_test) {
2920   int res;
2921   pr_redis_t *redis;
2922   module m;
2923   const char *key;
2924   char *val;
2925   size_t valsz;
2926 
2927   mark_point();
2928   res = pr_redis_list_pop(NULL, NULL, NULL, NULL, NULL, NULL, 0);
2929   fail_unless(res < 0, "Failed to handle null pool");
2930   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2931     strerror(errno), errno);
2932 
2933   mark_point();
2934   res = pr_redis_list_pop(p, NULL, NULL, NULL, NULL, NULL, 0);
2935   fail_unless(res < 0, "Failed to handle null redis");
2936   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2937     strerror(errno), errno);
2938 
2939   mark_point();
2940   redis = pr_redis_conn_new(p, NULL, 0);
2941   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
2942     strerror(errno));
2943 
2944   mark_point();
2945   res = pr_redis_list_pop(p, redis, NULL, NULL, NULL, NULL, 0);
2946   fail_unless(res < 0, "Failed to handle null module");
2947   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2948     strerror(errno), errno);
2949 
2950   mark_point();
2951   res = pr_redis_list_pop(p, redis, &m, NULL, NULL, NULL, 0);
2952   fail_unless(res < 0, "Failed to handle null key");
2953   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2954     strerror(errno), errno);
2955 
2956   key = "testkey";
2957 
2958   mark_point();
2959   res = pr_redis_list_pop(p, redis, &m, key, NULL, NULL, 0);
2960   fail_unless(res < 0, "Failed to handle null value");
2961   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2962     strerror(errno), errno);
2963 
2964   mark_point();
2965   res = pr_redis_list_pop(p, redis, &m, key, (void **) &val, NULL, 0);
2966   fail_unless(res < 0, "Failed to handle null valuesz");
2967   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2968     strerror(errno), errno);
2969 
2970   mark_point();
2971   res = pr_redis_list_pop(p, redis, &m, key, (void **) &val, &valsz, 0);
2972   fail_unless(res < 0, "Failed to handle invalid flags");
2973   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
2974     strerror(errno), errno);
2975 
2976   mark_point();
2977   res = pr_redis_conn_destroy(redis);
2978   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
2979 }
2980 END_TEST
2981 
START_TEST(redis_list_pop_left_test)2982 START_TEST (redis_list_pop_left_test) {
2983   int res, flags = PR_REDIS_LIST_FL_LEFT;
2984   pr_redis_t *redis;
2985   module m;
2986   const char *key;
2987   char *val;
2988   size_t valsz;
2989 
2990   mark_point();
2991   redis = pr_redis_conn_new(p, NULL, 0);
2992   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
2993     strerror(errno));
2994 
2995   key = "testkey";
2996   (void) pr_redis_remove(redis, &m, key);
2997 
2998   mark_point();
2999   res = pr_redis_list_pop(p, redis, &m, key, (void **) &val, &valsz, flags);
3000   fail_unless(res < 0, "Failed to handle nonexistent list");
3001   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
3002     strerror(errno), errno);
3003 
3004   val = "foo";
3005   valsz = strlen(val);
3006 
3007   mark_point();
3008   res = pr_redis_list_append(redis, &m, key, val, valsz);
3009   fail_unless(res == 0, "Failed to append item to key '%s': %s", key,
3010     strerror(errno));
3011 
3012   val = NULL;
3013   valsz = 0;
3014 
3015   mark_point();
3016   res = pr_redis_list_pop(p, redis, &m, key, (void **) &val, &valsz, flags);
3017   fail_unless(res == 0, "Failed to get item in list: %s", strerror(errno));
3018   fail_unless(val != NULL, "Expected value, got null");
3019   fail_unless(valsz == 3, "Expected 3, got %lu", (unsigned long) valsz);
3020   fail_unless(strncmp(val, "foo", 3) == 0, "Expected 'foo', got '%.*s'",
3021     (int) valsz, val);
3022 
3023   mark_point();
3024   res = pr_redis_conn_destroy(redis);
3025   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
3026 }
3027 END_TEST
3028 
START_TEST(redis_list_pop_right_test)3029 START_TEST (redis_list_pop_right_test) {
3030   int res, flags = PR_REDIS_LIST_FL_RIGHT;
3031   pr_redis_t *redis;
3032   module m;
3033   const char *key;
3034   char *val;
3035   size_t valsz;
3036 
3037   mark_point();
3038   redis = pr_redis_conn_new(p, NULL, 0);
3039   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
3040     strerror(errno));
3041 
3042   key = "testkey";
3043   (void) pr_redis_remove(redis, &m, key);
3044 
3045   mark_point();
3046   res = pr_redis_list_pop(p, redis, &m, key, (void **) &val, &valsz, flags);
3047   fail_unless(res < 0, "Failed to handle nonexistent list");
3048   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
3049     strerror(errno), errno);
3050 
3051   val = "foo";
3052   valsz = strlen(val);
3053 
3054   mark_point();
3055   res = pr_redis_list_append(redis, &m, key, val, valsz);
3056   fail_unless(res == 0, "Failed to append item to key '%s': %s", key,
3057     strerror(errno));
3058 
3059   val = NULL;
3060   valsz = 0;
3061 
3062   mark_point();
3063   res = pr_redis_list_pop(p, redis, &m, key, (void **) &val, &valsz, flags);
3064   fail_unless(res == 0, "Failed to get item in list: %s", strerror(errno));
3065   fail_unless(val != NULL, "Expected value, got null");
3066   fail_unless(valsz == 3, "Expected 3, got %lu", (unsigned long) valsz);
3067   fail_unless(strncmp(val, "foo", 3) == 0, "Expected 'foo', got '%.*s'",
3068     (int) valsz, val);
3069 
3070   mark_point();
3071   res = pr_redis_conn_destroy(redis);
3072   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
3073 }
3074 END_TEST
3075 
START_TEST(redis_list_push_params_test)3076 START_TEST (redis_list_push_params_test) {
3077   int res;
3078   pr_redis_t *redis;
3079   module m;
3080   const char *key;
3081   char *val;
3082   size_t valsz;
3083 
3084   mark_point();
3085   res = pr_redis_list_push(NULL, NULL, NULL, NULL, 0, 0);
3086   fail_unless(res < 0, "Failed to handle null redis");
3087   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3088     strerror(errno), errno);
3089 
3090   mark_point();
3091   redis = pr_redis_conn_new(p, NULL, 0);
3092   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
3093     strerror(errno));
3094 
3095   mark_point();
3096   res = pr_redis_list_push(redis, NULL, NULL, NULL, 0, 0);
3097   fail_unless(res < 0, "Failed to handle null module");
3098   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3099     strerror(errno), errno);
3100 
3101   mark_point();
3102   res = pr_redis_list_push(redis, &m, NULL, NULL, 0, 0);
3103   fail_unless(res < 0, "Failed to handle null key");
3104   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3105     strerror(errno), errno);
3106 
3107   key = "testkey";
3108 
3109   mark_point();
3110   res = pr_redis_list_push(redis, &m, key, NULL, 0, 0);
3111   fail_unless(res < 0, "Failed to handle null value");
3112   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3113     strerror(errno), errno);
3114 
3115   val = "testval";
3116   valsz = strlen(val);
3117 
3118   mark_point();
3119   res = pr_redis_list_push(redis, &m, key, val, 0, 0);
3120   fail_unless(res < 0, "Failed to handle empty valuesz");
3121   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3122     strerror(errno), errno);
3123 
3124   mark_point();
3125   res = pr_redis_list_push(redis, &m, key, val, valsz, 0);
3126   fail_unless(res < 0, "Failed to handle invalid flags");
3127   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3128     strerror(errno), errno);
3129 
3130   mark_point();
3131   res = pr_redis_conn_destroy(redis);
3132   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
3133 }
3134 END_TEST
3135 
START_TEST(redis_list_push_left_test)3136 START_TEST (redis_list_push_left_test) {
3137   int res, flags = PR_REDIS_LIST_FL_LEFT;
3138   pr_redis_t *redis;
3139   module m;
3140   const char *key;
3141   char *val;
3142   size_t valsz;
3143 
3144   mark_point();
3145   redis = pr_redis_conn_new(p, NULL, 0);
3146   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
3147     strerror(errno));
3148 
3149   key = "testlistkey";
3150   (void) pr_redis_remove(redis, &m, key);
3151 
3152   val = "Some JSON here";
3153   valsz = strlen(val);
3154 
3155   mark_point();
3156   res = pr_redis_list_push(redis, &m, key, val, valsz, flags);
3157   fail_unless(res == 0, "Failed to append to list '%s': %s", key,
3158     strerror(errno));
3159 
3160   mark_point();
3161   res = pr_redis_list_remove(redis, &m, key);
3162   fail_unless(res == 0, "Failed to remove list '%s': %s", key, strerror(errno));
3163 
3164   mark_point();
3165   res = pr_redis_conn_destroy(redis);
3166   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
3167 }
3168 END_TEST
3169 
START_TEST(redis_list_push_right_test)3170 START_TEST (redis_list_push_right_test) {
3171   int res, flags = PR_REDIS_LIST_FL_RIGHT;
3172   pr_redis_t *redis;
3173   module m;
3174   const char *key;
3175   char *val;
3176   size_t valsz;
3177 
3178   mark_point();
3179   redis = pr_redis_conn_new(p, NULL, 0);
3180   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
3181     strerror(errno));
3182 
3183   key = "testlistkey";
3184   (void) pr_redis_remove(redis, &m, key);
3185 
3186   val = "Some JSON here";
3187   valsz = strlen(val);
3188 
3189   mark_point();
3190   res = pr_redis_list_push(redis, &m, key, val, valsz, flags);
3191   fail_unless(res == 0, "Failed to append to list '%s': %s", key,
3192     strerror(errno));
3193 
3194   mark_point();
3195   res = pr_redis_list_remove(redis, &m, key);
3196   fail_unless(res == 0, "Failed to remove list '%s': %s", key, strerror(errno));
3197 
3198   mark_point();
3199   res = pr_redis_conn_destroy(redis);
3200   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
3201 }
3202 END_TEST
3203 
START_TEST(redis_list_rotate_test)3204 START_TEST (redis_list_rotate_test) {
3205   int res;
3206   pr_redis_t *redis;
3207   module m;
3208   const char *key;
3209   char *val = NULL;
3210   size_t valsz = 0;
3211 
3212   mark_point();
3213   res = pr_redis_list_rotate(NULL, NULL, NULL, NULL, NULL, NULL);
3214   fail_unless(res < 0, "Failed to handle null pool");
3215   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3216     strerror(errno), errno);
3217 
3218   mark_point();
3219   res = pr_redis_list_rotate(p, NULL, NULL, NULL, NULL, NULL);
3220   fail_unless(res < 0, "Failed to handle null redis");
3221   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3222     strerror(errno), errno);
3223 
3224   mark_point();
3225   redis = pr_redis_conn_new(p, NULL, 0);
3226   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
3227     strerror(errno));
3228 
3229   mark_point();
3230   res = pr_redis_list_rotate(p, redis, NULL, NULL, NULL, NULL);
3231   fail_unless(res < 0, "Failed to handle null module");
3232   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3233     strerror(errno), errno);
3234 
3235   mark_point();
3236   res = pr_redis_list_rotate(p, redis, &m, NULL, NULL, NULL);
3237   fail_unless(res < 0, "Failed to handle null key");
3238   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3239     strerror(errno), errno);
3240 
3241   key = "testlistkey";
3242   (void) pr_redis_remove(redis, &m, key);
3243 
3244   mark_point();
3245   res = pr_redis_list_rotate(p, redis, &m, key, NULL, NULL);
3246   fail_unless(res < 0, "Failed to handle null value");
3247   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3248     strerror(errno), errno);
3249 
3250   mark_point();
3251   res = pr_redis_list_rotate(p, redis, &m, key, (void **) &val, NULL);
3252   fail_unless(res < 0, "Failed to handle null value");
3253   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3254     strerror(errno), errno);
3255 
3256   mark_point();
3257   res = pr_redis_list_rotate(p, redis, &m, key, (void **) &val, &valsz);
3258   fail_unless(res < 0, "Failed to handle nonexistent key");
3259   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
3260     strerror(errno), errno);
3261 
3262   val = "foo";
3263   valsz = strlen(val);
3264 
3265   mark_point();
3266   res = pr_redis_list_append(redis, &m, key, val, valsz);
3267   fail_unless(res == 0, "Failed to append item using key '%s': %s", key,
3268     strerror(errno));
3269 
3270   val = "bar";
3271   valsz = strlen(val);
3272 
3273   mark_point();
3274   res = pr_redis_list_append(redis, &m, key, val, valsz);
3275   fail_unless(res == 0, "Failed to append item using key '%s': %s", key,
3276     strerror(errno));
3277 
3278   val = NULL;
3279   valsz = 0;
3280 
3281   mark_point();
3282   res = pr_redis_list_rotate(p, redis, &m, key, (void **) &val, &valsz);
3283   fail_unless(res == 0, "Failed to rotate list '%s': %s", key, strerror(errno));
3284   fail_unless(val != NULL, "Expected value, got NULL");
3285   fail_unless(valsz == 3, "Expected 3, got %lu", (unsigned long) valsz);
3286   fail_unless(strncmp(val, "bar", valsz) == 0, "Expected 'bar', got '%.*s'",
3287     (int) valsz, val);
3288 
3289   val = NULL;
3290   valsz = 0;
3291 
3292   mark_point();
3293   res = pr_redis_list_rotate(p, redis, &m, key, (void **) &val, &valsz);
3294   fail_unless(res == 0, "Failed to rotate list '%s': %s", key, strerror(errno));
3295   fail_unless(val != NULL, "Expected value, got NULL");
3296   fail_unless(valsz == 3, "Expected 3, got %lu", (unsigned long) valsz);
3297   fail_unless(strncmp(val, "foo", valsz) == 0, "Expected 'foo', got '%.*s'",
3298     (int) valsz, val);
3299 
3300   val = NULL;
3301   valsz = 0;
3302 
3303   mark_point();
3304   res = pr_redis_list_rotate(p, redis, &m, key, (void **) &val, &valsz);
3305   fail_unless(res == 0, "Failed to rotate list '%s': %s", key, strerror(errno));
3306   fail_unless(val != NULL, "Expected value, got NULL");
3307   fail_unless(valsz == 3, "Expected 3, got %lu", (unsigned long) valsz);
3308   fail_unless(strncmp(val, "bar", valsz) == 0, "Expected 'bar', got '%.*s'",
3309     (int) valsz, val);
3310 
3311   mark_point();
3312   res = pr_redis_list_remove(redis, &m, key);
3313   fail_unless(res == 0, "Failed to remove list '%s': %s", key, strerror(errno));
3314 
3315   mark_point();
3316   res = pr_redis_conn_destroy(redis);
3317   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
3318 }
3319 END_TEST
3320 
START_TEST(redis_list_set_test)3321 START_TEST (redis_list_set_test) {
3322   int res;
3323   pr_redis_t *redis;
3324   module m;
3325   const char *key;
3326   char *val;
3327   size_t valsz;
3328 
3329   mark_point();
3330   res = pr_redis_list_set(NULL, NULL, NULL, 0, NULL, 0);
3331   fail_unless(res < 0, "Failed to handle null redis");
3332   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3333     strerror(errno), errno);
3334 
3335   mark_point();
3336   redis = pr_redis_conn_new(p, NULL, 0);
3337   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
3338     strerror(errno));
3339 
3340   mark_point();
3341   res = pr_redis_list_set(redis, NULL, NULL, 0, NULL, 0);
3342   fail_unless(res < 0, "Failed to handle null module");
3343   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3344     strerror(errno), errno);
3345 
3346   mark_point();
3347   res = pr_redis_list_set(redis, &m, NULL, 0, NULL, 0);
3348   fail_unless(res < 0, "Failed to handle null key");
3349   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3350     strerror(errno), errno);
3351 
3352   key = "testlistkey";
3353   (void) pr_redis_remove(redis, &m, key);
3354 
3355   mark_point();
3356   res = pr_redis_list_set(redis, &m, key, 0, NULL, 0);
3357   fail_unless(res < 0, "Failed to handle null value");
3358   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3359     strerror(errno), errno);
3360 
3361   val = "Some JSON here";
3362 
3363   mark_point();
3364   res = pr_redis_list_set(redis, &m, key, 0, val, 0);
3365   fail_unless(res < 0, "Failed to handle empty value");
3366   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3367     strerror(errno), errno);
3368 
3369   valsz = strlen(val);
3370 
3371   mark_point();
3372   (void) pr_redis_list_remove(redis, &m, key);
3373 
3374   mark_point();
3375   res = pr_redis_list_set(redis, &m, key, 3, val, valsz);
3376   fail_unless(res < 0, "Failed to handle invalid index");
3377   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3378     strerror(errno), errno);
3379 
3380   mark_point();
3381   res = pr_redis_list_set(redis, &m, key, 0, val, valsz);
3382   fail_unless(res < 0, "Failed to handle invalid index");
3383   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3384     strerror(errno), errno);
3385 
3386   /* Append the item first, then set it. */
3387 
3388   mark_point();
3389   res = pr_redis_list_append(redis, &m, key, val, valsz);
3390   fail_unless(res == 0, "Failed to append item using key '%s': %s", key,
3391     strerror(errno));
3392 
3393   val = "listval2";
3394   valsz = strlen(val);
3395 
3396   mark_point();
3397   res = pr_redis_list_set(redis, &m, key, 0, val, valsz);
3398   fail_unless(res == 0, "Failed to set item at index 0 using key '%s': %s",
3399     key, strerror(errno));
3400 
3401   mark_point();
3402   res = pr_redis_list_remove(redis, &m, key);
3403   fail_unless(res == 0, "Failed to remove list '%s': %s", key, strerror(errno));
3404 
3405   mark_point();
3406   res = pr_redis_conn_destroy(redis);
3407   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
3408 }
3409 END_TEST
3410 
START_TEST(redis_list_setall_test)3411 START_TEST (redis_list_setall_test) {
3412   int res;
3413   pr_redis_t *redis;
3414   module m;
3415   const char *key;
3416   array_header *vals, *valszs;
3417 
3418   mark_point();
3419   res = pr_redis_list_setall(NULL, NULL, NULL, NULL, NULL);
3420   fail_unless(res < 0, "Failed to handle null redis");
3421   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3422     strerror(errno), errno);
3423 
3424   mark_point();
3425   redis = pr_redis_conn_new(p, NULL, 0);
3426   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
3427     strerror(errno));
3428 
3429   mark_point();
3430   res = pr_redis_list_setall(redis, NULL, NULL, NULL, NULL);
3431   fail_unless(res < 0, "Failed to handle null module");
3432   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3433     strerror(errno), errno);
3434 
3435   mark_point();
3436   res = pr_redis_list_setall(redis, &m, NULL, NULL, NULL);
3437   fail_unless(res < 0, "Failed to handle null key");
3438   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3439     strerror(errno), errno);
3440 
3441   key = "testlistkey";
3442   (void) pr_redis_remove(redis, &m, key);
3443 
3444   mark_point();
3445   res = pr_redis_list_setall(redis, &m, key, NULL, NULL);
3446   fail_unless(res < 0, "Failed to handle null values");
3447   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3448     strerror(errno), errno);
3449 
3450   vals = make_array(p, 0, sizeof(char *));
3451 
3452   mark_point();
3453   res = pr_redis_list_setall(redis, &m, key, vals, NULL);
3454   fail_unless(res < 0, "Failed to handle empty values");
3455   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3456     strerror(errno), errno);
3457 
3458   *((char **) push_array(vals)) = pstrdup(p, "Some JSON here");
3459 
3460   mark_point();
3461   res = pr_redis_list_setall(redis, &m, key, vals, NULL);
3462   fail_unless(res < 0, "Failed to handle null valueszs");
3463   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3464     strerror(errno), errno);
3465 
3466   valszs = make_array(p, 0, sizeof(char *));
3467 
3468   mark_point();
3469   res = pr_redis_list_setall(redis, &m, key, vals, valszs);
3470   fail_unless(res < 0, "Failed to handle empty valueszs");
3471   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3472     strerror(errno), errno);
3473 
3474   *((size_t *) push_array(valszs)) = strlen("Some JSON here");
3475   *((char **) push_array(vals)) = pstrdup(p, "bar");
3476 
3477   mark_point();
3478   res = pr_redis_list_setall(redis, &m, key, vals, valszs);
3479   fail_unless(res < 0, "Failed to handle mismatched values/valueszs");
3480   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3481     strerror(errno), errno);
3482 
3483   *((size_t *) push_array(valszs)) = strlen("bar");
3484 
3485   mark_point();
3486   (void) pr_redis_list_remove(redis, &m, key);
3487 
3488   mark_point();
3489   res = pr_redis_list_setall(redis, &m, key, vals, valszs);
3490   fail_unless(res == 0, "Failed to set items using key '%s': %s",
3491     key, strerror(errno));
3492 
3493   mark_point();
3494   res = pr_redis_list_remove(redis, &m, key);
3495   fail_unless(res == 0, "Failed to remove list '%s': %s", key, strerror(errno));
3496 
3497   mark_point();
3498   res = pr_redis_conn_destroy(redis);
3499   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
3500 }
3501 END_TEST
3502 
START_TEST(redis_set_remove_test)3503 START_TEST (redis_set_remove_test) {
3504   int res;
3505   pr_redis_t *redis;
3506   module m;
3507   const char *key;
3508 
3509   mark_point();
3510   res = pr_redis_set_remove(NULL, NULL, NULL);
3511   fail_unless(res < 0, "Failed to handle null redis");
3512   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3513     strerror(errno), errno);
3514 
3515   mark_point();
3516   redis = pr_redis_conn_new(p, NULL, 0);
3517   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
3518     strerror(errno));
3519 
3520   mark_point();
3521   res = pr_redis_set_remove(redis, NULL, NULL);
3522   fail_unless(res < 0, "Failed to handle null module");
3523   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3524     strerror(errno), errno);
3525 
3526   mark_point();
3527   res = pr_redis_set_remove(redis, &m, NULL);
3528   fail_unless(res < 0, "Failed to handle null key");
3529   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3530     strerror(errno), errno);
3531 
3532   key = "testkey";
3533 
3534   mark_point();
3535   res = pr_redis_set_remove(redis, &m, key);
3536   fail_unless(res < 0, "Unexpectedly removed key '%s'", key);
3537   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
3538     strerror(errno), errno);
3539 
3540   mark_point();
3541   res = pr_redis_conn_destroy(redis);
3542   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
3543 }
3544 END_TEST
3545 
START_TEST(redis_set_exists_test)3546 START_TEST (redis_set_exists_test) {
3547   int res;
3548   pr_redis_t *redis;
3549   module m;
3550   const char *key;
3551   char *val;
3552   size_t valsz;
3553 
3554   mark_point();
3555   res = pr_redis_set_exists(NULL, NULL, NULL, NULL, 0);
3556   fail_unless(res < 0, "Failed to handle null redis");
3557   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3558     strerror(errno), errno);
3559 
3560   mark_point();
3561   redis = pr_redis_conn_new(p, NULL, 0);
3562   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
3563     strerror(errno));
3564 
3565   mark_point();
3566   res = pr_redis_set_exists(redis, NULL, NULL, NULL, 0);
3567   fail_unless(res < 0, "Failed to handle null module");
3568   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3569     strerror(errno), errno);
3570 
3571   mark_point();
3572   res = pr_redis_set_exists(redis, &m, NULL, NULL, 0);
3573   fail_unless(res < 0, "Failed to handle null key");
3574   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3575     strerror(errno), errno);
3576 
3577   key = "testkey";
3578   (void) pr_redis_remove(redis, &m, key);
3579 
3580   mark_point();
3581   res = pr_redis_set_exists(redis, &m, key, NULL, 0);
3582   fail_unless(res < 0, "Failed to handle null value");
3583   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3584     strerror(errno), errno);
3585 
3586   val = "testval";
3587   valsz = 0;
3588 
3589   mark_point();
3590   res = pr_redis_set_exists(redis, &m, key, val, valsz);
3591   fail_unless(res < 0, "Failed to handle zero valuesz");
3592   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3593     strerror(errno), errno);
3594 
3595   valsz = strlen(val);
3596 
3597   mark_point();
3598   res = pr_redis_set_exists(redis, &m, key, val, valsz);
3599   fail_unless(res == FALSE, "Failed to handle nonexistent item");
3600 
3601   mark_point();
3602   res = pr_redis_set_add(redis, &m, key, val, valsz);
3603   fail_unless(res == 0, "Failed to add item to key '%s': %s", key,
3604     strerror(errno));
3605 
3606   mark_point();
3607   res = pr_redis_set_exists(redis, &m, key, val, valsz);
3608   fail_unless(res == TRUE, "Failed to handle existing item");
3609 
3610   mark_point();
3611   res = pr_redis_set_remove(redis, &m, key);
3612   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
3613 
3614   mark_point();
3615   res = pr_redis_conn_destroy(redis);
3616   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
3617 }
3618 END_TEST
3619 
START_TEST(redis_set_add_test)3620 START_TEST (redis_set_add_test) {
3621   int res;
3622   pr_redis_t *redis;
3623   module m;
3624   const char *key;
3625   char *val;
3626   size_t valsz;
3627 
3628   mark_point();
3629   res = pr_redis_set_add(NULL, NULL, NULL, NULL, 0);
3630   fail_unless(res < 0, "Failed to handle null redis");
3631   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3632     strerror(errno), errno);
3633 
3634   mark_point();
3635   redis = pr_redis_conn_new(p, NULL, 0);
3636   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
3637     strerror(errno));
3638 
3639   mark_point();
3640   res = pr_redis_set_add(redis, NULL, NULL, NULL, 0);
3641   fail_unless(res < 0, "Failed to handle null module");
3642   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3643     strerror(errno), errno);
3644 
3645   mark_point();
3646   res = pr_redis_set_add(redis, &m, NULL, NULL, 0);
3647   fail_unless(res < 0, "Failed to handle null key");
3648   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3649     strerror(errno), errno);
3650 
3651   key = "testkey";
3652   (void) pr_redis_set_remove(redis, &m, key);
3653 
3654   mark_point();
3655   res = pr_redis_set_add(redis, &m, key, NULL, 0);
3656   fail_unless(res < 0, "Failed to handle null value");
3657   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3658     strerror(errno), errno);
3659 
3660   val = "testval";
3661   valsz = 0;
3662 
3663   mark_point();
3664   res = pr_redis_set_add(redis, &m, key, val, 0);
3665   fail_unless(res < 0, "Failed to handle zero valuesz");
3666   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3667     strerror(errno), errno);
3668 
3669   valsz = strlen(val);
3670 
3671   mark_point();
3672   res = pr_redis_set_add(redis, &m, key, val, valsz);
3673   fail_unless(res == 0, "Failed to add key '%s', val '%s': %s", key, val,
3674     strerror(errno));
3675 
3676   mark_point();
3677   res = pr_redis_set_add(redis, &m, key, val, valsz);
3678   fail_unless(res < 0, "Failed to handle duplicates");
3679   fail_unless(errno == EEXIST, "Expected EEXIST (%d), got %s (%d)", EEXIST,
3680     strerror(errno), errno);
3681 
3682   mark_point();
3683   res = pr_redis_remove(redis, &m, key);
3684   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
3685 
3686   mark_point();
3687   res = pr_redis_conn_destroy(redis);
3688   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
3689 }
3690 END_TEST
3691 
START_TEST(redis_set_count_test)3692 START_TEST (redis_set_count_test) {
3693   int res;
3694   pr_redis_t *redis;
3695   module m;
3696   const char *key;
3697   uint64_t count;
3698   void *val;
3699   size_t valsz;
3700 
3701   mark_point();
3702   res = pr_redis_set_count(NULL, NULL, NULL, NULL);
3703   fail_unless(res < 0, "Failed to handle null redis");
3704   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3705     strerror(errno), errno);
3706 
3707   mark_point();
3708   redis = pr_redis_conn_new(p, NULL, 0);
3709   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
3710     strerror(errno));
3711 
3712   mark_point();
3713   res = pr_redis_set_count(redis, NULL, NULL, NULL);
3714   fail_unless(res < 0, "Failed to handle null module");
3715   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3716     strerror(errno), errno);
3717 
3718   mark_point();
3719   res = pr_redis_set_count(redis, &m, NULL, NULL);
3720   fail_unless(res < 0, "Failed to handle null key");
3721   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3722     strerror(errno), errno);
3723 
3724   mark_point();
3725 
3726   key = "testkey";
3727   (void) pr_redis_remove(redis, &m, key);
3728 
3729   mark_point();
3730   res = pr_redis_set_count(redis, &m, key, NULL);
3731   fail_unless(res < 0, "Failed to handle null count");
3732   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3733     strerror(errno), errno);
3734 
3735   mark_point();
3736   res = pr_redis_set_count(redis, &m, key, &count);
3737   fail_unless(res == 0, "Failed to handle get set count: %s", strerror(errno));
3738   fail_unless(count == 0, "Expected 0, got %lu", (unsigned long) count);
3739 
3740   val = "testval";
3741   valsz = strlen(val);
3742 
3743   mark_point();
3744   res = pr_redis_set_add(redis, &m, key, val, valsz);
3745   fail_unless(res == 0, "Failed to add item to key '%s': %s", key,
3746     strerror(errno));
3747 
3748   mark_point();
3749   res = pr_redis_set_count(redis, &m, key, &count);
3750   fail_unless(res == 0, "Failed to handle get set count: %s", strerror(errno));
3751   fail_unless(count == 1, "Expected 1, got %lu", (unsigned long) count);
3752 
3753   mark_point();
3754   res = pr_redis_remove(redis, &m, key);
3755   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
3756 
3757   mark_point();
3758   res = pr_redis_conn_destroy(redis);
3759   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
3760 }
3761 END_TEST
3762 
START_TEST(redis_set_delete_test)3763 START_TEST (redis_set_delete_test) {
3764   int res;
3765   pr_redis_t *redis;
3766   module m;
3767   const char *key;
3768   char *val;
3769   size_t valsz;
3770 
3771   mark_point();
3772   res = pr_redis_set_delete(NULL, NULL, NULL, NULL, 0);
3773   fail_unless(res < 0, "Failed to handle null redis");
3774   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3775     strerror(errno), errno);
3776 
3777   mark_point();
3778   redis = pr_redis_conn_new(p, NULL, 0);
3779   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
3780     strerror(errno));
3781 
3782   mark_point();
3783   res = pr_redis_set_delete(redis, NULL, NULL, NULL, 0);
3784   fail_unless(res < 0, "Failed to handle null module");
3785   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3786     strerror(errno), errno);
3787 
3788   mark_point();
3789   res = pr_redis_set_delete(redis, &m, NULL, NULL, 0);
3790   fail_unless(res < 0, "Failed to handle null key");
3791   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3792     strerror(errno), errno);
3793 
3794   key = "testkey";
3795   (void) pr_redis_remove(redis, &m, key);
3796 
3797   mark_point();
3798   res = pr_redis_set_delete(redis, &m, key, NULL, 0);
3799   fail_unless(res < 0, "Failed to handle null value");
3800   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3801     strerror(errno), errno);
3802 
3803   val = "testval";
3804   valsz = 0;
3805 
3806   mark_point();
3807   res = pr_redis_set_delete(redis, &m, key, val, valsz);
3808   fail_unless(res < 0, "Failed to handle zero valuesz");
3809   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3810     strerror(errno), errno);
3811 
3812   valsz = strlen(val);
3813 
3814   mark_point();
3815   res = pr_redis_set_delete(redis, &m, key, val, valsz);
3816   fail_unless(res < 0, "Failed to handle nonexistent item");
3817   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
3818     strerror(errno), errno);
3819 
3820   mark_point();
3821   res = pr_redis_set_add(redis, &m, key, val, valsz);
3822   fail_unless(res == 0, "Failed to add item to key '%s': %s", key,
3823     strerror(errno));
3824 
3825   mark_point();
3826   res = pr_redis_set_delete(redis, &m, key, val, valsz);
3827   fail_unless(res == 0, "Failed to delete item from set: %s", strerror(errno));
3828 
3829   /* Note that we add this item back, just so that the set is NOT empty when
3830    * we go to remove it entirely.
3831    */
3832 
3833   mark_point();
3834   res = pr_redis_set_add(redis, &m, key, val, valsz);
3835   fail_unless(res == 0, "Failed to add item to key '%s': %s", key,
3836     strerror(errno));
3837 
3838   mark_point();
3839   res = pr_redis_remove(redis, &m, key);
3840   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
3841 
3842   mark_point();
3843   res = pr_redis_conn_destroy(redis);
3844   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
3845 }
3846 END_TEST
3847 
START_TEST(redis_set_getall_test)3848 START_TEST (redis_set_getall_test) {
3849   int res;
3850   pr_redis_t *redis;
3851   module m;
3852   const char *key;
3853   char *val;
3854   size_t valsz;
3855   array_header *values = NULL, *valueszs = NULL;
3856 
3857   mark_point();
3858   res = pr_redis_set_getall(NULL, NULL, NULL, NULL, NULL, NULL);
3859   fail_unless(res < 0, "Failed to handle null pool");
3860   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3861     strerror(errno), errno);
3862 
3863   mark_point();
3864   res = pr_redis_set_getall(p, NULL, NULL, NULL, NULL, NULL);
3865   fail_unless(res < 0, "Failed to handle null redis");
3866   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3867     strerror(errno), errno);
3868 
3869   mark_point();
3870   redis = pr_redis_conn_new(p, NULL, 0);
3871   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
3872     strerror(errno));
3873 
3874   mark_point();
3875   res = pr_redis_set_getall(p, redis, NULL, NULL, NULL, NULL);
3876   fail_unless(res < 0, "Failed to handle null module");
3877   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3878     strerror(errno), errno);
3879 
3880   mark_point();
3881   res = pr_redis_set_getall(p, redis, &m, NULL, NULL, NULL);
3882   fail_unless(res < 0, "Failed to handle null key");
3883   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3884     strerror(errno), errno);
3885 
3886   key = "testkey";
3887   (void) pr_redis_remove(redis, &m, key);
3888 
3889   mark_point();
3890   res = pr_redis_set_getall(p, redis, &m, key, NULL, NULL);
3891   fail_unless(res < 0, "Failed to handle null values");
3892   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3893     strerror(errno), errno);
3894 
3895   mark_point();
3896   res = pr_redis_set_getall(p, redis, &m, key, &values, NULL);
3897   fail_unless(res < 0, "Failed to handle null valueszs");
3898   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3899     strerror(errno), errno);
3900 
3901   val = "foo";
3902   valsz = strlen(val);
3903 
3904   mark_point();
3905   res = pr_redis_set_add(redis, &m, key, val, valsz);
3906   fail_unless(res == 0, "Failed to add item to key '%s': %s", key,
3907     strerror(errno));
3908 
3909   val = "bar";
3910   valsz = strlen(val);
3911 
3912   mark_point();
3913   res = pr_redis_set_add(redis, &m, key, val, valsz);
3914   fail_unless(res == 0, "Failed to add item to key '%s': %s", key,
3915     strerror(errno));
3916 
3917   val = "baz";
3918   valsz = strlen(val);
3919 
3920   mark_point();
3921   res = pr_redis_set_add(redis, &m, key, val, valsz);
3922   fail_unless(res == 0, "Failed to add item to key '%s': %s", key,
3923     strerror(errno));
3924 
3925   mark_point();
3926   res = pr_redis_set_getall(p, redis, &m, key, &values, &valueszs);
3927   fail_unless(res == 0, "Failed to get items in set: %s", strerror(errno));
3928   fail_unless(values != NULL, "Expected values, got null");
3929   fail_unless(valueszs != NULL, "Expected valueszs, got null");
3930   fail_unless(values->nelts == 3, "Expected 3, got %u", values->nelts);
3931   fail_unless(valueszs->nelts == 3, "Expected 3, got %u", valueszs->nelts);
3932 
3933   mark_point();
3934   res = pr_redis_remove(redis, &m, key);
3935   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
3936 
3937   mark_point();
3938   res = pr_redis_conn_destroy(redis);
3939   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
3940 }
3941 END_TEST
3942 
START_TEST(redis_set_setall_test)3943 START_TEST (redis_set_setall_test) {
3944   int res;
3945   pr_redis_t *redis;
3946   module m;
3947   const char *key;
3948   array_header *vals, *valszs;
3949 
3950   mark_point();
3951   res = pr_redis_set_setall(NULL, NULL, NULL, NULL, NULL);
3952   fail_unless(res < 0, "Failed to handle null redis");
3953   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3954     strerror(errno), errno);
3955 
3956   mark_point();
3957   redis = pr_redis_conn_new(p, NULL, 0);
3958   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
3959     strerror(errno));
3960 
3961   mark_point();
3962   res = pr_redis_set_setall(redis, NULL, NULL, NULL, NULL);
3963   fail_unless(res < 0, "Failed to handle null module");
3964   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3965     strerror(errno), errno);
3966 
3967   mark_point();
3968   res = pr_redis_set_setall(redis, &m, NULL, NULL, NULL);
3969   fail_unless(res < 0, "Failed to handle null key");
3970   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3971     strerror(errno), errno);
3972 
3973   key = "testsetkey";
3974   (void) pr_redis_remove(redis, &m, key);
3975 
3976   mark_point();
3977   res = pr_redis_set_setall(redis, &m, key, NULL, NULL);
3978   fail_unless(res < 0, "Failed to handle null values");
3979   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3980     strerror(errno), errno);
3981 
3982   vals = make_array(p, 0, sizeof(char *));
3983 
3984   mark_point();
3985   res = pr_redis_set_setall(redis, &m, key, vals, NULL);
3986   fail_unless(res < 0, "Failed to handle empty values");
3987   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3988     strerror(errno), errno);
3989 
3990   *((char **) push_array(vals)) = pstrdup(p, "Some JSON here");
3991 
3992   mark_point();
3993   res = pr_redis_set_setall(redis, &m, key, vals, NULL);
3994   fail_unless(res < 0, "Failed to handle null valueszs");
3995   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
3996     strerror(errno), errno);
3997 
3998   valszs = make_array(p, 0, sizeof(char *));
3999 
4000   mark_point();
4001   res = pr_redis_set_setall(redis, &m, key, vals, valszs);
4002   fail_unless(res < 0, "Failed to handle empty valueszs");
4003   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4004     strerror(errno), errno);
4005 
4006   *((size_t *) push_array(valszs)) = strlen("Some JSON here");
4007   *((char **) push_array(vals)) = pstrdup(p, "bar");
4008 
4009   mark_point();
4010   res = pr_redis_set_setall(redis, &m, key, vals, valszs);
4011   fail_unless(res < 0, "Failed to handle mismatched values/valueszs");
4012   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4013     strerror(errno), errno);
4014 
4015   *((size_t *) push_array(valszs)) = strlen("bar");
4016 
4017   mark_point();
4018   (void) pr_redis_set_remove(redis, &m, key);
4019 
4020   mark_point();
4021   res = pr_redis_set_setall(redis, &m, key, vals, valszs);
4022   fail_unless(res == 0, "Failed to set items using key '%s': %s",
4023     key, strerror(errno));
4024 
4025   mark_point();
4026   res = pr_redis_set_remove(redis, &m, key);
4027   fail_unless(res == 0, "Failed to remove set '%s': %s", key, strerror(errno));
4028 
4029   mark_point();
4030   res = pr_redis_conn_destroy(redis);
4031   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
4032 }
4033 END_TEST
4034 
START_TEST(redis_sorted_set_remove_test)4035 START_TEST (redis_sorted_set_remove_test) {
4036   int res;
4037   pr_redis_t *redis;
4038   module m;
4039   const char *key;
4040 
4041   mark_point();
4042   res = pr_redis_sorted_set_remove(NULL, NULL, NULL);
4043   fail_unless(res < 0, "Failed to handle null redis");
4044   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4045     strerror(errno), errno);
4046 
4047   mark_point();
4048   redis = pr_redis_conn_new(p, NULL, 0);
4049   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
4050     strerror(errno));
4051 
4052   mark_point();
4053   res = pr_redis_sorted_set_remove(redis, NULL, NULL);
4054   fail_unless(res < 0, "Failed to handle null module");
4055   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4056     strerror(errno), errno);
4057 
4058   mark_point();
4059   res = pr_redis_sorted_set_remove(redis, &m, NULL);
4060   fail_unless(res < 0, "Failed to handle null key");
4061   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4062     strerror(errno), errno);
4063 
4064   key = "testkey";
4065 
4066   mark_point();
4067   res = pr_redis_sorted_set_remove(redis, &m, key);
4068   fail_unless(res < 0, "Unexpectedly removed key '%s'", key);
4069   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
4070     strerror(errno), errno);
4071 
4072   mark_point();
4073   res = pr_redis_conn_destroy(redis);
4074   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
4075 }
4076 END_TEST
4077 
START_TEST(redis_sorted_set_exists_test)4078 START_TEST (redis_sorted_set_exists_test) {
4079   int res;
4080   pr_redis_t *redis;
4081   module m;
4082   const char *key;
4083   char *val;
4084   size_t valsz;
4085 
4086   mark_point();
4087   res = pr_redis_sorted_set_exists(NULL, NULL, NULL, NULL, 0);
4088   fail_unless(res < 0, "Failed to handle null redis");
4089   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4090     strerror(errno), errno);
4091 
4092   mark_point();
4093   redis = pr_redis_conn_new(p, NULL, 0);
4094   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
4095     strerror(errno));
4096 
4097   mark_point();
4098   res = pr_redis_sorted_set_exists(redis, NULL, NULL, NULL, 0);
4099   fail_unless(res < 0, "Failed to handle null module");
4100   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4101     strerror(errno), errno);
4102 
4103   mark_point();
4104   res = pr_redis_sorted_set_exists(redis, &m, NULL, NULL, 0);
4105   fail_unless(res < 0, "Failed to handle null key");
4106   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4107     strerror(errno), errno);
4108 
4109   key = "testkey";
4110   (void) pr_redis_remove(redis, &m, key);
4111 
4112   mark_point();
4113   res = pr_redis_sorted_set_exists(redis, &m, key, NULL, 0);
4114   fail_unless(res < 0, "Failed to handle null value");
4115   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4116     strerror(errno), errno);
4117 
4118   val = "testval";
4119   valsz = 0;
4120 
4121   mark_point();
4122   res = pr_redis_sorted_set_exists(redis, &m, key, val, valsz);
4123   fail_unless(res < 0, "Failed to handle zero valuesz");
4124   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4125     strerror(errno), errno);
4126 
4127   valsz = strlen(val);
4128 
4129   mark_point();
4130   res = pr_redis_sorted_set_exists(redis, &m, key, val, valsz);
4131   fail_unless(res == FALSE, "Failed to handle nonexistent item");
4132 
4133   mark_point();
4134   res = pr_redis_sorted_set_add(redis, &m, key, val, valsz, 1.0);
4135   fail_unless(res == 0, "Failed to add item to key '%s': %s", key,
4136     strerror(errno));
4137 
4138   mark_point();
4139   res = pr_redis_sorted_set_exists(redis, &m, key, val, valsz);
4140   fail_unless(res == TRUE, "Failed to handle existing item");
4141 
4142   mark_point();
4143   res = pr_redis_sorted_set_remove(redis, &m, key);
4144   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
4145 
4146   mark_point();
4147   res = pr_redis_conn_destroy(redis);
4148   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
4149 }
4150 END_TEST
4151 
START_TEST(redis_sorted_set_add_test)4152 START_TEST (redis_sorted_set_add_test) {
4153   int res;
4154   pr_redis_t *redis;
4155   module m;
4156   const char *key;
4157   char *val;
4158   size_t valsz;
4159   float score;
4160 
4161   mark_point();
4162   res = pr_redis_sorted_set_add(NULL, NULL, NULL, NULL, 0, 0.0);
4163   fail_unless(res < 0, "Failed to handle null redis");
4164   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4165     strerror(errno), errno);
4166 
4167   mark_point();
4168   redis = pr_redis_conn_new(p, NULL, 0);
4169   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
4170     strerror(errno));
4171 
4172   mark_point();
4173   res = pr_redis_sorted_set_add(redis, NULL, NULL, NULL, 0, 0.0);
4174   fail_unless(res < 0, "Failed to handle null module");
4175   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4176     strerror(errno), errno);
4177 
4178   mark_point();
4179   res = pr_redis_sorted_set_add(redis, &m, NULL, NULL, 0, 0.0);
4180   fail_unless(res < 0, "Failed to handle null key");
4181   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4182     strerror(errno), errno);
4183 
4184   key = "testkey";
4185   (void) pr_redis_remove(redis, &m, key);
4186 
4187   mark_point();
4188   res = pr_redis_sorted_set_add(redis, &m, key, NULL, 0, 0.0);
4189   fail_unless(res < 0, "Failed to handle null value");
4190   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4191     strerror(errno), errno);
4192 
4193   val = "testval";
4194   valsz = 0;
4195 
4196   mark_point();
4197   res = pr_redis_sorted_set_add(redis, &m, key, val, 0, 0.0);
4198   fail_unless(res < 0, "Failed to handle zero valuesz");
4199   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4200     strerror(errno), errno);
4201 
4202   valsz = strlen(val);
4203   score = 75.32;
4204 
4205   mark_point();
4206   res = pr_redis_sorted_set_add(redis, &m, key, val, valsz, score);
4207   fail_unless(res == 0, "Failed to add key '%s', val '%s': %s", key, val,
4208     strerror(errno));
4209 
4210   mark_point();
4211   res = pr_redis_sorted_set_add(redis, &m, key, val, valsz, score);
4212   fail_unless(res < 0, "Failed to handle duplicates");
4213   fail_unless(errno == EEXIST, "Expected EEXIST (%d), got %s (%d)", EEXIST,
4214     strerror(errno), errno);
4215 
4216   mark_point();
4217   res = pr_redis_remove(redis, &m, key);
4218   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
4219 
4220   mark_point();
4221   res = pr_redis_conn_destroy(redis);
4222   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
4223 }
4224 END_TEST
4225 
START_TEST(redis_sorted_set_count_test)4226 START_TEST (redis_sorted_set_count_test) {
4227   int res;
4228   pr_redis_t *redis;
4229   module m;
4230   const char *key;
4231   uint64_t count;
4232   void *val;
4233   size_t valsz;
4234   float score;
4235 
4236   mark_point();
4237   res = pr_redis_sorted_set_count(NULL, NULL, NULL, NULL);
4238   fail_unless(res < 0, "Failed to handle null redis");
4239   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4240     strerror(errno), errno);
4241 
4242   mark_point();
4243   redis = pr_redis_conn_new(p, NULL, 0);
4244   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
4245     strerror(errno));
4246 
4247   mark_point();
4248   res = pr_redis_sorted_set_count(redis, NULL, NULL, NULL);
4249   fail_unless(res < 0, "Failed to handle null module");
4250   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4251     strerror(errno), errno);
4252 
4253   mark_point();
4254   res = pr_redis_sorted_set_count(redis, &m, NULL, NULL);
4255   fail_unless(res < 0, "Failed to handle null key");
4256   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4257     strerror(errno), errno);
4258 
4259   mark_point();
4260 
4261   key = "testkey";
4262   (void) pr_redis_remove(redis, &m, key);
4263 
4264   mark_point();
4265   res = pr_redis_sorted_set_count(redis, &m, key, NULL);
4266   fail_unless(res < 0, "Failed to handle null count");
4267   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4268     strerror(errno), errno);
4269 
4270   mark_point();
4271   res = pr_redis_sorted_set_count(redis, &m, key, &count);
4272   fail_unless(res == 0, "Failed to handle get sorted set count: %s",
4273     strerror(errno));
4274   fail_unless(count == 0, "Expected 0, got %lu", (unsigned long) count);
4275 
4276   val = "testval";
4277   valsz = strlen(val);
4278   score = 23.45;
4279 
4280   mark_point();
4281   res = pr_redis_sorted_set_add(redis, &m, key, val, valsz, score);
4282   fail_unless(res == 0, "Failed to add item to key '%s': %s", key,
4283     strerror(errno));
4284 
4285   mark_point();
4286   res = pr_redis_sorted_set_count(redis, &m, key, &count);
4287   fail_unless(res == 0, "Failed to handle get set count: %s", strerror(errno));
4288   fail_unless(count == 1, "Expected 1, got %lu", (unsigned long) count);
4289 
4290   mark_point();
4291   res = pr_redis_remove(redis, &m, key);
4292   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
4293 
4294   mark_point();
4295   res = pr_redis_conn_destroy(redis);
4296   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
4297 }
4298 END_TEST
4299 
START_TEST(redis_sorted_set_delete_test)4300 START_TEST (redis_sorted_set_delete_test) {
4301   int res;
4302   pr_redis_t *redis;
4303   module m;
4304   const char *key;
4305   char *val;
4306   size_t valsz;
4307   float score;
4308 
4309   mark_point();
4310   res = pr_redis_sorted_set_delete(NULL, NULL, NULL, NULL, 0);
4311   fail_unless(res < 0, "Failed to handle null redis");
4312   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4313     strerror(errno), errno);
4314 
4315   mark_point();
4316   redis = pr_redis_conn_new(p, NULL, 0);
4317   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
4318     strerror(errno));
4319 
4320   mark_point();
4321   res = pr_redis_sorted_set_delete(redis, NULL, NULL, NULL, 0);
4322   fail_unless(res < 0, "Failed to handle null module");
4323   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4324     strerror(errno), errno);
4325 
4326   mark_point();
4327   res = pr_redis_sorted_set_delete(redis, &m, NULL, NULL, 0);
4328   fail_unless(res < 0, "Failed to handle null key");
4329   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4330     strerror(errno), errno);
4331 
4332   key = "testkey";
4333   (void) pr_redis_remove(redis, &m, key);
4334 
4335   mark_point();
4336   res = pr_redis_sorted_set_delete(redis, &m, key, NULL, 0);
4337   fail_unless(res < 0, "Failed to handle null value");
4338   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4339     strerror(errno), errno);
4340 
4341   val = "testval";
4342   valsz = 0;
4343 
4344   mark_point();
4345   res = pr_redis_sorted_set_delete(redis, &m, key, val, valsz);
4346   fail_unless(res < 0, "Failed to handle zero valuesz");
4347   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4348     strerror(errno), errno);
4349 
4350   valsz = strlen(val);
4351 
4352   mark_point();
4353   res = pr_redis_sorted_set_delete(redis, &m, key, val, valsz);
4354   fail_unless(res < 0, "Failed to handle nonexistent item");
4355   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
4356     strerror(errno), errno);
4357 
4358   score = 1.23;
4359 
4360   mark_point();
4361   res = pr_redis_sorted_set_add(redis, &m, key, val, valsz, score);
4362   fail_unless(res == 0, "Failed to add item to key '%s': %s", key,
4363     strerror(errno));
4364 
4365   mark_point();
4366   res = pr_redis_sorted_set_delete(redis, &m, key, val, valsz);
4367   fail_unless(res == 0, "Failed to delete item from set: %s", strerror(errno));
4368 
4369   /* Note that we add this item back, just so that the set is NOT empty when
4370    * we go to remove it entirely.
4371    */
4372 
4373   mark_point();
4374   res = pr_redis_sorted_set_add(redis, &m, key, val, valsz, score);
4375   fail_unless(res == 0, "Failed to add item to key '%s': %s", key,
4376     strerror(errno));
4377 
4378   mark_point();
4379   res = pr_redis_remove(redis, &m, key);
4380   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
4381 
4382   mark_point();
4383   res = pr_redis_conn_destroy(redis);
4384   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
4385 }
4386 END_TEST
4387 
START_TEST(redis_sorted_set_getn_test)4388 START_TEST (redis_sorted_set_getn_test) {
4389   int res;
4390   pr_redis_t *redis;
4391   module m;
4392   const char *key;
4393   char *val;
4394   size_t valsz;
4395   float score;
4396   array_header *values = NULL, *valueszs = NULL;
4397 
4398   mark_point();
4399   res = pr_redis_sorted_set_getn(NULL, NULL, NULL, NULL, 0, 0, NULL, NULL, 0);
4400   fail_unless(res < 0, "Failed to handle null pool");
4401   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4402     strerror(errno), errno);
4403 
4404   mark_point();
4405   res = pr_redis_sorted_set_getn(p, NULL, NULL, NULL, 0, 0, NULL, NULL, 0);
4406   fail_unless(res < 0, "Failed to handle null redis");
4407   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4408     strerror(errno), errno);
4409 
4410   mark_point();
4411   redis = pr_redis_conn_new(p, NULL, 0);
4412   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
4413     strerror(errno));
4414 
4415   mark_point();
4416   res = pr_redis_sorted_set_getn(p, redis, NULL, NULL, 0, 0, NULL, NULL, 0);
4417   fail_unless(res < 0, "Failed to handle null module");
4418   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4419     strerror(errno), errno);
4420 
4421   mark_point();
4422   res = pr_redis_sorted_set_getn(p, redis, &m, NULL, 0, 0, NULL, NULL, 0);
4423   fail_unless(res < 0, "Failed to handle null key");
4424   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4425     strerror(errno), errno);
4426 
4427   key = "testkey";
4428   (void) pr_redis_remove(redis, &m, key);
4429 
4430   mark_point();
4431   res = pr_redis_sorted_set_getn(p, redis, &m, key, 0, 0, NULL, NULL, 0);
4432   fail_unless(res < 0, "Failed to handle null values");
4433   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4434     strerror(errno), errno);
4435 
4436   mark_point();
4437   res = pr_redis_sorted_set_getn(p, redis, &m, key, 0, 0, &values, NULL, 0);
4438   fail_unless(res < 0, "Failed to handle null valueszs");
4439   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4440     strerror(errno), errno);
4441 
4442   mark_point();
4443   res = pr_redis_sorted_set_getn(p, redis, &m, key, 0, 0, &values, &valueszs,
4444     0);
4445   fail_unless(res < 0, "Failed to handle invalid flags value");
4446   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4447     strerror(errno), errno);
4448 
4449   val = "foo";
4450   valsz = strlen(val);
4451   score = 0.123;
4452 
4453   mark_point();
4454   res = pr_redis_sorted_set_add(redis, &m, key, val, valsz, score);
4455   fail_unless(res == 0, "Failed to add item to key '%s': %s", key,
4456     strerror(errno));
4457 
4458   val = "bar";
4459   valsz = strlen(val);
4460   score = -1.56;
4461 
4462   mark_point();
4463   res = pr_redis_sorted_set_add(redis, &m, key, val, valsz, score);
4464   fail_unless(res == 0, "Failed to add item to key '%s': %s", key,
4465     strerror(errno));
4466 
4467   val = "baz";
4468   valsz = strlen(val);
4469   score = 234235.1;
4470 
4471   mark_point();
4472   res = pr_redis_sorted_set_add(redis, &m, key, val, valsz, score);
4473   fail_unless(res == 0, "Failed to add item to key '%s': %s", key,
4474     strerror(errno));
4475 
4476   mark_point();
4477   res = pr_redis_sorted_set_getn(p, redis, &m, key, 0, 3, &values, &valueszs,
4478     PR_REDIS_SORTED_SET_FL_DESC);
4479   fail_unless(res == 0, "Failed to get items in sorted set: %s",
4480     strerror(errno));
4481   fail_unless(values != NULL, "Expected values, got null");
4482   fail_unless(valueszs != NULL, "Expected valueszs, got null");
4483   fail_unless(values->nelts == 3, "Expected 3, got %u", values->nelts);
4484   fail_unless(valueszs->nelts == 3, "Expected 3, got %u", valueszs->nelts);
4485 
4486   mark_point();
4487   res = pr_redis_sorted_set_getn(p, redis, &m, key, 1, 2, &values, &valueszs,
4488     PR_REDIS_SORTED_SET_FL_ASC);
4489   fail_unless(res == 0, "Failed to get items in sorted set: %s",
4490     strerror(errno));
4491   fail_unless(values != NULL, "Expected values, got null");
4492   fail_unless(valueszs != NULL, "Expected valueszs, got null");
4493   fail_unless(values->nelts == 2, "Expected 2, got %u", values->nelts);
4494   fail_unless(valueszs->nelts == 2, "Expected 2, got %u", valueszs->nelts);
4495 
4496   mark_point();
4497   res = pr_redis_sorted_set_getn(p, redis, &m, key, 1, 10, &values, &valueszs,
4498     PR_REDIS_SORTED_SET_FL_ASC);
4499   fail_unless(res == 0, "Failed to get items in sorted set: %s",
4500     strerror(errno));
4501   fail_unless(values != NULL, "Expected values, got null");
4502   fail_unless(valueszs != NULL, "Expected valueszs, got null");
4503   fail_unless(values->nelts == 2, "Expected 2, got %u", values->nelts);
4504   fail_unless(valueszs->nelts == 2, "Expected 2, got %u", valueszs->nelts);
4505 
4506   mark_point();
4507   res = pr_redis_remove(redis, &m, key);
4508   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
4509 
4510   mark_point();
4511   res = pr_redis_conn_destroy(redis);
4512   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
4513 }
4514 END_TEST
4515 
START_TEST(redis_sorted_set_incr_test)4516 START_TEST (redis_sorted_set_incr_test) {
4517   int res;
4518   pr_redis_t *redis;
4519   module m;
4520   const char *key;
4521   char *val;
4522   size_t valsz;
4523   float incr, curr;
4524 
4525   mark_point();
4526   res = pr_redis_sorted_set_incr(NULL, NULL, NULL, NULL, 0, 0.0, NULL);
4527   fail_unless(res < 0, "Failed to handle null redis");
4528   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4529     strerror(errno), errno);
4530 
4531   mark_point();
4532   redis = pr_redis_conn_new(p, NULL, 0);
4533   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
4534     strerror(errno));
4535 
4536   mark_point();
4537   res = pr_redis_sorted_set_incr(redis, NULL, NULL, NULL, 0, 0.0, NULL);
4538   fail_unless(res < 0, "Failed to handle null module");
4539   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4540     strerror(errno), errno);
4541 
4542   mark_point();
4543   res = pr_redis_sorted_set_incr(redis, &m, NULL, NULL, 0, 0.0, NULL);
4544   fail_unless(res < 0, "Failed to handle null key");
4545   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4546     strerror(errno), errno);
4547 
4548   key = "testval";
4549   (void) pr_redis_remove(redis, &m, key);
4550 
4551   mark_point();
4552   res = pr_redis_sorted_set_incr(redis, &m, key, NULL, 0, 0.0, NULL);
4553   fail_unless(res < 0, "Failed to handle null value");
4554   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4555     strerror(errno), errno);
4556 
4557   val = "foo";
4558 
4559   mark_point();
4560   res = pr_redis_sorted_set_incr(redis, &m, key, val, 0, 0.0, NULL);
4561   fail_unless(res < 0, "Failed to handle empty value");
4562   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4563     strerror(errno), errno);
4564 
4565   valsz = strlen(val);
4566   incr = 2.0;
4567 
4568   mark_point();
4569   res = pr_redis_sorted_set_incr(redis, &m, key, val, valsz, incr, NULL);
4570   fail_unless(res < 0, "Failed to handle null current value");
4571   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4572     strerror(errno), errno);
4573 
4574   mark_point();
4575   res = pr_redis_sorted_set_incr(redis, &m, key, val, valsz, incr, &curr);
4576   fail_unless(res < 0, "Failed to handle nonexistent key");
4577   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
4578     strerror(errno), errno);
4579 
4580   mark_point();
4581   res = pr_redis_sorted_set_add(redis, &m, key, val, valsz, incr);
4582   fail_unless(res == 0, "Failed to set key '%s', val '%s': %s", key, val,
4583     strerror(errno));
4584 
4585   mark_point();
4586   res = pr_redis_sorted_set_incr(redis, &m, key, val, valsz, -incr, &curr);
4587   fail_unless(res == 0, "Failed to increment key '%s', val '%s': %s", key, val,
4588     strerror(errno));
4589 
4590   mark_point();
4591   res = pr_redis_remove(redis, &m, key);
4592   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
4593 
4594   mark_point();
4595   res = pr_redis_conn_destroy(redis);
4596   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
4597 }
4598 END_TEST
4599 
START_TEST(redis_sorted_set_score_test)4600 START_TEST (redis_sorted_set_score_test) {
4601   int res;
4602   pr_redis_t *redis;
4603   module m;
4604   const char *key;
4605   char *val;
4606   size_t valsz;
4607   float score;
4608 
4609   mark_point();
4610   res = pr_redis_sorted_set_score(NULL, NULL, NULL, NULL, 0, NULL);
4611   fail_unless(res < 0, "Failed to handle null redis");
4612   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4613     strerror(errno), errno);
4614 
4615   mark_point();
4616   redis = pr_redis_conn_new(p, NULL, 0);
4617   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
4618     strerror(errno));
4619 
4620   mark_point();
4621   res = pr_redis_sorted_set_score(redis, NULL, NULL, NULL, 0, NULL);
4622   fail_unless(res < 0, "Failed to handle null module");
4623   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4624     strerror(errno), errno);
4625 
4626   mark_point();
4627   res = pr_redis_sorted_set_score(redis, &m, NULL, NULL, 0, NULL);
4628   fail_unless(res < 0, "Failed to handle null key");
4629   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4630     strerror(errno), errno);
4631 
4632   key = "testval";
4633   (void) pr_redis_remove(redis, &m, key);
4634 
4635   mark_point();
4636   res = pr_redis_sorted_set_score(redis, &m, key, NULL, 0, NULL);
4637   fail_unless(res < 0, "Failed to handle null value");
4638   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4639     strerror(errno), errno);
4640 
4641   val = "foo";
4642 
4643   mark_point();
4644   res = pr_redis_sorted_set_score(redis, &m, key, val, 0, NULL);
4645   fail_unless(res < 0, "Failed to handle empty value");
4646   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4647     strerror(errno), errno);
4648 
4649   valsz = strlen(val);
4650 
4651   mark_point();
4652   res = pr_redis_sorted_set_score(redis, &m, key, val, valsz, NULL);
4653   fail_unless(res < 0, "Failed to handle null score");
4654   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4655     strerror(errno), errno);
4656 
4657   mark_point();
4658   res = pr_redis_sorted_set_score(redis, &m, key, val, valsz, &score);
4659   fail_unless(res < 0, "Failed to handle nonexistent key");
4660   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
4661     strerror(errno), errno);
4662 
4663   mark_point();
4664   res = pr_redis_sorted_set_add(redis, &m, key, val, valsz, 1.0);
4665   fail_unless(res == 0, "Failed to set key '%s', val '%s': %s", key, val,
4666     strerror(errno));
4667 
4668   mark_point();
4669   res = pr_redis_sorted_set_score(redis, &m, key, val, valsz, &score);
4670   fail_unless(res == 0, "Failed to score key '%s', val '%s': %s", key, val,
4671     strerror(errno));
4672   fail_unless(score > 0.0, "Expected > 0.0, got %0.3f", score);
4673 
4674   mark_point();
4675   res = pr_redis_remove(redis, &m, key);
4676   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
4677 
4678   mark_point();
4679   res = pr_redis_conn_destroy(redis);
4680   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
4681 }
4682 END_TEST
4683 
START_TEST(redis_sorted_set_set_test)4684 START_TEST (redis_sorted_set_set_test) {
4685   int res;
4686   pr_redis_t *redis;
4687   module m;
4688   const char *key;
4689   char *val;
4690   size_t valsz;
4691   float score;
4692 
4693   mark_point();
4694   res = pr_redis_sorted_set_set(NULL, NULL, NULL, NULL, 0, 0.0);
4695   fail_unless(res < 0, "Failed to handle null redis");
4696   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4697     strerror(errno), errno);
4698 
4699   mark_point();
4700   redis = pr_redis_conn_new(p, NULL, 0);
4701   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
4702     strerror(errno));
4703 
4704   mark_point();
4705   res = pr_redis_sorted_set_set(redis, NULL, NULL, NULL, 0, 0.0);
4706   fail_unless(res < 0, "Failed to handle null module");
4707   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4708     strerror(errno), errno);
4709 
4710   mark_point();
4711   res = pr_redis_sorted_set_set(redis, &m, NULL, NULL, 0, 0.0);
4712   fail_unless(res < 0, "Failed to handle null key");
4713   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4714     strerror(errno), errno);
4715 
4716   key = "testkey";
4717   (void) pr_redis_remove(redis, &m, key);
4718 
4719   mark_point();
4720   res = pr_redis_sorted_set_set(redis, &m, key, NULL, 0, 0.0);
4721   fail_unless(res < 0, "Failed to handle null value");
4722   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4723     strerror(errno), errno);
4724 
4725   val = "testval";
4726   valsz = 0;
4727 
4728   mark_point();
4729   res = pr_redis_sorted_set_set(redis, &m, key, val, 0, 0.0);
4730   fail_unless(res < 0, "Failed to handle zero valuesz");
4731   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4732     strerror(errno), errno);
4733 
4734   valsz = strlen(val);
4735   score = 75.32;
4736 
4737   mark_point();
4738   res = pr_redis_sorted_set_set(redis, &m, key, val, valsz, score);
4739   fail_unless(res < 0, "Failed to handle nonexistent key");
4740   fail_unless(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
4741     strerror(errno), errno);
4742 
4743   mark_point();
4744   res = pr_redis_sorted_set_add(redis, &m, key, val, valsz, score);
4745   fail_unless(res == 0, "Failed to add key '%s', val '%s': %s", key, val,
4746     strerror(errno));
4747 
4748   score = 23.11;
4749 
4750   mark_point();
4751   res = pr_redis_sorted_set_set(redis, &m, key, val, valsz, score);
4752   fail_unless(res == 0, "Failed to set key '%s', val '%s': %s", key, val,
4753     strerror(errno));
4754 
4755   mark_point();
4756   res = pr_redis_remove(redis, &m, key);
4757   fail_unless(res == 0, "Failed to remove key '%s': %s", key, strerror(errno));
4758 
4759   mark_point();
4760   res = pr_redis_conn_destroy(redis);
4761   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
4762 }
4763 END_TEST
4764 
START_TEST(redis_sorted_set_setall_test)4765 START_TEST (redis_sorted_set_setall_test) {
4766   int res;
4767   pr_redis_t *redis;
4768   module m;
4769   const char *key;
4770   array_header *vals, *valszs, *scores;
4771 
4772   mark_point();
4773   res = pr_redis_sorted_set_setall(NULL, NULL, NULL, NULL, NULL, NULL);
4774   fail_unless(res < 0, "Failed to handle null redis");
4775   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4776     strerror(errno), errno);
4777 
4778   mark_point();
4779   redis = pr_redis_conn_new(p, NULL, 0);
4780   fail_unless(redis != NULL, "Failed to open connection to Redis: %s",
4781     strerror(errno));
4782 
4783   mark_point();
4784   res = pr_redis_sorted_set_setall(redis, NULL, NULL, NULL, NULL, NULL);
4785   fail_unless(res < 0, "Failed to handle null module");
4786   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4787     strerror(errno), errno);
4788 
4789   mark_point();
4790   res = pr_redis_sorted_set_setall(redis, &m, NULL, NULL, NULL, NULL);
4791   fail_unless(res < 0, "Failed to handle null key");
4792   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4793     strerror(errno), errno);
4794 
4795   key = "testsetkey";
4796   (void) pr_redis_remove(redis, &m, key);
4797 
4798   mark_point();
4799   res = pr_redis_sorted_set_setall(redis, &m, key, NULL, NULL, NULL);
4800   fail_unless(res < 0, "Failed to handle null values");
4801   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4802     strerror(errno), errno);
4803 
4804   vals = make_array(p, 0, sizeof(char *));
4805 
4806   mark_point();
4807   res = pr_redis_sorted_set_setall(redis, &m, key, vals, NULL, NULL);
4808   fail_unless(res < 0, "Failed to handle empty values");
4809   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4810     strerror(errno), errno);
4811 
4812   *((char **) push_array(vals)) = pstrdup(p, "Some JSON here");
4813 
4814   mark_point();
4815   res = pr_redis_sorted_set_setall(redis, &m, key, vals, NULL, NULL);
4816   fail_unless(res < 0, "Failed to handle null valueszs");
4817   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4818     strerror(errno), errno);
4819 
4820   valszs = make_array(p, 0, sizeof(char *));
4821 
4822   mark_point();
4823   res = pr_redis_sorted_set_setall(redis, &m, key, vals, valszs, NULL);
4824   fail_unless(res < 0, "Failed to handle empty valueszs");
4825   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4826     strerror(errno), errno);
4827 
4828   *((size_t *) push_array(valszs)) = strlen("Some JSON here");
4829   *((char **) push_array(vals)) = pstrdup(p, "bar");
4830 
4831   mark_point();
4832   res = pr_redis_sorted_set_setall(redis, &m, key, vals, valszs, NULL);
4833   fail_unless(res < 0, "Failed to handle mismatched values/valueszs");
4834   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4835     strerror(errno), errno);
4836 
4837   *((size_t *) push_array(valszs)) = strlen("bar");
4838 
4839   mark_point();
4840   res = pr_redis_sorted_set_setall(redis, &m, key, vals, valszs, NULL);
4841   fail_unless(res < 0, "Failed to handle null scores");
4842   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4843     strerror(errno), errno);
4844 
4845   scores = make_array(p, 0, sizeof(char *));
4846 
4847   mark_point();
4848   res = pr_redis_sorted_set_setall(redis, &m, key, vals, valszs, scores);
4849   fail_unless(res < 0, "Failed to handle empty scores");
4850   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4851     strerror(errno), errno);
4852 
4853   *((float *) push_array(scores)) = 1.0;
4854 
4855   mark_point();
4856   res = pr_redis_sorted_set_setall(redis, &m, key, vals, valszs, scores);
4857   fail_unless(res < 0, "Failed to handle mismatched values/scores");
4858   fail_unless(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
4859     strerror(errno), errno);
4860 
4861   *((float *) push_array(scores)) = 2.0;
4862 
4863   mark_point();
4864   (void) pr_redis_set_remove(redis, &m, key);
4865 
4866   mark_point();
4867   res = pr_redis_sorted_set_setall(redis, &m, key, vals, valszs, scores);
4868   fail_unless(res == 0, "Failed to set items using key '%s': %s",
4869     key, strerror(errno));
4870 
4871   mark_point();
4872   res = pr_redis_set_remove(redis, &m, key);
4873   fail_unless(res == 0, "Failed to remove set '%s': %s", key, strerror(errno));
4874 
4875   mark_point();
4876   res = pr_redis_conn_destroy(redis);
4877   fail_unless(res == TRUE, "Failed to close redis: %s", strerror(errno));
4878 }
4879 END_TEST
4880 
4881 #endif /* PR_USE_REDIS */
4882 
tests_get_redis_suite(void)4883 Suite *tests_get_redis_suite(void) {
4884   Suite *suite;
4885   TCase *testcase;
4886 
4887   suite = suite_create("redis");
4888   testcase = tcase_create("base");
4889 
4890 #ifdef PR_USE_REDIS
4891   tcase_add_checked_fixture(testcase, set_up, tear_down);
4892 
4893   tcase_add_test(testcase, redis_conn_destroy_test);
4894   tcase_add_test(testcase, redis_conn_close_test);
4895   tcase_add_test(testcase, redis_conn_new_test);
4896   tcase_add_test(testcase, redis_conn_get_test);
4897   tcase_add_test(testcase, redis_conn_set_namespace_test);
4898   tcase_add_test(testcase, redis_conn_get_version_test);
4899   tcase_add_test(testcase, redis_conn_auth_test);
4900   tcase_add_test(testcase, redis_conn_auth2_test);
4901   tcase_add_test(testcase, redis_conn_select_test);
4902   tcase_add_test(testcase, redis_conn_reconnect_test);
4903   tcase_add_test(testcase, redis_command_test);
4904 
4905   tcase_add_test(testcase, redis_sentinel_get_master_addr_test);
4906   tcase_add_test(testcase, redis_sentinel_get_masters_test);
4907   tcase_add_test(testcase, redis_sentinel_conn_new_test);
4908 
4909   tcase_add_test(testcase, redis_remove_test);
4910   tcase_add_test(testcase, redis_add_test);
4911   tcase_add_test(testcase, redis_add_with_namespace_test);
4912   tcase_add_test(testcase, redis_get_test);
4913   tcase_add_test(testcase, redis_get_with_namespace_test);
4914   tcase_add_test(testcase, redis_get_str_test);
4915   tcase_add_test(testcase, redis_incr_test);
4916   tcase_add_test(testcase, redis_decr_test);
4917   tcase_add_test(testcase, redis_rename_test);
4918   tcase_add_test(testcase, redis_set_test);
4919 
4920   tcase_add_test(testcase, redis_hash_remove_test);
4921   tcase_add_test(testcase, redis_hash_get_test);
4922   tcase_add_test(testcase, redis_hash_set_test);
4923   tcase_add_test(testcase, redis_hash_delete_test);
4924   tcase_add_test(testcase, redis_hash_count_test);
4925   tcase_add_test(testcase, redis_hash_exists_test);
4926   tcase_add_test(testcase, redis_hash_incr_test);
4927   tcase_add_test(testcase, redis_hash_keys_test);
4928   tcase_add_test(testcase, redis_hash_values_test);
4929   tcase_add_test(testcase, redis_hash_getall_test);
4930   tcase_add_test(testcase, redis_hash_setall_test);
4931 
4932   tcase_add_test(testcase, redis_list_remove_test);
4933   tcase_add_test(testcase, redis_list_append_test);
4934   tcase_add_test(testcase, redis_list_count_test);
4935   tcase_add_test(testcase, redis_list_delete_test);
4936   tcase_add_test(testcase, redis_list_exists_test);
4937   tcase_add_test(testcase, redis_list_get_test);
4938   tcase_add_test(testcase, redis_list_getall_test);
4939   tcase_add_test(testcase, redis_list_pop_params_test);
4940   tcase_add_test(testcase, redis_list_pop_left_test);
4941   tcase_add_test(testcase, redis_list_pop_right_test);
4942   tcase_add_test(testcase, redis_list_push_params_test);
4943   tcase_add_test(testcase, redis_list_push_left_test);
4944   tcase_add_test(testcase, redis_list_push_right_test);
4945   tcase_add_test(testcase, redis_list_rotate_test);
4946   tcase_add_test(testcase, redis_list_set_test);
4947   tcase_add_test(testcase, redis_list_setall_test);
4948 
4949   tcase_add_test(testcase, redis_set_remove_test);
4950   tcase_add_test(testcase, redis_set_exists_test);
4951   tcase_add_test(testcase, redis_set_add_test);
4952   tcase_add_test(testcase, redis_set_count_test);
4953   tcase_add_test(testcase, redis_set_delete_test);
4954   tcase_add_test(testcase, redis_set_getall_test);
4955   tcase_add_test(testcase, redis_set_setall_test);
4956 
4957   tcase_add_test(testcase, redis_sorted_set_remove_test);
4958   tcase_add_test(testcase, redis_sorted_set_exists_test);
4959   tcase_add_test(testcase, redis_sorted_set_add_test);
4960   tcase_add_test(testcase, redis_sorted_set_count_test);
4961   tcase_add_test(testcase, redis_sorted_set_delete_test);
4962   tcase_add_test(testcase, redis_sorted_set_getn_test);
4963   tcase_add_test(testcase, redis_sorted_set_incr_test);
4964   tcase_add_test(testcase, redis_sorted_set_score_test);
4965   tcase_add_test(testcase, redis_sorted_set_set_test);
4966   tcase_add_test(testcase, redis_sorted_set_setall_test);
4967 
4968   /* Some of the Redis tests may take a little longer. */
4969   tcase_set_timeout(testcase, 30);
4970 
4971   suite_add_tcase(suite, testcase);
4972 #endif /* PR_USE_REDIS */
4973 
4974   return suite;
4975 }
4976