samba-tool/backup: set the right permissions on our root dir
[samba.git] / source3 / lib / tevent_glib_glue_tests.c
blobd6cf66462f6e05b67f0b2d58d3b6c92b424cc1e6
1 /*
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
13 ** under the LGPL
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/>.
29 #include "replace.h"
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.
35 #undef TRUE
36 #undef FALSE
37 #include <glib.h>
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;
51 (*i)++;
53 return TRUE;
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;
71 gint a;
72 gint b;
73 gint c;
75 a = b = c = 0;
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);
115 TALLOC_FREE(glue);
116 g_main_context_unref(ctx);
119 struct test_glib_ev_source_data {
120 GMainContext *ctx;
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,
135 state,
136 NULL);
137 g_source_attach(source, state->ctx);
138 g_source_unref(source);
140 return TRUE;
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);
169 state->ctx = ctx;
170 state->glue = glue;
172 source = g_timeout_source_new(100);
173 g_source_set_callback(source,
174 test_glib_ev_source_timeout_cb,
175 state,
176 NULL);
177 g_source_attach(source, ctx);
178 g_source_unref(source);
180 g_assert(tevent_loop_wait(ev) == 0);
182 TALLOC_FREE(glue);
183 g_main_context_unref(ctx);
186 struct test_tevent_ev_source_data {
187 GMainContext *ctx;
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,
196 void *data)
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,
205 state,
206 NULL);
207 g_source_attach(source, state->ctx);
208 g_source_unref(source);
210 return;
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);
239 state->ctx = ctx;
240 state->glue = glue;
242 timer = tevent_add_timer(ev,
243 state,
244 tevent_timeval_current_ofs(0, 1000),
245 test_tevent_ev_source_timeout_cb,
246 state);
247 g_assert(timer != NULL);
249 g_assert(tevent_loop_wait(ev) == 0);
251 TALLOC_FREE(glue);
252 g_main_context_unref(ctx);
255 static gchar zeros[1024];
257 static gsize fill_a_pipe(gint fd)
259 gsize written = 0;
260 GPollFD pfd;
262 pfd.fd = 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);
268 return written;
271 static gboolean write_bytes(gint fd,
272 GIOCondition condition,
273 gpointer user_data)
275 gssize *to_write = user_data;
276 gint limit;
278 if (*to_write == 0)
279 return FALSE;
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);
287 return TRUE;
290 static gboolean read_bytes(gint fd,
291 GIOCondition condition,
292 gpointer user_data)
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.
302 return TRUE;
305 static void test_unix_fd(void)
307 gssize to_write = -1;
308 gssize to_read;
309 gint fds[2];
310 gint a, b;
311 gint s;
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);
319 s = pipe(fds);
320 g_assert(s == 0);
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,
325 fds[1],
326 G_IO_OUT,
327 write_bytes,
328 &to_write,
329 NULL);
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)
349 break;
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);
363 g_source_remove(b);
364 g_assert(g_source_is_destroyed(source_b));
365 g_source_unref(source_b);
367 samba_tevent_glib_glue_quit(glue);
368 TALLOC_FREE(glue);
370 close(fds[1]);
371 close(fds[0]);
374 int main(int argc, const char *argv[])
376 int test_argc = 3;
377 char *test_argv[] = {
378 discard_const("test_glib_glue"),
379 discard_const("-m"),
380 discard_const("no-undefined")
382 char **argvp = test_argv;
384 g_test_init(&test_argc, &argvp, NULL);
386 ev = tevent_context_init(NULL);
387 if (ev == NULL) {
388 exit(1);
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);
396 return g_test_run();