Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add asynchronous API tests #1010

Merged
merged 2 commits into from
Nov 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ jobs:
run: |
sudo add-apt-repository -y ppa:chris-lea/redis-server
sudo apt-get update
sudo apt-get install -y redis-server valgrind
sudo apt-get install -y redis-server valgrind libevent-dev

- name: Build using cmake
env:
EXTRA_CMAKE_OPTS: -DENABLE_EXAMPLES:BOOL=ON -DENABLE_SSL:BOOL=ON -DENABLE_SSL_TESTS:BOOL=ON
EXTRA_CMAKE_OPTS: -DENABLE_EXAMPLES:BOOL=ON -DENABLE_SSL:BOOL=ON -DENABLE_SSL_TESTS:BOOL=ON -DENABLE_ASYNC_TESTS:BOOL=ON
CFLAGS: -Werror
CXXFLAGS: -Werror
run: mkdir build-ubuntu && cd build-ubuntu && cmake ..

- name: Build using makefile
run: USE_SSL=1 make
run: USE_SSL=1 TEST_ASYNC=1 make

- name: Run tests
env:
Expand Down Expand Up @@ -53,17 +53,17 @@ jobs:
run: |
yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
yum -y --enablerepo=remi install redis
yum -y install gcc gcc-c++ make openssl openssl-devel cmake3 valgrind
yum -y install gcc gcc-c++ make openssl openssl-devel cmake3 valgrind libevent-devel

- name: Build using cmake
env:
EXTRA_CMAKE_OPTS: -DENABLE_EXAMPLES:BOOL=ON -DENABLE_SSL:BOOL=ON -DENABLE_SSL_TESTS:BOOL=ON
EXTRA_CMAKE_OPTS: -DENABLE_EXAMPLES:BOOL=ON -DENABLE_SSL:BOOL=ON -DENABLE_SSL_TESTS:BOOL=ON -DENABLE_ASYNC_TESTS:BOOL=ON
CFLAGS: -Werror
CXXFLAGS: -Werror
run: mkdir build-centos7 && cd build-centos7 && cmake3 ..

- name: Build using Makefile
run: USE_SSL=1 make
run: USE_SSL=1 TEST_ASYNC=1 make

- name: Run tests
env:
Expand Down Expand Up @@ -93,17 +93,17 @@ jobs:
dnf -y install https://rpms.remirepo.net/enterprise/remi-release-8.rpm
dnf -y module install redis:remi-6.0
dnf -y group install "Development Tools"
dnf -y install openssl-devel cmake valgrind
dnf -y install openssl-devel cmake valgrind libevent-devel

- name: Build using cmake
env:
EXTRA_CMAKE_OPTS: -DENABLE_EXAMPLES:BOOL=ON -DENABLE_SSL:BOOL=ON -DENABLE_SSL_TESTS:BOOL=ON
EXTRA_CMAKE_OPTS: -DENABLE_EXAMPLES:BOOL=ON -DENABLE_SSL:BOOL=ON -DENABLE_SSL_TESTS:BOOL=ON -DENABLE_ASYNC_TESTS:BOOL=ON
CFLAGS: -Werror
CXXFLAGS: -Werror
run: mkdir build-centos8 && cd build-centos8 && cmake ..

- name: Build using Makefile
run: USE_SSL=1 make
run: USE_SSL=1 TEST_ASYNC=1 make

- name: Run tests
env:
Expand Down
10 changes: 7 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ PROJECT(hiredis)
OPTION(ENABLE_SSL "Build hiredis_ssl for SSL support" OFF)
OPTION(DISABLE_TESTS "If tests should be compiled or not" OFF)
OPTION(ENABLE_SSL_TESTS "Should we test SSL connections" OFF)
OPTION(ENABLE_ASYNC_TESTS "Should we run all asynchronous API tests" OFF)

MACRO(getVersionBit name)
SET(VERSION_REGEX "^#define ${name} (.+)$")
Expand Down Expand Up @@ -218,11 +219,14 @@ ENDIF()
IF(NOT DISABLE_TESTS)
ENABLE_TESTING()
ADD_EXECUTABLE(hiredis-test test.c)
TARGET_LINK_LIBRARIES(hiredis-test hiredis)
IF(ENABLE_SSL_TESTS)
ADD_DEFINITIONS(-DHIREDIS_TEST_SSL=1)
TARGET_LINK_LIBRARIES(hiredis-test hiredis hiredis_ssl)
ELSE()
TARGET_LINK_LIBRARIES(hiredis-test hiredis)
TARGET_LINK_LIBRARIES(hiredis-test hiredis_ssl)
ENDIF()
IF(ENABLE_ASYNC_TESTS)
ADD_DEFINITIONS(-DHIREDIS_TEST_ASYNC=1)
TARGET_LINK_LIBRARIES(hiredis-test event)
ENDIF()
ADD_TEST(NAME hiredis-test
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test.sh)
Expand Down
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ USE_SSL?=0
ifeq ($(USE_SSL),1)
export CFLAGS+=-DHIREDIS_TEST_SSL
endif
ifeq ($(TEST_ASYNC),1)
export CFLAGS+=-DHIREDIS_TEST_ASYNC
endif

ifeq ($(uname_S),Linux)
ifdef OPENSSL_PREFIX
Expand Down Expand Up @@ -211,6 +214,9 @@ ifeq ($(USE_SSL),1)
TEST_LIBS += $(SSL_STLIBNAME)
TEST_LDFLAGS = $(SSL_LDFLAGS) -lssl -lcrypto -lpthread
endif
ifeq ($(TEST_ASYNC),1)
TEST_LDFLAGS += -levent
endif

hiredis-test: test.o $(TEST_LIBS)
$(CC) -o $@ $(REAL_CFLAGS) -I. $^ $(REAL_LDFLAGS) $(TEST_LDFLAGS)
Expand Down
107 changes: 107 additions & 0 deletions test.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#ifdef HIREDIS_TEST_SSL
#include "hiredis_ssl.h"
#endif
#ifdef HIREDIS_TEST_ASYNC
#include "adapters/libevent.h"
#include <event.h>
#endif
#include "net.h"
#include "win32.h"

Expand Down Expand Up @@ -1443,6 +1447,104 @@ static void test_throughput(struct config config) {
// redisFree(c);
// }

#ifdef HIREDIS_TEST_ASYNC
struct event_base *base;

typedef struct TestState {
redisOptions *options;
int checkpoint;
} TestState;

/* Testcase timeout, will trigger a failure */
void timeout_cb(int fd, short event, void *arg) {
(void) fd; (void) event; (void) arg;
printf("Timeout in async testing!\n");
exit(1);
}

/* Unexpected call, will trigger a failure */
void unexpected_cb(redisAsyncContext *ac, void *r, void *privdata) {
(void) ac; (void) r;
printf("Unexpected call: %s\n",(char*)privdata);
exit(1);
}

/* Helper function to publish a message via own client. */
void publish_msg(redisOptions *options, const char* channel, const char* msg) {
redisContext *c = redisConnectWithOptions(options);
assert(c != NULL);
redisReply *reply = redisCommand(c,"PUBLISH %s %s",channel,msg);
assert(reply->type == REDIS_REPLY_INTEGER && reply->integer == 1);
freeReplyObject(reply);
disconnect(c, 0);
}

/* Subscribe callback for test_pubsub_handling:
* - a published message triggers an unsubscribe
* - an unsubscribe response triggers a disconnect */
void subscribe_cb(redisAsyncContext *ac, void *r, void *privdata) {
redisReply *reply = r;
TestState *state = privdata;

assert(reply != NULL &&
reply->type == REDIS_REPLY_ARRAY &&
reply->elements == 3);

if (strcmp(reply->element[0]->str,"subscribe") == 0) {
assert(strcmp(reply->element[1]->str,"mychannel") == 0 &&
reply->element[2]->str == NULL);
publish_msg(state->options,"mychannel","Hello!");
} else if (strcmp(reply->element[0]->str,"message") == 0) {
assert(strcmp(reply->element[1]->str,"mychannel") == 0 &&
strcmp(reply->element[2]->str,"Hello!") == 0);
state->checkpoint++;

/* Unsubscribe after receiving the published message. Send unsubscribe
* which should call the callback registered during subscribe */
redisAsyncCommand(ac,unexpected_cb,
(void*)"unsubscribe should call subscribe_cb()",
"unsubscribe");
} else if (strcmp(reply->element[0]->str,"unsubscribe") == 0) {
assert(strcmp(reply->element[1]->str,"mychannel") == 0 &&
reply->element[2]->str == NULL);

/* Disconnect after unsubscribe */
redisAsyncDisconnect(ac);
event_base_loopbreak(base);
} else {
printf("Unexpected pubsub command: %s\n", reply->element[0]->str);
exit(1);
}
}

static void test_pubsub_handling(struct config config) {
test("Subscribe, handle published message and unsubscribe: ");
/* Setup event dispatcher with a testcase timeout */
base = event_base_new();
struct event timeout;
evtimer_assign(&timeout,base,timeout_cb,NULL);
struct timeval timeout_tv = {.tv_sec = 10};
evtimer_add(&timeout, &timeout_tv);

/* Connect */
redisOptions options = get_redis_tcp_options(config);
redisAsyncContext *ac = redisAsyncConnectWithOptions(&options);
assert(ac != NULL && ac->err == 0);
redisLibeventAttach(ac,base);

/* Start subscribe */
TestState state = {.options = &options};
redisAsyncCommand(ac,subscribe_cb,&state,"subscribe mychannel");

/* Start event dispatching loop */
test_cond(event_base_dispatch(base) == 0);
event_base_free(base);

/* Verify test checkpoints */
assert(state.checkpoint == 1);
}
#endif

int main(int argc, char **argv) {
struct config cfg = {
.tcp = {
Expand Down Expand Up @@ -1561,6 +1663,11 @@ int main(int argc, char **argv) {
}
#endif

#ifdef HIREDIS_TEST_ASYNC
printf("\nTesting asynchronous API against TCP connection (%s:%d):\n", cfg.tcp.host, cfg.tcp.port);
test_pubsub_handling(cfg);
#endif

if (test_inherit_fd) {
printf("\nTesting against inherited fd (%s): ", cfg.unix_sock.path);
if (test_unix_socket) {
Expand Down