[tarantool-patches] [PATCH 2/6] test: introduce breakpoints for swim's event loop
Vladislav Shpilevoy
v.shpilevoy at tarantool.org
Wed Mar 20 13:49:15 MSK 2019
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)
More information about the Tarantool-patches
mailing list