]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: test-http-payload - Add test for blocking client output payload.
authorStephan Bosch <stephan.bosch@dovecot.fi>
Wed, 4 Apr 2018 13:18:51 +0000 (15:18 +0200)
committerTimo Sirainen <timo.sirainen@open-xchange.com>
Tue, 1 Dec 2020 16:38:47 +0000 (18:38 +0200)
src/lib-http/test-http-payload.c

index d7278cd58ca79d8923bd90e2c9bc0354aa2d3d46..4e638618a41b4396a27510213fdc962b8fa3be11 100644 (file)
@@ -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
 };