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
Show whitespace changes
Inline
Side-by-side
deps/hiredis/test.c
View file @
e7a3d3d1
...
...
@@ -15,6 +15,7 @@
#include "hiredis.h"
#include "async.h"
#include "adapters/poll.h"
#ifdef HIREDIS_TEST_SSL
#include "hiredis_ssl.h"
#endif
...
...
@@ -34,11 +35,11 @@ enum connection_type {
struct
config
{
enum
connection_type
type
;
struct
timeval
connect_timeout
;
struct
{
const
char
*
host
;
int
port
;
struct
timeval
timeout
;
}
tcp
;
struct
{
...
...
@@ -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_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
)
{
#ifndef _MSC_VER
struct
timeval
tv
;
...
...
@@ -329,10 +339,14 @@ static void test_format_commands(void) {
FLOAT_WIDTH_TEST
(
float
);
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
);
test_cond
(
len
==
-
1
);
test
(
"Format command with invalid printf format (specifier missing): "
);
len
=
redisFormatCommand
(
&
cmd
,
"%-"
);
test_cond
(
len
==
-
1
);
const
char
*
argv
[
3
];
argv
[
0
]
=
"SET"
;
argv
[
1
]
=
"foo
\0
xxx"
;
...
...
@@ -391,6 +405,16 @@ static void test_append_formatted_commands(struct config config) {
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
)
{
redisReader
*
reader
;
void
*
reply
,
*
root
;
...
...
@@ -568,6 +592,19 @@ static void test_reply_reader(void) {
test_cond
(
ret
==
REDIS_ERR
&&
reply
==
NULL
);
redisReaderFree
(
reader
);
test
(
"Don't reset state after protocol error(not segfault): "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,(
char
*
)
"*3
\r\n
$3
\r\n
SET
\r\n
$5
\r\n
hello
\r\n
$"
,
25
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
assert
(
ret
==
REDIS_OK
);
redisReaderFeed
(
reader
,(
char
*
)
"3
\r\n
val
\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. */
test
(
"Don't do empty allocation for empty multi bulk: "
);
reader
=
redisReaderCreate
();
...
...
@@ -637,12 +674,23 @@ static void test_reply_reader(void) {
freeReplyObject
(
reply
);
redisReaderFree
(
reader
);
test
(
"
Set error when
RESP3 double
is
NaN: "
);
test
(
"
Correctly parses
RESP3 double NaN: "
);
reader
=
redisReaderCreate
();
redisReaderFeed
(
reader
,
",nan
\r\n
"
,
6
);
ret
=
redisReaderGetReply
(
reader
,
&
reply
);
test_cond
(
ret
==
REDIS_ERR
&&
strcasecmp
(
reader
->
errstr
,
"Bad double value"
)
==
0
);
test_cond
(
ret
==
REDIS_OK
&&
((
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
);
redisReaderFree
(
reader
);
...
...
@@ -745,6 +793,20 @@ static void test_reply_reader(void) {
!
strcmp
(((
redisReply
*
)
reply
)
->
str
,
"3492890328409238509324850943850943825024385"
));
freeReplyObject
(
reply
);
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
)
{
...
...
@@ -819,9 +881,9 @@ static void test_allocator_injection(void) {
#define HIREDIS_BAD_DOMAIN "idontexist-noreally.com"
static
void
test_blocking_connection_errors
(
void
)
{
redisContext
*
c
;
struct
addrinfo
hints
=
{.
ai_family
=
AF_INET
};
struct
addrinfo
*
ai_tmp
=
NULL
;
redisContext
*
c
;
int
rv
=
getaddrinfo
(
HIREDIS_BAD_DOMAIN
,
"6379"
,
&
hints
,
&
ai_tmp
);
if
(
rv
!=
0
)
{
...
...
@@ -835,6 +897,7 @@ static void test_blocking_connection_errors(void) {
strcmp
(
c
->
errstr
,
"Can't resolve: "
HIREDIS_BAD_DOMAIN
)
==
0
||
strcmp
(
c
->
errstr
,
"Name does not resolve"
)
==
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
,
"Temporary failure in name resolution"
)
==
0
||
strcmp
(
c
->
errstr
,
"hostname nor servname provided, or not known"
)
==
0
||
...
...
@@ -847,12 +910,26 @@ static void test_blocking_connection_errors(void) {
}
#ifndef _WIN32
redisOptions
opt
=
{
0
};
struct
timeval
tv
;
test
(
"Returns error when the port is not open: "
);
c
=
redisConnect
((
char
*
)
"localhost"
,
1
);
test_cond
(
c
->
err
==
REDIS_ERR_IO
&&
strcmp
(
c
->
errstr
,
"Connection refused"
)
==
0
);
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: "
);
c
=
redisConnectUnix
((
char
*
)
"/tmp/idontexist.sock"
);
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) {
old
=
redisSetPushCallback
(
c
,
push_handler
);
test
(
"We can set a custom RESP3 PUSH handler: "
);
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
);
freeReplyObject
(
reply
);
test
(
"We properly handle a NIL invalidation payload: "
);
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
);
freeReplyObject
(
reply
);
...
...
@@ -929,6 +1014,12 @@ static void test_resp3_push_handler(redisContext *c) {
assert
((
reply
=
redisCommand
(
c
,
"GET key:0"
))
!=
NULL
);
freeReplyObject
(
reply
);
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
);
freeReplyObject
(
reply
);
...
...
@@ -1089,6 +1180,13 @@ static void test_blocking_connection(struct config config) {
strcasecmp
(
reply
->
element
[
1
]
->
str
,
"pong"
)
==
0
);
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 */
test
(
"Can pass NULL to redisGetReply: "
);
assert
(
redisAppendCommand
(
c
,
"PING"
)
==
REDIS_OK
);
...
...
@@ -1143,7 +1241,13 @@ static void test_blocking_connection_timeouts(struct config config) {
test
(
"Does not return a reply when the command times out: "
);
if
(
detect_debug_sleep
(
c
))
{
redisAppendFormattedCommand
(
c
,
sleep_cmd
,
strlen
(
sleep_cmd
));
// flush connection buffer without waiting for the reply
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_usec
=
10000
;
redisSetTimeout
(
c
,
tv
);
...
...
@@ -1156,6 +1260,9 @@ static void test_blocking_connection_timeouts(struct config config) {
strcmp
(
c
->
errstr
,
"recv timeout"
)
==
0
);
#endif
freeReplyObject
(
reply
);
// wait for the DEBUG SLEEP to complete so that Redis server is unblocked for the following tests
millisleep
(
3000
);
}
else
{
test_skipped
();
}
...
...
@@ -1226,22 +1333,34 @@ static void test_blocking_io_errors(struct config config) {
static
void
test_invalid_timeout_errors
(
struct
config
config
)
{
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
.
tcp
.
timeout
.
tv_usec
=
10000001
;
config
.
connect_
timeout
.
tv_sec
=
0
;
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
);
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
.
tcp
.
timeout
.
tv_usec
=
0
;
config
.
connect_
timeout
.
tv_sec
=
(((
LONG_MAX
)
-
999
)
/
1000
)
+
1
;
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
);
redisFree
(
c
);
...
...
@@ -1729,10 +1848,14 @@ void subscribe_channel_a_cb(redisAsyncContext *ac, void *r, void *privdata) {
strcmp
(
reply
->
element
[
2
]
->
str
,
"Hello!"
)
==
0
);
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
,
(
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 */
state
->
disconnect
=
1
;
redisAsyncCommand
(
ac
,
integer_cb
,
state
,
"LPUSH mylist foo"
);
...
...
@@ -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
)
{
redisReply
*
reply
=
r
;
TestState
*
state
=
privdata
;
(
void
)
ac
;
assert
(
reply
!=
NULL
&&
reply
->
type
==
REDIS_REPLY_ARRAY
&&
reply
->
elements
==
3
);
...
...
@@ -1767,8 +1891,10 @@ void subscribe_channel_b_cb(redisAsyncContext *ac, void *r, void *privdata) {
/* Test handling of multiple channels
* - subscribe to channel A and B
* - a published message on A triggers an unsubscribe of channel B, X and A
* where channel X is not subscribed to.
* - a published message on A triggers an unsubscribe of channel B, X, A and Z
* 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 */
static
void
test_pubsub_multiple_channels
(
struct
config
config
)
{
test
(
"Subscribe to multiple channels: "
);
...
...
@@ -1881,6 +2007,250 @@ static void test_monitor(struct config config) {
}
#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
)
{
struct
config
cfg
=
{
.
tcp
=
{
...
...
@@ -1963,6 +2333,7 @@ int main(int argc, char **argv) {
test_blocking_io_errors
(
cfg
);
test_invalid_timeout_errors
(
cfg
);
test_append_formatted_commands
(
cfg
);
test_tcp_options
(
cfg
);
if
(
throughput
)
test_throughput
(
cfg
);
printf
(
"
\n
Testing against Unix socket connection (%s): "
,
cfg
.
unix_sock
.
path
);
...
...
@@ -1972,6 +2343,7 @@ int main(int argc, char **argv) {
test_blocking_connection
(
cfg
);
test_blocking_connection_timeouts
(
cfg
);
test_blocking_io_errors
(
cfg
);
test_invalid_timeout_errors
(
cfg
);
if
(
throughput
)
test_throughput
(
cfg
);
}
else
{
test_skipped
();
...
...
@@ -2000,6 +2372,7 @@ int main(int argc, char **argv) {
#endif
#ifdef HIREDIS_TEST_ASYNC
cfg
.
type
=
CONN_TCP
;
printf
(
"
\n
Testing asynchronous API against TCP connection (%s:%d):
\n
"
,
cfg
.
tcp
.
host
,
cfg
.
tcp
.
port
);
cfg
.
type
=
CONN_TCP
;
...
...
@@ -2017,6 +2390,15 @@ int main(int argc, char **argv) {
}
#endif
/* HIREDIS_TEST_ASYNC */
cfg
.
type
=
CONN_TCP
;
printf
(
"
\n
Testing 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
(
"
\n
Testing asynchronous API using polling_adapter UNIX (%s):
\n
"
,
cfg
.
unix_sock
.
path
);
test_async_polling
(
cfg
);
}
if
(
test_inherit_fd
)
{
printf
(
"
\n
Testing against inherited fd (%s): "
,
cfg
.
unix_sock
.
path
);
if
(
test_unix_socket
)
{
...
...
deps/hiredis/test.sh
View file @
e7a3d3d1
...
...
@@ -4,9 +4,17 @@ REDIS_SERVER=${REDIS_SERVER:-redis-server}
REDIS_PORT
=
${
REDIS_PORT
:-
56379
}
REDIS_SSL_PORT
=
${
REDIS_SSL_PORT
:-
56443
}
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
=
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
)
PID_FILE
=
${
tmpdir
}
/hiredis-test-redis.pid
...
...
@@ -43,20 +51,34 @@ if [ "$TEST_SSL" = "1" ]; then
fi
cleanup
()
{
if
[
-n
"
${
REDIS_DOCKER
}
"
]
;
then
docker
kill
redis-test-server
else
set
+e
kill
$(
cat
${
PID_FILE
}
)
fi
rm
-rf
${
tmpdir
}
}
trap
cleanup INT TERM EXIT
# base config
cat
>
${
tmpdir
}
/redis.conf
<<
EOF
daemonize yes
pidfile
${
PID_FILE
}
port
${
REDIS_PORT
}
bind 127.0.0.1
unixsocket
${
SOCK_FILE
}
unixsocketperm 777
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
cat
>>
${
tmpdir
}
/redis.conf
<<
EOF
tls-port
${
REDIS_SSL_PORT
}
...
...
@@ -66,13 +88,25 @@ tls-key-file ${SSL_KEY}
EOF
fi
echo
${
tmpdir
}
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
echo
waiting
for
server
while
[
!
-S
"
${
SOCK_FILE
}
"
]
;
do
sleep
1
;
done
# 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
}
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