1 /*
2 Copyright (c) 2017 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 #include <assert.h>
30
31 #include "testutil.hpp"
32 #include "testutil_unity.hpp"
33 #include "testutil_monitoring.hpp"
34
35 #include <unity.h>
36
37 // test behavior with (mostly) default values
reconnect_default()38 void reconnect_default ()
39 {
40 // setup pub socket
41 void *pub = test_context_socket (ZMQ_PUB);
42 // Bind pub socket
43 TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, ENDPOINT_0));
44
45 // setup sub socket
46 void *sub = test_context_socket (ZMQ_SUB);
47 // Monitor all events on sub
48 TEST_ASSERT_SUCCESS_ERRNO (
49 zmq_socket_monitor (sub, "inproc://monitor-sub", ZMQ_EVENT_ALL));
50 // Create socket for collecting monitor events
51 void *sub_mon = test_context_socket (ZMQ_PAIR);
52 // Connect so they'll get events
53 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_mon, "inproc://monitor-sub"));
54 // set reconnect interval so only a single reconnect is tried
55 int interval = 60 * 1000;
56 TEST_ASSERT_SUCCESS_ERRNO (
57 zmq_setsockopt (sub, ZMQ_RECONNECT_IVL, &interval, sizeof (interval)));
58 // connect to pub
59 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, ENDPOINT_0));
60
61 // confirm that we get following events
62 expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);
63 expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECTED);
64 expect_monitor_event (sub_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);
65
66 // close the pub socket
67 test_context_socket_close_zero_linger (pub);
68
69 // confirm that we get following events
70 expect_monitor_event (sub_mon, ZMQ_EVENT_DISCONNECTED);
71 expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_RETRIED);
72
73 // ZMQ_EVENT_CONNECT_RETRIED should be last event, because of timeout set above
74 int event;
75 char *event_address;
76 int rc = get_monitor_event_with_timeout (sub_mon, &event, &event_address,
77 2 * 1000);
78 assert (rc == -1);
79
80 // Close sub
81 // TODO why does this use zero_linger?
82 test_context_socket_close_zero_linger (sub);
83
84 // Close monitor
85 // TODO why does this use zero_linger?
86 test_context_socket_close_zero_linger (sub_mon);
87 }
88
89
90 // test successful reconnect
reconnect_success()91 void reconnect_success ()
92 {
93 // setup pub socket
94 void *pub = test_context_socket (ZMQ_PUB);
95 // Bind pub socket
96 TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, ENDPOINT_0));
97
98 // setup sub socket
99 void *sub = test_context_socket (ZMQ_SUB);
100 // Monitor all events on sub
101 TEST_ASSERT_SUCCESS_ERRNO (
102 zmq_socket_monitor (sub, "inproc://monitor-sub", ZMQ_EVENT_ALL));
103 // Create socket for collecting monitor events
104 void *sub_mon = test_context_socket (ZMQ_PAIR);
105 // Connect so they'll get events
106 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_mon, "inproc://monitor-sub"));
107 // set reconnect interval so only a single reconnect is tried
108 int interval = 1 * 1000;
109 TEST_ASSERT_SUCCESS_ERRNO (
110 zmq_setsockopt (sub, ZMQ_RECONNECT_IVL, &interval, sizeof (interval)));
111 // connect to pub
112 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, ENDPOINT_0));
113
114 // confirm that we get following events
115 expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);
116 expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECTED);
117 expect_monitor_event (sub_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);
118
119 // close the pub socket
120 test_context_socket_close_zero_linger (pub);
121
122 // confirm that we get following events
123 expect_monitor_event (sub_mon, ZMQ_EVENT_DISCONNECTED);
124 expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_RETRIED);
125
126 // ZMQ_EVENT_CONNECT_RETRIED should be last event, because of timeout set above
127 int event;
128 char *event_address;
129 int rc = get_monitor_event_with_timeout (sub_mon, &event, &event_address,
130 SETTLE_TIME);
131 assert (rc == -1);
132
133 // Now re-bind pub socket and wait for re-connect
134 pub = test_context_socket (ZMQ_PUB);
135 TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, ENDPOINT_0));
136 msleep (SETTLE_TIME);
137
138 // confirm that we get following events
139 expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);
140 expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECTED);
141 expect_monitor_event (sub_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);
142
143 // ZMQ_EVENT_HANDSHAKE_SUCCEEDED should be last event
144 rc = get_monitor_event_with_timeout (sub_mon, &event, &event_address,
145 SETTLE_TIME);
146 assert (rc == -1);
147
148 // Close sub
149 // TODO why does this use zero_linger?
150 test_context_socket_close_zero_linger (sub);
151 test_context_socket_close_zero_linger (pub);
152
153 // Close monitor
154 // TODO why does this use zero_linger?
155 test_context_socket_close_zero_linger (sub_mon);
156 }
157
158
159 #ifdef ZMQ_BUILD_DRAFT_API
160 // test stopping reconnect on connection refused
reconnect_stop_on_refused()161 void reconnect_stop_on_refused ()
162 {
163 // setup pub socket
164 void *pub = test_context_socket (ZMQ_PUB);
165 // Bind pub socket
166 TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, ENDPOINT_0));
167
168 // setup sub socket
169 void *sub = test_context_socket (ZMQ_SUB);
170 // Monitor all events on sub
171 TEST_ASSERT_SUCCESS_ERRNO (
172 zmq_socket_monitor (sub, "inproc://monitor-sub", ZMQ_EVENT_ALL));
173 // Create socket for collecting monitor events
174 void *sub_mon = test_context_socket (ZMQ_PAIR);
175 // Connect so they'll get events
176 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_mon, "inproc://monitor-sub"));
177 // set option to stop reconnecting on error
178 int stopReconnectOnError = ZMQ_RECONNECT_STOP_CONN_REFUSED;
179 TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_RECONNECT_STOP,
180 &stopReconnectOnError,
181 sizeof (stopReconnectOnError)));
182 // connect to pub
183 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, ENDPOINT_0));
184
185 // confirm that we get following events
186 expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);
187 expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECTED);
188 expect_monitor_event (sub_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);
189
190 // close the pub socket
191 test_context_socket_close_zero_linger (pub);
192
193 // confirm that we get following events
194 expect_monitor_event (sub_mon, ZMQ_EVENT_DISCONNECTED);
195 expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_RETRIED);
196 expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);
197 expect_monitor_event (sub_mon, ZMQ_EVENT_CLOSED);
198
199 // ZMQ_EVENT_CLOSED should be last event, because of ZMQ_RECONNECT_STOP set above
200 int event = 0;
201 char *event_address;
202 int rc = get_monitor_event_with_timeout (sub_mon, &event, &event_address,
203 2 * 1000);
204 int limit = 0;
205 while ((rc != -1) && (++limit < 1000)) {
206 print_unexpected_event_stderr (event, rc, 0, -1);
207 rc = get_monitor_event_with_timeout (sub_mon, &event, &event_address,
208 2 * 1000);
209 }
210
211 // Close sub
212 // TODO why does this use zero_linger?
213 test_context_socket_close_zero_linger (sub);
214
215 // Close monitor
216 // TODO why does this use zero_linger?
217 test_context_socket_close_zero_linger (sub_mon);
218 }
219 #endif
220
221 #ifdef ZMQ_BUILD_DRAFT_API
222 // test stopping reconnect on connection refused
reconnect_stop_on_handshake_failed()223 void reconnect_stop_on_handshake_failed ()
224 {
225 char bind_address[MAX_SOCKET_STRING];
226 size_t addr_length = sizeof (bind_address);
227 void *dummy = test_context_socket (ZMQ_STREAM);
228 TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (dummy, "tcp://127.0.0.1:0"));
229 TEST_ASSERT_SUCCESS_ERRNO (
230 zmq_getsockopt (dummy, ZMQ_LAST_ENDPOINT, bind_address, &addr_length));
231
232 // setup sub socket
233 void *sub = test_context_socket (ZMQ_SUB);
234 // Monitor all events on sub
235 TEST_ASSERT_SUCCESS_ERRNO (
236 zmq_socket_monitor (sub, "inproc://monitor-sub", ZMQ_EVENT_ALL));
237 // Create socket for collecting monitor events
238 void *sub_mon = test_context_socket (ZMQ_PAIR);
239 // Connect so they'll get events
240 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_mon, "inproc://monitor-sub"));
241 // set handshake interval (i.e., timeout) to a more reasonable value
242 int handshakeInterval = 1000;
243 TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
244 sub, ZMQ_HANDSHAKE_IVL, &handshakeInterval, sizeof (handshakeInterval)));
245 // set option to stop reconnecting on failed handshake
246 int stopReconnectOnError = ZMQ_RECONNECT_STOP_HANDSHAKE_FAILED;
247 TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_RECONNECT_STOP,
248 &stopReconnectOnError,
249 sizeof (stopReconnectOnError)));
250 // connect to dummy stream socket above
251 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, bind_address));
252
253 #if 1
254 // ZMQ_EVENT_DISCONNECTED should be last event, because of ZMQ_RECONNECT_STOP set above
255 expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);
256 expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECTED);
257 expect_monitor_event (sub_mon, ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL);
258 expect_monitor_event (sub_mon, ZMQ_EVENT_DISCONNECTED);
259 #else
260 print_events (sub_mon, 2 * 1000, 1000);
261 #endif
262
263 // Close sub
264 // TODO why does this use zero_linger?
265 test_context_socket_close_zero_linger (sub);
266 test_context_socket_close_zero_linger (dummy);
267
268 // Close monitor
269 // TODO why does this use zero_linger?
270 test_context_socket_close_zero_linger (sub_mon);
271 }
272 #endif
273
setUp()274 void setUp ()
275 {
276 setup_test_context ();
277 }
278
tearDown()279 void tearDown ()
280 {
281 teardown_test_context ();
282 }
283
main(void)284 int main (void)
285 {
286 setup_test_environment ();
287
288 UNITY_BEGIN ();
289
290 RUN_TEST (reconnect_default);
291 RUN_TEST (reconnect_success);
292 #ifdef ZMQ_BUILD_DRAFT_API
293 RUN_TEST (reconnect_stop_on_refused);
294 RUN_TEST (reconnect_stop_on_handshake_failed);
295 #endif
296 return UNITY_END ();
297 }
298