From: Stephan Bosch Date: Wed, 4 Apr 2018 13:18:51 +0000 (+0200) Subject: lib-http: test-http-payload - Add test for blocking client output payload. X-Git-Tag: 2.3.13~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ba19713dd2f567dbd2820a94999eef977d90f367;p=thirdparty%2Fdovecot%2Fcore.git lib-http: test-http-payload - Add test for blocking client output payload. --- diff --git a/src/lib-http/test-http-payload.c b/src/lib-http/test-http-payload.c index d7278cd58c..4e638618a4 100644 --- a/src/lib-http/test-http-payload.c +++ b/src/lib-http/test-http-payload.c @@ -47,6 +47,7 @@ static bool running_continue = FALSE; static struct test_settings { /* client */ + bool client_blocking; unsigned int max_pending; unsigned int client_ioloop_nesting; bool request_100_continue; @@ -879,11 +880,12 @@ struct test_client_request { int refcount; struct test_client_request *prev, *next; + struct http_client *client; struct http_client_request *hreq; struct io *io; struct istream *payload; - struct istream *file_in; + struct istream *file_in, *file_out; unsigned int files_idx; }; @@ -892,12 +894,14 @@ static struct test_client_request *client_requests; static unsigned int client_files_first, client_files_last; struct timeout *to_client_progress = NULL; -static struct test_client_request *test_client_request_new(void) +static struct test_client_request * +test_client_request_new(struct http_client *client) { struct test_client_request *tcreq; tcreq = i_new(struct test_client_request, 1); tcreq->refcount = 1; + tcreq->client = client; DLLIST_PREPEND(&client_requests, tcreq); return tcreq; @@ -921,6 +925,7 @@ static void test_client_request_unref(struct test_client_request **_tcreq) io_remove(&tcreq->io); i_stream_unref(&tcreq->payload); i_stream_unref(&tcreq->file_in); + i_stream_unref(&tcreq->file_out); DLLIST_REMOVE(&client_requests, tcreq); i_free(tcreq); @@ -1196,7 +1201,7 @@ static void test_client_download_continue(void) http_clients[client_files_last % tset.parallel_clients]; const char *path = paths[client_files_last]; - tcreq = test_client_request_new(); + tcreq = test_client_request_new(http_client); tcreq->files_idx = client_files_last; if (debug) { @@ -1240,6 +1245,16 @@ static void test_client_echo_finished(struct test_client_request *tcreq) i_assert(client_files_first < count); i_assert(paths[files_idx] != NULL); + if (tcreq->file_out != NULL) + return; + if (tcreq->file_in != NULL) + return; + + if (debug) { + i_debug("test client: echo: finished [%u]: %s", + files_idx, paths[files_idx]); + } + paths[files_idx] = NULL; files_finished = TRUE; if (!running_continue && to_continue == NULL) { @@ -1318,10 +1333,10 @@ static void test_client_echo_payload_input(struct test_client_request *tcreq) /* finished */ tcreq->payload = NULL; + i_stream_unref(&tcreq->file_in); test_client_echo_finished(tcreq); /* dereference payload stream; finishes the request */ - i_stream_unref(&tcreq->file_in); io_remove(&tcreq->io); /* holds a reference too */ i_stream_unref(&payload); } @@ -1403,6 +1418,67 @@ test_client_echo_response(const struct http_response *resp, test_client_echo_payload_input(tcreq); } +static void +test_client_echo_nonblocking(struct test_client_request *tcreq ATTR_UNUSED, + struct http_client_request *hreq, + struct istream *fstream) +{ + http_client_request_set_payload(hreq, fstream, + tset.request_100_continue); + http_client_request_submit(hreq); +} + +static void +test_client_echo_blocking(struct test_client_request *tcreq, + struct http_client_request *hreq, + struct istream *fstream) +{ + const unsigned char *data; + size_t size; + int ret; + + test_client_request_ref(tcreq); + tcreq->file_out = fstream; + + while ((ret = i_stream_read_more(fstream, &data, &size)) > 0) { + ret = http_client_request_send_payload(&hreq, data, size); + i_assert(ret <= 0); + if (ret < 0) + break; + i_stream_skip(fstream, size); + } + i_assert(ret < 0); + if (fstream->stream_errno != 0) { + i_fatal("test client: echo: " + "read(%s) failed: %s [%u]", + i_stream_get_name(fstream), + i_stream_get_error(fstream), + tcreq->files_idx); + } else if (i_stream_have_bytes_left(fstream)) { + i_fatal("test client: echo: " + "failed to send all blocking payload [%u]", + tcreq->files_idx); + } + + /* finish it */ + if (http_client_request_finish_payload(&hreq) < 0) { + i_fatal("test client: echo: " + "failed to finish blocking payload [%u]", + tcreq->files_idx); + } + http_client_wait(tcreq->client); + + if (debug) { + i_debug("test client: echo: " + "sent all payload [%u]", + tcreq->files_idx); + } + + tcreq->file_out = NULL; + test_client_echo_finished(tcreq); + test_client_request_unref(&tcreq); +} + static void test_client_echo_continue(void *context ATTR_UNUSED) { struct test_client_request *tcreq; @@ -1475,7 +1551,7 @@ static void test_client_echo_continue(void *context ATTR_UNUSED) fstream = ustream; } - tcreq = test_client_request_new(); + tcreq = test_client_request_new(http_client); tcreq->files_idx = client_files_last; hreq = tcreq->hreq = http_client_request(http_client, @@ -1484,13 +1560,20 @@ static void test_client_echo_continue(void *context ATTR_UNUSED) test_client_echo_response, tcreq); http_client_request_set_port(hreq, bind_port); http_client_request_set_ssl(hreq, tset.ssl); - http_client_request_set_payload(hreq, fstream, - tset.request_100_continue); http_client_request_set_destroy_callback(hreq, test_client_request_destroy, tcreq); - http_client_request_submit(hreq); + if (!tset.client_blocking) + test_client_echo_nonblocking(tcreq, hreq, fstream); + else + test_client_echo_blocking(tcreq, hreq, fstream); i_stream_unref(&fstream); + + if (tset.client_blocking && paths[client_files_last] != NULL) { + running_continue = FALSE; + files_finished = prev_files_finished; + return; + } } if (files_finished && to_continue == NULL) { @@ -2251,6 +2334,42 @@ static void test_echo_ssl(void) } #endif +static void test_echo_client_blocking(void) +{ + test_begin("http payload echo (client blocking)"); + test_init_defaults(); + tset.client_blocking = TRUE; + test_run_sequential(test_client_echo); + test_run_pipeline(test_client_echo); + test_run_parallel(test_client_echo); + test_end(); + + test_begin("http payload echo (client blocking; client shared)"); + test_init_defaults(); + tset.client_blocking = TRUE; + tset.parallel_clients = 4; + test_run_sequential(test_client_echo); + tset.parallel_clients = 4; + test_run_pipeline(test_client_echo); + tset.parallel_clients = 4; + test_run_parallel(test_client_echo); + test_end(); + + test_begin("http payload echo (client blocking; client global)"); + test_init_defaults(); + tset.client_blocking = TRUE; + tset.parallel_clients = 4; + tset.parallel_clients_global = TRUE; + test_run_sequential(test_client_echo); + tset.parallel_clients = 4; + tset.parallel_clients_global = TRUE; + test_run_pipeline(test_client_echo); + tset.parallel_clients = 4; + tset.parallel_clients_global = TRUE; + test_run_parallel(test_client_echo); + test_end(); +} + static void (*const test_functions[])(void) = { test_download_server_nonblocking, test_download_server_blocking, @@ -2266,6 +2385,7 @@ static void (*const test_functions[])(void) = { #ifdef HAVE_OPENSSL test_echo_ssl, #endif + test_echo_client_blocking, NULL };