]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: test-http-payload: Added tests for the use of nested ioloops.
authorStephan Bosch <stephan@dovecot.fi>
Tue, 24 May 2016 01:11:07 +0000 (03:11 +0200)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Mon, 20 Jun 2016 00:25:14 +0000 (03:25 +0300)
src/lib-http/test-http-payload.c

index 2497414a4ac2eef5b9e66a8ef09a8b709f0a81fc..047ff993db763ea79b33285724e3cea856ee12f4 100644 (file)
@@ -31,11 +31,15 @@ static bool request_100_continue = FALSE;
 static size_t read_server_partial = 0;
 static size_t read_client_partial = 0;
 static unsigned int test_max_pending = 200;
+static unsigned int client_ioloop_nesting = 0;
 
 static struct ip_addr bind_ip;
 static in_port_t bind_port = 0;
 static int fd_listen = -1;
 static pid_t server_pid = (pid_t)-1;
+static struct ioloop *ioloop_nested = NULL;
+static unsigned ioloop_nested_first = 0;
+static unsigned ioloop_nested_last = 0;
 
 /*
  * Test files
@@ -583,6 +587,9 @@ static void test_server_deinit(void)
  */
 
 struct test_client_request {
+       struct test_client_request *prev, *next;
+       struct http_client_request *hreq;
+
        struct io *io;
        struct istream *payload;
        struct istream *file;
@@ -590,8 +597,20 @@ struct test_client_request {
 };
 
 static struct http_client *http_client;
+static struct test_client_request *client_requests;
 static unsigned int client_files_first, client_files_last;
 
+static struct test_client_request *
+test_client_request_new(void)
+{
+       struct test_client_request *tcreq;
+
+       tcreq = i_new(struct test_client_request, 1);
+       DLLIST_PREPEND(&client_requests, tcreq);
+
+       return tcreq;
+}
+
 static void
 test_client_request_destroy(void *context)
 {
@@ -604,25 +623,41 @@ test_client_request_destroy(void *context)
                i_stream_unref(&tcreq->payload);
        if (tcreq->file != NULL)
                i_stream_unref(&tcreq->file);
+
+       DLLIST_REMOVE(&client_requests, tcreq);
        i_free(tcreq);
 }
 
+static void
+test_client_requests_switch_ioloop(void)
+{
+       struct test_client_request *tcreq;
+
+       for (tcreq = client_requests; tcreq != NULL;
+               tcreq = tcreq->next) {
+               if (tcreq->io != NULL)
+                       tcreq->io = io_loop_move_io(&tcreq->io);
+               if (tcreq->payload != NULL)
+                       i_stream_switch_ioloop(tcreq->payload);
+       }
+}
+
 /* download */
 
 static void test_client_download_continue(void);
 
 static void
-test_client_download_finished(struct test_client_request *tcreq)
+test_client_download_finished(unsigned int files_idx)
 {
        const char **paths;
        unsigned int count;
 
        paths = array_get_modifiable(&files, &count);
-       i_assert(tcreq->files_idx < count);
+       i_assert(files_idx < count);
        i_assert(client_files_first < count);
-       i_assert(paths[tcreq->files_idx] != NULL);
+       i_assert(paths[files_idx] != NULL);
 
-       paths[tcreq->files_idx] = NULL;
+       paths[files_idx] = NULL;
        test_client_download_continue();
 }
 
@@ -632,6 +667,7 @@ test_client_download_payload_input(struct test_client_request *tcreq)
        struct istream *payload = tcreq->payload;
        const unsigned char *pdata, *fdata;
        size_t psize, fsize, pleft;
+       unsigned int files_idx = tcreq->files_idx;
        off_t ret;
 
        /* read payload */
@@ -689,13 +725,13 @@ test_client_download_payload_input(struct test_client_request *tcreq)
                                tcreq->files_idx);
                }
 
-               /* finished */
-               test_client_download_finished(tcreq);
-
                /* dereference payload stream; finishes the request */
                tcreq->payload = NULL;
                io_remove(&tcreq->io); /* holds a reference too */
                i_stream_unref(&payload);
+
+               /* finished */
+               test_client_download_finished(files_idx);
        }
 }
 
@@ -741,7 +777,7 @@ test_client_download_response(const struct http_response *resp,
                                path, resp->status, resp->reason);
                }
                i_stream_unref(&fstream);
-               test_client_download_finished(tcreq);
+               test_client_download_finished(tcreq->files_idx);
                return;
        }
 
@@ -752,7 +788,7 @@ test_client_download_response(const struct http_response *resp,
                                path, tcreq->files_idx);
                }
                i_stream_unref(&fstream);
-               test_client_download_finished(tcreq);
+               test_client_download_finished(tcreq->files_idx);
                return;
        }
 
@@ -806,7 +842,7 @@ static void test_client_download_continue(void)
                client_files_last++) {
                const char *path = paths[client_files_last];
 
-               tcreq = i_new(struct test_client_request, 1);
+               tcreq = test_client_request_new();
                tcreq->files_idx = client_files_last;
 
                if (debug) {
@@ -814,7 +850,7 @@ static void test_client_download_continue(void)
                                "retrieving %s [%u]",
                                path, tcreq->files_idx);
                }
-               hreq = http_client_request(http_client,
+               hreq = tcreq->hreq = http_client_request(http_client,
                        "GET", net_ip2addr(&bind_ip),
                        t_strconcat("/download/", path, NULL),
                        test_client_download_response, tcreq);
@@ -841,17 +877,17 @@ test_client_download(const struct http_client_settings *client_set)
 static void test_client_echo_continue(void);
 
 static void
-test_client_echo_finished(struct test_client_request *tcreq)
+test_client_echo_finished(unsigned int files_idx)
 {
        const char **paths;
        unsigned int count;
 
        paths = array_get_modifiable(&files, &count);
-       i_assert(tcreq->files_idx < count);
+       i_assert(files_idx < count);
        i_assert(client_files_first < count);
-       i_assert(paths[tcreq->files_idx] != NULL);
+       i_assert(paths[files_idx] != NULL);
 
-       paths[tcreq->files_idx] = NULL;
+       paths[files_idx] = NULL;
        test_client_echo_continue();
 }
 
@@ -861,6 +897,7 @@ test_client_echo_payload_input(struct test_client_request *tcreq)
        struct istream *payload = tcreq->payload;
        const unsigned char *pdata, *fdata;
        size_t psize, fsize, pleft;
+       unsigned int files_idx = tcreq->files_idx;
        off_t ret;
 
        /* read payload */
@@ -918,13 +955,13 @@ test_client_echo_payload_input(struct test_client_request *tcreq)
                                tcreq->files_idx);
                }
 
-               /* finished */
-               test_client_echo_finished(tcreq);
-
                /* dereference payload stream; finishes the request */
                tcreq->payload = NULL;
                io_remove(&tcreq->io); /* holds a reference too */
                i_stream_unref(&payload);
+
+               /* finished */
+               test_client_echo_finished(files_idx);
        }
 }
 
@@ -982,7 +1019,7 @@ test_client_echo_response(const struct http_response *resp,
                                path, tcreq->files_idx);
                }
                i_stream_unref(&fstream);
-               test_client_echo_finished(tcreq);
+               test_client_echo_finished(tcreq->files_idx);
                return;
        }
 
@@ -1001,7 +1038,7 @@ static void test_client_echo_continue(void)
        struct test_client_request *tcreq;
        struct http_client_request *hreq;
        const char **paths;
-       unsigned int count;
+       unsigned int count, first_submitted;
 
        paths = array_get_modifiable(&files, &count);
 
@@ -1010,7 +1047,7 @@ static void test_client_echo_continue(void)
 
        i_assert(client_files_first <= client_files_last);
        for (; client_files_first < client_files_last &&
-               paths[client_files_first] == NULL; client_files_first++)
+               paths[client_files_first] == NULL; client_files_first++);
 
        if (debug) {
                i_debug("test client: echo: "
@@ -1020,7 +1057,9 @@ static void test_client_echo_continue(void)
        if (debug && client_files_first < count) {
                const char *path = paths[client_files_first];
                i_debug("test client: echo: "
-                       "next blocking: %s", (path == NULL ? "none" : path));
+                       "next blocking: %s [%d]",
+                       (path == NULL ? "none" : path),
+                       client_files_first);
        }
 
        if (client_files_first >= count) {
@@ -1028,6 +1067,7 @@ static void test_client_echo_continue(void)
                return;
        }
 
+       first_submitted = client_files_last;
        for (; client_files_last < count &&
                        (client_files_last - client_files_first) < test_max_pending;
                client_files_last++) {
@@ -1051,10 +1091,10 @@ static void test_client_echo_continue(void)
                                path, client_files_last);
                }
 
-               tcreq = i_new(struct test_client_request, 1);
+               tcreq = test_client_request_new();
                tcreq->files_idx = client_files_last;
 
-               hreq = http_client_request(http_client,
+               hreq = tcreq->hreq = http_client_request(http_client,
                        "PUT", net_ip2addr(&bind_ip),
                        t_strconcat("/echo/", path, NULL),
                        test_client_echo_response, tcreq);
@@ -1067,6 +1107,60 @@ static void test_client_echo_continue(void)
 
                i_stream_unref(&fstream);
        }
+
+       /* run nested ioloop (if requested) if new requests cross a nesting
+          boundary */
+       if (ioloop_nested != NULL) {
+               unsigned int i;
+
+               i_assert(ioloop_nested_first <= count);
+               i_assert(ioloop_nested_last <= count);
+               for (i = ioloop_nested_first; i < ioloop_nested_last; i++) {
+                       if (paths[i] != NULL) {
+                               if (debug) {
+                                       i_debug("test client: "
+                                               "not leaving ioloop [%u]", i);
+                               }
+                               break;
+                       }
+               }
+
+               if (i == ioloop_nested_last)
+                       io_loop_stop(ioloop_nested);
+       } else if (client_ioloop_nesting > 0 &&
+               ((client_files_last / client_ioloop_nesting) !=
+                       (first_submitted / client_ioloop_nesting)) ) {
+               struct ioloop *prev_ioloop = current_ioloop;
+
+               ioloop_nested_first = first_submitted;
+               ioloop_nested_last = first_submitted + client_ioloop_nesting;
+               if (ioloop_nested_last > client_files_last)
+                       ioloop_nested_last = client_files_last;
+
+               if (debug) {
+                       i_debug("test client: echo: entering ioloop for %u...%u",
+                               ioloop_nested_first, ioloop_nested_last);
+               }
+
+               ioloop_nested = io_loop_create();
+               http_client_switch_ioloop(http_client);
+               test_client_requests_switch_ioloop();
+
+               io_loop_run(ioloop_nested);
+
+               io_loop_set_current(prev_ioloop);
+               http_client_switch_ioloop(http_client);
+               test_client_requests_switch_ioloop();
+               io_loop_set_current(ioloop_nested);
+               io_loop_destroy(&ioloop_nested);
+               ioloop_nested = NULL;
+
+               if (debug) {
+                       i_debug("test client: echo: leaving ioloop for %u...%u",
+                               ioloop_nested_first, ioloop_nested_last);
+               }
+               ioloop_nested_first = ioloop_nested_last = 0;
+       }
 }
 
 static void
@@ -1128,6 +1222,7 @@ static void test_run_client_server(
                if (debug)
                        i_debug("server: PID=%s", my_pid);
                /* child: server */
+               ioloop_nested = FALSE;
                ioloop = io_loop_create();
                test_server_init(server_set);
                io_loop_run(ioloop);
@@ -1139,6 +1234,7 @@ static void test_run_client_server(
                        i_debug("client: PID=%s", my_pid);
                i_close_fd(&fd_listen);
                /* parent: client */
+               ioloop_nested = FALSE;
                ioloop = io_loop_create();
                client_init(client_set);
                io_loop_run(ioloop);
@@ -1247,6 +1343,7 @@ static void test_download_server_nonblocking(void)
        blocking = FALSE;
        request_100_continue = FALSE;
        read_server_partial = 0;
+       client_ioloop_nesting = 0;
        test_run_sequential(test_client_download);
        test_run_pipeline(test_client_download);
        test_run_parallel(test_client_download);
@@ -1259,6 +1356,7 @@ static void test_download_server_blocking(void)
        blocking = TRUE;
        request_100_continue = FALSE;
        read_server_partial = 0;
+       client_ioloop_nesting = 0;
        test_run_sequential(test_client_download);
        test_run_pipeline(test_client_download);
        test_run_parallel(test_client_download);
@@ -1271,6 +1369,7 @@ static void test_echo_server_nonblocking(void)
        blocking = FALSE;
        request_100_continue = FALSE;
        read_server_partial = 0;
+       client_ioloop_nesting = 0;
        test_run_sequential(test_client_echo);
        test_run_pipeline(test_client_echo);
        test_run_parallel(test_client_echo);
@@ -1283,6 +1382,7 @@ static void test_echo_server_blocking(void)
        blocking = TRUE;
        request_100_continue = FALSE;
        read_server_partial = 0;
+       client_ioloop_nesting = 0;
        test_run_sequential(test_client_echo);
        test_run_pipeline(test_client_echo);
        test_run_parallel(test_client_echo);
@@ -1295,6 +1395,7 @@ static void test_echo_server_nonblocking_sync(void)
        blocking = FALSE;
        request_100_continue = TRUE;
        read_server_partial = 0;
+       client_ioloop_nesting = 0;
        test_run_sequential(test_client_echo);
        test_run_pipeline(test_client_echo);
        test_run_parallel(test_client_echo);
@@ -1307,6 +1408,7 @@ static void test_echo_server_blocking_sync(void)
        blocking = TRUE;
        request_100_continue = TRUE;
        read_server_partial = 0;
+       client_ioloop_nesting = 0;
   test_run_sequential(test_client_echo);
        test_run_pipeline(test_client_echo);
        test_run_parallel(test_client_echo);
@@ -1319,6 +1421,7 @@ static void test_echo_server_nonblocking_partial(void)
        blocking = FALSE;
        request_100_continue = FALSE;
        read_server_partial = 1024;
+       client_ioloop_nesting = 0;
        test_run_sequential(test_client_echo);
        test_run_pipeline(test_client_echo);
        test_run_parallel(test_client_echo);
@@ -1337,6 +1440,7 @@ static void test_echo_server_blocking_partial(void)
        blocking = TRUE;
        request_100_continue = FALSE;
        read_server_partial = 1024;
+       client_ioloop_nesting = 0;
        test_run_sequential(test_client_echo);
        test_run_pipeline(test_client_echo);
        test_run_parallel(test_client_echo);
@@ -1356,6 +1460,7 @@ static void test_download_client_partial(void)
        request_100_continue = FALSE;
        read_server_partial = 0;
        read_client_partial = 1024;
+       client_ioloop_nesting = 0;
        test_run_sequential(test_client_download);
        test_run_pipeline(test_client_download);
        test_run_parallel(test_client_download);
@@ -1371,6 +1476,18 @@ static void test_download_client_partial(void)
        test_end();
 }
 
+static void test_download_client_nested_ioloop(void)
+{
+       test_begin("http payload echo (client nested ioloop)");
+       blocking = FALSE;
+       request_100_continue = FALSE;
+       read_server_partial = 0;
+       read_client_partial = 0;
+       client_ioloop_nesting = 10;
+       test_run_parallel(test_client_echo);
+       test_end();
+}
+
 static void (*test_functions[])(void) = {
        test_download_server_nonblocking,
        test_download_server_blocking,
@@ -1381,6 +1498,7 @@ static void (*test_functions[])(void) = {
        test_echo_server_nonblocking_partial,
        test_echo_server_blocking_partial,
        test_download_client_partial,
+       test_download_client_nested_ioloop,
        NULL
 };