EV-Hiredis

 view release on metacpan or  search on metacpan

deps/hiredis/test.c  view on Meta::CPAN

//
// static void __test_reply_callback(redisContext *c, redisReply *reply, void *privdata) {
//     ((void)c);
//     /* Shift to detect execution order */
//     __test_callback_flags <<= 8;
//     __test_callback_flags |= (long)privdata;
//     if (reply) freeReplyObject(reply);
// }
//
// static redisContext *__connect_nonblock() {
//     /* Reset callback flags */
//     __test_callback_flags = 0;
//     return redisConnectNonBlock("127.0.0.1", port, NULL);
// }
//
// static void test_nonblocking_connection() {
//     redisContext *c;
//     int wdone = 0;
//
//     test("Calls command callback when command is issued: ");
//     c = __connect_nonblock();
//     redisSetCommandCallback(c,__test_callback,(void*)1);
//     redisCommand(c,"PING");
//     test_cond(__test_callback_flags == 1);
//     redisFree(c);
//
//     test("Calls disconnect callback on redisDisconnect: ");
//     c = __connect_nonblock();
//     redisSetDisconnectCallback(c,__test_callback,(void*)2);
//     redisDisconnect(c);
//     test_cond(__test_callback_flags == 2);
//     redisFree(c);
//
//     test("Calls disconnect callback and free callback on redisFree: ");
//     c = __connect_nonblock();
//     redisSetDisconnectCallback(c,__test_callback,(void*)2);
//     redisSetFreeCallback(c,__test_callback,(void*)4);
//     redisFree(c);
//     test_cond(__test_callback_flags == ((2 << 8) | 4));
//
//     test("redisBufferWrite against empty write buffer: ");
//     c = __connect_nonblock();
//     test_cond(redisBufferWrite(c,&wdone) == REDIS_OK && wdone == 1);
//     redisFree(c);
//
//     test("redisBufferWrite against not yet connected fd: ");
//     c = __connect_nonblock();
//     redisCommand(c,"PING");
//     test_cond(redisBufferWrite(c,NULL) == REDIS_ERR &&
//               strncmp(c->error,"write:",6) == 0);
//     redisFree(c);
//
//     test("redisBufferWrite against closed fd: ");
//     c = __connect_nonblock();
//     redisCommand(c,"PING");
//     redisDisconnect(c);
//     test_cond(redisBufferWrite(c,NULL) == REDIS_ERR &&
//               strncmp(c->error,"write:",6) == 0);
//     redisFree(c);
//
//     test("Process callbacks in the right sequence: ");
//     c = __connect_nonblock();
//     redisCommandWithCallback(c,__test_reply_callback,(void*)1,"PING");
//     redisCommandWithCallback(c,__test_reply_callback,(void*)2,"PING");
//     redisCommandWithCallback(c,__test_reply_callback,(void*)3,"PING");
//
//     /* Write output buffer */
//     wdone = 0;
//     while(!wdone) {
//         usleep(500);
//         redisBufferWrite(c,&wdone);
//     }
//
//     /* Read until at least one callback is executed (the 3 replies will
//      * arrive in a single packet, causing all callbacks to be executed in
//      * a single pass). */
//     while(__test_callback_flags == 0) {
//         assert(redisBufferRead(c) == REDIS_OK);
//         redisProcessCallbacks(c);
//     }
//     test_cond(__test_callback_flags == 0x010203);
//     redisFree(c);
//
//     test("redisDisconnect executes pending callbacks with NULL reply: ");
//     c = __connect_nonblock();
//     redisSetDisconnectCallback(c,__test_callback,(void*)1);
//     redisCommandWithCallback(c,__test_reply_callback,(void*)2,"PING");
//     redisDisconnect(c);
//     test_cond(__test_callback_flags == 0x0201);
//     redisFree(c);
// }

#ifdef HIREDIS_TEST_ASYNC
struct event_base *base;

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

/* Helper to disconnect and stop event loop */
void async_disconnect(redisAsyncContext *ac) {
    redisAsyncDisconnect(ac);
    event_base_loopbreak(base);
}

/* 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);
}

/* Expect a reply of type INTEGER */
void integer_cb(redisAsyncContext *ac, void *r, void *privdata) {
    redisReply *reply = r;
    TestState *state = privdata;
    assert(reply != NULL && reply->type == REDIS_REPLY_INTEGER);
    state->checkpoint++;
    if (state->disconnect) async_disconnect(ac);
}

/* Subscribe callback for test_pubsub_handling and test_pubsub_handling_resp3:
 * - a published message triggers an unsubscribe
 * - a command is sent before the unsubscribe response is received. */

deps/hiredis/test.c  view on Meta::CPAN

        assert(reply->type == REDIS_REPLY_STATUS);
        freeReplyObject(reply);
        redisFree(c);
    } else if (state->checkpoint == 2) {
        /* Response for monitored command 'SET first 1' */
        assert(strstr(reply->str,"first") != NULL);
        redisContext *c = redisConnectWithOptions(state->options);
        assert(c != NULL);
        redisReply *reply = redisCommand(c,"SET second 2");
        assert(reply->type == REDIS_REPLY_STATUS);
        freeReplyObject(reply);
        redisFree(c);
    } else if (state->checkpoint == 3) {
        /* Response for monitored command 'SET second 2' */
        assert(strstr(reply->str,"second") != NULL);
        /* Send QUIT to disconnect */
        redisAsyncCommand(ac,NULL,NULL,"QUIT");
    }
}

/* Test handling of the monitor command
 * - sends MONITOR to enable monitoring.
 * - sends SET commands via separate clients to be monitored.
 * - sends QUIT to stop monitoring and disconnect. */
static void test_monitor(struct config config) {
    test("Enable monitoring: ");
    /* Setup event dispatcher with a testcase timeout */
    base = event_base_new();
    struct event *timeout = evtimer_new(base, timeout_cb, NULL);
    assert(timeout != NULL);

    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);

    /* Not expecting any push messages in this test */
    redisAsyncSetPushCallback(ac,unexpected_push_cb);

    /* Start monitor */
    TestState state = {.options = &options};
    redisAsyncCommand(ac,monitor_cb,&state,"monitor");

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

    /* Verify test checkpoints */
    assert(state.checkpoint == 3);
}
#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);



( run in 0.661 second using v1.01-cache-2.11-cpan-5a3173703d6 )