1/*
2 Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
3
4 This file is part of libzmq, the ZeroMQ core engine in C++.
5
6 libzmq is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License (LGPL) as published
8 by the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 As a special exception, the Contributors give you permission to link
12 this library with independent modules to produce an executable,
13 regardless of the license terms of these independent modules, and to
14 copy and distribute the resulting executable under terms of your choice,
15 provided that you also meet, for each linked independent module, the
16 terms and conditions of the license of that module. An independent
17 module is a module which is not derived from or based on this library.
18 If you modify this library, you must extend this exception to your
19 version of the library.
20
21 libzmq is distributed in the hope that it will be useful, but WITHOUT
22 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
24 License for more details.
25
26 You should have received a copy of the GNU Lesser General Public License
27 along with this program. If not, see <http://www.gnu.org/licenses/>.
28*/
29
30#define __STDC_LIMIT_MACROS // to define SIZE_MAX with older compilers
31#include "testutil.hpp"
32#include "testutil_unity.hpp"
33
34void setUp ()
35{
36}
37
38void tearDown ()
39{
40}
41
42void handler (int timer_id_, void *arg_)
43{
44 (void) timer_id_; // Stop 'unused' compiler warnings
45 *(static_cast<bool *> (arg_)) = true;
46}
47
48int sleep_and_execute (void *timers_)
49{
50 int timeout = zmq_timers_timeout (timers_);
51
52 // Sleep methods are inaccurate, so we sleep in a loop until time arrived
53 while (timeout > 0) {
54 msleep (timeout);
55 timeout = zmq_timers_timeout (timers_);
56 }
57
58 return zmq_timers_execute (timers_);
59}
60
61void test_null_timer_pointers ()
62{
63 void *timers = NULL;
64
65 TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_timers_destroy (&timers));
66
67// TODO this currently triggers an access violation
68#if 0
69 TEST_ASSERT_FAILURE_ERRNO(EFAULT, zmq_timers_destroy (NULL));
70#endif
71
72 const size_t dummy_interval = 100;
73 const int dummy_timer_id = 1;
74
75 TEST_ASSERT_FAILURE_ERRNO (
76 EFAULT, zmq_timers_add (timers, dummy_interval, &handler, NULL));
77 TEST_ASSERT_FAILURE_ERRNO (
78 EFAULT, zmq_timers_add (&timers, dummy_interval, &handler, NULL));
79
80 TEST_ASSERT_FAILURE_ERRNO (EFAULT,
81 zmq_timers_cancel (timers, dummy_timer_id));
82 TEST_ASSERT_FAILURE_ERRNO (EFAULT,
83 zmq_timers_cancel (&timers, dummy_timer_id));
84
85 TEST_ASSERT_FAILURE_ERRNO (
86 EFAULT, zmq_timers_set_interval (timers, dummy_timer_id, dummy_interval));
87 TEST_ASSERT_FAILURE_ERRNO (
88 EFAULT,
89 zmq_timers_set_interval (&timers, dummy_timer_id, dummy_interval));
90
91 TEST_ASSERT_FAILURE_ERRNO (EFAULT,
92 zmq_timers_reset (timers, dummy_timer_id));
93 TEST_ASSERT_FAILURE_ERRNO (EFAULT,
94 zmq_timers_reset (&timers, dummy_timer_id));
95
96 TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_timers_timeout (timers));
97 TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_timers_timeout (&timers));
98
99 TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_timers_execute (timers));
100 TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_timers_execute (&timers));
101}
102
103void test_corner_cases ()
104{
105 void *timers = zmq_timers_new ();
106 TEST_ASSERT_NOT_NULL (timers);
107
108 const size_t dummy_interval = SIZE_MAX;
109 const int dummy_timer_id = 1;
110
111 // attempt to cancel non-existent timer
112 TEST_ASSERT_FAILURE_ERRNO (EINVAL,
113 zmq_timers_cancel (timers, dummy_timer_id));
114
115 // attempt to set interval of non-existent timer
116 TEST_ASSERT_FAILURE_ERRNO (
117 EINVAL, zmq_timers_set_interval (timers, dummy_timer_id, dummy_interval));
118
119 // attempt to reset non-existent timer
120 TEST_ASSERT_FAILURE_ERRNO (EINVAL,
121 zmq_timers_reset (timers, dummy_timer_id));
122
123 // attempt to add NULL handler
124 TEST_ASSERT_FAILURE_ERRNO (
125 EFAULT, zmq_timers_add (timers, dummy_interval, NULL, NULL));
126
127 const int timer_id = TEST_ASSERT_SUCCESS_ERRNO (
128 zmq_timers_add (timers, dummy_interval, handler, NULL));
129
130 // attempt to cancel timer twice
131 // TODO should this case really be an error? canceling twice could be allowed
132 TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_cancel (timers, timer_id));
133
134 TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_timers_cancel (timers, timer_id));
135
136 // timeout without any timers active
137 TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_timers_timeout (timers));
138
139 // cleanup
140 TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_destroy (&timers));
141}
142
143void test_timers ()
144{
145 void *timers = zmq_timers_new ();
146 TEST_ASSERT_NOT_NULL (timers);
147
148 bool timer_invoked = false;
149
150 const unsigned long full_timeout = 100;
151 void *const stopwatch = zmq_stopwatch_start ();
152
153 const int timer_id = TEST_ASSERT_SUCCESS_ERRNO (
154 zmq_timers_add (timers, full_timeout, handler, &timer_invoked));
155
156 // Timer should not have been invoked yet
157 TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_execute (timers));
158
159 if (zmq_stopwatch_intermediate (stopwatch) < full_timeout) {
160 TEST_ASSERT_FALSE (timer_invoked);
161 }
162
163 // Wait half the time and check again
164 long timeout = TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_timeout (timers));
165 msleep (timeout / 2);
166 TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_execute (timers));
167 if (zmq_stopwatch_intermediate (stopwatch) < full_timeout) {
168 TEST_ASSERT_FALSE (timer_invoked);
169 }
170
171 // Wait until the end
172 TEST_ASSERT_SUCCESS_ERRNO (sleep_and_execute (timers));
173 TEST_ASSERT_TRUE (timer_invoked);
174 timer_invoked = false;
175
176 // Wait half the time and check again
177 timeout = TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_timeout (timers));
178 msleep (timeout / 2);
179 TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_execute (timers));
180 if (zmq_stopwatch_intermediate (stopwatch) < 2 * full_timeout) {
181 TEST_ASSERT_FALSE (timer_invoked);
182 }
183
184 // Reset timer and wait half of the time left
185 TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_reset (timers, timer_id));
186 msleep (timeout / 2);
187 TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_execute (timers));
188 if (zmq_stopwatch_stop (stopwatch) < 2 * full_timeout) {
189 TEST_ASSERT_FALSE (timer_invoked);
190 }
191
192 // Wait until the end
193 TEST_ASSERT_SUCCESS_ERRNO (sleep_and_execute (timers));
194 TEST_ASSERT_TRUE (timer_invoked);
195 timer_invoked = false;
196
197 // reschedule
198 TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_set_interval (timers, timer_id, 50));
199 TEST_ASSERT_SUCCESS_ERRNO (sleep_and_execute (timers));
200 TEST_ASSERT_TRUE (timer_invoked);
201 timer_invoked = false;
202
203 // cancel timer
204 timeout = TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_timeout (timers));
205 TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_cancel (timers, timer_id));
206 msleep (timeout * 2);
207 TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_execute (timers));
208 TEST_ASSERT_FALSE (timer_invoked);
209
210 TEST_ASSERT_SUCCESS_ERRNO (zmq_timers_destroy (&timers));
211}
212
213int main ()
214{
215 setup_test_environment ();
216
217 UNITY_BEGIN ();
218 RUN_TEST (test_timers);
219 RUN_TEST (test_null_timer_pointers);
220 RUN_TEST (test_corner_cases);
221 return UNITY_END ();
222}
223