static struct test_settings {
/* client */
+ bool client_blocking;
unsigned int max_pending;
unsigned int client_ioloop_nesting;
bool request_100_continue;
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;
};
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;
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);
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) {
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) {
/* 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);
}
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;
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,
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) {
}
#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,
#ifdef HAVE_OPENSSL
test_echo_ssl,
#endif
+ test_echo_client_blocking,
NULL
};