Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
e7a3d3d1
Unverified
Commit
e7a3d3d1
authored
Jun 06, 2023
by
Yossi Gottlieb
Committed by
GitHub
Jun 06, 2023
Browse files
Merge pull request #12254 from yossigo/hiredis-refresh
Refresh deps/hiredis to latest (unreleased) version.
parents
0bd1a3a4
032bb2a2
Changes
42
Hide whitespace changes
Inline
Side-by-side
deps/hiredis/test.c
View file @
e7a3d3d1
...
@@ -15,6 +15,7 @@
...
@@ -15,6 +15,7 @@
#include "hiredis.h"
#include "hiredis.h"
#include "async.h"
#include "async.h"
#include "adapters/poll.h"
#ifdef HIREDIS_TEST_SSL
#ifdef HIREDIS_TEST_SSL
#include "hiredis_ssl.h"
#include "hiredis_ssl.h"
#endif
#endif
...
@@ -34,11 +35,11 @@ enum connection_type {
...
@@ -34,11 +35,11 @@ enum connection_type {
struct config {
struct config {
enum connection_type type;
enum connection_type type;
struct timeval connect_timeout;
struct {
struct {
const char *host;
const char *host;
int port;
int port;
struct
timeval
timeout
;
} tcp;
} tcp;
struct {
struct {
...
@@ -75,6 +76,15 @@ static int tests = 0, fails = 0, skips = 0;
...
@@ -75,6 +76,15 @@ static int tests = 0, fails = 0, skips = 0;
#define test_cond(_c) if(_c) printf("\033[0;32mPASSED\033[0;0m\n"); else {printf("\033[0;31mFAILED\033[0;0m\n"); fails++;}
#define test_cond(_c) if(_c) printf("\033[0;32mPASSED\033[0;0m\n"); else {printf("\033[0;31mFAILED\033[0;0m\n"); fails++;}
#define test_skipped() { printf("\033[01;33mSKIPPED\033[0;0m\n"); skips++; }
#define test_skipped() { printf("\033[01;33mSKIPPED\033[0;0m\n"); skips++; }
static void millisleep(int ms)
{
#if _MSC_VER
Sleep(ms);
#else
usleep(ms*1000);
#endif
}
static long long usec(void) {
static long long usec(void) {
#ifndef _MSC_VER
#ifndef _MSC_VER
struct timeval tv;
struct timeval tv;
...
@@ -329,10 +339,14 @@ static void test_format_commands(void) {
...
@@ -329,10 +339,14 @@ static void test_format_commands(void) {
FLOAT_WIDTH_TEST(float);
FLOAT_WIDTH_TEST(float);
FLOAT_WIDTH_TEST(double);
FLOAT_WIDTH_TEST(double);
test
(
"Format command with
invali
d printf format: "
);
test("Format command with
unhandle
d printf format
(specifier 'p' not supported)
: ");
len = redisFormatCommand(&cmd,"key:%08p %b",(void*)1234,"foo",(size_t)3);
len = redisFormatCommand(&cmd,"key:%08p %b",(void*)1234,"foo",(size_t)3);
test_cond(len == -1);
test_cond(len == -1);
test("Format command with invalid printf format (specifier missing): ");
len = redisFormatCommand(&cmd,"%-");
test_cond(len == -1);
const char *argv[3];
const char *argv[3];
argv[0] = "SET";
argv[0] = "SET";
argv[1] = "foo\0xxx";
argv[1] = "foo\0xxx";
...
@@ -391,6 +405,16 @@ static void test_append_formatted_commands(struct config config) {
...
@@ -391,6 +405,16 @@ static void test_append_formatted_commands(struct config config) {
disconnect(c, 0);
disconnect(c, 0);
}
}
static void test_tcp_options(struct config cfg) {
redisContext *c;
c = do_connect(cfg);
test("We can enable TCP_KEEPALIVE: ");
test_cond(redisEnableKeepAlive(c) == REDIS_OK);
disconnect(c, 0);
}
static void test_reply_reader(void) {
static void test_reply_reader(void) {
redisReader *reader;
redisReader *reader;
void *reply, *root;
void *reply, *root;
...
@@ -568,6 +592,19 @@ static void test_reply_reader(void) {
...
@@ -568,6 +592,19 @@ static void test_reply_reader(void) {
test_cond(ret == REDIS_ERR && reply == NULL);
test_cond(ret == REDIS_ERR && reply == NULL);
redisReaderFree(reader);
redisReaderFree(reader);
test("Don't reset state after protocol error(not segfault): ");
reader = redisReaderCreate();
redisReaderFeed(reader,(char*)"*3\r\n$3\r\nSET\r\n$5\r\nhello\r\n$", 25);
ret = redisReaderGetReply(reader,&reply);
assert(ret == REDIS_OK);
redisReaderFeed(reader,(char*)"3\r\nval\r\n", 8);
ret = redisReaderGetReply(reader,&reply);
test_cond(ret == REDIS_OK &&
((redisReply*)reply)->type == REDIS_REPLY_ARRAY &&
((redisReply*)reply)->elements == 3);
freeReplyObject(reply);
redisReaderFree(reader);
/* Regression test for issue #45 on GitHub. */
/* Regression test for issue #45 on GitHub. */
test("Don't do empty allocation for empty multi bulk: ");
test("Don't do empty allocation for empty multi bulk: ");
reader = redisReaderCreate();
reader = redisReaderCreate();
...
@@ -637,12 +674,23 @@ static void test_reply_reader(void) {
...
@@ -637,12 +674,23 @@ static void test_reply_reader(void) {
freeReplyObject(reply);
freeReplyObject(reply);
redisReaderFree(reader);
redisReaderFree(reader);
test
(
"
Set error when
RESP3 double
is
NaN: "
);
test("
Correctly parses
RESP3 double NaN: ");
reader = redisReaderCreate();
reader = redisReaderCreate();
redisReaderFeed(reader, ",nan\r\n",6);
redisReaderFeed(reader, ",nan\r\n",6);
ret = redisReaderGetReply(reader,&reply);
ret = redisReaderGetReply(reader,&reply);
test_cond
(
ret
==
REDIS_ERR
&&
test_cond(ret == REDIS_OK &&
strcasecmp
(
reader
->
errstr
,
"Bad double value"
)
==
0
);
((redisReply*)reply)->type == REDIS_REPLY_DOUBLE &&
isnan(((redisReply*)reply)->dval));
freeReplyObject(reply);
redisReaderFree(reader);
test("Correctly parses RESP3 double -Nan: ");
reader = redisReaderCreate();
redisReaderFeed(reader, ",-nan\r\n", 7);
ret = redisReaderGetReply(reader, &reply);
test_cond(ret == REDIS_OK &&
((redisReply*)reply)->type == REDIS_REPLY_DOUBLE &&
isnan(((redisReply*)reply)->dval));
freeReplyObject(reply);
freeReplyObject(reply);
redisReaderFree(reader);
redisReaderFree(reader);
...
@@ -745,6 +793,20 @@ static void test_reply_reader(void) {
...
@@ -745,6 +793,20 @@ static void test_reply_reader(void) {
!strcmp(((redisReply*)reply)->str,"3492890328409238509324850943850943825024385"));
!strcmp(((redisReply*)reply)->str,"3492890328409238509324850943850943825024385"));
freeReplyObject(reply);
freeReplyObject(reply);
redisReaderFree(reader);
redisReaderFree(reader);
test("Can parse RESP3 doubles in an array: ");
reader = redisReaderCreate();
redisReaderFeed(reader, "*1\r\n,3.14159265358979323846\r\n",31);
ret = redisReaderGetReply(reader,&reply);
test_cond(ret == REDIS_OK &&
((redisReply*)reply)->type == REDIS_REPLY_ARRAY &&
((redisReply*)reply)->elements == 1 &&
((redisReply*)reply)->element[0]->type == REDIS_REPLY_DOUBLE &&
fabs(((redisReply*)reply)->element[0]->dval - 3.14159265358979323846) < 0.00000001 &&
((redisReply*)reply)->element[0]->len == 22 &&
strcmp(((redisReply*)reply)->element[0]->str, "3.14159265358979323846") == 0);
freeReplyObject(reply);
redisReaderFree(reader);
}
}
static void test_free_null(void) {
static void test_free_null(void) {
...
@@ -819,9 +881,9 @@ static void test_allocator_injection(void) {
...
@@ -819,9 +881,9 @@ static void test_allocator_injection(void) {
#define HIREDIS_BAD_DOMAIN "idontexist-noreally.com"
#define HIREDIS_BAD_DOMAIN "idontexist-noreally.com"
static void test_blocking_connection_errors(void) {
static void test_blocking_connection_errors(void) {
redisContext
*
c
;
struct addrinfo hints = {.ai_family = AF_INET};
struct addrinfo hints = {.ai_family = AF_INET};
struct addrinfo *ai_tmp = NULL;
struct addrinfo *ai_tmp = NULL;
redisContext *c;
int rv = getaddrinfo(HIREDIS_BAD_DOMAIN, "6379", &hints, &ai_tmp);
int rv = getaddrinfo(HIREDIS_BAD_DOMAIN, "6379", &hints, &ai_tmp);
if (rv != 0) {
if (rv != 0) {
...
@@ -835,6 +897,7 @@ static void test_blocking_connection_errors(void) {
...
@@ -835,6 +897,7 @@ static void test_blocking_connection_errors(void) {
strcmp(c->errstr, "Can't resolve: " HIREDIS_BAD_DOMAIN) == 0 ||
strcmp(c->errstr, "Can't resolve: " HIREDIS_BAD_DOMAIN) == 0 ||
strcmp(c->errstr, "Name does not resolve") == 0 ||
strcmp(c->errstr, "Name does not resolve") == 0 ||
strcmp(c->errstr, "nodename nor servname provided, or not known") == 0 ||
strcmp(c->errstr, "nodename nor servname provided, or not known") == 0 ||
strcmp(c->errstr, "node name or service name not known") == 0 ||
strcmp(c->errstr, "No address associated with hostname") == 0 ||
strcmp(c->errstr, "No address associated with hostname") == 0 ||
strcmp(c->errstr, "Temporary failure in name resolution") == 0 ||
strcmp(c->errstr, "Temporary failure in name resolution") == 0 ||
strcmp(c->errstr, "hostname nor servname provided, or not known") == 0 ||
strcmp(c->errstr, "hostname nor servname provided, or not known") == 0 ||
...
@@ -847,12 +910,26 @@ static void test_blocking_connection_errors(void) {
...
@@ -847,12 +910,26 @@ static void test_blocking_connection_errors(void) {
}
}
#ifndef _WIN32
#ifndef _WIN32
redisOptions opt = {0};
struct timeval tv;
test("Returns error when the port is not open: ");
test("Returns error when the port is not open: ");
c = redisConnect((char*)"localhost", 1);
c = redisConnect((char*)"localhost", 1);
test_cond(c->err == REDIS_ERR_IO &&
test_cond(c->err == REDIS_ERR_IO &&
strcmp(c->errstr,"Connection refused") == 0);
strcmp(c->errstr,"Connection refused") == 0);
redisFree(c);
redisFree(c);
/* Verify we don't regress from the fix in PR #1180 */
test("We don't clobber connection exception with setsockopt error: ");
tv = (struct timeval){.tv_sec = 0, .tv_usec = 500000};
opt.command_timeout = opt.connect_timeout = &tv;
REDIS_OPTIONS_SET_TCP(&opt, "localhost", 10337);
c = redisConnectWithOptions(&opt);
test_cond(c->err == REDIS_ERR_IO &&
strcmp(c->errstr, "Connection refused") == 0);
redisFree(c);
test("Returns error when the unix_sock socket path doesn't accept connections: ");
test("Returns error when the unix_sock socket path doesn't accept connections: ");
c = redisConnectUnix((char*)"/tmp/idontexist.sock");
c = redisConnectUnix((char*)"/tmp/idontexist.sock");
test_cond(c->err == REDIS_ERR_IO); /* Don't care about the message... */
test_cond(c->err == REDIS_ERR_IO); /* Don't care about the message... */
...
@@ -914,11 +991,19 @@ static void test_resp3_push_handler(redisContext *c) {
...
@@ -914,11 +991,19 @@ static void test_resp3_push_handler(redisContext *c) {
old = redisSetPushCallback(c, push_handler);
old = redisSetPushCallback(c, push_handler);
test("We can set a custom RESP3 PUSH handler: ");
test("We can set a custom RESP3 PUSH handler: ");
reply = redisCommand(c, "SET key:0 val:0");
reply = redisCommand(c, "SET key:0 val:0");
/* We need another command because depending on the version of Redis, the
* notification may be delivered after the command's reply. */
assert(reply != NULL);
freeReplyObject(reply);
reply = redisCommand(c, "PING");
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && pc.str == 1);
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && pc.str == 1);
freeReplyObject(reply);
freeReplyObject(reply);
test("We properly handle a NIL invalidation payload: ");
test("We properly handle a NIL invalidation payload: ");
reply = redisCommand(c, "FLUSHDB");
reply = redisCommand(c, "FLUSHDB");
assert(reply != NULL);
freeReplyObject(reply);
reply = redisCommand(c, "PING");
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && pc.nil == 1);
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && pc.nil == 1);
freeReplyObject(reply);
freeReplyObject(reply);
...
@@ -929,6 +1014,12 @@ static void test_resp3_push_handler(redisContext *c) {
...
@@ -929,6 +1014,12 @@ static void test_resp3_push_handler(redisContext *c) {
assert((reply = redisCommand(c, "GET key:0")) != NULL);
assert((reply = redisCommand(c, "GET key:0")) != NULL);
freeReplyObject(reply);
freeReplyObject(reply);
assert((reply = redisCommand(c, "SET key:0 invalid")) != NULL);
assert((reply = redisCommand(c, "SET key:0 invalid")) != NULL);
/* Depending on Redis version, we may receive either push notification or
* status reply. Both cases are valid. */
if (reply->type == REDIS_REPLY_STATUS) {
freeReplyObject(reply);
reply = redisCommand(c, "PING");
}
test_cond(reply->type == REDIS_REPLY_PUSH);
test_cond(reply->type == REDIS_REPLY_PUSH);
freeReplyObject(reply);
freeReplyObject(reply);
...
@@ -1089,6 +1180,13 @@ static void test_blocking_connection(struct config config) {
...
@@ -1089,6 +1180,13 @@ static void test_blocking_connection(struct config config) {
strcasecmp(reply->element[1]->str,"pong") == 0);
strcasecmp(reply->element[1]->str,"pong") == 0);
freeReplyObject(reply);
freeReplyObject(reply);
test("Send command by passing argc/argv: ");
const char *argv[3] = {"SET", "foo", "bar"};
size_t argvlen[3] = {3, 3, 3};
reply = redisCommandArgv(c,3,argv,argvlen);
test_cond(reply->type == REDIS_REPLY_STATUS);
freeReplyObject(reply);
/* Make sure passing NULL to redisGetReply is safe */
/* Make sure passing NULL to redisGetReply is safe */
test("Can pass NULL to redisGetReply: ");
test("Can pass NULL to redisGetReply: ");
assert(redisAppendCommand(c, "PING") == REDIS_OK);
assert(redisAppendCommand(c, "PING") == REDIS_OK);
...
@@ -1143,7 +1241,13 @@ static void test_blocking_connection_timeouts(struct config config) {
...
@@ -1143,7 +1241,13 @@ static void test_blocking_connection_timeouts(struct config config) {
test("Does not return a reply when the command times out: ");
test("Does not return a reply when the command times out: ");
if (detect_debug_sleep(c)) {
if (detect_debug_sleep(c)) {
redisAppendFormattedCommand(c, sleep_cmd, strlen(sleep_cmd));
redisAppendFormattedCommand(c, sleep_cmd, strlen(sleep_cmd));
// flush connection buffer without waiting for the reply
s = c->funcs->write(c);
s = c->funcs->write(c);
assert(s == (ssize_t)hi_sdslen(c->obuf));
hi_sdsfree(c->obuf);
c->obuf = hi_sdsempty();
tv.tv_sec = 0;
tv.tv_sec = 0;
tv.tv_usec = 10000;
tv.tv_usec = 10000;
redisSetTimeout(c, tv);
redisSetTimeout(c, tv);
...
@@ -1156,6 +1260,9 @@ static void test_blocking_connection_timeouts(struct config config) {
...
@@ -1156,6 +1260,9 @@ static void test_blocking_connection_timeouts(struct config config) {
strcmp(c->errstr, "recv timeout") == 0);
strcmp(c->errstr, "recv timeout") == 0);
#endif
#endif
freeReplyObject(reply);
freeReplyObject(reply);
// wait for the DEBUG SLEEP to complete so that Redis server is unblocked for the following tests
millisleep(3000);
} else {
} else {
test_skipped();
test_skipped();
}
}
...
@@ -1226,22 +1333,34 @@ static void test_blocking_io_errors(struct config config) {
...
@@ -1226,22 +1333,34 @@ static void test_blocking_io_errors(struct config config) {
static void test_invalid_timeout_errors(struct config config) {
static void test_invalid_timeout_errors(struct config config) {
redisContext *c;
redisContext *c;
test
(
"Set error when an invalid timeout usec value is
given to redisConnectWithTimeou
t: "
);
test("Set error when an invalid timeout usec value is
used during connec
t: ");
config
.
tcp
.
timeout
.
tv_sec
=
0
;
config.
connect_
timeout.tv_sec = 0;
config
.
tcp
.
timeout
.
tv_usec
=
10000001
;
config.
connect_
timeout.tv_usec = 10000001;
c
=
redisConnectWithTimeout
(
config
.
tcp
.
host
,
config
.
tcp
.
port
,
config
.
tcp
.
timeout
);
if (config.type == CONN_TCP || config.type == CONN_SSL) {
c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.connect_timeout);
} else if(config.type == CONN_UNIX) {
c = redisConnectUnixWithTimeout(config.unix_sock.path, config.connect_timeout);
} else {
assert(NULL);
}
test_cond(c->err == REDIS_ERR_IO && strcmp(c->errstr, "Invalid timeout specified") == 0);
test_cond(c->err == REDIS_ERR_IO && strcmp(c->errstr, "Invalid timeout specified") == 0);
redisFree(c);
redisFree(c);
test
(
"Set error when an invalid timeout sec value is
given to redisConnectWithTimeou
t: "
);
test("Set error when an invalid timeout sec value is
used during connec
t: ");
config
.
tcp
.
timeout
.
tv_sec
=
(((
LONG_MAX
)
-
999
)
/
1000
)
+
1
;
config.
connect_
timeout.tv_sec = (((LONG_MAX) - 999) / 1000) + 1;
config
.
tcp
.
timeout
.
tv_usec
=
0
;
config.
connect_
timeout.tv_usec = 0;
c
=
redisConnectWithTimeout
(
config
.
tcp
.
host
,
config
.
tcp
.
port
,
config
.
tcp
.
timeout
);
if (config.type == CONN_TCP || config.type == CONN_SSL) {
c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.connect_timeout);
} else if(config.type == CONN_UNIX) {
c = redisConnectUnixWithTimeout(config.unix_sock.path, config.connect_timeout);
} else {
assert(NULL);
}
test_cond(c->err == REDIS_ERR_IO && strcmp(c->errstr, "Invalid timeout specified") == 0);
test_cond(c->err == REDIS_ERR_IO && strcmp(c->errstr, "Invalid timeout specified") == 0);
redisFree(c);
redisFree(c);
...
@@ -1729,10 +1848,14 @@ void subscribe_channel_a_cb(redisAsyncContext *ac, void *r, void *privdata) {
...
@@ -1729,10 +1848,14 @@ void subscribe_channel_a_cb(redisAsyncContext *ac, void *r, void *privdata) {
strcmp(reply->element[2]->str,"Hello!") == 0);
strcmp(reply->element[2]->str,"Hello!") == 0);
state->checkpoint++;
state->checkpoint++;
/* Unsubscribe to channels, including
a
channel X which we don't subscribe to */
/* Unsubscribe to channels, including channel X
& Z
which we don't subscribe to */
redisAsyncCommand(ac,unexpected_cb,
redisAsyncCommand(ac,unexpected_cb,
(void*)"unsubscribe should not call unexpected_cb()",
(void*)"unsubscribe should not call unexpected_cb()",
"unsubscribe B X A"
);
"unsubscribe B X A A Z");
/* Unsubscribe to patterns, none which we subscribe to */
redisAsyncCommand(ac,unexpected_cb,
(void*)"punsubscribe should not call unexpected_cb()",
"punsubscribe");
/* Send a regular command after unsubscribing, then disconnect */
/* Send a regular command after unsubscribing, then disconnect */
state->disconnect = 1;
state->disconnect = 1;
redisAsyncCommand(ac,integer_cb,state,"LPUSH mylist foo");
redisAsyncCommand(ac,integer_cb,state,"LPUSH mylist foo");
...
@@ -1749,6 +1872,7 @@ void subscribe_channel_a_cb(redisAsyncContext *ac, void *r, void *privdata) {
...
@@ -1749,6 +1872,7 @@ void subscribe_channel_a_cb(redisAsyncContext *ac, void *r, void *privdata) {
void subscribe_channel_b_cb(redisAsyncContext *ac, void *r, void *privdata) {
void subscribe_channel_b_cb(redisAsyncContext *ac, void *r, void *privdata) {
redisReply *reply = r;
redisReply *reply = r;
TestState *state = privdata;
TestState *state = privdata;
(void)ac;
assert(reply != NULL && reply->type == REDIS_REPLY_ARRAY &&
assert(reply != NULL && reply->type == REDIS_REPLY_ARRAY &&
reply->elements == 3);
reply->elements == 3);
...
@@ -1767,8 +1891,10 @@ void subscribe_channel_b_cb(redisAsyncContext *ac, void *r, void *privdata) {
...
@@ -1767,8 +1891,10 @@ void subscribe_channel_b_cb(redisAsyncContext *ac, void *r, void *privdata) {
/* Test handling of multiple channels
/* Test handling of multiple channels
* - subscribe to channel A and B
* - subscribe to channel A and B
* - a published message on A triggers an unsubscribe of channel B, X and A
* - a published message on A triggers an unsubscribe of channel B, X, A and Z
* where channel X is not subscribed to.
* where channel X and Z are not subscribed to.
* - the published message also triggers an unsubscribe to patterns. Since no
* pattern is subscribed to the responded pattern element type is NIL.
* - a command sent after unsubscribe triggers a disconnect */
* - a command sent after unsubscribe triggers a disconnect */
static void test_pubsub_multiple_channels(struct config config) {
static void test_pubsub_multiple_channels(struct config config) {
test("Subscribe to multiple channels: ");
test("Subscribe to multiple channels: ");
...
@@ -1881,6 +2007,250 @@ static void test_monitor(struct config config) {
...
@@ -1881,6 +2007,250 @@ static void test_monitor(struct config config) {
}
}
#endif /* HIREDIS_TEST_ASYNC */
#endif /* HIREDIS_TEST_ASYNC */
/* tests for async api using polling adapter, requires no extra libraries*/
/* enum for the test cases, the callbacks have different logic based on them */
typedef enum astest_no
{
ASTEST_CONNECT=0,
ASTEST_CONN_TIMEOUT,
ASTEST_PINGPONG,
ASTEST_PINGPONG_TIMEOUT,
ASTEST_ISSUE_931,
ASTEST_ISSUE_931_PING
}astest_no;
/* a static context for the async tests */
struct _astest {
redisAsyncContext *ac;
astest_no testno;
int counter;
int connects;
int connect_status;
int disconnects;
int pongs;
int disconnect_status;
int connected;
int err;
char errstr[256];
};
static struct _astest astest;
/* async callbacks */
static void asCleanup(void* data)
{
struct _astest *t = (struct _astest *)data;
t->ac = NULL;
}
static void commandCallback(struct redisAsyncContext *ac, void* _reply, void* _privdata);
static void connectCallback(redisAsyncContext *c, int status) {
struct _astest *t = (struct _astest *)c->data;
assert(t == &astest);
assert(t->connects == 0);
t->err = c->err;
strcpy(t->errstr, c->errstr);
t->connects++;
t->connect_status = status;
t->connected = status == REDIS_OK ? 1 : -1;
if (t->testno == ASTEST_ISSUE_931) {
/* disconnect again */
redisAsyncDisconnect(c);
}
else if (t->testno == ASTEST_ISSUE_931_PING)
{
redisAsyncCommand(c, commandCallback, NULL, "PING");
}
}
static void disconnectCallback(const redisAsyncContext *c, int status) {
assert(c->data == (void*)&astest);
assert(astest.disconnects == 0);
astest.err = c->err;
strcpy(astest.errstr, c->errstr);
astest.disconnects++;
astest.disconnect_status = status;
astest.connected = 0;
}
static void commandCallback(struct redisAsyncContext *ac, void* _reply, void* _privdata)
{
redisReply *reply = (redisReply*)_reply;
struct _astest *t = (struct _astest *)ac->data;
assert(t == &astest);
(void)_privdata;
t->err = ac->err;
strcpy(t->errstr, ac->errstr);
t->counter++;
if (t->testno == ASTEST_PINGPONG ||t->testno == ASTEST_ISSUE_931_PING)
{
assert(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0);
t->pongs++;
redisAsyncFree(ac);
}
if (t->testno == ASTEST_PINGPONG_TIMEOUT)
{
/* two ping pongs */
assert(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0);
t->pongs++;
if (t->counter == 1) {
int status = redisAsyncCommand(ac, commandCallback, NULL, "PING");
assert(status == REDIS_OK);
} else {
redisAsyncFree(ac);
}
}
}
static redisAsyncContext *do_aconnect(struct config config, astest_no testno)
{
redisOptions options = {0};
memset(&astest, 0, sizeof(astest));
astest.testno = testno;
astest.connect_status = astest.disconnect_status = -2;
if (config.type == CONN_TCP) {
options.type = REDIS_CONN_TCP;
options.connect_timeout = &config.connect_timeout;
REDIS_OPTIONS_SET_TCP(&options, config.tcp.host, config.tcp.port);
} else if (config.type == CONN_SSL) {
options.type = REDIS_CONN_TCP;
options.connect_timeout = &config.connect_timeout;
REDIS_OPTIONS_SET_TCP(&options, config.ssl.host, config.ssl.port);
} else if (config.type == CONN_UNIX) {
options.type = REDIS_CONN_UNIX;
options.endpoint.unix_socket = config.unix_sock.path;
} else if (config.type == CONN_FD) {
options.type = REDIS_CONN_USERFD;
/* Create a dummy connection just to get an fd to inherit */
redisContext *dummy_ctx = redisConnectUnix(config.unix_sock.path);
if (dummy_ctx) {
redisFD fd = disconnect(dummy_ctx, 1);
printf("Connecting to inherited fd %d\n", (int)fd);
options.endpoint.fd = fd;
}
}
redisAsyncContext *c = redisAsyncConnectWithOptions(&options);
assert(c);
astest.ac = c;
c->data = &astest;
c->dataCleanup = asCleanup;
redisPollAttach(c);
redisAsyncSetConnectCallbackNC(c, connectCallback);
redisAsyncSetDisconnectCallback(c, disconnectCallback);
return c;
}
static void as_printerr(void) {
printf("Async err %d : %s\n", astest.err, astest.errstr);
}
#define ASASSERT(e) do { \
if (!(e)) \
as_printerr(); \
assert(e); \
} while (0);
static void test_async_polling(struct config config) {
int status;
redisAsyncContext *c;
struct config defaultconfig = config;
test("Async connect: ");
c = do_aconnect(config, ASTEST_CONNECT);
assert(c);
while(astest.connected == 0)
redisPollTick(c, 0.1);
assert(astest.connects == 1);
ASASSERT(astest.connect_status == REDIS_OK);
assert(astest.disconnects == 0);
test_cond(astest.connected == 1);
test("Async free after connect: ");
assert(astest.ac != NULL);
redisAsyncFree(c);
assert(astest.disconnects == 1);
assert(astest.ac == NULL);
test_cond(astest.disconnect_status == REDIS_OK);
if (config.type == CONN_TCP || config.type == CONN_SSL) {
/* timeout can only be simulated with network */
test("Async connect timeout: ");
config.tcp.host = "192.168.254.254"; /* blackhole ip */
config.connect_timeout.tv_usec = 100000;
c = do_aconnect(config, ASTEST_CONN_TIMEOUT);
assert(c);
assert(c->err == 0);
while(astest.connected == 0)
redisPollTick(c, 0.1);
assert(astest.connected == -1);
/*
* freeing should not be done, clearing should have happened.
*redisAsyncFree(c);
*/
assert(astest.ac == NULL);
test_cond(astest.connect_status == REDIS_ERR);
config = defaultconfig;
}
/* Test a ping/pong after connection */
test("Async PING/PONG: ");
c = do_aconnect(config, ASTEST_PINGPONG);
while(astest.connected == 0)
redisPollTick(c, 0.1);
status = redisAsyncCommand(c, commandCallback, NULL, "PING");
assert(status == REDIS_OK);
while(astest.ac)
redisPollTick(c, 0.1);
test_cond(astest.pongs == 1);
/* Test a ping/pong after connection that didn't time out.
* see https://github.com/redis/hiredis/issues/945
*/
if (config.type == CONN_TCP || config.type == CONN_SSL) {
test("Async PING/PONG after connect timeout: ");
config.connect_timeout.tv_usec = 10000; /* 10ms */
c = do_aconnect(config, ASTEST_PINGPONG_TIMEOUT);
while(astest.connected == 0)
redisPollTick(c, 0.1);
/* sleep 0.1 s, allowing old timeout to arrive */
millisleep(10);
status = redisAsyncCommand(c, commandCallback, NULL, "PING");
assert(status == REDIS_OK);
while(astest.ac)
redisPollTick(c, 0.1);
test_cond(astest.pongs == 2);
config = defaultconfig;
}
/* Test disconnect from an on_connect callback
* see https://github.com/redis/hiredis/issues/931
*/
test("Disconnect from onConnected callback (Issue #931): ");
c = do_aconnect(config, ASTEST_ISSUE_931);
while(astest.disconnects == 0)
redisPollTick(c, 0.1);
assert(astest.connected == 0);
assert(astest.connects == 1);
test_cond(astest.disconnects == 1);
/* Test ping/pong from an on_connect callback
* see https://github.com/redis/hiredis/issues/931
*/
test("Ping/Pong from onConnected callback (Issue #931): ");
c = do_aconnect(config, ASTEST_ISSUE_931_PING);
/* connect callback issues ping, reponse callback destroys context */
while(astest.ac)
redisPollTick(c, 0.1);
assert(astest.connected == 0);
assert(astest.connects == 1);
assert(astest.disconnects == 1);
test_cond(astest.pongs == 1);
}
/* End of Async polling_adapter driven tests */
int main(int argc, char **argv) {
int main(int argc, char **argv) {
struct config cfg = {
struct config cfg = {
.tcp = {
.tcp = {
...
@@ -1963,6 +2333,7 @@ int main(int argc, char **argv) {
...
@@ -1963,6 +2333,7 @@ int main(int argc, char **argv) {
test_blocking_io_errors(cfg);
test_blocking_io_errors(cfg);
test_invalid_timeout_errors(cfg);
test_invalid_timeout_errors(cfg);
test_append_formatted_commands(cfg);
test_append_formatted_commands(cfg);
test_tcp_options(cfg);
if (throughput) test_throughput(cfg);
if (throughput) test_throughput(cfg);
printf("\nTesting against Unix socket connection (%s): ", cfg.unix_sock.path);
printf("\nTesting against Unix socket connection (%s): ", cfg.unix_sock.path);
...
@@ -1972,6 +2343,7 @@ int main(int argc, char **argv) {
...
@@ -1972,6 +2343,7 @@ int main(int argc, char **argv) {
test_blocking_connection(cfg);
test_blocking_connection(cfg);
test_blocking_connection_timeouts(cfg);
test_blocking_connection_timeouts(cfg);
test_blocking_io_errors(cfg);
test_blocking_io_errors(cfg);
test_invalid_timeout_errors(cfg);
if (throughput) test_throughput(cfg);
if (throughput) test_throughput(cfg);
} else {
} else {
test_skipped();
test_skipped();
...
@@ -2000,6 +2372,7 @@ int main(int argc, char **argv) {
...
@@ -2000,6 +2372,7 @@ int main(int argc, char **argv) {
#endif
#endif
#ifdef HIREDIS_TEST_ASYNC
#ifdef HIREDIS_TEST_ASYNC
cfg.type = CONN_TCP;
printf("\nTesting asynchronous API against TCP connection (%s:%d):\n", cfg.tcp.host, cfg.tcp.port);
printf("\nTesting asynchronous API against TCP connection (%s:%d):\n", cfg.tcp.host, cfg.tcp.port);
cfg.type = CONN_TCP;
cfg.type = CONN_TCP;
...
@@ -2017,6 +2390,15 @@ int main(int argc, char **argv) {
...
@@ -2017,6 +2390,15 @@ int main(int argc, char **argv) {
}
}
#endif /* HIREDIS_TEST_ASYNC */
#endif /* HIREDIS_TEST_ASYNC */
cfg.type = CONN_TCP;
printf("\nTesting asynchronous API using polling_adapter TCP (%s:%d):\n", cfg.tcp.host, cfg.tcp.port);
test_async_polling(cfg);
if (test_unix_socket) {
cfg.type = CONN_UNIX;
printf("\nTesting asynchronous API using polling_adapter UNIX (%s):\n", cfg.unix_sock.path);
test_async_polling(cfg);
}
if (test_inherit_fd) {
if (test_inherit_fd) {
printf("\nTesting against inherited fd (%s): ", cfg.unix_sock.path);
printf("\nTesting against inherited fd (%s): ", cfg.unix_sock.path);
if (test_unix_socket) {
if (test_unix_socket) {
...
...
deps/hiredis/test.sh
View file @
e7a3d3d1
...
@@ -4,9 +4,17 @@ REDIS_SERVER=${REDIS_SERVER:-redis-server}
...
@@ -4,9 +4,17 @@ REDIS_SERVER=${REDIS_SERVER:-redis-server}
REDIS_PORT
=
${
REDIS_PORT
:-
56379
}
REDIS_PORT
=
${
REDIS_PORT
:-
56379
}
REDIS_SSL_PORT
=
${
REDIS_SSL_PORT
:-
56443
}
REDIS_SSL_PORT
=
${
REDIS_SSL_PORT
:-
56443
}
TEST_SSL
=
${
TEST_SSL
:-
0
}
TEST_SSL
=
${
TEST_SSL
:-
0
}
SKIPS_AS_FAILS
=
${
SKIPS_AS_FAILS
-
:0
}
SKIPS_AS_FAILS
=
${
SKIPS_AS_FAILS
:-
0
}
ENABLE_DEBUG_CMD
=
SSL_TEST_ARGS
=
SSL_TEST_ARGS
=
SKIPS_ARG
=
SKIPS_ARG
=
${
SKIPS_ARG
:-}
REDIS_DOCKER
=
${
REDIS_DOCKER
:-}
# We need to enable the DEBUG command for redis-server >= 7.0.0
REDIS_MAJOR_VERSION
=
"
$(
redis-server
--version
|awk
-F
'[^0-9]+'
'{ print $2 }'
)
"
if
[
"
$REDIS_MAJOR_VERSION
"
-gt
"6"
]
;
then
ENABLE_DEBUG_CMD
=
"enable-debug-command local"
fi
tmpdir
=
$(
mktemp
-d
)
tmpdir
=
$(
mktemp
-d
)
PID_FILE
=
${
tmpdir
}
/hiredis-test-redis.pid
PID_FILE
=
${
tmpdir
}
/hiredis-test-redis.pid
...
@@ -43,20 +51,34 @@ if [ "$TEST_SSL" = "1" ]; then
...
@@ -43,20 +51,34 @@ if [ "$TEST_SSL" = "1" ]; then
fi
fi
cleanup
()
{
cleanup
()
{
set
+e
if
[
-n
"
${
REDIS_DOCKER
}
"
]
;
then
kill
$(
cat
${
PID_FILE
}
)
docker
kill
redis-test-server
else
set
+e
kill
$(
cat
${
PID_FILE
}
)
fi
rm
-rf
${
tmpdir
}
rm
-rf
${
tmpdir
}
}
}
trap
cleanup INT TERM EXIT
trap
cleanup INT TERM EXIT
# base config
cat
>
${
tmpdir
}
/redis.conf
<<
EOF
cat
>
${
tmpdir
}
/redis.conf
<<
EOF
daemonize yes
pidfile
${
PID_FILE
}
pidfile
${
PID_FILE
}
port
${
REDIS_PORT
}
port
${
REDIS_PORT
}
bind 127.0.0.1
unixsocket
${
SOCK_FILE
}
unixsocket
${
SOCK_FILE
}
unixsocketperm 777
EOF
EOF
# if not running in docker add these:
if
[
!
-n
"
${
REDIS_DOCKER
}
"
]
;
then
cat
>>
${
tmpdir
}
/redis.conf
<<
EOF
daemonize yes
${
ENABLE_DEBUG_CMD
}
bind 127.0.0.1
EOF
fi
# if doing ssl, add these
if
[
"
$TEST_SSL
"
=
"1"
]
;
then
if
[
"
$TEST_SSL
"
=
"1"
]
;
then
cat
>>
${
tmpdir
}
/redis.conf
<<
EOF
cat
>>
${
tmpdir
}
/redis.conf
<<
EOF
tls-port
${
REDIS_SSL_PORT
}
tls-port
${
REDIS_SSL_PORT
}
...
@@ -66,13 +88,25 @@ tls-key-file ${SSL_KEY}
...
@@ -66,13 +88,25 @@ tls-key-file ${SSL_KEY}
EOF
EOF
fi
fi
echo
${
tmpdir
}
cat
${
tmpdir
}
/redis.conf
cat
${
tmpdir
}
/redis.conf
${
REDIS_SERVER
}
${
tmpdir
}
/redis.conf
if
[
-n
"
${
REDIS_DOCKER
}
"
]
;
then
chmod
a+wx
${
tmpdir
}
chmod
a+r
${
tmpdir
}
/
*
docker run
-d
--rm
--name
redis-test-server
\
-p
${
REDIS_PORT
}
:
${
REDIS_PORT
}
\
-p
${
REDIS_SSL_PORT
}
:
${
REDIS_SSL_PORT
}
\
-v
${
tmpdir
}
:
${
tmpdir
}
\
${
REDIS_DOCKER
}
\
redis-server
${
tmpdir
}
/redis.conf
else
${
REDIS_SERVER
}
${
tmpdir
}
/redis.conf
fi
# Wait until we detect the unix socket
# Wait until we detect the unix socket
echo
waiting
for
server
while
[
!
-S
"
${
SOCK_FILE
}
"
]
;
do
sleep
1
;
done
while
[
!
-S
"
${
SOCK_FILE
}
"
]
;
do
sleep
1
;
done
# Treat skips as failures if directed
# Treat skips as failures if directed
[
"
$SKIPS_AS_FAILS
"
=
1
]
&&
SKIPS_ARG
=
"--skips-as-fails"
[
"
$SKIPS_AS_FAILS
"
=
1
]
&&
SKIPS_ARG
=
"
${
SKIPS_ARG
}
--skips-as-fails"
${
TEST_PREFIX
:-}
./hiredis-test
-h
127.0.0.1
-p
${
REDIS_PORT
}
-s
${
SOCK_FILE
}
${
SSL_TEST_ARGS
}
${
SKIPS_ARG
}
${
TEST_PREFIX
:-}
./hiredis-test
-h
127.0.0.1
-p
${
REDIS_PORT
}
-s
${
SOCK_FILE
}
${
SSL_TEST_ARGS
}
${
SKIPS_ARG
}
Prev
1
2
3
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment