1#include <gtest/gtest.h>
2#include <pthread.h>
3#include <sys/eventfd.h>
4#include <sys/time.h>
5#include <unistd.h>
6
7#include "AllocationTestHarness.h"
8
9extern "C" {
10#include "reactor.h"
11}
12
13class ReactorTest : public AllocationTestHarness {};
14
15static pthread_t thread;
16static volatile bool thread_running;
17
18static void *reactor_thread(void *ptr) {
19  reactor_t *reactor = (reactor_t *)ptr;
20
21  thread_running = true;
22  reactor_start(reactor);
23  thread_running = false;
24
25  return NULL;
26}
27
28static void spawn_reactor_thread(reactor_t *reactor) {
29  int ret = pthread_create(&thread, NULL, reactor_thread, reactor);
30  EXPECT_EQ(ret, 0);
31}
32
33static void join_reactor_thread() {
34  pthread_join(thread, NULL);
35}
36
37TEST_F(ReactorTest, reactor_new) {
38  reactor_t *reactor = reactor_new();
39  EXPECT_TRUE(reactor != NULL);
40  reactor_free(reactor);
41}
42
43TEST_F(ReactorTest, reactor_free_null) {
44  reactor_free(NULL);
45}
46
47TEST_F(ReactorTest, reactor_stop_start) {
48  reactor_t *reactor = reactor_new();
49  reactor_stop(reactor);
50  reactor_start(reactor);
51  reactor_free(reactor);
52}
53
54TEST_F(ReactorTest, reactor_repeated_stop_start) {
55  reactor_t *reactor = reactor_new();
56  for (int i = 0; i < 10; ++i) {
57    reactor_stop(reactor);
58    reactor_start(reactor);
59  }
60  reactor_free(reactor);
61}
62
63TEST_F(ReactorTest, reactor_start_wait_stop) {
64  reactor_t *reactor = reactor_new();
65
66  spawn_reactor_thread(reactor);
67  usleep(50 * 1000);
68  EXPECT_TRUE(thread_running);
69
70  reactor_stop(reactor);
71  join_reactor_thread();
72  EXPECT_FALSE(thread_running);
73
74  reactor_free(reactor);
75}
76
77typedef struct {
78  reactor_t *reactor;
79  reactor_object_t *object;
80} unregister_arg_t;
81
82static void unregister_cb(void *context) {
83  unregister_arg_t *arg = (unregister_arg_t *)context;
84  reactor_unregister(arg->object);
85  reactor_stop(arg->reactor);
86}
87
88TEST_F(ReactorTest, reactor_unregister_from_callback) {
89  reactor_t *reactor = reactor_new();
90
91  int fd = eventfd(0, 0);
92  unregister_arg_t arg;
93  arg.reactor = reactor;
94  arg.object = reactor_register(reactor, fd, &arg, unregister_cb, NULL);
95  spawn_reactor_thread(reactor);
96  eventfd_write(fd, 1);
97
98  join_reactor_thread();
99
100  close(fd);
101  reactor_free(reactor);
102}
103
104TEST_F(ReactorTest, reactor_unregister_from_separate_thread) {
105  reactor_t *reactor = reactor_new();
106
107  int fd = eventfd(0, 0);
108
109  reactor_object_t *object = reactor_register(reactor, fd, NULL, NULL, NULL);
110  spawn_reactor_thread(reactor);
111  usleep(50 * 1000);
112  reactor_unregister(object);
113
114  reactor_stop(reactor);
115  join_reactor_thread();
116
117  close(fd);
118  reactor_free(reactor);
119}
120