libamxrt  0.4.2
Ambiorix Run Time Library
test_amxrt_eloop.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 #include <stdlib.h>
55 #include <stdio.h>
56 #include <setjmp.h>
57 #include <stdarg.h>
58 #include <cmocka.h>
59 #include <string.h>
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 #include <unistd.h>
63 
64 #include <event2/event.h>
65 
66 #include "test_amxrt_eloop.h"
67 #include "amxrt_priv.h"
68 
69 typedef struct _event_cb_fns {
70  event_callback_fn fn;
71  amxc_llist_it_t it;
73 
74 static amxc_llist_t functions;
75 
76 struct event_base* __wrap_event_base_new(void);
77 struct event_base* __real_event_base_new(void);
78 int __wrap_event_base_dispatch(struct event_base* base);
79 int __real_event_base_dispatch(struct event_base* base);
80 int __wrap_event_new(struct event_base* base, evutil_socket_t fd, short events, event_callback_fn callback, void* callback_arg);
81 int __real_event_new(struct event_base* base, evutil_socket_t fd, short events, event_callback_fn callback, void* callback_arg);
82 int __wrap_event_add(struct event* ev, const struct timeval* timeout);
83 int __real_event_add(struct event* ev, const struct timeval* timeout);
84 
85 struct event_base* __wrap_event_base_new(void) {
86  int call = (int) mock();
87  if(call == 0) {
88  return __real_event_base_new();
89  }
90 
91  return NULL;
92 }
93 
94 int __wrap_event_add(struct event* ev, const struct timeval* timeout) {
95  int call = (int) mock();
96  if(call == 0) {
97  return __real_event_add(ev, timeout);
98  }
99  return 0;
100 }
101 
102 int __wrap_event_base_dispatch(struct event_base* base) {
103  int call = (int) mock();
104  if(call == 0) {
106  } else if(call > 0) {
107  amxc_llist_it_t* it = amxc_llist_get_at(&functions, call - 1);
108  if(it != NULL) {
109  event_cb_fns_t* fn = amxc_container_of(it, event_cb_fns_t, it);
110  fn->fn(0, 0, NULL);
111  return 0;
112  } else {
113  return -1;
114  }
115  }
116 
117  return call;
118 }
119 
120 int __wrap_event_new(struct event_base* base, evutil_socket_t fd, short events, event_callback_fn callback, void* callback_arg) {
121  int call = (int) mock();
122 
123  switch(call) {
124  case 0:
125  return __real_event_new(base, fd, events, callback, callback_arg);
126  break;
127  case 1: {
128  event_cb_fns_t* fn = calloc(1, sizeof(event_cb_fns_t));
129  fn->fn = callback;
130  amxc_llist_append(&functions, &fn->it);
131  }
132  break;
133  }
134  return 0;
135 }
136 
137 static void remove_cb_fns(amxc_llist_it_t* it) {
138  event_cb_fns_t* fn = amxc_container_of(it, event_cb_fns_t, it);
139  free(fn);
140 }
141 
142 int test_amxrt_el_setup(UNUSED void** state) {
143  amxc_llist_init(&functions);
144  return 0;
145 }
146 
147 int test_amxrt_el_teardown(UNUSED void** state) {
148  amxd_dm_t* dm = amxrt_get_dm();
149  amxc_llist_clean(&functions, remove_cb_fns);
150 
151  amxd_dm_clean(dm);
152  return 0;
153 }
154 
155 static void test_stop_eventloop(UNUSED amxp_timer_t* timer, void* priv) {
156  int* counter = (int*) priv;
157  assert_int_equal(amxrt_el_stop(), 0);
158  (*counter)++;
159 }
160 
161 static void test_amxp_signal(UNUSED const char* const sig_name,
162  UNUSED const amxc_var_t* const data,
163  void* const priv) {
164  int* counter = (int*) priv;
165  assert_int_equal(amxrt_el_stop(), 0);
166  printf("AMXP-TEST-SIGNAL OK\n");
167  fflush(stdout);
168  (*counter)++;
169 }
170 
171 void test_eventloop_is_working(UNUSED void** state) {
172  amxp_timer_t* timer = NULL;
173  int counter = 0;
174 
175  will_return_always(__wrap_event_base_new, 0);
176  will_return_always(__wrap_event_new, 0);
177  will_return_always(__wrap_event_add, 0);
178  will_return_always(__wrap_event_base_dispatch, 0);
179 
180  amxp_sigmngr_add_signal(NULL, "AMXP-TEST-SIGNAL");
181  amxp_slot_connect(NULL, "AMXP-TEST-SIGNAL", NULL, test_amxp_signal, &counter);
182  amxp_sigmngr_emit_signal(NULL, "AMXP-TEST-SIGNAL", NULL);
183 
184  amxp_timer_new(&timer, test_stop_eventloop, &counter);
185  amxp_timer_start(timer, 1000);
186 
187  printf("Create eventloop\n");
188  fflush(stdout);
189  assert_int_equal(amxrt_el_create(), 0);
190  printf("Start eventloop\n");
191  fflush(stdout);
192  assert_int_equal(amxrt_el_start(), 0);
193  printf("eventloop stopped - because of AMXP-TEST-SIGNAL\n");
194  fflush(stdout);
195  assert_int_equal(counter, 1);
196  printf("Start eventloop\n");
197  fflush(stdout);
198  assert_int_equal(amxrt_el_start(), 0);
199  printf("eventloop stopped - because of timer\n");
200  fflush(stdout);
201  assert_int_equal(counter, 2);
202  assert_int_equal(amxrt_el_destroy(), 0);
203 
204  amxp_timer_delete(&timer);
205 }
206 
207 static void test_reader(int fd, UNUSED void* priv) {
208  char buf[10];
209 
210  printf("Read from file descriptor (%d)\n", fd);
211  fflush(stdout);
212 
213  memset(buf, 0, 10);
214  read(fd, buf, 10);
215  printf("Buffer = %s\n", buf);
216  fflush(stdout);
217 
218  amxrt_el_stop();
219  return;
220 }
221 
222 static void test_add_fd(UNUSED amxp_timer_t* timer, void* priv) {
223  int* fd = (int*) priv;
224 
225  printf("Adding file descriptor (%d) to eventloop\n", *fd);
226  fflush(stdout);
227 
228  amxp_connection_add(*fd, test_reader, "test://127.0.0.1:5001", AMXO_CUSTOM, NULL);
229 }
230 
231 static void test_write_fd(UNUSED amxp_timer_t* timer, void* priv) {
232  int* fd = (int*) priv;
233 
234  printf("Write byte to file descriptor (%d)\n", *fd);
235  fflush(stdout);
236 
237  write(*fd, "A", 1);
238 }
239 
240 void test_can_add_fds(UNUSED void** state) {
241  amxp_timer_t* timer = NULL;
242  amxp_timer_t* timer_write = NULL;
243  int data_pipe[2];
244  int retval = pipe(data_pipe);
245  assert_int_equal(retval, 0);
246 
247  will_return_always(__wrap_event_base_new, 0);
248  will_return_always(__wrap_event_new, 0);
249  will_return_always(__wrap_event_add, 0);
250  will_return_always(__wrap_event_base_dispatch, 0);
251 
252  amxp_sigmngr_add_signal(NULL, "connection-added");
253  amxp_sigmngr_add_signal(NULL, "connection-deleted");
254 
255  amxp_timer_new(&timer, test_add_fd, data_pipe);
256  amxp_timer_start(timer, 1000);
257 
258  amxp_timer_new(&timer_write, test_write_fd, data_pipe + 1);
259  amxp_timer_set_interval(timer_write, 2000);
260  amxp_timer_start(timer_write, 1000);
261 
262  assert_int_equal(amxrt_el_create(), 0);
263  assert_int_equal(amxrt_el_start(), 0);
264 
265  assert_non_null(amxrt_el_get_connection(amxp_connection_get_connections(), data_pipe[0]));
266  assert_null(amxrt_el_get_connection(amxp_connection_get_connections(), data_pipe[1]));
267 
268  assert_int_equal(amxrt_el_destroy(), 0);
269 
270  amxp_timer_delete(&timer);
271  amxp_timer_delete(&timer_write);
272 
273  amxp_connection_remove(data_pipe[0]);
274  amxp_connection_remove(data_pipe[1]);
275 
276  close(data_pipe[0]);
277  close(data_pipe[1]);
278 }
279 
280 void test_can_add_fds_before_el_start(UNUSED void** state) {
281  amxp_timer_t* timer_write = NULL;
282  int data_pipe[2];
283  int retval = pipe(data_pipe);
284  assert_int_equal(retval, 0);
285 
286  will_return_always(__wrap_event_base_new, 0);
287  will_return_always(__wrap_event_new, 0);
288  will_return_always(__wrap_event_add, 0);
289  will_return_always(__wrap_event_base_dispatch, 0);
290 
291  amxp_sigmngr_add_signal(NULL, "connection-added");
292  amxp_sigmngr_add_signal(NULL, "connection-deleted");
293 
294  assert_int_equal(amxrt_el_create(), 0);
295 
296  amxp_timer_new(&timer_write, test_write_fd, data_pipe + 1);
297  amxp_timer_set_interval(timer_write, 2000);
298  amxp_timer_start(timer_write, 1000);
299 
300  printf("Adding connection\n");
301  amxp_connection_add(data_pipe[0], test_reader, "test://127.0.0.1:5001", AMXO_CUSTOM, NULL);
302 
303  assert_int_equal(amxrt_el_start(), 0);
304 
305  assert_non_null(amxrt_el_get_connection(amxp_connection_get_connections(), data_pipe[0]));
306  assert_null(amxrt_el_get_connection(amxp_connection_get_connections(), data_pipe[1]));
307 
308  assert_int_equal(amxrt_el_destroy(), 0);
309 
310  amxp_timer_delete(&timer_write);
311 
312  amxp_connection_remove(data_pipe[0]);
313  amxp_connection_remove(data_pipe[1]);
314 
315  close(data_pipe[0]);
316  close(data_pipe[1]);
317 }
318 
319 static void test_ready_write(int fd, UNUSED void* priv) {
320  printf("READY_WRITE: Write byte to file descriptor (%d)\n", fd);
321  fflush(stdout);
322 
323  write(fd, "BB", 2);
324 }
325 
326 static void test_add_wait_for_write(UNUSED amxp_timer_t* timer, void* priv) {
327  int* fd = (int*) priv;
328  amxp_connection_t* con = amxrt_el_get_connection(amxp_connection_get_connections(), *fd);
329 
330  printf("Adding wait for write descriptor (%d) to eventloop\n", *fd);
331  fflush(stdout);
332  assert_non_null(con->el_data);
333 
334  amxp_connection_wait_write(*fd, test_ready_write);
335 }
336 
337 void test_can_wait_ready_write(UNUSED void** state) {
338  int data_pipe[2];
339  int retval = pipe(data_pipe);
340  assert_int_equal(retval, 0);
341  amxp_timer_t* timer = NULL;
342 
343  will_return_always(__wrap_event_base_new, 0);
344  will_return_always(__wrap_event_new, 0);
345  will_return_always(__wrap_event_add, 0);
346  will_return_always(__wrap_event_base_dispatch, 0);
347 
348  amxp_sigmngr_add_signal(NULL, "connection-wait-write");
349 
350  amxp_connection_add(data_pipe[0], test_reader, "test://127.0.0.1:5001", AMXO_CUSTOM, NULL);
351  amxp_connection_add(data_pipe[1], test_reader, "test://127.0.0.1:5001", AMXO_CUSTOM, NULL);
352 
353  amxp_timer_new(&timer, test_add_wait_for_write, data_pipe + 1);
354  amxp_timer_start(timer, 1000);
355 
356  assert_int_equal(amxrt_el_create(), 0);
357  assert_int_equal(amxrt_el_start(), 0);
358 
359  assert_non_null(amxrt_el_get_connection(amxp_connection_get_connections(), data_pipe[0]));
360  assert_non_null(amxrt_el_get_connection(amxp_connection_get_connections(), data_pipe[1]));
361 
362  assert_int_equal(amxrt_el_destroy(), 0);
363 
364  amxp_connection_remove(data_pipe[0]);
365  amxp_connection_remove(data_pipe[1]);
366 
367  close(data_pipe[0]);
368  close(data_pipe[1]);
369 }
370 
371 static void test_remove_fd(UNUSED amxp_timer_t* timer, void* priv) {
372  int* fd = (int*) priv;
373 
374  printf("Adding file descriptor (%d) to eventloop\n", *fd);
375  fflush(stdout);
376 
377  amxp_connection_remove(*fd);
378  amxrt_el_stop();
379 }
380 
381 void test_can_remove_fds(UNUSED void** state) {
382  amxp_timer_t* timer = NULL;
383  int data_pipe[2];
384  int retval = pipe(data_pipe);
385  assert_int_equal(retval, 0);
386 
387  will_return_always(__wrap_event_base_new, 0);
388  will_return_always(__wrap_event_new, 0);
389  will_return_always(__wrap_event_add, 0);
390  will_return_always(__wrap_event_base_dispatch, 0);
391 
392  amxp_sigmngr_add_signal(NULL, "connection-added");
393  amxp_sigmngr_add_signal(NULL, "connection-deleted");
394 
395  amxp_timer_new(&timer, test_remove_fd, data_pipe);
396  amxp_timer_start(timer, 1000);
397 
398  amxp_connection_add(data_pipe[0], test_reader, "test://127.0.0.1:5001", AMXO_CUSTOM, NULL);
399 
400  assert_int_equal(amxrt_el_create(), 0);
401  assert_int_equal(amxrt_el_start(), 0);
402 
403  assert_null(amxrt_el_get_connection(amxp_connection_get_connections(), data_pipe[0]));
404  assert_null(amxrt_el_get_connection(amxp_connection_get_connections(), data_pipe[1]));
405 
406  assert_int_equal(amxrt_el_destroy(), 0);
407 
408  amxp_timer_delete(&timer);
409 
410  close(data_pipe[0]);
411  close(data_pipe[1]);
412 }
413 
414 void test_can_destroy_el_without_create(UNUSED void** state) {
415  assert_int_equal(amxrt_el_destroy(), 0);
416 }
417 
418 void test_runtime_run_creates_el(UNUSED void** state) {
419  amxp_timer_t* timer = NULL;
420  int counter = 0;
421 
422  amxp_timer_new(&timer, test_stop_eventloop, &counter);
423  amxp_timer_start(timer, 1000);
424 
425  will_return_always(__wrap_event_base_new, 0);
426  will_return_always(__wrap_event_new, 0);
427  will_return_always(__wrap_event_add, 0);
428  will_return_always(__wrap_event_base_dispatch, 0);
429 
430  assert_int_equal(amxrt_el_create(), 0);
431  assert_int_equal(amxrt_run(), 0);
432  assert_int_equal(amxrt_el_destroy(), 0);
433 }
434 
435 void test_eventloop_cbs(UNUSED void** state) {
436  will_return_always(__wrap_event_base_new, 0);
437  will_return_always(__wrap_event_new, 1);
438  will_return_always(__wrap_event_add, 1);
439 
440  assert_int_equal(amxrt_el_create(), 0);
441  will_return(__wrap_event_base_dispatch, 1);
442  assert_int_equal(amxrt_el_start(), 0);
443  will_return(__wrap_event_base_dispatch, 2);
444  assert_int_equal(amxrt_el_start(), 0);
445 
446  assert_int_equal(amxrt_el_destroy(), 0);
447 }
448 
449 void test_eventloop_event_base_new_fails(UNUSED void** state) {
450  will_return_always(__wrap_event_base_new, 1);
451  assert_int_not_equal(amxrt_el_create(), 0);
452  assert_int_not_equal(amxrt_el_start(), 0);
453  assert_int_not_equal(amxrt_el_stop(), 0);
454  assert_int_equal(amxrt_el_destroy(), 0);
455 }
static struct event_base * base
PRIVATE amxp_connection_t * amxrt_el_get_connection(amxc_llist_t *cons, int fd)
int amxrt_el_destroy(void)
Cleans-up the event loop components.
int amxrt_el_start(void)
Starts the event loop.
int amxrt_el_stop(void)
Stops the event loop.
int amxrt_el_create(void)
Creates and initializes all needed event loop components.
int amxrt_run(void)
Starts the event loop.
Definition: amxrt.c:425
amxd_dm_t * amxrt_get_dm(void)
Gets the runtime data model storage.
Definition: amxrt.c:309
amxc_llist_it_t it
event_callback_fn fn
static void test_reader(int fd, UNUSED void *priv)
int test_amxrt_el_setup(UNUSED void **state)
static void test_add_fd(UNUSED amxp_timer_t *timer, void *priv)
void test_can_add_fds_before_el_start(UNUSED void **state)
void test_runtime_run_creates_el(UNUSED void **state)
void test_eventloop_event_base_new_fails(UNUSED void **state)
static void test_add_wait_for_write(UNUSED amxp_timer_t *timer, void *priv)
void test_eventloop_cbs(UNUSED void **state)
static void test_remove_fd(UNUSED amxp_timer_t *timer, void *priv)
static amxc_llist_t functions
int test_amxrt_el_teardown(UNUSED void **state)
static void test_stop_eventloop(UNUSED amxp_timer_t *timer, void *priv)
static void remove_cb_fns(amxc_llist_it_t *it)
static void test_write_fd(UNUSED amxp_timer_t *timer, void *priv)
void test_eventloop_is_working(UNUSED void **state)
static void test_amxp_signal(UNUSED const char *const sig_name, UNUSED const amxc_var_t *const data, void *const priv)
int __real_event_add(struct event *ev, const struct timeval *timeout)
int __wrap_event_add(struct event *ev, const struct timeval *timeout)
struct event_base * __wrap_event_base_new(void)
void test_can_wait_ready_write(UNUSED void **state)
void test_can_destroy_el_without_create(UNUSED void **state)
static void test_ready_write(int fd, UNUSED void *priv)
int __real_event_base_dispatch(struct event_base *base)
void test_can_add_fds(UNUSED void **state)
int __wrap_event_new(struct event_base *base, evutil_socket_t fd, short events, event_callback_fn callback, void *callback_arg)
struct _event_cb_fns event_cb_fns_t
struct event_base * __real_event_base_new(void)
int __real_event_new(struct event_base *base, evutil_socket_t fd, short events, event_callback_fn callback, void *callback_arg)
void test_can_remove_fds(UNUSED void **state)
int __wrap_event_base_dispatch(struct event_base *base)