From 8daa83a594a2e98f39d764422bfbdbc62c9efd44 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 19:20:00 +0200 Subject: Adding upstream version 2:4.20.0+dfsg. Signed-off-by: Daniel Baumann --- source3/lib/tevent_glib_glue_tests.c | 397 +++++++++++++++++++++++++++++++++++ 1 file changed, 397 insertions(+) create mode 100644 source3/lib/tevent_glib_glue_tests.c (limited to 'source3/lib/tevent_glib_glue_tests.c') diff --git a/source3/lib/tevent_glib_glue_tests.c b/source3/lib/tevent_glib_glue_tests.c new file mode 100644 index 0000000..d6cf664 --- /dev/null +++ b/source3/lib/tevent_glib_glue_tests.c @@ -0,0 +1,397 @@ +/* + Unix SMB/CIFS implementation. + + testing of the tevent glib glue subsystem + + Copyright (C) Ralph Boehme 2016 + + glib tests adapted from glib2 glib/tests/mainloop.c + Copyright (C) 2011 Red Hat Inc., Matthias Clasen + + ** NOTE! The following LGPL license applies to the tevent + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see . +*/ + +#include "replace.h" + +/* + * glib uses TRUE and FALSE which may have redefined by "includes.h" to be + * unusable. Unndefine so glib can establish its own working replacement. + */ +#undef TRUE +#undef FALSE +#include +#include +#include "lib/tevent_glib_glue.h" + +/* + * Unfortunately the glib test suite runner doesn't pass args to tests + * so we must keep a few globals here. + */ +static struct tevent_context *ev; + +static gboolean count_calls(gpointer data) +{ + gint *i = (gint *)data; + + (*i)++; + + return TRUE; +} + +static gboolean quit_loop(gpointer data) +{ + struct tevent_glib_glue *glue = talloc_get_type_abort( + data, struct tevent_glib_glue); + + samba_tevent_glib_glue_quit(glue); + + return G_SOURCE_REMOVE; +} + +static void test_timeouts(void) +{ + GMainContext *ctx = NULL; + struct tevent_glib_glue *glue = NULL; + GSource *source = NULL; + gint a; + gint b; + gint c; + + a = b = c = 0; + + ctx = g_main_context_new(); + glue = samba_tevent_glib_glue_create(ev, ev, ctx); + g_assert(glue != NULL); + + source = g_timeout_source_new(100); + g_source_set_callback(source, count_calls, &a, NULL); + g_source_attach(source, ctx); + g_source_unref(source); + + source = g_timeout_source_new(250); + g_source_set_callback(source, count_calls, &b, NULL); + g_source_attach(source, ctx); + g_source_unref(source); + + source = g_timeout_source_new(330); + g_source_set_callback(source, count_calls, &c, NULL); + g_source_attach(source, ctx); + g_source_unref(source); + + source = g_timeout_source_new(1050); + g_source_set_callback(source, quit_loop, glue, NULL); + g_source_attach(source, ctx); + g_source_unref(source); + + g_assert(tevent_loop_wait(ev) == 0); + + /* We may be delayed for an arbitrary amount of time - for example, + * it's possible for all timeouts to fire exactly once. + */ + g_assert_cmpint(a, >, 0); + g_assert_cmpint(a, >=, b); + g_assert_cmpint(b, >=, c); + + g_assert_cmpint(a, <=, 10); + g_assert_cmpint(b, <=, 4); + g_assert_cmpint(c, <=, 3); + + samba_tevent_glib_glue_quit(glue); + TALLOC_FREE(glue); + g_main_context_unref(ctx); +} + +struct test_glib_ev_source_data { + GMainContext *ctx; + struct tevent_glib_glue *glue; +}; + +static gboolean test_glib_ev_source_quit_loop(gpointer data); + +static gboolean test_glib_ev_source_timeout_cb(gpointer data) +{ + struct test_glib_ev_source_data *state = talloc_get_type_abort( + data, struct test_glib_ev_source_data); + GSource *source = NULL; + + source = g_timeout_source_new(100); + g_source_set_callback(source, + test_glib_ev_source_quit_loop, + state, + NULL); + g_source_attach(source, state->ctx); + g_source_unref(source); + + return TRUE; +} + +static gboolean test_glib_ev_source_quit_loop(gpointer data) +{ + struct test_glib_ev_source_data *state = talloc_get_type_abort( + data, struct test_glib_ev_source_data); + + samba_tevent_glib_glue_quit(state->glue); + + return G_SOURCE_REMOVE; +} + +static void test_glib_ev_source(void) +{ + GMainContext *ctx = NULL; + struct tevent_glib_glue *glue = NULL; + struct test_glib_ev_source_data *state = NULL; + GSource *source = NULL; + + ctx = g_main_context_new(); + g_assert(ctx != NULL); + + glue = samba_tevent_glib_glue_create(ev, ev, ctx); + g_assert(glue != NULL); + + state = talloc_zero(glue, struct test_glib_ev_source_data); + g_assert(state != NULL); + + state->ctx = ctx; + state->glue = glue; + + source = g_timeout_source_new(100); + g_source_set_callback(source, + test_glib_ev_source_timeout_cb, + state, + NULL); + g_source_attach(source, ctx); + g_source_unref(source); + + g_assert(tevent_loop_wait(ev) == 0); + + TALLOC_FREE(glue); + g_main_context_unref(ctx); +} + +struct test_tevent_ev_source_data { + GMainContext *ctx; + struct tevent_glib_glue *glue; +}; + +static gboolean test_tevent_ev_source_quit_loop(gpointer data); + +static void test_tevent_ev_source_timeout_cb(struct tevent_context *_ev, + struct tevent_timer *te, + struct timeval current_time, + void *data) +{ + struct test_tevent_ev_source_data *state = talloc_get_type_abort( + data, struct test_tevent_ev_source_data); + GSource *source = NULL; + + source = g_timeout_source_new(100); + g_source_set_callback(source, + test_tevent_ev_source_quit_loop, + state, + NULL); + g_source_attach(source, state->ctx); + g_source_unref(source); + + return; +} + +static gboolean test_tevent_ev_source_quit_loop(gpointer data) +{ + struct test_tevent_ev_source_data *state = talloc_get_type_abort( + data, struct test_tevent_ev_source_data); + + samba_tevent_glib_glue_quit(state->glue); + + return G_SOURCE_REMOVE; +} + +static void test_tevent_ev_source(void) +{ + GMainContext *ctx = NULL; + struct tevent_glib_glue *glue = NULL; + struct test_tevent_ev_source_data *state = NULL; + struct tevent_timer *timer = NULL; + + ctx = g_main_context_new(); + g_assert(ctx != NULL); + + glue = samba_tevent_glib_glue_create(ev, ev, ctx); + g_assert(glue != NULL); + + state = talloc_zero(glue, struct test_tevent_ev_source_data); + g_assert(state != NULL); + + state->ctx = ctx; + state->glue = glue; + + timer = tevent_add_timer(ev, + state, + tevent_timeval_current_ofs(0, 1000), + test_tevent_ev_source_timeout_cb, + state); + g_assert(timer != NULL); + + g_assert(tevent_loop_wait(ev) == 0); + + TALLOC_FREE(glue); + g_main_context_unref(ctx); +} + +static gchar zeros[1024]; + +static gsize fill_a_pipe(gint fd) +{ + gsize written = 0; + GPollFD pfd; + + pfd.fd = fd; + pfd.events = G_IO_OUT; + while (g_poll(&pfd, 1, 0) == 1) + /* we should never see -1 here */ + written += write(fd, zeros, sizeof zeros); + + return written; +} + +static gboolean write_bytes(gint fd, + GIOCondition condition, + gpointer user_data) +{ + gssize *to_write = user_data; + gint limit; + + if (*to_write == 0) + return FALSE; + + /* Detect if we run before we should */ + g_assert(*to_write >= 0); + + limit = MIN(*to_write, sizeof zeros); + *to_write -= write(fd, zeros, limit); + + return TRUE; +} + +static gboolean read_bytes(gint fd, + GIOCondition condition, + gpointer user_data) +{ + static gchar buffer[1024]; + gssize *to_read = user_data; + + *to_read -= read(fd, buffer, sizeof buffer); + + /* The loop will exit when there is nothing else to read, then we will + * use g_source_remove() to destroy this source. + */ + return TRUE; +} + +static void test_unix_fd(void) +{ + gssize to_write = -1; + gssize to_read; + gint fds[2]; + gint a, b; + gint s; + GSource *source_a = NULL; + GSource *source_b = NULL; + struct tevent_glib_glue *glue = NULL; + + glue = samba_tevent_glib_glue_create(ev, ev, g_main_context_default()); + g_assert(glue != NULL); + + s = pipe(fds); + g_assert(s == 0); + + to_read = fill_a_pipe(fds[1]); + /* write at higher priority to keep the pipe full... */ + a = g_unix_fd_add_full(G_PRIORITY_HIGH, + fds[1], + G_IO_OUT, + write_bytes, + &to_write, + NULL); + source_a = g_source_ref(g_main_context_find_source_by_id(NULL, a)); + /* make sure no 'writes' get dispatched yet */ + while (tevent_loop_once(ev)); + + to_read += 128 * 1024 * 1024; + to_write = 128 * 1024 * 1024; + b = g_unix_fd_add(fds[0], G_IO_IN, read_bytes, &to_read); + source_b = g_source_ref(g_main_context_find_source_by_id(NULL, b)); + + /* Assuming the kernel isn't internally 'laggy' then there will always + * be either data to read or room in which to write. That will keep + * the loop running until all data has been read and written. + */ + while (to_write > 0 || to_read > 0) + { + gssize to_write_was = to_write; + gssize to_read_was = to_read; + + if (tevent_loop_once(ev) != 0) + break; + + /* Since the sources are at different priority, only one of them + * should possibly have run. + */ + g_assert(to_write == to_write_was || to_read == to_read_was); + } + + g_assert(to_write == 0); + g_assert(to_read == 0); + + /* 'a' is already removed by itself */ + g_assert(g_source_is_destroyed(source_a)); + g_source_unref(source_a); + g_source_remove(b); + g_assert(g_source_is_destroyed(source_b)); + g_source_unref(source_b); + + samba_tevent_glib_glue_quit(glue); + TALLOC_FREE(glue); + + close(fds[1]); + close(fds[0]); +} + +int main(int argc, const char *argv[]) +{ + int test_argc = 3; + char *test_argv[] = { + discard_const("test_glib_glue"), + discard_const("-m"), + discard_const("no-undefined") + }; + char **argvp = test_argv; + + g_test_init(&test_argc, &argvp, NULL); + + ev = tevent_context_init(NULL); + if (ev == NULL) { + exit(1); + } + + g_test_add_func("/mainloop/timeouts", test_timeouts); + g_test_add_func("/mainloop/glib_ev_source", test_glib_ev_source); + g_test_add_func("/mainloop/tevent_ev_source", test_tevent_ev_source); + g_test_add_func("/mainloop/unix-fd", test_unix_fd); + + return g_test_run(); +} -- cgit v1.2.3