From 43f7d837f0dd371f0dd3dd306a93eef6ca1c3c70 Mon Sep 17 00:00:00 2001 From: Snaipe Date: Sun, 13 Dec 2015 17:18:06 +0100 Subject: [PATCH] Started to integrate the new message pump into the runner --- include/criterion/event.h | 3 + src/core/client.c | 294 +++++++++++++++++++++++++++++++++++ src/core/client.h | 74 +++++++++ src/core/runner.c | 209 +++++++------------------ src/core/worker.c | 27 +--- src/io/event.c | 4 + src/io/event.h | 5 +- src/protocol/connect.c | 63 ++++++++ src/protocol/connect.h | 30 ++++ src/protocol/criterion.pb.c | 30 +++- src/protocol/criterion.pb.h | 44 +++++- src/protocol/criterion.proto | 33 +++- src/protocol/protocol.c | 33 ++-- src/protocol/protocol.h | 53 +++++++ 14 files changed, 689 insertions(+), 213 deletions(-) create mode 100644 src/core/client.c create mode 100644 src/core/client.h create mode 100644 src/protocol/connect.c create mode 100644 src/protocol/connect.h create mode 100644 src/protocol/protocol.h diff --git a/include/criterion/event.h b/include/criterion/event.h index 6d2d3a0..9fe2983 100644 --- a/include/criterion/event.h +++ b/include/criterion/event.h @@ -30,11 +30,14 @@ # include # endif # include "internal/common.h" +# include "stats.h" CR_BEGIN_C_API CR_API void criterion_send_event(int kind, void *data, size_t size); +CR_API void criterion_send_assert(struct criterion_assert_stats *stats); + CR_END_C_API #endif /* !CRITERION_EVENT_H_ */ diff --git a/src/core/client.c b/src/core/client.c new file mode 100644 index 0000000..395a94c --- /dev/null +++ b/src/core/client.c @@ -0,0 +1,294 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2015 Franklin "Snaipe" Mathieu + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include "protocol/protocol.h" +#include "criterion/logging.h" +#include "criterion/options.h" +#include "io/event.h" +#include "report.h" +#include "stats.h" +#include "client.h" + +void nothing(); + +enum protocol_version { + PROTOCOL_V1 = 1, +}; + +KHASH_MAP_INIT_INT(ht_client, struct client_ctx) + +static enum client_state msg_to_state[] = { + [criterion_protocol_submessage_birth_tag] = CS_BIRTH, + [criterion_protocol_submessage_pre_init_tag] = CS_PRE_INIT, + [criterion_protocol_submessage_pre_test_tag] = CS_PRE_TEST, + [criterion_protocol_submessage_post_test_tag] = CS_POST_TEST, + [criterion_protocol_submessage_post_fini_tag] = CS_POST_FINI, + [criterion_protocol_submessage_death_tag] = CS_DEATH, +}; + +static const char *state_to_string[] = { + [CS_BIRTH] = "BIRTH", + [CS_PRE_INIT] = "PRE_INIT", + [CS_PRE_TEST] = "PRE_TEST", + [CS_POST_TEST] = "POST_TEST", + [CS_POST_FINI] = "POST_FINI", + [CS_DEATH] = "DEATH", +}; + +typedef void message_handler(struct server_ctx *, struct client_ctx *, const criterion_protocol_msg *); + +void handle_birth(struct server_ctx *, struct client_ctx *, const criterion_protocol_msg *); +void handle_pre_init(struct server_ctx *, struct client_ctx *, const criterion_protocol_msg *); +void handle_pre_test(struct server_ctx *, struct client_ctx *, const criterion_protocol_msg *); +void handle_post_test(struct server_ctx *, struct client_ctx *, const criterion_protocol_msg *); +void handle_death(struct server_ctx *, struct client_ctx *, const criterion_protocol_msg *); + +static message_handler *message_handlers[] = { + [criterion_protocol_submessage_birth_tag] = handle_birth, + [criterion_protocol_submessage_pre_init_tag] = handle_pre_init, + [criterion_protocol_submessage_pre_test_tag] = handle_pre_test, + [criterion_protocol_submessage_post_test_tag] = handle_post_test, + [criterion_protocol_submessage_death_tag] = handle_death, +}; + +static void get_message_id(char *out, size_t n, const criterion_protocol_msg *msg) { + switch (msg->which_id) { + case criterion_protocol_msg_pid_tag: + snprintf(out, n, "[PID %" PRId64 "]", msg->id.pid); return; + default: break; + } +} + +void init_server_context(struct server_ctx *sctx) { + sctx->subprocesses = kh_init(ht_client); +} + +void destroy_server_context(struct server_ctx *sctx) { + kh_destroy(ht_client, sctx->subprocesses); +} + +struct client_ctx *add_client_from_worker(struct server_ctx *sctx, struct client_ctx *ctx, struct worker *w) { + unsigned long long pid = get_process_id_of(w->proc); + int absent; + khint_t k = kh_put(ht_client, sctx->subprocesses, pid, &absent); + ctx->worker = w; + ctx->kind = WORKER; + kh_value(sctx->subprocesses, k) = *ctx; + return &kh_value(sctx->subprocesses, k); +} + +void remove_client_by_pid(struct server_ctx *sctx, int pid) { + khint_t k = kh_get(ht_client, sctx->subprocesses, pid); + if (k != kh_end(sctx->subprocesses)) + kh_del(ht_client, sctx->subprocesses, pid); +} + +static void process_client_message_impl(struct server_ctx *sctx, struct client_ctx *ctx, const criterion_protocol_msg *msg) { + if (msg->data.which_value >= CS_MAX_CLIENT_STATES + || msg_to_state[msg->data.which_value] == 0) { + char id[32]; + get_message_id(id, sizeof (id), msg); + + criterion_perror("%s: Received message with malformed data.value tag '%d'.", + id, + msg->data.which_value); + return; + } + + enum client_state new_state = msg_to_state[msg->data.which_value]; + if (new_state < CS_DEATH && new_state != ctx->state + 1) { + char id[32]; + get_message_id(id, sizeof (id), msg); + + criterion_perror("%s: Expected message to change to state '%s', got '%s' instead.", + id, + state_to_string[ctx->state + 1], + state_to_string[new_state]); + return; + } + + message_handler *handler = message_handlers[msg->data.which_value]; + if (handler) + handler(sctx, ctx, msg); + + if (new_state <= CS_DEATH) + ctx->state = new_state; +} + +struct client_ctx *process_client_message(struct server_ctx *ctx, const criterion_protocol_msg *msg) { + if (msg->version != PROTOCOL_V1) { + criterion_perror("Received message using invalid protocol version number '%d'.", msg->version); + return NULL; + } + + switch (msg->which_id) { + case criterion_protocol_msg_pid_tag: { + khiter_t k = kh_get(ht_client, ctx->subprocesses, msg->id.pid); + if (k != kh_end(ctx->subprocesses)) { + process_client_message_impl(ctx, &kh_value(ctx->subprocesses, k), msg); + return &kh_value(ctx->subprocesses, k); + } else { + char id[32]; + get_message_id(id, sizeof (id), msg); + + criterion_perror("%s: Received message identified by a PID " + "that is not a child process.", + id); + } + } break; + default: { + criterion_perror("Received message with malformed id tag '%d'.", + criterion_protocol_msg_pid_tag); + } break; + } + return NULL; +} + +#define push_event(...) \ + do { \ + push_event_noreport(__VA_ARGS__); \ + report(CR_VA_HEAD(__VA_ARGS__), ctx->tstats); \ + } while (0) + +#define push_event_noreport(...) \ + do { \ + stat_push_event(ctx->gstats, \ + ctx->sstats, \ + ctx->tstats, \ + &(struct event) { \ + .kind = CR_VA_HEAD(__VA_ARGS__), \ + CR_VA_TAIL(__VA_ARGS__) \ + }); \ + } while (0) + +void handle_birth(struct server_ctx *sctx, struct client_ctx *ctx, const criterion_protocol_msg *msg) { + (void) sctx; + (void) ctx; + (void) msg; +} + +void handle_pre_init(struct server_ctx *sctx, struct client_ctx *ctx, const criterion_protocol_msg *msg) { + (void) sctx; + (void) msg; + + push_event_noreport(PRE_INIT); + report(PRE_INIT, ctx->test); + log(pre_init, ctx->test); +} + +void handle_pre_test(struct server_ctx *sctx, struct client_ctx *ctx, const criterion_protocol_msg *msg) { + (void) sctx; + (void) msg; + + report(PRE_TEST, ctx->test); + log(pre_test, ctx->test); +} + +void handle_post_test(struct server_ctx *sctx, struct client_ctx *ctx, const criterion_protocol_msg *msg) { + (void) sctx; + (void) msg; + + double elapsed_time = 0; // TODO: restore elapsed time handling + push_event_noreport(POST_TEST, .data = &elapsed_time); + report(POST_TEST, ctx->tstats); + log(post_test, ctx->tstats); +} + +void handle_death(struct server_ctx *sctx, struct client_ctx *ctx, const criterion_protocol_msg *msg) { + (void) sctx; + const criterion_protocol_death *death = &msg->data.value.death; + switch (death->result) { + case criterion_protocol_death_result_type_CRASH: { + if (ctx->state >= CS_POST_TEST || ctx->state < CS_PRE_TEST) { + log(other_crash, ctx->tstats); + + if (ctx->state < CS_PRE_TEST) { + stat_push_event(ctx->gstats, + ctx->sstats, + ctx->tstats, + &(struct event) { .kind = TEST_CRASH }); + } + } else { + ctx->tstats->signal = death->status; + if (ctx->test->data->signal == 0) { + push_event(TEST_CRASH); + log(test_crash, ctx->tstats); + } else { + double elapsed_time = 0; + push_event(POST_TEST, .data = &elapsed_time); + log(post_test, ctx->tstats); + push_event(POST_FINI); + log(post_fini, ctx->tstats); + } + } + } break; + case criterion_protocol_death_result_type_TIMEOUT: { + ctx->tstats->timed_out = true; + double elapsed_time = ctx->test->data->timeout; + if (elapsed_time == 0 && ctx->suite->data) + elapsed_time = ctx->suite->data->timeout; + push_event(POST_TEST, .data = &elapsed_time); + push_event(POST_FINI); + log(test_timeout, ctx->tstats); + } break; + case criterion_protocol_death_result_type_ABORT: { + if (ctx->state < CS_POST_TEST) { + double elapsed_time = 0; + push_event(POST_TEST, .data = &elapsed_time); + log(post_test, ctx->tstats); + } + if (ctx->state < CS_POST_FINI) { + push_event(POST_FINI); + log(post_fini, ctx->tstats); + } + } break; + case criterion_protocol_death_result_type_NORMAL: { + if ((ctx->state >= CS_POST_TEST && ctx->state < CS_POST_FINI) || ctx->state < CS_PRE_TEST) { + log(abnormal_exit, ctx->tstats); + if (ctx->state < CS_PRE_TEST) { + stat_push_event(ctx->gstats, + ctx->sstats, + ctx->tstats, + &(struct event) { .kind = TEST_CRASH }); + } + return; + } + ctx->tstats->exit_code = death->status; + if (ctx->state < CS_POST_TEST) { + if (ctx->test->data->exit_code == 0) { + push_event(TEST_CRASH); + log(abnormal_exit, ctx->tstats); + } else { + double elapsed_time = 0; + push_event(POST_TEST, .data = &elapsed_time); + log(post_test, ctx->tstats); + push_event(POST_FINI); + log(post_fini, ctx->tstats); + } + } + } break; + default: break; + } +} diff --git a/src/core/client.h b/src/core/client.h new file mode 100644 index 0000000..409d220 --- /dev/null +++ b/src/core/client.h @@ -0,0 +1,74 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2015 Franklin "Snaipe" Mathieu + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef CLIENT_H_ +# define CLIENT_H_ + +# include + +// order matters here +enum client_state { + CS_BIRTH = 1, + CS_PRE_INIT, + CS_PRE_TEST, + CS_POST_TEST, + CS_POST_FINI, + CS_DEATH, + + CS_PRE_SUBTEST, + CS_POST_SUBTEST, + + CS_MAX_CLIENT_STATES // always leave at the end +}; + +enum client_kind { + WORKER, + EXTERN, +}; + +struct client_ctx { + enum client_kind kind; + struct worker *worker; + + enum client_state state; + struct criterion_global_stats *gstats; + struct criterion_suite_stats *sstats; + struct criterion_test_stats *tstats; + struct criterion_test *test; + struct criterion_suite *suite; +}; + +typedef struct kh_ht_client_s khash_t(ht_client); + +struct server_ctx { + khash_t(ht_client) *subprocesses; +}; + +struct client_ctx *process_client_message(struct server_ctx *ctx, const criterion_protocol_msg *msg); + +void init_server_context(struct server_ctx *sctx); +void destroy_server_context(struct server_ctx *sctx); +struct client_ctx *add_client_from_worker(struct server_ctx *sctx, struct client_ctx *ctx, struct worker *w); +void remove_client_by_pid(struct server_ctx *sctx, int pid); + +#endif /* !CLIENT_H_ */ diff --git a/src/core/runner.c b/src/core/runner.c index 9078a6a..a08ac0f 100644 --- a/src/core/runner.c +++ b/src/core/runner.c @@ -27,11 +27,14 @@ #include #include #include +#include #include "criterion/internal/test.h" #include "criterion/options.h" #include "criterion/internal/ordered-set.h" #include "criterion/logging.h" #include "criterion/internal/preprocess.h" +#include "protocol/protocol.h" +#include "protocol/connect.h" #include "compat/time.h" #include "compat/posix.h" #include "compat/processor.h" @@ -46,6 +49,7 @@ #include "abort.h" #include "config.h" #include "common.h" +#include "client.h" #ifdef HAVE_PCRE #include "string/extmatch.h" @@ -194,131 +198,6 @@ void run_test_child(struct criterion_test *test, s_pipe_handle *g_worker_pipe; -static void handle_worker_terminated(struct event *ev, - struct execution_context *ctx) { - - struct worker_status *ws = ev->data; - struct process_status status = ws->status; - - if (status.kind == SIGNAL) { - if (status.status == SIGPROF) { - ctx->test_stats->timed_out = true; - double elapsed_time = ctx->test->data->timeout; - if (elapsed_time == 0 && ctx->suite->data) - elapsed_time = ctx->suite->data->timeout; - push_event(POST_TEST, .data = &elapsed_time); - push_event(POST_FINI); - log(test_timeout, ctx->test_stats); - return; - } - - if (ctx->normal_finish || !ctx->test_started) { - log(other_crash, ctx->test_stats); - if (!ctx->test_started) { - stat_push_event(ctx->stats, - ctx->suite_stats, - ctx->test_stats, - &(struct event) { .kind = TEST_CRASH }); - } - return; - } - ctx->test_stats->signal = status.status; - if (ctx->test->data->signal == 0) { - push_event(TEST_CRASH); - log(test_crash, ctx->test_stats); - } else { - double elapsed_time = 0; - push_event(POST_TEST, .data = &elapsed_time); - log(post_test, ctx->test_stats); - push_event(POST_FINI); - log(post_fini, ctx->test_stats); - } - } else { - if (ctx->aborted) { - if (!ctx->normal_finish) { - double elapsed_time = 0; - push_event(POST_TEST, .data = &elapsed_time); - log(post_test, ctx->test_stats); - } - if (!ctx->cleaned_up) { - push_event(POST_FINI); - log(post_fini, ctx->test_stats); - } - return; - } - if ((ctx->normal_finish && !ctx->cleaned_up) || !ctx->test_started) { - log(abnormal_exit, ctx->test_stats); - if (!ctx->test_started) { - stat_push_event(ctx->stats, - ctx->suite_stats, - ctx->test_stats, - &(struct event) { .kind = TEST_CRASH }); - } - return; - } - ctx->test_stats->exit_code = status.status; - if (!ctx->normal_finish) { - if (ctx->test->data->exit_code == 0) { - push_event(TEST_CRASH); - log(abnormal_exit, ctx->test_stats); - } else { - double elapsed_time = 0; - push_event(POST_TEST, .data = &elapsed_time); - log(post_test, ctx->test_stats); - push_event(POST_FINI); - log(post_fini, ctx->test_stats); - } - } - } -} - -static void handle_event(struct event *ev) { - struct execution_context *ctx = &ev->worker->ctx; - if (ev->kind < WORKER_TERMINATED) - stat_push_event(ctx->stats, ctx->suite_stats, ctx->test_stats, ev); - switch (ev->kind) { - case PRE_INIT: - report(PRE_INIT, ctx->test); - log(pre_init, ctx->test); - break; - case PRE_TEST: - report(PRE_TEST, ctx->test); - log(pre_test, ctx->test); - ctx->test_started = true; - break; - case THEORY_FAIL: { - struct criterion_theory_stats ths = { - .formatted_args = (char*) ev->data, - .stats = ctx->test_stats, - }; - report(THEORY_FAIL, &ths); - log(theory_fail, &ths); - } break; - case ASSERT: - report(ASSERT, ev->data); - log(assert, ev->data); - break; - case TEST_ABORT: - log(test_abort, ctx->test_stats, ev->data); - ctx->test_stats->failed = 1; - ctx->aborted = true; - break; - case POST_TEST: - report(POST_TEST, ctx->test_stats); - log(post_test, ctx->test_stats); - ctx->normal_finish = true; - break; - case POST_FINI: - report(POST_FINI, ctx->test_stats); - log(post_fini, ctx->test_stats); - ctx->cleaned_up = true; - break; - case WORKER_TERMINATED: - handle_worker_terminated(ev, ctx); - break; - } -} - #ifdef HAVE_PCRE void disable_unmatching(struct criterion_test_set *set) { FOREACH_SET(struct criterion_suite_set *s, set->suites) { @@ -370,31 +249,44 @@ void criterion_finalize(struct criterion_test_set *set) { criterion_free_output(); } +static struct client_ctx *spawn_next_client(struct server_ctx *sctx, ccrContext *ctx) { + struct worker *w = ctx ? run_next_test(NULL, NULL, ctx) : NULL; + + if (!is_runner() || w == NULL) + return NULL; + + struct client_ctx new_ctx = (struct client_ctx) { + .test = w->ctx.test, + .tstats = w->ctx.test_stats, + .suite = w->ctx.suite, + .sstats = w->ctx.suite_stats, + .gstats = w->ctx.stats, + }; + + return add_client_from_worker(sctx, &new_ctx, w); +} + static void run_tests_async(struct criterion_test_set *set, - struct criterion_global_stats *stats) { + struct criterion_global_stats *stats, + int socket) { ccrContext ctx = 0; size_t nb_workers = DEF(criterion_options.jobs, get_processor_count()); - struct worker_set workers = { - .max_workers = nb_workers, - .workers = calloc(nb_workers, sizeof (struct worker*)), - }; - size_t active_workers = 0; - s_pipe_file_handle *event_pipe = pipe_in_handle(g_worker_pipe, PIPE_DUP); - struct event *ev = NULL; + struct server_ctx sctx; + init_server_context(&sctx); // initialization of coroutine run_next_test(set, stats, &ctx); for (size_t i = 0; i < nb_workers; ++i) { - workers.workers[i] = run_next_test(NULL, NULL, &ctx); + struct client_ctx *cctx = spawn_next_client(&sctx, &ctx); if (!is_runner()) goto cleanup; - if (!ctx) + if (!cctx) break; ++active_workers; } @@ -402,31 +294,33 @@ static void run_tests_async(struct criterion_test_set *set, if (!active_workers) goto cleanup; - while ((ev = worker_read_event(&workers, event_pipe)) != NULL) { - handle_event(ev); - size_t wi = ev->worker_index; - if (ev->kind == WORKER_TERMINATED) { - sfree(workers.workers[wi]); - workers.workers[wi] = ctx ? run_next_test(NULL, NULL, &ctx) : NULL; + criterion_protocol_msg msg = criterion_protocol_msg_init_zero; + unsigned char *buf = NULL; + int length; + while ((length = nn_recv(socket, &buf, NN_MSG, 0)) > 0) { + pb_istream_t in = pb_istream_from_buffer(buf, length); + if (pb_decode(&in, criterion_protocol_msg_fields, &msg)) { + struct client_ctx *cctx = process_client_message(&sctx, &msg); + if (cctx->state == CS_DEATH && cctx->kind == WORKER) { + remove_client_by_pid(&sctx, get_process_id_of(cctx->worker->proc)); + sfree(cctx->worker); - if (!is_runner()) - goto cleanup; + cctx = spawn_next_client(&sctx, &ctx); + if (!is_runner()) + goto cleanup; - if (workers.workers[wi] == NULL) - --active_workers; + if (cctx == NULL) + --active_workers; + } } - sfree(ev); + nn_freemsg(buf); if (!active_workers) break; } - ev = NULL; + + destroy_server_context(&sctx); cleanup: - sfree(event_pipe); - sfree(ev); - for (size_t i = 0; i < nb_workers; ++i) - sfree(workers.workers[i]); - free(workers.workers); ccrAbort(ctx); } @@ -445,16 +339,17 @@ static int criterion_run_all_tests_impl(struct criterion_test_set *set) { fflush(NULL); // flush everything before forking - g_worker_pipe = stdpipe(); - if (g_worker_pipe == NULL) { - criterion_perror("Could not initialize the event pipe: %s.\n", + int sock = bind_server(); + if (sock < 0) { + criterion_perror("Could not initialize the message server: %s.\n", strerror(errno)); abort(); } + init_proc_compat(); struct criterion_global_stats *stats = stats_init(); - run_tests_async(set, stats); + run_tests_async(set, stats, sock); int result = is_runner() ? stats->tests_failed == 0 : -1; @@ -467,7 +362,7 @@ static int criterion_run_all_tests_impl(struct criterion_test_set *set) { cleanup: free_proc_compat(); - sfree(g_worker_pipe); + nn_close(sock); sfree(stats); return result; } diff --git a/src/core/worker.c b/src/core/worker.c index 54d6868..363d478 100644 --- a/src/core/worker.c +++ b/src/core/worker.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "criterion/types.h" #include "criterion/options.h" @@ -32,6 +33,7 @@ #include "io/event.h" #include "compat/posix.h" #include "worker.h" +#include "protocol/connect.h" static s_proc_handle *g_current_proc; @@ -56,33 +58,12 @@ static void close_process(void *ptr, CR_UNUSED void *meta) { sfree(proc->proc); } -struct event *worker_read_event(struct worker_set *workers, s_pipe_file_handle *pipe) { - struct event *ev = read_event(pipe); - if (ev) { - ev->worker_index = -1; - for (size_t i = 0; i < workers->max_workers; ++i) { - if (!workers->workers[i]) - continue; - - if (get_process_id_of(workers->workers[i]->proc) == ev->pid) { - ev->worker = workers->workers[i]; - ev->worker_index = i; - return ev; - } - } - criterion_perror("Could not link back the event PID to the active workers.\n"); - criterion_perror("The event pipe might have been corrupted.\n"); - abort(); - } - return NULL; -} - void run_worker(struct worker_context *ctx) { cr_redirect_stdin(); - g_event_pipe = pipe_out_handle(ctx->pipe, PIPE_CLOSE); + g_client_socket = connect_client(); ctx->func(ctx->test, ctx->suite); - sfree(g_event_pipe); + nn_close(g_client_socket); fflush(NULL); // flush all opened streams if (criterion_options.no_early_exit) diff --git a/src/io/event.c b/src/io/event.c index 8d45c4b..4c84d6f 100644 --- a/src/io/event.c +++ b/src/io/event.c @@ -30,10 +30,14 @@ #include "criterion/hooks.h" #include "criterion/logging.h" #include "core/worker.h" +#include "protocol/protocol.h" #include "event.h" s_pipe_file_handle *g_event_pipe = NULL; +int g_client_socket = -1; +pb_ostream_t g_event_stream; + void destroy_event(void *ptr, CR_UNUSED void *meta) { struct event *ev = ptr; free(ev->data); diff --git a/src/io/event.h b/src/io/event.h index e4e555b..07cf391 100644 --- a/src/io/event.h +++ b/src/io/event.h @@ -27,8 +27,11 @@ # include "criterion/event.h" # include "core/worker.h" # include +# include extern s_pipe_file_handle *g_event_pipe; +extern pb_ostream_t g_event_stream; +extern int g_client_socket; struct event { unsigned long long pid; @@ -44,6 +47,4 @@ enum other_event_kinds { TEST_ABORT, }; -struct event *read_event(s_pipe_file_handle *f); - #endif /* !EVENT_H_ */ diff --git a/src/protocol/connect.c b/src/protocol/connect.c new file mode 100644 index 0000000..4615217 --- /dev/null +++ b/src/protocol/connect.c @@ -0,0 +1,63 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2015 Franklin "Snaipe" Mathieu + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include + +#define URL "ipc://criterion.sock" + +#define errno_ignore(Stmt) do { int err = errno; Stmt; errno = err; } while (0) + +int bind_server(void) { + int sock = nn_socket(AF_SP, NN_SUB); + if (sock < 0) + return -1; + + if (nn_setsockopt(sock, NN_SUB, NN_SUB_SUBSCRIBE, "", 0) < 0) + goto error; + + if (nn_bind(sock, URL) < 0) + goto error; + + return sock; + +error: {} + errno_ignore(nn_close(sock)); + return -1; +} + +int connect_client(void) { + int sock = nn_socket(AF_SP, NN_PUB); + if (sock < 0) + return -1; + + if (nn_connect (sock, URL) < 0) + goto error; + + return sock; + +error: {} + errno_ignore(nn_close(sock)); + return -1; +} diff --git a/src/protocol/connect.h b/src/protocol/connect.h new file mode 100644 index 0000000..cc84df9 --- /dev/null +++ b/src/protocol/connect.h @@ -0,0 +1,30 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2015 Franklin "Snaipe" Mathieu + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef CONNECT_H_ +# define CONNECT_H_ + +int connect_client(void); +int bind_server(void); + +#endif /* !CONNECT_H_ */ diff --git a/src/protocol/criterion.pb.c b/src/protocol/criterion.pb.c index 307ef47..3bfbdba 100644 --- a/src/protocol/criterion.pb.c +++ b/src/protocol/criterion.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.3.5-dev at Fri Dec 11 17:13:49 2015. */ +/* Generated by nanopb-0.3.5-dev at Sun Dec 13 17:07:36 2015. */ #include "criterion.pb.h" @@ -32,6 +32,16 @@ const pb_field_t criterion_protocol_post_fini_fields[1] = { PB_LAST_FIELD }; +const pb_field_t criterion_protocol_pre_subtest_fields[2] = { + PB_FIELD( 1, STRING , REQUIRED, CALLBACK, FIRST, criterion_protocol_pre_subtest, id, id, 0), + PB_LAST_FIELD +}; + +const pb_field_t criterion_protocol_post_subtest_fields[2] = { + PB_FIELD( 1, STRING , REQUIRED, CALLBACK, FIRST, criterion_protocol_post_subtest, id, id, 0), + PB_LAST_FIELD +}; + const pb_field_t criterion_protocol_death_fields[3] = { PB_FIELD( 1, UENUM , OPTIONAL, STATIC , FIRST, criterion_protocol_death, result, result, 0), PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, criterion_protocol_death, status, result, 0), @@ -46,14 +56,24 @@ const pb_field_t criterion_protocol_assert_fields[5] = { PB_LAST_FIELD }; -const pb_field_t criterion_protocol_submessage_fields[8] = { +const pb_field_t criterion_protocol_log_fields[4] = { + PB_FIELD( 1, INT32 , REQUIRED, STATIC , FIRST, criterion_protocol_log, severity, severity, 0), + PB_FIELD( 2, STRING , REQUIRED, POINTER , OTHER, criterion_protocol_log, message, severity, 0), + PB_FIELD( 3, INT32 , OPTIONAL, STATIC , OTHER, criterion_protocol_log, prefix, message, 0), + PB_LAST_FIELD +}; + +const pb_field_t criterion_protocol_submessage_fields[11] = { PB_ONEOF_FIELD(value, 1, MESSAGE , ONEOF, STATIC , FIRST, criterion_protocol_submessage, birth, birth, &criterion_protocol_birth_fields), PB_ONEOF_FIELD(value, 2, MESSAGE , ONEOF, STATIC , FIRST, criterion_protocol_submessage, pre_init, pre_init, &criterion_protocol_pre_init_fields), PB_ONEOF_FIELD(value, 3, MESSAGE , ONEOF, STATIC , FIRST, criterion_protocol_submessage, pre_test, pre_test, &criterion_protocol_pre_test_fields), PB_ONEOF_FIELD(value, 4, MESSAGE , ONEOF, STATIC , FIRST, criterion_protocol_submessage, post_test, post_test, &criterion_protocol_post_test_fields), PB_ONEOF_FIELD(value, 5, MESSAGE , ONEOF, STATIC , FIRST, criterion_protocol_submessage, post_fini, post_fini, &criterion_protocol_post_fini_fields), PB_ONEOF_FIELD(value, 6, MESSAGE , ONEOF, STATIC , FIRST, criterion_protocol_submessage, death, death, &criterion_protocol_death_fields), - PB_ONEOF_FIELD(value, 7, MESSAGE , ONEOF, STATIC , FIRST, criterion_protocol_submessage, assert, assert, &criterion_protocol_assert_fields), + PB_ONEOF_FIELD(value, 7, MESSAGE , ONEOF, STATIC , FIRST, criterion_protocol_submessage, message, message, &criterion_protocol_log_fields), + PB_ONEOF_FIELD(value, 8, MESSAGE , ONEOF, STATIC , FIRST, criterion_protocol_submessage, assert, assert, &criterion_protocol_assert_fields), + PB_ONEOF_FIELD(value, 9, MESSAGE , ONEOF, STATIC , FIRST, criterion_protocol_submessage, pre_subtest, pre_subtest, &criterion_protocol_pre_subtest_fields), + PB_ONEOF_FIELD(value, 10, MESSAGE , ONEOF, STATIC , FIRST, criterion_protocol_submessage, post_subtest, post_subtest, &criterion_protocol_post_subtest_fields), PB_LAST_FIELD }; @@ -74,7 +94,7 @@ const pb_field_t criterion_protocol_msg_fields[4] = { * numbers or field sizes that are larger than what can fit in 8 or 16 bit * field descriptors. */ -PB_STATIC_ASSERT((pb_membersize(criterion_protocol_submessage, value.birth) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 65536 && pb_membersize(criterion_protocol_submessage, value.death) < 65536 && pb_membersize(criterion_protocol_submessage, value.assert) < 65536 && pb_membersize(criterion_protocol_submessage, value.birth) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 65536 && pb_membersize(criterion_protocol_submessage, value.death) < 65536 && pb_membersize(criterion_protocol_submessage, value.assert) < 65536 && pb_membersize(criterion_protocol_submessage, value.birth) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 65536 && pb_membersize(criterion_protocol_submessage, value.death) < 65536 && pb_membersize(criterion_protocol_submessage, value.assert) < 65536 && pb_membersize(criterion_protocol_submessage, value.birth) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 65536 && pb_membersize(criterion_protocol_submessage, value.death) < 65536 && pb_membersize(criterion_protocol_submessage, value.assert) < 65536 && pb_membersize(criterion_protocol_msg, data) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_criterion_protocol_birth_criterion_protocol_pre_init_criterion_protocol_pre_test_criterion_protocol_post_test_criterion_protocol_post_fini_criterion_protocol_death_criterion_protocol_assert_criterion_protocol_submessage_criterion_protocol_msg) +PB_STATIC_ASSERT((pb_membersize(criterion_protocol_submessage, value.birth) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 65536 && pb_membersize(criterion_protocol_submessage, value.death) < 65536 && pb_membersize(criterion_protocol_submessage, value.message) < 65536 && pb_membersize(criterion_protocol_submessage, value.assert) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_subtest) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_subtest) < 65536 && pb_membersize(criterion_protocol_submessage, value.birth) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 65536 && pb_membersize(criterion_protocol_submessage, value.death) < 65536 && pb_membersize(criterion_protocol_submessage, value.message) < 65536 && pb_membersize(criterion_protocol_submessage, value.assert) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_subtest) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_subtest) < 65536 && pb_membersize(criterion_protocol_submessage, value.birth) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 65536 && pb_membersize(criterion_protocol_submessage, value.death) < 65536 && pb_membersize(criterion_protocol_submessage, value.message) < 65536 && pb_membersize(criterion_protocol_submessage, value.assert) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_subtest) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_subtest) < 65536 && pb_membersize(criterion_protocol_submessage, value.birth) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_test) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 65536 && pb_membersize(criterion_protocol_submessage, value.death) < 65536 && pb_membersize(criterion_protocol_submessage, value.message) < 65536 && pb_membersize(criterion_protocol_submessage, value.assert) < 65536 && pb_membersize(criterion_protocol_submessage, value.pre_subtest) < 65536 && pb_membersize(criterion_protocol_submessage, value.post_subtest) < 65536 && pb_membersize(criterion_protocol_msg, data) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_criterion_protocol_birth_criterion_protocol_pre_init_criterion_protocol_pre_test_criterion_protocol_post_test_criterion_protocol_post_fini_criterion_protocol_pre_subtest_criterion_protocol_post_subtest_criterion_protocol_death_criterion_protocol_assert_criterion_protocol_log_criterion_protocol_submessage_criterion_protocol_msg) #endif #if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) @@ -85,7 +105,7 @@ PB_STATIC_ASSERT((pb_membersize(criterion_protocol_submessage, value.birth) < 65 * numbers or field sizes that are larger than what can fit in the default * 8 bit descriptors. */ -PB_STATIC_ASSERT((pb_membersize(criterion_protocol_submessage, value.birth) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 256 && pb_membersize(criterion_protocol_submessage, value.death) < 256 && pb_membersize(criterion_protocol_submessage, value.assert) < 256 && pb_membersize(criterion_protocol_submessage, value.birth) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 256 && pb_membersize(criterion_protocol_submessage, value.death) < 256 && pb_membersize(criterion_protocol_submessage, value.assert) < 256 && pb_membersize(criterion_protocol_submessage, value.birth) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 256 && pb_membersize(criterion_protocol_submessage, value.death) < 256 && pb_membersize(criterion_protocol_submessage, value.assert) < 256 && pb_membersize(criterion_protocol_submessage, value.birth) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 256 && pb_membersize(criterion_protocol_submessage, value.death) < 256 && pb_membersize(criterion_protocol_submessage, value.assert) < 256 && pb_membersize(criterion_protocol_msg, data) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_criterion_protocol_birth_criterion_protocol_pre_init_criterion_protocol_pre_test_criterion_protocol_post_test_criterion_protocol_post_fini_criterion_protocol_death_criterion_protocol_assert_criterion_protocol_submessage_criterion_protocol_msg) +PB_STATIC_ASSERT((pb_membersize(criterion_protocol_submessage, value.birth) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 256 && pb_membersize(criterion_protocol_submessage, value.death) < 256 && pb_membersize(criterion_protocol_submessage, value.message) < 256 && pb_membersize(criterion_protocol_submessage, value.assert) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_subtest) < 256 && pb_membersize(criterion_protocol_submessage, value.post_subtest) < 256 && pb_membersize(criterion_protocol_submessage, value.birth) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 256 && pb_membersize(criterion_protocol_submessage, value.death) < 256 && pb_membersize(criterion_protocol_submessage, value.message) < 256 && pb_membersize(criterion_protocol_submessage, value.assert) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_subtest) < 256 && pb_membersize(criterion_protocol_submessage, value.post_subtest) < 256 && pb_membersize(criterion_protocol_submessage, value.birth) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 256 && pb_membersize(criterion_protocol_submessage, value.death) < 256 && pb_membersize(criterion_protocol_submessage, value.message) < 256 && pb_membersize(criterion_protocol_submessage, value.assert) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_subtest) < 256 && pb_membersize(criterion_protocol_submessage, value.post_subtest) < 256 && pb_membersize(criterion_protocol_submessage, value.birth) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_init) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_test) < 256 && pb_membersize(criterion_protocol_submessage, value.post_fini) < 256 && pb_membersize(criterion_protocol_submessage, value.death) < 256 && pb_membersize(criterion_protocol_submessage, value.message) < 256 && pb_membersize(criterion_protocol_submessage, value.assert) < 256 && pb_membersize(criterion_protocol_submessage, value.pre_subtest) < 256 && pb_membersize(criterion_protocol_submessage, value.post_subtest) < 256 && pb_membersize(criterion_protocol_msg, data) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_criterion_protocol_birth_criterion_protocol_pre_init_criterion_protocol_pre_test_criterion_protocol_post_test_criterion_protocol_post_fini_criterion_protocol_pre_subtest_criterion_protocol_post_subtest_criterion_protocol_death_criterion_protocol_assert_criterion_protocol_log_criterion_protocol_submessage_criterion_protocol_msg) #endif diff --git a/src/protocol/criterion.pb.h b/src/protocol/criterion.pb.h index 9f7ab62..fea9d14 100644 --- a/src/protocol/criterion.pb.h +++ b/src/protocol/criterion.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.3.5-dev at Fri Dec 11 17:13:49 2015. */ +/* Generated by nanopb-0.3.5-dev at Sun Dec 13 17:07:36 2015. */ #ifndef PB_CRITERION_PB_H_INCLUDED #define PB_CRITERION_PB_H_INCLUDED @@ -17,7 +17,8 @@ extern "C" { typedef enum _criterion_protocol_death_result_type { criterion_protocol_death_result_type_NORMAL = 0, criterion_protocol_death_result_type_CRASH = 1, - criterion_protocol_death_result_type_TIMEOUT = 2 + criterion_protocol_death_result_type_TIMEOUT = 2, + criterion_protocol_death_result_type_ABORT = 3 } criterion_protocol_death_result_type; /* Struct definitions */ @@ -29,10 +30,18 @@ typedef struct _criterion_protocol_post_fini { uint8_t dummy_field; } criterion_protocol_post_fini; +typedef struct _criterion_protocol_post_subtest { + pb_callback_t id; +} criterion_protocol_post_subtest; + typedef struct _criterion_protocol_pre_init { uint8_t dummy_field; } criterion_protocol_pre_init; +typedef struct _criterion_protocol_pre_subtest { + pb_callback_t id; +} criterion_protocol_pre_subtest; + typedef struct _criterion_protocol_assert { char *message; bool passed; @@ -48,6 +57,13 @@ typedef struct _criterion_protocol_death { int64_t status; } criterion_protocol_death; +typedef struct _criterion_protocol_log { + int32_t severity; + char *message; + bool has_prefix; + int32_t prefix; +} criterion_protocol_log; + typedef struct _criterion_protocol_post_test { bool has_timestamp; int64_t timestamp; @@ -67,7 +83,10 @@ typedef struct _criterion_protocol_submessage { criterion_protocol_post_test post_test; criterion_protocol_post_fini post_fini; criterion_protocol_death death; + criterion_protocol_log message; criterion_protocol_assert assert; + criterion_protocol_pre_subtest pre_subtest; + criterion_protocol_post_subtest post_subtest; } value; } criterion_protocol_submessage; @@ -89,8 +108,11 @@ extern const int32_t criterion_protocol_msg_version_default; #define criterion_protocol_pre_test_init_default {false, 0} #define criterion_protocol_post_test_init_default {false, 0} #define criterion_protocol_post_fini_init_default {0} +#define criterion_protocol_pre_subtest_init_default {{{NULL}, NULL}} +#define criterion_protocol_post_subtest_init_default {{{NULL}, NULL}} #define criterion_protocol_death_init_default {false, (criterion_protocol_death_result_type)0, false, 0} #define criterion_protocol_assert_init_default {NULL, 0, NULL, false, 0} +#define criterion_protocol_log_init_default {0, NULL, false, 0} #define criterion_protocol_submessage_init_default {0, {criterion_protocol_birth_init_default}} #define criterion_protocol_msg_init_default {1, 0, {0}, criterion_protocol_submessage_init_default} #define criterion_protocol_birth_init_zero {0} @@ -98,18 +120,26 @@ extern const int32_t criterion_protocol_msg_version_default; #define criterion_protocol_pre_test_init_zero {false, 0} #define criterion_protocol_post_test_init_zero {false, 0} #define criterion_protocol_post_fini_init_zero {0} +#define criterion_protocol_pre_subtest_init_zero {{{NULL}, NULL}} +#define criterion_protocol_post_subtest_init_zero {{{NULL}, NULL}} #define criterion_protocol_death_init_zero {false, (criterion_protocol_death_result_type)0, false, 0} #define criterion_protocol_assert_init_zero {NULL, 0, NULL, false, 0} +#define criterion_protocol_log_init_zero {0, NULL, false, 0} #define criterion_protocol_submessage_init_zero {0, {criterion_protocol_birth_init_zero}} #define criterion_protocol_msg_init_zero {0, 0, {0}, criterion_protocol_submessage_init_zero} /* Field tags (for use in manual encoding/decoding) */ +#define criterion_protocol_post_subtest_id_tag 1 +#define criterion_protocol_pre_subtest_id_tag 1 #define criterion_protocol_assert_message_tag 1 #define criterion_protocol_assert_passed_tag 2 #define criterion_protocol_assert_file_tag 3 #define criterion_protocol_assert_line_tag 4 #define criterion_protocol_death_result_tag 1 #define criterion_protocol_death_status_tag 2 +#define criterion_protocol_log_severity_tag 1 +#define criterion_protocol_log_message_tag 2 +#define criterion_protocol_log_prefix_tag 3 #define criterion_protocol_post_test_timestamp_tag 1 #define criterion_protocol_pre_test_timestamp_tag 1 #define criterion_protocol_submessage_birth_tag 1 @@ -118,7 +148,10 @@ extern const int32_t criterion_protocol_msg_version_default; #define criterion_protocol_submessage_post_test_tag 4 #define criterion_protocol_submessage_post_fini_tag 5 #define criterion_protocol_submessage_death_tag 6 -#define criterion_protocol_submessage_assert_tag 7 +#define criterion_protocol_submessage_message_tag 7 +#define criterion_protocol_submessage_assert_tag 8 +#define criterion_protocol_submessage_pre_subtest_tag 9 +#define criterion_protocol_submessage_post_subtest_tag 10 #define criterion_protocol_msg_pid_tag 2 #define criterion_protocol_msg_version_tag 1 #define criterion_protocol_msg_data_tag 16 @@ -129,9 +162,12 @@ extern const pb_field_t criterion_protocol_pre_init_fields[1]; extern const pb_field_t criterion_protocol_pre_test_fields[2]; extern const pb_field_t criterion_protocol_post_test_fields[2]; extern const pb_field_t criterion_protocol_post_fini_fields[1]; +extern const pb_field_t criterion_protocol_pre_subtest_fields[2]; +extern const pb_field_t criterion_protocol_post_subtest_fields[2]; extern const pb_field_t criterion_protocol_death_fields[3]; extern const pb_field_t criterion_protocol_assert_fields[5]; -extern const pb_field_t criterion_protocol_submessage_fields[8]; +extern const pb_field_t criterion_protocol_log_fields[4]; +extern const pb_field_t criterion_protocol_submessage_fields[11]; extern const pb_field_t criterion_protocol_msg_fields[4]; /* Maximum encoded size of messages (where known) */ diff --git a/src/protocol/criterion.proto b/src/protocol/criterion.proto index bb671a6..2eb3ce9 100644 --- a/src/protocol/criterion.proto +++ b/src/protocol/criterion.proto @@ -18,11 +18,20 @@ message post_test { message post_fini { } +message pre_subtest { + required string id = 1; +} + +message post_subtest { + required string id = 1; +} + message death { enum result_type { NORMAL = 0; CRASH = 1; TIMEOUT = 2; + ABORT = 3; } optional result_type result = 1; @@ -36,16 +45,26 @@ message assert { optional int64 line = 4; } +message log { + required int32 severity = 1; + required string message = 2; + optional int32 prefix = 3; +} + message submessage { oneof value { - criterion.protocol.birth birth = 1; - criterion.protocol.pre_init pre_init = 2; - criterion.protocol.pre_test pre_test = 3; - criterion.protocol.post_test post_test = 4; - criterion.protocol.post_fini post_fini = 5; - criterion.protocol.death death = 6; - criterion.protocol.assert assert = 7; + criterion.protocol.birth birth = 1; + criterion.protocol.pre_init pre_init = 2; + criterion.protocol.pre_test pre_test = 3; + criterion.protocol.post_test post_test = 4; + criterion.protocol.post_fini post_fini = 5; + criterion.protocol.death death = 6; + + criterion.protocol.log message = 7; + criterion.protocol.assert assert = 8; + criterion.protocol.pre_subtest pre_subtest = 9; + criterion.protocol.post_subtest post_subtest = 10; } } diff --git a/src/protocol/protocol.c b/src/protocol/protocol.c index bb7c0ac..b788378 100644 --- a/src/protocol/protocol.c +++ b/src/protocol/protocol.c @@ -2,37 +2,40 @@ #include #include #include +#include +#include +#include -static bool write_callback(pb_ostream_t *stream, const uint8_t *buf, size_t count) { - int sock = (intptr_t) stream->state; - int result = nn_send(sock, buf, count, 0); +#include "criterion/internal/common.h" +#include "protocol.h" + +static bool write_fd_callback(pb_ostream_t *stream, const uint8_t *buf, size_t count) { + int fd = (intptr_t) stream->state; + ssize_t result = write(fd, buf, count); if (result < 0) return false; return (size_t) result == count; } -static bool read_callback(pb_istream_t *stream, uint8_t *buf, size_t count) { - int sock = (intptr_t)stream->state; - int result; - - result = nn_recv(sock, buf, count, 0); - - if (result == 0) - stream->bytes_left = 0; /* EOF */ +static bool read_fd_callback(pb_istream_t *stream, uint8_t *buf, size_t count) { + int fd = (intptr_t) stream->state; + ssize_t result = read(fd, buf, count); if (result < 0) return false; + if ((size_t) result < count) + stream->bytes_left = result; return (size_t) result == count; } -pb_ostream_t pb_ostream_from_nn_socket(int sock) { - pb_ostream_t stream = {&write_callback, (void*)(intptr_t) sock, SIZE_MAX, 0, ""}; +pb_ostream_t pb_ostream_from_fd(int fd) { + pb_ostream_t stream = {&write_fd_callback, (void*)(intptr_t) fd, SIZE_MAX, 0, NULL}; return stream; } -pb_istream_t pb_istream_from_nn_socket(int sock) { - pb_istream_t stream = {&read_callback, (void*)(intptr_t) sock, SIZE_MAX, ""}; +pb_istream_t pb_istream_from_fd(int fd) { + pb_istream_t stream = {&read_fd_callback, (void*)(intptr_t) fd, SIZE_MAX, NULL}; return stream; } diff --git a/src/protocol/protocol.h b/src/protocol/protocol.h new file mode 100644 index 0000000..b7b9b82 --- /dev/null +++ b/src/protocol/protocol.h @@ -0,0 +1,53 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2015 Franklin "Snaipe" Mathieu + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef PROTOCOL_H_ +# define PROTOCOL_H_ + +# include +# include +# include "criterion.pb.h" +# include "criterion/internal/preprocess.h" + +bool pb_write_string(pb_ostream_t *stream, const pb_field_t *field, void * const *arg); +bool pb_read_string(pb_istream_t *stream, const pb_field_t *field, void **arg); + +pb_ostream_t pb_ostream_from_fd(int fd); +pb_istream_t pb_istream_from_fd(int fd); + +# define criterion_message(Kind, ...) \ + (criterion_protocol_msg) { \ + .version = 1, \ + .which_id = criterion_protocol_msg_pid_tag, \ + .id = { \ + .pid = get_process_id(), \ + }, \ + .data = { \ + .which_value = criterion_protocol_submessage_ ## Kind ## _tag, \ + .value = { \ + .Kind = { CR_EXPAND(__VA_ARGS__) }, \ + } \ + } \ + } + +#endif /* !PROTOCOL_H_ */