From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 579672A4F5 for ; Wed, 20 Mar 2019 06:49:23 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id e6uUotnk9o2k for ; Wed, 20 Mar 2019 06:49:23 -0400 (EDT) Received: from smtpng2.m.smailru.net (smtpng2.m.smailru.net [94.100.179.3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 739422A4D2 for ; Wed, 20 Mar 2019 06:49:22 -0400 (EDT) From: Vladislav Shpilevoy Subject: [tarantool-patches] [PATCH 2/6] test: introduce breakpoints for swim's event loop Date: Wed, 20 Mar 2019 13:49:15 +0300 Message-Id: In-Reply-To: References: In-Reply-To: References: Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-Help: List-Unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-Subscribe: List-Owner: List-post: List-Archive: To: tarantool-patches@freelists.org Cc: kostja@tarantool.org Breakpoint as API gives a test writer more control over timing of condition checks. Breakpoint stops the swim's event loop in a certain moment of virtual time. Without breakpoints it is possible, that a condition has failed its deadline, but it can not be checked properly. For example, assume that there is a cluster of two members, and after 1 second they should become fullmesh. It means, that any checks in [0, 1) time have to fail. But without breakpoints it is not so: // event_queue: [round_step, 1 sec] // time: 0 swim_cluster_wait_fullmesh(cluster, 0.5); // Fails. // event_queue: [] // time: 1 swim_cluster_wait_fullmesh(cluster, 0.1); // Success. The second test should fail, but it does not, because global time is already 1 after the first test and the cluster is in fullmesh already. It looks weird, so such checks should be done not later than deadline. Follow-up for 03b9a6e91baf246ee2bb9841d01ba3824b6768a6 --- test/unit/swim.c | 6 ++++-- test/unit/swim.result | 5 +++-- test/unit/swim_test_ev.c | 39 +++++++++++++++++++++++++++++++++++++ test/unit/swim_test_ev.h | 8 ++++++++ test/unit/swim_test_utils.c | 26 ++++++++++++++++++------- 5 files changed, 73 insertions(+), 11 deletions(-) diff --git a/test/unit/swim.c b/test/unit/swim.c index 921fc8f07..3a97aeb18 100644 --- a/test/unit/swim.c +++ b/test/unit/swim.c @@ -50,7 +50,7 @@ static int test_result; static void swim_test_one_link(void) { - swim_start_test(1); + swim_start_test(2); /* * Run a simple cluster of two elements. One of them * learns about another explicitly. Another should add the @@ -58,7 +58,9 @@ swim_test_one_link(void) */ struct swim_cluster *cluster = swim_cluster_new(2); fail_if(swim_cluster_add_link(cluster, 0, 1) != 0); - is(swim_cluster_wait_fullmesh(cluster, 1), 0, "one link"); + is(swim_cluster_wait_fullmesh(cluster, 0.9), -1, + "no rounds - no fullmesh"); + is(swim_cluster_wait_fullmesh(cluster, 0.1), 0, "one link"); swim_cluster_delete(cluster); swim_finish_test(); diff --git a/test/unit/swim.result b/test/unit/swim.result index e8991d8d8..b58325b73 100644 --- a/test/unit/swim.result +++ b/test/unit/swim.result @@ -1,8 +1,9 @@ *** main_f *** 1..5 *** swim_test_one_link *** - 1..1 - ok 1 - one link + 1..2 + ok 1 - no rounds - no fullmesh + ok 2 - one link ok 1 - subtests *** swim_test_one_link: done *** *** swim_test_sequence *** diff --git a/test/unit/swim_test_ev.c b/test/unit/swim_test_ev.c index ee1fcdbb7..d4a0a4752 100644 --- a/test/unit/swim_test_ev.c +++ b/test/unit/swim_test_ev.c @@ -55,6 +55,7 @@ static int event_id = 0; enum swim_event_type { SWIM_EVENT_TIMER, SWIM_EVENT_FD_UNBLOCK, + SWIM_EVENT_BRK, }; struct swim_event; @@ -250,6 +251,44 @@ swim_test_ev_block_fd(int fd, double delay) e->fd = fd; } +/** + * Breakpoint event for debug. It does nothing but stops the event + * loop after a timeout to allow highlevel API to check some + * cases. + */ +struct swim_brk_event { + struct swim_event base; +}; + +/** Delete a breakpoint event. */ +static void +swim_brk_event_delete(struct swim_event *e) +{ + assert(e->type == SWIM_EVENT_BRK); + swim_event_destroy(e); + free(e); +} + +/** + * Breakpoint event processing is nothing but the event deletion. + */ +static void +swim_brk_event_process(struct swim_event *e, struct ev_loop *loop) +{ + (void) loop; + assert(e->type == SWIM_EVENT_BRK); + swim_brk_event_delete(e); +} + +void +swim_ev_set_brk(double delay) +{ + struct swim_brk_event *e = (struct swim_brk_event *) malloc(sizeof(*e)); + assert(e != NULL); + swim_event_create(&e->base, SWIM_EVENT_BRK, delay, + swim_brk_event_process, swim_brk_event_delete); +} + /** Implementation of global time visible in SWIM. */ double swim_time(void) diff --git a/test/unit/swim_test_ev.h b/test/unit/swim_test_ev.h index 808bc510e..01a1b8868 100644 --- a/test/unit/swim_test_ev.h +++ b/test/unit/swim_test_ev.h @@ -51,6 +51,14 @@ swim_test_ev_free(void); void swim_test_ev_block_fd(int fd, double delay); +/** + * Stop the event loop after @a delay fake seconds. It does not + * affect other events, so the loop can stop earlier multiple + * times. + */ +void +swim_ev_set_brk(double delay); + /** Play one step of event loop, process generated events. */ void swim_do_loop_step(struct ev_loop *loop); diff --git a/test/unit/swim_test_utils.c b/test/unit/swim_test_utils.c index a92e55233..0b301333b 100644 --- a/test/unit/swim_test_utils.c +++ b/test/unit/swim_test_utils.c @@ -129,16 +129,28 @@ swim_cluster_is_fullmesh(struct swim_cluster *cluster) return true; } +/** + * A common wrapper for some conditions checking after each event + * loop step. + */ +#define swim_wait_timeout(timeout, target_cond) ({ \ + swim_ev_set_brk(timeout); \ + double deadline = swim_time() + timeout; \ + int rc = 0; \ + while (! (target_cond)) { \ + if (swim_time() >= deadline) { \ + rc = -1; \ + break; \ + } \ + swim_do_loop_step(loop()); \ + } \ + rc; \ +}) + int swim_cluster_wait_fullmesh(struct swim_cluster *cluster, double timeout) { - double deadline = swim_time() + timeout; - while (! swim_cluster_is_fullmesh(cluster)) { - if (swim_time() >= deadline) - return -1; - swim_do_loop_step(loop()); - } - return 0; + return swim_wait_timeout(timeout, swim_cluster_is_fullmesh(cluster)); } bool -- 2.17.2 (Apple Git-113)