1 /*
2 Copyright (c) 2007-2019 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 "testutil_unity.hpp"
30
31 #include <stdlib.h>
32 #include <string.h>
33
34 #ifdef _WIN32
35 #include <direct.h>
36 #else
37 #include <unistd.h>
38 #endif
39
test_assert_success_message_errno_helper(int rc_,const char * msg_,const char * expr_,int line_)40 int test_assert_success_message_errno_helper (int rc_,
41 const char *msg_,
42 const char *expr_,
43 int line_)
44 {
45 if (rc_ == -1) {
46 char buffer[512];
47 buffer[sizeof (buffer) - 1] =
48 0; // to ensure defined behavior with VC++ <= 2013
49 snprintf (buffer, sizeof (buffer) - 1,
50 "%s failed%s%s%s, errno = %i (%s)", expr_,
51 msg_ ? " (additional info: " : "", msg_ ? msg_ : "",
52 msg_ ? ")" : "", zmq_errno (), zmq_strerror (zmq_errno ()));
53 UNITY_TEST_FAIL (line_, buffer);
54 }
55 return rc_;
56 }
57
test_assert_success_message_raw_errno_helper(int rc_,const char * msg_,const char * expr_,int line_,bool zero)58 int test_assert_success_message_raw_errno_helper (
59 int rc_, const char *msg_, const char *expr_, int line_, bool zero)
60 {
61 if (rc_ == -1 || (zero && rc_ != 0)) {
62 #if defined ZMQ_HAVE_WINDOWS
63 int current_errno = WSAGetLastError ();
64 #else
65 int current_errno = errno;
66 #endif
67
68 char buffer[512];
69 buffer[sizeof (buffer) - 1] =
70 0; // to ensure defined behavior with VC++ <= 2013
71 snprintf (
72 buffer, sizeof (buffer) - 1, "%s failed%s%s%s with %d, errno = %i/%s",
73 expr_, msg_ ? " (additional info: " : "", msg_ ? msg_ : "",
74 msg_ ? ")" : "", rc_, current_errno, strerror (current_errno));
75 UNITY_TEST_FAIL (line_, buffer);
76 }
77 return rc_;
78 }
79
test_assert_success_message_raw_zero_errno_helper(int rc_,const char * msg_,const char * expr_,int line_)80 int test_assert_success_message_raw_zero_errno_helper (int rc_,
81 const char *msg_,
82 const char *expr_,
83 int line_)
84 {
85 return test_assert_success_message_raw_errno_helper (rc_, msg_, expr_,
86 line_, true);
87 }
88
test_assert_failure_message_raw_errno_helper(int rc_,int expected_errno_,const char * msg_,const char * expr_,int line_)89 int test_assert_failure_message_raw_errno_helper (
90 int rc_, int expected_errno_, const char *msg_, const char *expr_, int line_)
91 {
92 char buffer[512];
93 buffer[sizeof (buffer) - 1] =
94 0; // to ensure defined behavior with VC++ <= 2013
95 if (rc_ != -1) {
96 snprintf (buffer, sizeof (buffer) - 1,
97 "%s was unexpectedly successful%s%s%s, expected "
98 "errno = %i, actual return value = %i",
99 expr_, msg_ ? " (additional info: " : "", msg_ ? msg_ : "",
100 msg_ ? ")" : "", expected_errno_, rc_);
101 UNITY_TEST_FAIL (line_, buffer);
102 } else {
103 #if defined ZMQ_HAVE_WINDOWS
104 int current_errno = WSAGetLastError ();
105 #else
106 int current_errno = errno;
107 #endif
108 if (current_errno != expected_errno_) {
109 snprintf (buffer, sizeof (buffer) - 1,
110 "%s failed with an unexpected error%s%s%s, expected "
111 "errno = %i, actual errno = %i",
112 expr_, msg_ ? " (additional info: " : "",
113 msg_ ? msg_ : "", msg_ ? ")" : "", expected_errno_,
114 current_errno);
115 UNITY_TEST_FAIL (line_, buffer);
116 }
117 }
118 return rc_;
119 }
120
send_string_expect_success(void * socket_,const char * str_,int flags_)121 void send_string_expect_success (void *socket_, const char *str_, int flags_)
122 {
123 const size_t len = str_ ? strlen (str_) : 0;
124 const int rc = zmq_send (socket_, str_, len, flags_);
125 TEST_ASSERT_EQUAL_INT ((int) len, rc);
126 }
127
recv_string_expect_success(void * socket_,const char * str_,int flags_)128 void recv_string_expect_success (void *socket_, const char *str_, int flags_)
129 {
130 const size_t len = str_ ? strlen (str_) : 0;
131 char buffer[255];
132 TEST_ASSERT_LESS_OR_EQUAL_MESSAGE (sizeof (buffer), len,
133 "recv_string_expect_success cannot be "
134 "used for strings longer than 255 "
135 "characters");
136
137 const int rc = TEST_ASSERT_SUCCESS_ERRNO (
138 zmq_recv (socket_, buffer, sizeof (buffer), flags_));
139 TEST_ASSERT_EQUAL_INT ((int) len, rc);
140 if (str_)
141 TEST_ASSERT_EQUAL_STRING_LEN (str_, buffer, len);
142 }
143
internal_manage_test_context(bool init_,bool clear_)144 static void *internal_manage_test_context (bool init_, bool clear_)
145 {
146 static void *test_context = NULL;
147 if (clear_) {
148 TEST_ASSERT_NOT_NULL (test_context);
149 TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_term (test_context));
150 test_context = NULL;
151 } else {
152 if (init_) {
153 TEST_ASSERT_NULL (test_context);
154 test_context = zmq_ctx_new ();
155 TEST_ASSERT_NOT_NULL (test_context);
156 }
157 }
158 return test_context;
159 }
160
internal_manage_test_sockets(void * socket_,bool add_)161 static void internal_manage_test_sockets (void *socket_, bool add_)
162 {
163 static void *test_sockets[MAX_TEST_SOCKETS];
164 static size_t test_socket_count = 0;
165 if (!socket_) {
166 TEST_ASSERT_FALSE (add_);
167
168 // force-close all sockets
169 if (test_socket_count) {
170 for (size_t i = 0; i < test_socket_count; ++i) {
171 close_zero_linger (test_sockets[i]);
172 }
173 fprintf (stderr,
174 "WARNING: Forced closure of %i sockets, this is an "
175 "implementation error unless the test case failed\n",
176 static_cast<int> (test_socket_count));
177 test_socket_count = 0;
178 }
179 } else {
180 if (add_) {
181 ++test_socket_count;
182 TEST_ASSERT_LESS_THAN_MESSAGE (MAX_TEST_SOCKETS, test_socket_count,
183 "MAX_TEST_SOCKETS must be "
184 "increased, or you cannot use the "
185 "test context");
186 test_sockets[test_socket_count - 1] = socket_;
187 } else {
188 bool found = false;
189 for (size_t i = 0; i < test_socket_count; ++i) {
190 if (test_sockets[i] == socket_) {
191 found = true;
192 }
193 if (found) {
194 if (i < test_socket_count)
195 test_sockets[i] = test_sockets[i + 1];
196 }
197 }
198 TEST_ASSERT_TRUE_MESSAGE (found,
199 "Attempted to close a socket that was "
200 "not created by test_context_socket");
201 --test_socket_count;
202 }
203 }
204 }
205
setup_test_context()206 void setup_test_context ()
207 {
208 internal_manage_test_context (true, false);
209 }
210
get_test_context()211 void *get_test_context ()
212 {
213 return internal_manage_test_context (false, false);
214 }
215
teardown_test_context()216 void teardown_test_context ()
217 {
218 // this condition allows an explicit call to teardown_test_context from a
219 // test. if this is never used, it should probably be removed, to detect
220 // misuses
221 if (get_test_context ()) {
222 internal_manage_test_sockets (NULL, false);
223 internal_manage_test_context (false, true);
224 }
225 }
226
test_context_socket(int type_)227 void *test_context_socket (int type_)
228 {
229 void *const socket = zmq_socket (get_test_context (), type_);
230 TEST_ASSERT_NOT_NULL (socket);
231 internal_manage_test_sockets (socket, true);
232 return socket;
233 }
234
test_context_socket_close(void * socket_)235 void *test_context_socket_close (void *socket_)
236 {
237 TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket_));
238 internal_manage_test_sockets (socket_, false);
239 return socket_;
240 }
241
test_context_socket_close_zero_linger(void * socket_)242 void *test_context_socket_close_zero_linger (void *socket_)
243 {
244 const int linger = 0;
245 int rc = zmq_setsockopt (socket_, ZMQ_LINGER, &linger, sizeof (linger));
246 TEST_ASSERT_TRUE (rc == 0 || zmq_errno () == ETERM);
247 return test_context_socket_close (socket_);
248 }
249
test_bind(void * socket_,const char * bind_address_,char * my_endpoint_,size_t len_)250 void test_bind (void *socket_,
251 const char *bind_address_,
252 char *my_endpoint_,
253 size_t len_)
254 {
255 TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (socket_, bind_address_));
256 TEST_ASSERT_SUCCESS_ERRNO (
257 zmq_getsockopt (socket_, ZMQ_LAST_ENDPOINT, my_endpoint_, &len_));
258 }
259
bind_loopback(void * socket_,int ipv6_,char * my_endpoint_,size_t len_)260 void bind_loopback (void *socket_, int ipv6_, char *my_endpoint_, size_t len_)
261 {
262 if (ipv6_ && !is_ipv6_available ()) {
263 TEST_IGNORE_MESSAGE ("ipv6 is not available");
264 }
265
266 TEST_ASSERT_SUCCESS_ERRNO (
267 zmq_setsockopt (socket_, ZMQ_IPV6, &ipv6_, sizeof (int)));
268
269 test_bind (socket_, ipv6_ ? "tcp://[::1]:*" : "tcp://127.0.0.1:*",
270 my_endpoint_, len_);
271 }
272
bind_loopback_ipv4(void * socket_,char * my_endpoint_,size_t len_)273 void bind_loopback_ipv4 (void *socket_, char *my_endpoint_, size_t len_)
274 {
275 bind_loopback (socket_, false, my_endpoint_, len_);
276 }
277
bind_loopback_ipv6(void * socket_,char * my_endpoint_,size_t len_)278 void bind_loopback_ipv6 (void *socket_, char *my_endpoint_, size_t len_)
279 {
280 bind_loopback (socket_, true, my_endpoint_, len_);
281 }
282
bind_loopback_ipc(void * socket_,char * my_endpoint_,size_t len_)283 void bind_loopback_ipc (void *socket_, char *my_endpoint_, size_t len_)
284 {
285 if (!zmq_has ("ipc")) {
286 TEST_IGNORE_MESSAGE ("ipc is not available");
287 }
288
289 test_bind (socket_, "ipc://*", my_endpoint_, len_);
290 }
291
bind_loopback_tipc(void * socket_,char * my_endpoint_,size_t len_)292 void bind_loopback_tipc (void *socket_, char *my_endpoint_, size_t len_)
293 {
294 if (!is_tipc_available ()) {
295 TEST_IGNORE_MESSAGE ("tipc is not available");
296 }
297
298 test_bind (socket_, "tipc://<*>", my_endpoint_, len_);
299 }
300
301 #if defined(ZMQ_HAVE_IPC)
make_random_ipc_endpoint(char * out_endpoint_)302 void make_random_ipc_endpoint (char *out_endpoint_)
303 {
304 #ifdef ZMQ_HAVE_WINDOWS
305 char random_file[MAX_PATH];
306
307 {
308 const errno_t rc = tmpnam_s (random_file);
309 TEST_ASSERT_EQUAL (0, rc);
310 }
311
312 // TODO or use CreateDirectoryA and specify permissions?
313 const int rc = _mkdir (random_file);
314 TEST_ASSERT_EQUAL (0, rc);
315
316 strcat (random_file, "/ipc");
317
318 #else
319 char random_file[16];
320 strcpy (random_file, "tmpXXXXXX");
321
322 #ifdef HAVE_MKDTEMP
323 TEST_ASSERT_TRUE (mkdtemp (random_file));
324 strcat (random_file, "/ipc");
325 #else
326 int fd = mkstemp (random_file);
327 TEST_ASSERT_TRUE (fd != -1);
328 close (fd);
329 #endif
330 #endif
331
332 strcpy (out_endpoint_, "ipc://");
333 strcat (out_endpoint_, random_file);
334 }
335 #endif
336