diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2013-06-03 18:34:10 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2013-06-03 18:34:10 +0000 |
commit | f143c3cab79c59dd57124f19d16ac35253843136 (patch) | |
tree | 9fa67aa3d59e9d96f5f37858e95c4ab91960ea92 /test/test_context.c | |
parent | 6f61a1acd01dc2ad1d2f5c1f7458702c77c69f9c (diff) | |
download | libserf-tarball-f143c3cab79c59dd57124f19d16ac35253843136.tar.gz |
serf-1.2.1HEADserf-1.2.1master
Diffstat (limited to 'test/test_context.c')
-rw-r--r-- | test/test_context.c | 850 |
1 files changed, 550 insertions, 300 deletions
diff --git a/test/test_context.c b/test/test_context.c index d2a24d0..14d4fa9 100644 --- a/test/test_context.c +++ b/test/test_context.c @@ -43,6 +43,61 @@ typedef struct { test_baton_t *tb; } handler_baton_t; +/* Helper function, runs the client and server context loops and validates + that no errors were encountered, and all messages were sent and received. */ +static apr_status_t +test_helper_run_requests_no_check(CuTest *tc, test_baton_t *tb, + int num_requests, + handler_baton_t handler_ctx[], + apr_pool_t *pool) +{ + apr_pool_t *iter_pool; + int i, done = 0; + apr_status_t status; + + apr_pool_create(&iter_pool, pool); + + while (!done) + { + apr_pool_clear(iter_pool); + + status = test_server_run(tb->serv_ctx, 0, iter_pool); + if (!APR_STATUS_IS_TIMEUP(status) && + SERF_BUCKET_READ_ERROR(status)) + return status; + + status = serf_context_run(tb->context, 0, iter_pool); + if (!APR_STATUS_IS_TIMEUP(status) && + SERF_BUCKET_READ_ERROR(status)) + return status; + + done = 1; + for (i = 0; i < num_requests; i++) + done &= handler_ctx[i].done; + } + apr_pool_destroy(iter_pool); + + return APR_SUCCESS; +} + +static void +test_helper_run_requests_expect_ok(CuTest *tc, test_baton_t *tb, + int num_requests, + handler_baton_t handler_ctx[], + apr_pool_t *pool) +{ + apr_status_t status; + + status = test_helper_run_requests_no_check(tc, tb, num_requests, + handler_ctx, pool); + CuAssertIntEquals(tc, APR_SUCCESS, status); + + /* Check that all requests were received */ + CuAssertIntEquals(tc, num_requests, tb->sent_requests->nelts); + CuAssertIntEquals(tc, num_requests, tb->accepted_requests->nelts); + CuAssertIntEquals(tc, num_requests, tb->handled_requests->nelts); +} + static serf_bucket_t* accept_response(serf_request_t *request, serf_bucket_t *stream, void *acceptor_baton, @@ -133,15 +188,67 @@ static apr_status_t handle_response(serf_request_t *request, return APR_SUCCESS; } +static void setup_handler(test_baton_t *tb, handler_baton_t *handler_ctx, + const char *method, const char *path, + int req_id, + serf_response_handler_t handler) +{ + handler_ctx->method = method; + handler_ctx->path = path; + handler_ctx->done = FALSE; + + handler_ctx->acceptor = accept_response; + handler_ctx->acceptor_baton = NULL; + handler_ctx->handler = handler ? handler : handle_response; + handler_ctx->req_id = req_id; + handler_ctx->accepted_requests = tb->accepted_requests; + handler_ctx->sent_requests = tb->sent_requests; + handler_ctx->handled_requests = tb->handled_requests; + handler_ctx->tb = tb; +} + +static void create_new_prio_request(test_baton_t *tb, + handler_baton_t *handler_ctx, + const char *method, const char *path, + int req_id) +{ + setup_handler(tb, handler_ctx, method, path, req_id, NULL); + serf_connection_priority_request_create(tb->connection, + setup_request, + handler_ctx); +} + +static void create_new_request(test_baton_t *tb, + handler_baton_t *handler_ctx, + const char *method, const char *path, + int req_id) +{ + setup_handler(tb, handler_ctx, method, path, req_id, NULL); + serf_connection_request_create(tb->connection, + setup_request, + handler_ctx); +} + +static void +create_new_request_with_resp_hdlr(test_baton_t *tb, + handler_baton_t *handler_ctx, + const char *method, const char *path, + int req_id, + serf_response_handler_t handler) +{ + setup_handler(tb, handler_ctx, method, path, req_id, handler); + serf_connection_request_create(tb->connection, + setup_request, + handler_ctx); +} + /* Validate that requests are sent and completed in the order of creation. */ static void test_serf_connection_request_create(CuTest *tc) { test_baton_t *tb; - serf_request_t *request1, *request2; - handler_baton_t handler_ctx, handler2_ctx; + handler_baton_t handler_ctx[2]; + const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]); apr_status_t status; - apr_pool_t *iter_pool; - apr_array_header_t *accepted_requests, *handled_requests, *sent_requests; int i; test_server_message_t message_list[] = { {CHUNKED_REQUEST(1, "1")}, @@ -152,74 +259,31 @@ static void test_serf_connection_request_create(CuTest *tc) {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE}, {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE}, }; - apr_pool_t *test_pool = test_setup(); - accepted_requests = apr_array_make(test_pool, 2, sizeof(int)); - sent_requests = apr_array_make(test_pool, 2, sizeof(int)); - handled_requests = apr_array_make(test_pool, 2, sizeof(int)); + apr_pool_t *test_pool = test_setup(); /* Set up a test context with a server */ status = test_server_setup(&tb, - message_list, 2, - action_list, 2, 0, NULL, + message_list, num_requests, + action_list, num_requests, 0, NULL, test_pool); CuAssertIntEquals(tc, APR_SUCCESS, status); - handler_ctx.method = "GET"; - handler_ctx.path = "/"; - handler_ctx.done = FALSE; - - handler_ctx.acceptor = accept_response; - handler_ctx.acceptor_baton = NULL; - handler_ctx.handler = handle_response; - handler_ctx.req_id = 1; - handler_ctx.accepted_requests = accepted_requests; - handler_ctx.sent_requests = sent_requests; - handler_ctx.handled_requests = handled_requests; - - request1 = serf_connection_request_create(tb->connection, - setup_request, - &handler_ctx); + create_new_request(tb, &handler_ctx[0], "GET", "/", 1); + create_new_request(tb, &handler_ctx[1], "GET", "/", 2); - handler2_ctx = handler_ctx; - handler2_ctx.req_id = 2; - - request2 = serf_connection_request_create(tb->connection, - setup_request, - &handler2_ctx); - - apr_pool_create(&iter_pool, test_pool); - - while (!handler_ctx.done || !handler2_ctx.done) - { - apr_pool_clear(iter_pool); - - status = test_server_run(tb->serv_ctx, 0, iter_pool); - if (APR_STATUS_IS_TIMEUP(status)) - status = APR_SUCCESS; - CuAssertIntEquals(tc, APR_SUCCESS, status); - - status = serf_context_run(tb->context, 0, iter_pool); - if (APR_STATUS_IS_TIMEUP(status)) - status = APR_SUCCESS; - CuAssertIntEquals(tc, APR_SUCCESS, status); - } - apr_pool_destroy(iter_pool); - - /* Check that all requests were received */ - CuAssertIntEquals(tc, 2, sent_requests->nelts); - CuAssertIntEquals(tc, 2, accepted_requests->nelts); - CuAssertIntEquals(tc, 2, handled_requests->nelts); + test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx, + test_pool); /* Check that the requests were sent in the order we created them */ - for (i = 0; i < sent_requests->nelts; i++) { - int req_nr = APR_ARRAY_IDX(sent_requests, i, int); + for (i = 0; i < tb->sent_requests->nelts; i++) { + int req_nr = APR_ARRAY_IDX(tb->sent_requests, i, int); CuAssertIntEquals(tc, i + 1, req_nr); } /* Check that the requests were received in the order we created them */ - for (i = 0; i < handled_requests->nelts; i++) { - int req_nr = APR_ARRAY_IDX(handled_requests, i, int); + for (i = 0; i < tb->handled_requests->nelts; i++) { + int req_nr = APR_ARRAY_IDX(tb->handled_requests, i, int); CuAssertIntEquals(tc, i + 1, req_nr); } @@ -232,11 +296,9 @@ static void test_serf_connection_request_create(CuTest *tc) static void test_serf_connection_priority_request_create(CuTest *tc) { test_baton_t *tb; - serf_request_t *request1, *request2, *request3; - handler_baton_t handler_ctx, handler2_ctx, handler3_ctx; + handler_baton_t handler_ctx[3]; + const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]); apr_status_t status; - apr_pool_t *iter_pool; - apr_array_header_t *accepted_requests, *handled_requests, *sent_requests; int i; test_server_message_t message_list[] = { @@ -253,81 +315,29 @@ static void test_serf_connection_priority_request_create(CuTest *tc) apr_pool_t *test_pool = test_setup(); - accepted_requests = apr_array_make(test_pool, 3, sizeof(int)); - sent_requests = apr_array_make(test_pool, 3, sizeof(int)); - handled_requests = apr_array_make(test_pool, 3, sizeof(int)); - /* Set up a test context with a server */ status = test_server_setup(&tb, - message_list, 3, - action_list, 3, 0, NULL, + message_list, num_requests, + action_list, num_requests, 0, NULL, test_pool); CuAssertIntEquals(tc, APR_SUCCESS, status); - handler_ctx.method = "GET"; - handler_ctx.path = "/"; - handler_ctx.done = FALSE; - - handler_ctx.acceptor = accept_response; - handler_ctx.acceptor_baton = NULL; - handler_ctx.handler = handle_response; - handler_ctx.req_id = 2; - handler_ctx.accepted_requests = accepted_requests; - handler_ctx.sent_requests = sent_requests; - handler_ctx.handled_requests = handled_requests; - - request1 = serf_connection_request_create(tb->connection, - setup_request, - &handler_ctx); - - handler2_ctx = handler_ctx; - handler2_ctx.req_id = 3; + create_new_request(tb, &handler_ctx[0], "GET", "/", 2); + create_new_request(tb, &handler_ctx[1], "GET", "/", 3); + create_new_prio_request(tb, &handler_ctx[2], "GET", "/", 1); - request2 = serf_connection_request_create(tb->connection, - setup_request, - &handler2_ctx); - handler3_ctx = handler_ctx; - handler3_ctx.req_id = 1; - - request3 = serf_connection_priority_request_create(tb->connection, - setup_request, - &handler3_ctx); - - apr_pool_create(&iter_pool, test_pool); - - while (!handler_ctx.done || !handler2_ctx.done || !handler3_ctx.done) - { - apr_pool_clear(iter_pool); - - status = test_server_run(tb->serv_ctx, 0, iter_pool); - if (APR_STATUS_IS_TIMEUP(status)) - status = APR_SUCCESS; - CuAssertIntEquals(tc, APR_SUCCESS, status); - - status = serf_context_run(tb->context, 0, iter_pool); - if (APR_STATUS_IS_TIMEUP(status)) - status = APR_SUCCESS; - CuAssertIntEquals(tc, APR_SUCCESS, status); - - /* Debugging purposes only! */ - serf_debug__closed_conn(tb->bkt_alloc); - } - apr_pool_destroy(iter_pool); - - /* Check that all requests were received */ - CuAssertIntEquals(tc, 3, sent_requests->nelts); - CuAssertIntEquals(tc, 3, accepted_requests->nelts); - CuAssertIntEquals(tc, 3, handled_requests->nelts); + test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx, + test_pool); /* Check that the requests were sent in the order we created them */ - for (i = 0; i < sent_requests->nelts; i++) { - int req_nr = APR_ARRAY_IDX(sent_requests, i, int); + for (i = 0; i < tb->sent_requests->nelts; i++) { + int req_nr = APR_ARRAY_IDX(tb->sent_requests, i, int); CuAssertIntEquals(tc, i + 1, req_nr); } /* Check that the requests were received in the order we created them */ - for (i = 0; i < handled_requests->nelts; i++) { - int req_nr = APR_ARRAY_IDX(handled_requests, i, int); + for (i = 0; i < tb->handled_requests->nelts; i++) { + int req_nr = APR_ARRAY_IDX(tb->handled_requests, i, int); CuAssertIntEquals(tc, i + 1, req_nr); } @@ -337,13 +347,12 @@ static void test_serf_connection_priority_request_create(CuTest *tc) /* Test that serf correctly handles the 'Connection:close' header when the server is planning to close the connection. */ -#define NUM_REQUESTS 10 static void test_serf_closed_connection(CuTest *tc) { test_baton_t *tb; - apr_array_header_t *accepted_requests, *handled_requests, *sent_requests; apr_status_t status; - handler_baton_t handler_ctx[NUM_REQUESTS]; + handler_baton_t handler_ctx[10]; + const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]); int done = FALSE, i; test_server_message_t message_list[] = { @@ -390,37 +399,18 @@ static void test_serf_closed_connection(CuTest *tc) apr_pool_t *test_pool = test_setup(); - accepted_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int)); - sent_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int)); - handled_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int)); - /* Set up a test context with a server. */ status = test_server_setup(&tb, - message_list, 10, + message_list, num_requests, action_list, 12, 0, NULL, test_pool); CuAssertIntEquals(tc, APR_SUCCESS, status); - for (i = 0 ; i < NUM_REQUESTS ; i++) { - /* Send some requests on the connections */ - handler_ctx[i].method = "GET"; - handler_ctx[i].path = "/"; - handler_ctx[i].done = FALSE; - - handler_ctx[i].acceptor = accept_response; - handler_ctx[i].acceptor_baton = NULL; - handler_ctx[i].handler = handle_response; - handler_ctx[i].req_id = i+1; - handler_ctx[i].accepted_requests = accepted_requests; - handler_ctx[i].sent_requests = sent_requests; - handler_ctx[i].handled_requests = handled_requests; - handler_ctx[i].tb = tb; - - serf_connection_request_create(tb->connection, - setup_request, - &handler_ctx[i]); + /* Send some requests on the connections */ + for (i = 0 ; i < num_requests ; i++) { + create_new_request(tb, &handler_ctx[i], "GET", "/", i+1); } while (1) { @@ -438,7 +428,7 @@ static void test_serf_closed_connection(CuTest *tc) serf_debug__closed_conn(tb->bkt_alloc); done = TRUE; - for (i = 0 ; i < NUM_REQUESTS ; i++) + for (i = 0 ; i < num_requests ; i++) if (handler_ctx[i].done == FALSE) { done = FALSE; break; @@ -447,29 +437,26 @@ static void test_serf_closed_connection(CuTest *tc) break; } - /* Check that all requests were received */ - CuAssertTrue(tc, sent_requests->nelts >= NUM_REQUESTS); - CuAssertIntEquals(tc, NUM_REQUESTS, accepted_requests->nelts); - CuAssertIntEquals(tc, NUM_REQUESTS, handled_requests->nelts); + /* Check that all requests were received */ + CuAssertTrue(tc, tb->sent_requests->nelts >= num_requests); + CuAssertIntEquals(tc, num_requests, tb->accepted_requests->nelts); + CuAssertIntEquals(tc, num_requests, tb->handled_requests->nelts); /* Cleanup */ test_server_teardown(tb, test_pool); test_teardown(test_pool); } -#undef NUM_REQUESTS /* Test if serf is sending the request to the proxy, not to the server directly. */ static void test_serf_setup_proxy(CuTest *tc) { test_baton_t *tb; - serf_request_t *request; - handler_baton_t handler_ctx; - apr_status_t status; - apr_pool_t *iter_pool; - apr_array_header_t *accepted_requests, *handled_requests, *sent_requests; int i; - int numrequests = 1; + handler_baton_t handler_ctx[1]; + const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]); + apr_pool_t *iter_pool; + apr_status_t status; test_server_message_t message_list[] = { {"GET http://localhost:" SERV_PORT_STR " HTTP/1.1" CRLF\ @@ -488,10 +475,6 @@ static void test_serf_setup_proxy(CuTest *tc) apr_pool_t *test_pool = test_setup(); - accepted_requests = apr_array_make(test_pool, numrequests, sizeof(int)); - sent_requests = apr_array_make(test_pool, numrequests, sizeof(int)); - handled_requests = apr_array_make(test_pool, numrequests, sizeof(int)); - /* Set up a test context with a server, no messages expected. */ status = test_server_proxy_setup(&tb, /* server messages and actions */ @@ -504,25 +487,11 @@ static void test_serf_setup_proxy(CuTest *tc) NULL, test_pool); CuAssertIntEquals(tc, APR_SUCCESS, status); - handler_ctx.method = "GET"; - handler_ctx.path = "/"; - handler_ctx.done = FALSE; - - handler_ctx.acceptor = accept_response; - handler_ctx.acceptor_baton = NULL; - handler_ctx.handler = handle_response; - handler_ctx.req_id = 1; - handler_ctx.accepted_requests = accepted_requests; - handler_ctx.sent_requests = sent_requests; - handler_ctx.handled_requests = handled_requests; - - request = serf_connection_request_create(tb->connection, - setup_request, - &handler_ctx); + create_new_request(tb, &handler_ctx[0], "GET", "/", 1); apr_pool_create(&iter_pool, test_pool); - while (!handler_ctx.done) + while (!handler_ctx[0].done) { apr_pool_clear(iter_pool); @@ -547,19 +516,20 @@ static void test_serf_setup_proxy(CuTest *tc) apr_pool_destroy(iter_pool); /* Check that all requests were received */ - CuAssertIntEquals(tc, numrequests, sent_requests->nelts); - CuAssertIntEquals(tc, numrequests, accepted_requests->nelts); - CuAssertIntEquals(tc, numrequests, handled_requests->nelts); + CuAssertIntEquals(tc, num_requests, tb->sent_requests->nelts); + CuAssertIntEquals(tc, num_requests, tb->accepted_requests->nelts); + CuAssertIntEquals(tc, num_requests, tb->handled_requests->nelts); + /* Check that the requests were sent in the order we created them */ - for (i = 0; i < sent_requests->nelts; i++) { - int req_nr = APR_ARRAY_IDX(sent_requests, i, int); + for (i = 0; i < tb->sent_requests->nelts; i++) { + int req_nr = APR_ARRAY_IDX(tb->sent_requests, i, int); CuAssertIntEquals(tc, i + 1, req_nr); } /* Check that the requests were received in the order we created them */ - for (i = 0; i < handled_requests->nelts; i++) { - int req_nr = APR_ARRAY_IDX(handled_requests, i, int); + for (i = 0; i < tb->handled_requests->nelts; i++) { + int req_nr = APR_ARRAY_IDX(tb->handled_requests, i, int); CuAssertIntEquals(tc, i + 1, req_nr); } @@ -617,7 +587,6 @@ handle_response_keepalive_limit(serf_request_t *request, static void test_keepalive_limit_one_by_one(CuTest *tc) { test_baton_t *tb; - apr_array_header_t *accepted_requests, *handled_requests, *sent_requests; apr_status_t status; handler_baton_t handler_ctx[SEND_REQUESTS]; int done = FALSE, i; @@ -644,35 +613,17 @@ static void test_keepalive_limit_one_by_one(CuTest *tc) apr_pool_t *test_pool = test_setup(); - accepted_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int)); - sent_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int)); - handled_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int)); - /* Set up a test context with a server. */ status = test_server_setup(&tb, - message_list, 7, - action_list, 7, 0, NULL, + message_list, RCVD_REQUESTS, + action_list, RCVD_REQUESTS, 0, NULL, test_pool); CuAssertIntEquals(tc, APR_SUCCESS, status); for (i = 0 ; i < SEND_REQUESTS ; i++) { - /* Send some requests on the connections */ - handler_ctx[i].method = "GET"; - handler_ctx[i].path = "/"; - handler_ctx[i].done = FALSE; - - handler_ctx[i].acceptor = accept_response; - handler_ctx[i].acceptor_baton = NULL; - handler_ctx[i].handler = handle_response_keepalive_limit; - handler_ctx[i].req_id = i+1; - handler_ctx[i].accepted_requests = accepted_requests; - handler_ctx[i].sent_requests = sent_requests; - handler_ctx[i].handled_requests = handled_requests; - handler_ctx[i].tb = tb; - - serf_connection_request_create(tb->connection, - setup_request, - &handler_ctx[i]); + create_new_request_with_resp_hdlr(tb, &handler_ctx[i], "GET", "/", i+1, + handle_response_keepalive_limit); + /* TODO: don't think this needs to be done in the loop. */ serf_connection_set_max_outstanding_requests(tb->connection, 1); } @@ -701,9 +652,9 @@ static void test_keepalive_limit_one_by_one(CuTest *tc) } /* Check that all requests were received */ - CuAssertIntEquals(tc, RCVD_REQUESTS, sent_requests->nelts); - CuAssertIntEquals(tc, RCVD_REQUESTS, accepted_requests->nelts); - CuAssertIntEquals(tc, RCVD_REQUESTS, handled_requests->nelts); + CuAssertIntEquals(tc, RCVD_REQUESTS, tb->sent_requests->nelts); + CuAssertIntEquals(tc, RCVD_REQUESTS, tb->accepted_requests->nelts); + CuAssertIntEquals(tc, RCVD_REQUESTS, tb->handled_requests->nelts); /* Cleanup */ test_server_teardown(tb, test_pool); @@ -771,8 +722,7 @@ handle_response_keepalive_limit_burst(serf_request_t *request, static void test_keepalive_limit_one_by_one_and_burst(CuTest *tc) { test_baton_t *tb; - apr_array_header_t *accepted_requests, *handled_requests, *sent_requests; - apr_status_t status; + apr_status_t status; handler_baton_t handler_ctx[SEND_REQUESTS]; int done = FALSE, i; @@ -798,35 +748,16 @@ static void test_keepalive_limit_one_by_one_and_burst(CuTest *tc) apr_pool_t *test_pool = test_setup(); - accepted_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int)); - sent_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int)); - handled_requests = apr_array_make(test_pool, RCVD_REQUESTS, sizeof(int)); - /* Set up a test context with a server. */ status = test_server_setup(&tb, - message_list, 7, - action_list, 7, 0, NULL, + message_list, RCVD_REQUESTS, + action_list, RCVD_REQUESTS, 0, NULL, test_pool); CuAssertIntEquals(tc, APR_SUCCESS, status); for (i = 0 ; i < SEND_REQUESTS ; i++) { - /* Send some requests on the connections */ - handler_ctx[i].method = "GET"; - handler_ctx[i].path = "/"; - handler_ctx[i].done = FALSE; - - handler_ctx[i].acceptor = accept_response; - handler_ctx[i].acceptor_baton = NULL; - handler_ctx[i].handler = handle_response_keepalive_limit_burst; - handler_ctx[i].req_id = i+1; - handler_ctx[i].accepted_requests = accepted_requests; - handler_ctx[i].sent_requests = sent_requests; - handler_ctx[i].handled_requests = handled_requests; - handler_ctx[i].tb = tb; - - serf_connection_request_create(tb->connection, - setup_request, - &handler_ctx[i]); + create_new_request_with_resp_hdlr(tb, &handler_ctx[i], "GET", "/", i+1, + handle_response_keepalive_limit_burst); serf_connection_set_max_outstanding_requests(tb->connection, 1); } @@ -855,9 +786,9 @@ static void test_keepalive_limit_one_by_one_and_burst(CuTest *tc) } /* Check that all requests were received */ - CuAssertIntEquals(tc, RCVD_REQUESTS, sent_requests->nelts); - CuAssertIntEquals(tc, RCVD_REQUESTS, accepted_requests->nelts); - CuAssertIntEquals(tc, RCVD_REQUESTS, handled_requests->nelts); + CuAssertIntEquals(tc, RCVD_REQUESTS, tb->sent_requests->nelts); + CuAssertIntEquals(tc, RCVD_REQUESTS, tb->accepted_requests->nelts); + CuAssertIntEquals(tc, RCVD_REQUESTS, tb->handled_requests->nelts); /* Cleanup */ test_server_teardown(tb, test_pool); @@ -866,7 +797,6 @@ static void test_keepalive_limit_one_by_one_and_burst(CuTest *tc) #undef SEND_REQUESTS #undef RCVD_REQUESTS -#define NUM_REQUESTS 5 typedef struct { apr_off_t read; apr_off_t written; @@ -896,10 +826,10 @@ static apr_status_t progress_conn_setup(apr_socket_t *skt, static void test_serf_progress_callback(CuTest *tc) { test_baton_t *tb; - apr_array_header_t *accepted_requests, *handled_requests, *sent_requests; apr_status_t status; - handler_baton_t handler_ctx[NUM_REQUESTS]; - int done = FALSE, i; + handler_baton_t handler_ctx[5]; + const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]); + int i; progress_baton_t *pb; test_server_message_t message_list[] = { @@ -919,15 +849,11 @@ static void test_serf_progress_callback(CuTest *tc) }; apr_pool_t *test_pool = test_setup(); - - accepted_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int)); - sent_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int)); - handled_requests = apr_array_make(test_pool, NUM_REQUESTS, sizeof(int)); - + /* Set up a test context with a server. */ status = test_server_setup(&tb, - message_list, 5, - action_list, 5, 0, + message_list, num_requests, + action_list, num_requests, 0, progress_conn_setup, test_pool); CuAssertIntEquals(tc, APR_SUCCESS, status); @@ -936,64 +862,384 @@ static void test_serf_progress_callback(CuTest *tc) tb->user_baton = pb; serf_context_set_progress_cb(tb->context, progress_cb, tb); - for (i = 0 ; i < NUM_REQUESTS ; i++) { - /* Send some requests on the connections */ - handler_ctx[i].method = "GET"; - handler_ctx[i].path = "/"; - handler_ctx[i].done = FALSE; - - handler_ctx[i].acceptor = accept_response; - handler_ctx[i].acceptor_baton = NULL; - handler_ctx[i].handler = handle_response; - handler_ctx[i].req_id = i+1; - handler_ctx[i].accepted_requests = accepted_requests; - handler_ctx[i].sent_requests = sent_requests; - handler_ctx[i].handled_requests = handled_requests; - handler_ctx[i].tb = tb; - - serf_connection_request_create(tb->connection, + /* Send some requests on the connections */ + for (i = 0 ; i < num_requests ; i++) { + create_new_request(tb, &handler_ctx[i], "GET", "/", i+1); + } + + test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx, + test_pool); + + /* Check that progress was reported. */ + CuAssertTrue(tc, pb->written > 0); + CuAssertTrue(tc, pb->read > 0); + + /* Cleanup */ + test_server_teardown(tb, test_pool); + test_teardown(test_pool); +} + + +/***************************************************************************** + * Issue #91: test that serf correctly handle an incoming 4xx reponse while + * the outgoing request wasn't written completely yet. + *****************************************************************************/ + +#define REQUEST_PART1 "PROPFIND / HTTP/1.1" CRLF\ +"Host: lgo-ubuntu.local" CRLF\ +"User-Agent: SVN/1.8.0-dev (x86_64-apple-darwin11.4.2) serf/2.0.0" CRLF\ +"Content-Type: text/xml" CRLF\ +"Transfer-Encoding: chunked" CRLF \ +CRLF\ +"12d" CRLF\ +"<?xml version=""1.0"" encoding=""utf-8""?><propfind xmlns=""DAV:""><prop>" + +#define REQUEST_PART2 \ +"<resourcetype xmlns=""DAV:""/><getcontentlength xmlns=""DAV:""/>"\ +"<deadprop-count xmlns=""http://subversion.tigris.org/xmlns/dav/""/>"\ +"<version-name xmlns=""DAV:""/><creationdate xmlns=""DAV:""/>"\ +"<creator-displayname xmlns=""DAV:""/></prop></propfind>" CRLF\ +"0" CRLF \ +CRLF + +#define RESPONSE_408 "HTTP/1.1 408 Request Time-out" CRLF\ +"Date: Wed, 14 Nov 2012 19:50:35 GMT" CRLF\ +"Server: Apache/2.2.17 (Ubuntu)" CRLF\ +"Vary: Accept-Encoding" CRLF\ +"Content-Length: 305" CRLF\ +"Connection: close" CRLF\ +"Content-Type: text/html; charset=iso-8859-1" CRLF \ +CRLF\ +"<!DOCTYPE HTML PUBLIC ""-//IETF//DTD HTML 2.0//EN""><html><head>"\ +"<title>408 Request Time-out</title></head><body><h1>Request Time-out</h1>"\ +"<p>Server timeout waiting for the HTTP request from the client.</p><hr>"\ +"<address>Apache/2.2.17 (Ubuntu) Server at lgo-ubuntu.local Port 80</address>"\ +"</body></html>" + + +static apr_status_t detect_eof(void *baton, serf_bucket_t *aggregate_bucket) +{ + serf_bucket_t *body_bkt; + handler_baton_t *ctx = baton; + + if (ctx->done) { + body_bkt = serf_bucket_simple_create(REQUEST_PART1, strlen(REQUEST_PART2), + NULL, NULL, + ctx->tb->bkt_alloc); + serf_bucket_aggregate_append(aggregate_bucket, body_bkt); + } + + return APR_EAGAIN; +} + +static apr_status_t setup_request_timeout( + serf_request_t *request, + void *setup_baton, + serf_bucket_t **req_bkt, + serf_response_acceptor_t *acceptor, + void **acceptor_baton, + serf_response_handler_t *handler, + void **handler_baton, + apr_pool_t *pool) +{ + handler_baton_t *ctx = setup_baton; + serf_bucket_t *body_bkt; + + *req_bkt = serf__bucket_stream_create(serf_request_get_alloc(request), + detect_eof, + ctx); + + /* create a simple body text */ + body_bkt = serf_bucket_simple_create(REQUEST_PART1, strlen(REQUEST_PART1), + NULL, NULL, + serf_request_get_alloc(request)); + serf_bucket_aggregate_append(*req_bkt, body_bkt); + + APR_ARRAY_PUSH(ctx->sent_requests, int) = ctx->req_id; + + *acceptor = ctx->acceptor; + *acceptor_baton = ctx; + *handler = ctx->handler; + *handler_baton = ctx; + + return APR_SUCCESS; +} + +static apr_status_t handle_response_timeout( + serf_request_t *request, + serf_bucket_t *response, + void *handler_baton, + apr_pool_t *pool) +{ + handler_baton_t *ctx = handler_baton; + serf_status_line sl; + apr_status_t status; + + if (! response) { + serf_connection_request_create(ctx->tb->connection, setup_request, - &handler_ctx[i]); + ctx); + return APR_SUCCESS; } - while (1) { - status = test_server_run(tb->serv_ctx, 0, test_pool); - if (APR_STATUS_IS_TIMEUP(status)) - status = APR_SUCCESS; - CuAssertIntEquals(tc, APR_SUCCESS, status); + if (serf_request_is_written(request) != APR_EBUSY) { + return APR_EGENERAL; + } - status = serf_context_run(tb->context, 0, test_pool); - if (APR_STATUS_IS_TIMEUP(status)) - status = APR_SUCCESS; - CuAssertIntEquals(tc, APR_SUCCESS, status); - /* Debugging purposes only! */ - serf_debug__closed_conn(tb->bkt_alloc); + status = serf_bucket_response_status(response, &sl); + if (SERF_BUCKET_READ_ERROR(status)) { + return status; + } + if (!sl.version && (APR_STATUS_IS_EOF(status) || + APR_STATUS_IS_EAGAIN(status))) { + return status; + } + if (sl.code == 408) { + APR_ARRAY_PUSH(ctx->handled_requests, int) = ctx->req_id; + ctx->done = TRUE; + } - done = TRUE; - for (i = 0 ; i < NUM_REQUESTS ; i++) - if (handler_ctx[i].done == FALSE) { - done = FALSE; - break; - } - if (done) - break; + /* discard the rest of the body */ + while (1) { + const char *data; + apr_size_t len; + + status = serf_bucket_read(response, 2048, &data, &len); + if (SERF_BUCKET_READ_ERROR(status) || + APR_STATUS_IS_EAGAIN(status) || + APR_STATUS_IS_EOF(status)) + return status; } - /* Check that all requests were received */ - CuAssertTrue(tc, sent_requests->nelts >= NUM_REQUESTS); - CuAssertIntEquals(tc, NUM_REQUESTS, accepted_requests->nelts); - CuAssertIntEquals(tc, NUM_REQUESTS, handled_requests->nelts); + return APR_SUCCESS; +} - /* Check that progress was reported. */ - CuAssertTrue(tc, pb->written > 0); - CuAssertTrue(tc, pb->read > 0); +static void test_serf_request_timeout(CuTest *tc) +{ + test_baton_t *tb; + apr_status_t status; + handler_baton_t handler_ctx[1]; + const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]); + + test_server_message_t message_list[] = { + {REQUEST_PART1}, + {REQUEST_PART2}, + }; + + test_server_action_t action_list[] = { + {SERVER_RESPOND, RESPONSE_408}, + }; + + apr_pool_t *test_pool = test_setup(); + + /* Set up a test context with a server. */ + status = test_server_setup(&tb, + message_list, 2, + action_list, 1, 0, + NULL, test_pool); + CuAssertIntEquals(tc, APR_SUCCESS, status); + + /* Send some requests on the connection */ + handler_ctx[0].method = "PROPFIND"; + handler_ctx[0].path = "/"; + handler_ctx[0].done = FALSE; + + handler_ctx[0].acceptor = accept_response; + handler_ctx[0].acceptor_baton = NULL; + handler_ctx[0].handler = handle_response_timeout; + handler_ctx[0].req_id = 1; + handler_ctx[0].accepted_requests = tb->accepted_requests; + handler_ctx[0].sent_requests = tb->sent_requests; + handler_ctx[0].handled_requests = tb->handled_requests; + handler_ctx[0].tb = tb; + + serf_connection_request_create(tb->connection, + setup_request_timeout, + &handler_ctx[0]); + + test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx, + test_pool); /* Cleanup */ test_server_teardown(tb, test_pool); test_teardown(test_pool); } -#undef NUM_REQUESTS + +static apr_status_t +ssl_server_cert_cb_expect_failures(void *baton, int failures, + const serf_ssl_certificate_t *cert) +{ + /* We expect an error from the certificate validation function. */ + if (failures) + return APR_SUCCESS; + else + return APR_EGENERAL; +} + +static apr_status_t +ssl_server_cert_cb_expect_allok(void *baton, int failures, + const serf_ssl_certificate_t *cert) +{ + /* No error expected, certificate is valid. */ + if (failures) + return APR_EGENERAL; + else + return APR_SUCCESS; +} + +/* Validate that we can connect successfully to an https server. */ +static void test_serf_ssl_handshake(CuTest *tc) +{ + test_baton_t *tb; + handler_baton_t handler_ctx[1]; + const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]); + apr_status_t status; + test_server_message_t message_list[] = { + {CHUNKED_REQUEST(1, "1")}, + }; + + test_server_action_t action_list[] = { + {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE}, + }; + + + /* Set up a test context with a server */ + apr_pool_t *test_pool = test_setup(); + status = test_https_server_setup(&tb, + message_list, num_requests, + action_list, num_requests, 0, + NULL, /* default conn setup */ + "test/server/serfserverkey.pem", + "test/server/serfservercert.pem", + ssl_server_cert_cb_expect_failures, + test_pool); + CuAssertIntEquals(tc, APR_SUCCESS, status); + + create_new_request(tb, &handler_ctx[0], "GET", "/", 1); + + test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx, + test_pool); + + test_server_teardown(tb, test_pool); + test_teardown(test_pool); +} + +static apr_status_t +https_set_root_ca_conn_setup(apr_socket_t *skt, + serf_bucket_t **input_bkt, + serf_bucket_t **output_bkt, + void *setup_baton, + apr_pool_t *pool) +{ + serf_ssl_certificate_t *cacert, *rootcacert; + test_baton_t *tb = setup_baton; + apr_status_t status; + + status = default_https_conn_setup(skt, input_bkt, output_bkt, + setup_baton, pool); + if (status) + return status; + + status = serf_ssl_load_cert_file(&cacert, "test/server/serfcacert.pem", + pool); + if (status) + return status; + status = serf_ssl_trust_cert(tb->ssl_context, cacert); + if (status) + return status; + + status = serf_ssl_load_cert_file(&rootcacert, + "test/server/serfrootcacert.pem", + pool); + if (status) + return status; + status = serf_ssl_trust_cert(tb->ssl_context, rootcacert); + if (status) + return status; + + return status; +} + +/* Validate that server certificate validation is ok when we + explicitly trust our self-signed root ca. */ +static void test_serf_ssl_trust_rootca(CuTest *tc) +{ + test_baton_t *tb; + handler_baton_t handler_ctx[1]; + const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]); + apr_status_t status; + test_server_message_t message_list[] = { + {CHUNKED_REQUEST(1, "1")}, + }; + + test_server_action_t action_list[] = { + {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE}, + }; + + /* Set up a test context with a server */ + apr_pool_t *test_pool = test_setup(); + status = test_https_server_setup(&tb, + message_list, num_requests, + action_list, num_requests, 0, + https_set_root_ca_conn_setup, + "test/server/serfserverkey.pem", + "test/server/serfservercert.pem", + ssl_server_cert_cb_expect_allok, + test_pool); + CuAssertIntEquals(tc, APR_SUCCESS, status); + + create_new_request(tb, &handler_ctx[0], "GET", "/", 1); + + test_helper_run_requests_expect_ok(tc, tb, num_requests, handler_ctx, + test_pool); + + test_server_teardown(tb, test_pool); + test_teardown(test_pool); +} + +/* Validate that when the application rejects the cert, the context loop + bails out with an error. */ +static void test_serf_ssl_application_rejects_cert(CuTest *tc) +{ + test_baton_t *tb; + handler_baton_t handler_ctx[1]; + const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]); + apr_status_t status; + test_server_message_t message_list[] = { + {CHUNKED_REQUEST(1, "1")}, + }; + + test_server_action_t action_list[] = { + {SERVER_RESPOND, CHUNKED_EMPTY_RESPONSE}, + }; + + /* Set up a test context with a server */ + apr_pool_t *test_pool = test_setup(); + + /* The certificate is valid, but we tell serf to reject it by using the + ssl_server_cert_cb_expect_failures callback. */ + status = test_https_server_setup(&tb, + message_list, num_requests, + action_list, num_requests, 0, + https_set_root_ca_conn_setup, + "test/server/serfserverkey.pem", + "test/server/serfservercert.pem", + ssl_server_cert_cb_expect_failures, + test_pool); + CuAssertIntEquals(tc, APR_SUCCESS, status); + + create_new_request(tb, &handler_ctx[0], "GET", "/", 1); + + status = test_helper_run_requests_no_check(tc, tb, num_requests, + handler_ctx, test_pool); + /* We expect an error from the certificate validation function. */ + CuAssert(tc, "Application told serf the certificate should be rejected," + " expected error!", status != APR_SUCCESS); + + test_server_teardown(tb, test_pool); + test_teardown(test_pool); +} CuSuite *test_context(void) { @@ -1006,6 +1252,10 @@ CuSuite *test_context(void) SUITE_ADD_TEST(suite, test_keepalive_limit_one_by_one); SUITE_ADD_TEST(suite, test_keepalive_limit_one_by_one_and_burst); SUITE_ADD_TEST(suite, test_serf_progress_callback); + SUITE_ADD_TEST(suite, test_serf_request_timeout); + SUITE_ADD_TEST(suite, test_serf_ssl_handshake); + SUITE_ADD_TEST(suite, test_serf_ssl_trust_rootca); + SUITE_ADD_TEST(suite, test_serf_ssl_application_rejects_cert); return suite; } |