mirror of
https://github.com/samba-team/samba.git
synced 2025-03-27 22:50:26 +03:00
s3/lib: add a tevent_glib_glue subsystem test
Tests adapted from glib2 glib/tests/mainloop.c. Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Noel Power <npower@samba.org>
This commit is contained in:
parent
fa39a7b2e6
commit
1f836d4c7f
397
source3/lib/tevent_glib_glue_tests.c
Normal file
397
source3/lib/tevent_glib_glue_tests.c
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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 <glib.h>
|
||||
#include <glib-unix.h>
|
||||
#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();
|
||||
}
|
21
source3/script/tests/test_tevent_glib_glue.sh
Executable file
21
source3/script/tests/test_tevent_glib_glue.sh
Executable file
@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
incdir=`dirname $0`/../../../testprogs/blackbox
|
||||
. $incdir/subunit.sh
|
||||
|
||||
failed=0
|
||||
TESTNAME="tevent_glib_glue_test"
|
||||
|
||||
if [ ! -x $BINDIR/tevent_glib_glue_test ] ; then
|
||||
subunit_start_test "$TESTNAME"
|
||||
subunit_skip_test "$TESTNAME" <<EOF
|
||||
Test needs glib2-devel
|
||||
EOF
|
||||
testok $0 $failed
|
||||
fi
|
||||
|
||||
|
||||
testit "$TESTNAME" $VALGRIND $BINDIR/tevent_glib_glue_test ||
|
||||
failed=`expr $failed + 1`
|
||||
|
||||
testok $0 $failed
|
@ -419,6 +419,9 @@ plantestsuite(
|
||||
"samba3.resolvconf", "none",
|
||||
[os.path.join(samba3srcdir, "script/tests/test_resolvconf.sh")])
|
||||
|
||||
plantestsuite("samba3.tevent_glib_glue", "none",
|
||||
[os.path.join(samba3srcdir, "script/tests/test_tevent_glib_glue.sh")])
|
||||
|
||||
plantestsuite("samba3.async_req", "nt4_dc",
|
||||
[os.path.join(samba3srcdir, "script/tests/test_async_req.sh")])
|
||||
|
||||
|
@ -1323,6 +1323,16 @@ bld.SAMBA3_BINARY('spotlight2sparql',
|
||||
enabled=bld.env.with_spotlight,
|
||||
install=False)
|
||||
|
||||
bld.SAMBA3_BINARY('tevent_glib_glue_test',
|
||||
source='lib/tevent_glib_glue_tests.c',
|
||||
deps='''
|
||||
talloc
|
||||
libsmb
|
||||
popt_samba3
|
||||
tevent-glib-glue''',
|
||||
enabled=bld.CONFIG_SET('WITH_TEVENT_GLIB_GLUE'),
|
||||
install=False)
|
||||
|
||||
########################## INCLUDES #################################
|
||||
|
||||
bld.RECURSE('auth')
|
||||
|
Loading…
x
Reference in New Issue
Block a user