2 Unix SMB/CIFS implementation.
4 testing of the tevent glib glue subsystem
6 Copyright (C) Ralph Boehme 2016
8 glib tests adapted from glib2 glib/tests/mainloop.c
9 Copyright (C) 2011 Red Hat Inc., Matthias Clasen
11 ** NOTE! The following LGPL license applies to the tevent
12 ** library. This does NOT imply that all of Samba is released
15 This library is free software; you can redistribute it and/or
16 modify it under the terms of the GNU Lesser General Public
17 License as published by the Free Software Foundation; either
18 version 3 of the License, or (at your option) any later version.
20 This library is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 Lesser General Public License for more details.
25 You should have received a copy of the GNU Lesser General Public
26 License along with this library; if not, see <http://www.gnu.org/licenses/>.
32 * glib uses TRUE and FALSE which may have redefined by "includes.h" to be
33 * unusable. Unndefine so glib can establish its own working replacement.
38 #include <glib-unix.h>
39 #include "lib/tevent_glib_glue.h"
42 * Unfortunately the glib test suite runner doesn't pass args to tests
43 * so we must keep a few globals here.
45 static struct tevent_context
*ev
;
47 static gboolean
count_calls(gpointer data
)
49 gint
*i
= (gint
*)data
;
56 static gboolean
quit_loop(gpointer data
)
58 struct tevent_glib_glue
*glue
= talloc_get_type_abort(
59 data
, struct tevent_glib_glue
);
61 samba_tevent_glib_glue_quit(glue
);
63 return G_SOURCE_REMOVE
;
66 static void test_timeouts(void)
68 GMainContext
*ctx
= NULL
;
69 struct tevent_glib_glue
*glue
= NULL
;
70 GSource
*source
= NULL
;
77 ctx
= g_main_context_new();
78 glue
= samba_tevent_glib_glue_create(ev
, ev
, ctx
);
79 g_assert(glue
!= NULL
);
81 source
= g_timeout_source_new(100);
82 g_source_set_callback(source
, count_calls
, &a
, NULL
);
83 g_source_attach(source
, ctx
);
84 g_source_unref(source
);
86 source
= g_timeout_source_new(250);
87 g_source_set_callback(source
, count_calls
, &b
, NULL
);
88 g_source_attach(source
, ctx
);
89 g_source_unref(source
);
91 source
= g_timeout_source_new(330);
92 g_source_set_callback(source
, count_calls
, &c
, NULL
);
93 g_source_attach(source
, ctx
);
94 g_source_unref(source
);
96 source
= g_timeout_source_new(1050);
97 g_source_set_callback(source
, quit_loop
, glue
, NULL
);
98 g_source_attach(source
, ctx
);
99 g_source_unref(source
);
101 g_assert(tevent_loop_wait(ev
) == 0);
103 /* We may be delayed for an arbitrary amount of time - for example,
104 * it's possible for all timeouts to fire exactly once.
106 g_assert_cmpint(a
, >, 0);
107 g_assert_cmpint(a
, >=, b
);
108 g_assert_cmpint(b
, >=, c
);
110 g_assert_cmpint(a
, <=, 10);
111 g_assert_cmpint(b
, <=, 4);
112 g_assert_cmpint(c
, <=, 3);
114 samba_tevent_glib_glue_quit(glue
);
116 g_main_context_unref(ctx
);
119 struct test_glib_ev_source_data
{
121 struct tevent_glib_glue
*glue
;
124 static gboolean
test_glib_ev_source_quit_loop(gpointer data
);
126 static gboolean
test_glib_ev_source_timeout_cb(gpointer data
)
128 struct test_glib_ev_source_data
*state
= talloc_get_type_abort(
129 data
, struct test_glib_ev_source_data
);
130 GSource
*source
= NULL
;
132 source
= g_timeout_source_new(100);
133 g_source_set_callback(source
,
134 test_glib_ev_source_quit_loop
,
137 g_source_attach(source
, state
->ctx
);
138 g_source_unref(source
);
143 static gboolean
test_glib_ev_source_quit_loop(gpointer data
)
145 struct test_glib_ev_source_data
*state
= talloc_get_type_abort(
146 data
, struct test_glib_ev_source_data
);
148 samba_tevent_glib_glue_quit(state
->glue
);
150 return G_SOURCE_REMOVE
;
153 static void test_glib_ev_source(void)
155 GMainContext
*ctx
= NULL
;
156 struct tevent_glib_glue
*glue
= NULL
;
157 struct test_glib_ev_source_data
*state
= NULL
;
158 GSource
*source
= NULL
;
160 ctx
= g_main_context_new();
161 g_assert(ctx
!= NULL
);
163 glue
= samba_tevent_glib_glue_create(ev
, ev
, ctx
);
164 g_assert(glue
!= NULL
);
166 state
= talloc_zero(glue
, struct test_glib_ev_source_data
);
167 g_assert(state
!= NULL
);
172 source
= g_timeout_source_new(100);
173 g_source_set_callback(source
,
174 test_glib_ev_source_timeout_cb
,
177 g_source_attach(source
, ctx
);
178 g_source_unref(source
);
180 g_assert(tevent_loop_wait(ev
) == 0);
183 g_main_context_unref(ctx
);
186 struct test_tevent_ev_source_data
{
188 struct tevent_glib_glue
*glue
;
191 static gboolean
test_tevent_ev_source_quit_loop(gpointer data
);
193 static void test_tevent_ev_source_timeout_cb(struct tevent_context
*_ev
,
194 struct tevent_timer
*te
,
195 struct timeval current_time
,
198 struct test_tevent_ev_source_data
*state
= talloc_get_type_abort(
199 data
, struct test_tevent_ev_source_data
);
200 GSource
*source
= NULL
;
202 source
= g_timeout_source_new(100);
203 g_source_set_callback(source
,
204 test_tevent_ev_source_quit_loop
,
207 g_source_attach(source
, state
->ctx
);
208 g_source_unref(source
);
213 static gboolean
test_tevent_ev_source_quit_loop(gpointer data
)
215 struct test_tevent_ev_source_data
*state
= talloc_get_type_abort(
216 data
, struct test_tevent_ev_source_data
);
218 samba_tevent_glib_glue_quit(state
->glue
);
220 return G_SOURCE_REMOVE
;
223 static void test_tevent_ev_source(void)
225 GMainContext
*ctx
= NULL
;
226 struct tevent_glib_glue
*glue
= NULL
;
227 struct test_tevent_ev_source_data
*state
= NULL
;
228 struct tevent_timer
*timer
= NULL
;
230 ctx
= g_main_context_new();
231 g_assert(ctx
!= NULL
);
233 glue
= samba_tevent_glib_glue_create(ev
, ev
, ctx
);
234 g_assert(glue
!= NULL
);
236 state
= talloc_zero(glue
, struct test_tevent_ev_source_data
);
237 g_assert(state
!= NULL
);
242 timer
= tevent_add_timer(ev
,
244 tevent_timeval_current_ofs(0, 1000),
245 test_tevent_ev_source_timeout_cb
,
247 g_assert(timer
!= NULL
);
249 g_assert(tevent_loop_wait(ev
) == 0);
252 g_main_context_unref(ctx
);
255 static gchar zeros
[1024];
257 static gsize
fill_a_pipe(gint fd
)
263 pfd
.events
= G_IO_OUT
;
264 while (g_poll(&pfd
, 1, 0) == 1)
265 /* we should never see -1 here */
266 written
+= write(fd
, zeros
, sizeof zeros
);
271 static gboolean
write_bytes(gint fd
,
272 GIOCondition condition
,
275 gssize
*to_write
= user_data
;
281 /* Detect if we run before we should */
282 g_assert(*to_write
>= 0);
284 limit
= MIN(*to_write
, sizeof zeros
);
285 *to_write
-= write(fd
, zeros
, limit
);
290 static gboolean
read_bytes(gint fd
,
291 GIOCondition condition
,
294 static gchar buffer
[1024];
295 gssize
*to_read
= user_data
;
297 *to_read
-= read(fd
, buffer
, sizeof buffer
);
299 /* The loop will exit when there is nothing else to read, then we will
300 * use g_source_remove() to destroy this source.
305 static void test_unix_fd(void)
307 gssize to_write
= -1;
312 GSource
*source_a
= NULL
;
313 GSource
*source_b
= NULL
;
314 struct tevent_glib_glue
*glue
= NULL
;
316 glue
= samba_tevent_glib_glue_create(ev
, ev
, g_main_context_default());
317 g_assert(glue
!= NULL
);
322 to_read
= fill_a_pipe(fds
[1]);
323 /* write at higher priority to keep the pipe full... */
324 a
= g_unix_fd_add_full(G_PRIORITY_HIGH
,
330 source_a
= g_source_ref(g_main_context_find_source_by_id(NULL
, a
));
331 /* make sure no 'writes' get dispatched yet */
332 while (tevent_loop_once(ev
));
334 to_read
+= 128 * 1024 * 1024;
335 to_write
= 128 * 1024 * 1024;
336 b
= g_unix_fd_add(fds
[0], G_IO_IN
, read_bytes
, &to_read
);
337 source_b
= g_source_ref(g_main_context_find_source_by_id(NULL
, b
));
339 /* Assuming the kernel isn't internally 'laggy' then there will always
340 * be either data to read or room in which to write. That will keep
341 * the loop running until all data has been read and written.
343 while (to_write
> 0 || to_read
> 0)
345 gssize to_write_was
= to_write
;
346 gssize to_read_was
= to_read
;
348 if (tevent_loop_once(ev
) != 0)
351 /* Since the sources are at different priority, only one of them
352 * should possibly have run.
354 g_assert(to_write
== to_write_was
|| to_read
== to_read_was
);
357 g_assert(to_write
== 0);
358 g_assert(to_read
== 0);
360 /* 'a' is already removed by itself */
361 g_assert(g_source_is_destroyed(source_a
));
362 g_source_unref(source_a
);
364 g_assert(g_source_is_destroyed(source_b
));
365 g_source_unref(source_b
);
367 samba_tevent_glib_glue_quit(glue
);
374 int main(int argc
, const char *argv
[])
377 char *test_argv
[] = {
378 discard_const("test_glib_glue"),
380 discard_const("no-undefined")
382 char **argvp
= test_argv
;
384 g_test_init(&test_argc
, &argvp
, NULL
);
386 ev
= tevent_context_init(NULL
);
391 g_test_add_func("/mainloop/timeouts", test_timeouts
);
392 g_test_add_func("/mainloop/glib_ev_source", test_glib_ev_source
);
393 g_test_add_func("/mainloop/tevent_ev_source", test_tevent_ev_source
);
394 g_test_add_func("/mainloop/unix-fd", test_unix_fd
);