diff options
Diffstat (limited to 'test.c')
-rw-r--r-- | test.c | 113 |
1 files changed, 89 insertions, 24 deletions
@@ -180,43 +180,43 @@ static void test_format_commands(void) { len = redisFormatCommand(&cmd,"SET foo bar"); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(3+2)); - free(cmd); + hi_free(cmd); test("Format command with %%s string interpolation: "); len = redisFormatCommand(&cmd,"SET %s %s","foo","bar"); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(3+2)); - free(cmd); + hi_free(cmd); test("Format command with %%s and an empty string: "); len = redisFormatCommand(&cmd,"SET %s %s","foo",""); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(0+2)); - free(cmd); + hi_free(cmd); test("Format command with an empty string in between proper interpolations: "); len = redisFormatCommand(&cmd,"SET %s %s","","foo"); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$0\r\n\r\n$3\r\nfoo\r\n",len) == 0 && len == 4+4+(3+2)+4+(0+2)+4+(3+2)); - free(cmd); + hi_free(cmd); test("Format command with %%b string interpolation: "); len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"b\0r",(size_t)3); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nb\0r\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(3+2)); - free(cmd); + hi_free(cmd); test("Format command with %%b and an empty string: "); len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"",(size_t)0); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(0+2)); - free(cmd); + hi_free(cmd); test("Format command with literal %%: "); len = redisFormatCommand(&cmd,"SET %% %%"); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$1\r\n%\r\n$1\r\n%\r\n",len) == 0 && len == 4+4+(3+2)+4+(1+2)+4+(1+2)); - free(cmd); + hi_free(cmd); /* Vararg width depends on the type. These tests make sure that the * width is correctly determined using the format and subsequent varargs @@ -227,7 +227,7 @@ static void test_format_commands(void) { len = redisFormatCommand(&cmd,"key:%08" fmt " str:%s", value, "hello"); \ test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:00000123\r\n$9\r\nstr:hello\r\n",len) == 0 && \ len == 4+5+(12+2)+4+(9+2)); \ - free(cmd); \ + hi_free(cmd); \ } while(0) #define FLOAT_WIDTH_TEST(type) do { \ @@ -236,7 +236,7 @@ static void test_format_commands(void) { len = redisFormatCommand(&cmd,"key:%08.3f str:%s", value, "hello"); \ test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:0123.000\r\n$9\r\nstr:hello\r\n",len) == 0 && \ len == 4+5+(12+2)+4+(9+2)); \ - free(cmd); \ + hi_free(cmd); \ } while(0) INTEGER_WIDTH_TEST("d", int); @@ -267,13 +267,13 @@ static void test_format_commands(void) { len = redisFormatCommandArgv(&cmd,argc,argv,NULL); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && len == 4+4+(3+2)+4+(3+2)+4+(3+2)); - free(cmd); + hi_free(cmd); test("Format command by passing argc/argv with lengths: "); len = redisFormatCommandArgv(&cmd,argc,argv,lens); test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 && len == 4+4+(3+2)+4+(7+2)+4+(3+2)); - free(cmd); + hi_free(cmd); sds sds_cmd; @@ -308,7 +308,7 @@ static void test_append_formatted_commands(struct config config) { assert(redisGetReply(c, (void*)&reply) == REDIS_OK); - free(cmd); + hi_free(cmd); freeReplyObject(reply); disconnect(c, 0); @@ -418,6 +418,16 @@ static void test_reply_reader(void) { freeReplyObject(reply); redisReaderFree(reader); + test("Can configure maximum multi-bulk elements: "); + reader = redisReaderCreate(); + reader->maxelements = 1024; + redisReaderFeed(reader, "*1025\r\n", 7); + ret = redisReaderGetReply(reader,&reply); + test_cond(ret == REDIS_ERR && + strcasecmp(reader->errstr, "Multi-bulk length out of range") == 0); + freeReplyObject(reply); + redisReaderFree(reader); + #if LLONG_MAX > SIZE_MAX test("Set error when array > SIZE_MAX: "); reader = redisReaderCreate(); @@ -518,6 +528,46 @@ static void test_free_null(void) { test_cond(reply == NULL); } +static void *hi_malloc_fail(size_t size) { + (void)size; + return NULL; +} + +static void *hi_calloc_fail(size_t nmemb, size_t size) { + (void)nmemb; + (void)size; + return NULL; +} + +static void *hi_realloc_fail(void *ptr, size_t size) { + (void)ptr; + (void)size; + return NULL; +} + +static void test_allocator_injection(void) { + hiredisAllocFuncs ha = { + .malloc = hi_malloc_fail, + .calloc = hi_calloc_fail, + .realloc = hi_realloc_fail, + .free = NULL, + }; + + // Override hiredis allocators + hiredisSetAllocators(&ha); + + test("redisContext uses injected allocators: "); + redisContext *c = redisConnect("localhost", 6379); + test_cond(c == NULL); + + test("redisReader uses injected allocators: "); + redisReader *reader = redisReaderCreate(); + test_cond(reader == NULL); + + // Return allocators to default + hiredisResetAllocators(); +} + #define HIREDIS_BAD_DOMAIN "idontexist-noreally.com" static void test_blocking_connection_errors(void) { redisContext *c; @@ -799,6 +849,18 @@ static void test_invalid_timeout_errors(struct config config) { redisFree(c); } +/* Wrap malloc to abort on failure so OOM checks don't make the test logic + * harder to follow. */ +void *hi_malloc_safe(size_t size) { + void *ptr = hi_malloc(size); + if (ptr == NULL) { + fprintf(stderr, "Error: Out of memory\n"); + exit(-1); + } + + return ptr; +} + static void test_throughput(struct config config) { redisContext *c = do_connect(config); redisReply **replies; @@ -810,7 +872,7 @@ static void test_throughput(struct config config) { freeReplyObject(redisCommand(c,"LPUSH mylist foo")); num = 1000; - replies = malloc(sizeof(redisReply*)*num); + replies = hi_malloc_safe(sizeof(redisReply*)*num); t1 = usec(); for (i = 0; i < num; i++) { replies[i] = redisCommand(c,"PING"); @@ -818,10 +880,10 @@ static void test_throughput(struct config config) { } t2 = usec(); for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); + hi_free(replies); printf("\t(%dx PING: %.3fs)\n", num, (t2-t1)/1000000.0); - replies = malloc(sizeof(redisReply*)*num); + replies = hi_malloc_safe(sizeof(redisReply*)*num); t1 = usec(); for (i = 0; i < num; i++) { replies[i] = redisCommand(c,"LRANGE mylist 0 499"); @@ -830,10 +892,10 @@ static void test_throughput(struct config config) { } t2 = usec(); for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); + hi_free(replies); printf("\t(%dx LRANGE with 500 elements: %.3fs)\n", num, (t2-t1)/1000000.0); - replies = malloc(sizeof(redisReply*)*num); + replies = hi_malloc_safe(sizeof(redisReply*)*num); t1 = usec(); for (i = 0; i < num; i++) { replies[i] = redisCommand(c, "INCRBY incrkey %d", 1000000); @@ -841,11 +903,11 @@ static void test_throughput(struct config config) { } t2 = usec(); for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); + hi_free(replies); printf("\t(%dx INCRBY: %.3fs)\n", num, (t2-t1)/1000000.0); num = 10000; - replies = malloc(sizeof(redisReply*)*num); + replies = hi_malloc_safe(sizeof(redisReply*)*num); for (i = 0; i < num; i++) redisAppendCommand(c,"PING"); t1 = usec(); @@ -855,10 +917,10 @@ static void test_throughput(struct config config) { } t2 = usec(); for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); + hi_free(replies); printf("\t(%dx PING (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); - replies = malloc(sizeof(redisReply*)*num); + replies = hi_malloc_safe(sizeof(redisReply*)*num); for (i = 0; i < num; i++) redisAppendCommand(c,"LRANGE mylist 0 499"); t1 = usec(); @@ -869,10 +931,10 @@ static void test_throughput(struct config config) { } t2 = usec(); for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); + hi_free(replies); printf("\t(%dx LRANGE with 500 elements (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); - replies = malloc(sizeof(redisReply*)*num); + replies = hi_malloc_safe(sizeof(redisReply*)*num); for (i = 0; i < num; i++) redisAppendCommand(c,"INCRBY incrkey %d", 1000000); t1 = usec(); @@ -882,7 +944,7 @@ static void test_throughput(struct config config) { } t2 = usec(); for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); + hi_free(replies); printf("\t(%dx INCRBY (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); disconnect(c, 0); @@ -1049,11 +1111,14 @@ int main(int argc, char **argv) { signal(SIGPIPE, SIG_IGN); test_unix_socket = access(cfg.unix_sock.path, F_OK) == 0; + #else /* Unix sockets don't exist in Windows */ test_unix_socket = 0; #endif + test_allocator_injection(); + test_format_commands(); test_reply_reader(); test_blocking_connection_errors(); |