Merge branch 'childless'
[strongswan.git] / src / libcharon / tests / utils / exchange_test_asserts.h
1 /*
2 * Copyright (C) 2016-2017 Tobias Brunner
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 /**
17 * Special assertions using listener_t etc.
18 *
19 * @defgroup exchange_test_asserts exchange_test_asserts
20 * @{ @ingroup test_utils_c
21 */
22
23 #ifndef EXCHANGE_TEST_ASSERTS_H_
24 #define EXCHANGE_TEST_ASSERTS_H_
25
26 #include <bus/listeners/listener.h>
27
28 typedef struct listener_hook_assert_t listener_hook_assert_t;
29 typedef struct listener_message_assert_t listener_message_assert_t;
30 typedef struct listener_message_rule_t listener_message_rule_t;
31 typedef struct ipsec_sas_assert_t ipsec_sas_assert_t;
32
33 struct listener_hook_assert_t {
34
35 /**
36 * Implemented interface
37 */
38 listener_t listener;
39
40 /**
41 * Original source file
42 */
43 const char *file;
44
45 /**
46 * Source line
47 */
48 int line;
49
50 /**
51 * Name of the hook
52 */
53 const char *name;
54
55 /**
56 * Expected number of calls (-1 to ignore)
57 */
58 int expected;
59
60 /**
61 * Number of times the hook was called
62 */
63 int count;
64
65 /**
66 * Expected updown result
67 */
68 bool up;
69
70 /**
71 * Initiator/Inbound SPIs to expect in rekey event
72 */
73 uint64_t spi_old, spi_new;
74 };
75
76 /**
77 * Basic callback for methods on listener_t, counting the number of calls.
78 */
79 bool exchange_test_asserts_hook(listener_t *this);
80
81 /**
82 * Implementation of listener_t::ike_updown.
83 */
84 bool exchange_test_asserts_ike_updown(listener_t *this, ike_sa_t *ike_sa,
85 bool up);
86
87 /**
88 * Implementation of listener_t::child_updown.
89 */
90 bool exchange_test_asserts_child_updown(listener_t *this, ike_sa_t *ike_sa,
91 child_sa_t *child_sa, bool up);
92
93 /**
94 * Implementation of listener_t::ike_rekey.
95 */
96 bool exchange_test_asserts_ike_rekey(listener_t *this, ike_sa_t *old,
97 ike_sa_t *new);
98
99 /**
100 * Implementation of listener_t::child_rekey.
101 */
102 bool exchange_test_asserts_child_rekey(listener_t *this, ike_sa_t *ike_sa,
103 child_sa_t *old, child_sa_t *new);
104
105 /**
106 * Check if a statement evaluates to TRUE, use original source file and line
107 * in the error message if not.
108 *
109 * @param x statement to evaluate
110 * @param l listener providing original source file and line
111 * @param fmt printf format string
112 * @param ... arguments for fmt
113 */
114 #define assert_listener_msg(x, l, fmt, ...) ({ \
115 test_fail_if_worker_failed(); \
116 if (!(x)) \
117 { \
118 test_fail_msg((l)->file, (l)->line, "%s: " fmt, #x, ##__VA_ARGS__); \
119 } \
120 })
121
122 /**
123 * Initialize an assertion that enforces that the given hook was called.
124 * Must be matched by a call to assert_hook().
125 *
126 * @param name name of the hook
127 */
128 #define assert_hook_called(name) \
129 _assert_hook_init(name, exchange_test_asserts_hook, .expected = 1)
130
131 /**
132 * Initialize an assertion that enforces that the given hook was not called.
133 * Must be matched by a call to assert_hook().
134 *
135 * @param name name of the hook
136 */
137 #define assert_hook_not_called(name) \
138 _assert_hook_init(name, exchange_test_asserts_hook, .expected = 0)
139
140 /**
141 * Initialize an assertion that enforces that the given updown hook was called
142 * with the expected result.
143 * Must be matched by a call to assert_hook().
144 *
145 * @param name name of the hook
146 * @param e whether to expect up in the hook to be TRUE or not
147 */
148 #define assert_hook_updown(name, e) \
149 _assert_hook_init(name, \
150 streq(#name, "ike_updown") ? (void*)exchange_test_asserts_ike_updown \
151 : (void*)exchange_test_asserts_child_updown, \
152 .expected = 1, \
153 .up = e, \
154 )
155
156 /**
157 * Initialize an assertion that enforces that the given rekey hook was called
158 * with the SAs with the matching initiator/inbound SPIs.
159 * Must be matched by a call to assert_hook().
160 *
161 * @param name name of the hook
162 * @param old SPI of the old SA
163 * @param new SPI of the new SA
164 */
165 #define assert_hook_rekey(name, old, new) \
166 _assert_hook_init(name, \
167 streq(#name, "ike_rekey") ? (void*)exchange_test_asserts_ike_rekey \
168 : (void*)exchange_test_asserts_child_rekey, \
169 .expected = 1, \
170 .spi_old = old, \
171 .spi_new = new, \
172 )
173
174 /**
175 * Initialize assertions against invocations of listener_t hooks. Each call
176 * must be matched by a call to assert_hook().
177 */
178 #define _assert_hook_init(n, callback, ...) \
179 do { \
180 listener_hook_assert_t _hook_listener = { \
181 .listener = { .n = (void*)callback, }, \
182 .file = __FILE__, \
183 .line = __LINE__, \
184 .name = #n, \
185 ##__VA_ARGS__ \
186 }; \
187 exchange_test_helper->add_listener(exchange_test_helper, &_hook_listener.listener)
188
189 /**
190 * Enforce the most recently initialized hook assertion.
191 */
192 #define assert_hook() \
193 charon->bus->remove_listener(charon->bus, &_hook_listener.listener); \
194 if (_hook_listener.expected > 0) { \
195 if (_hook_listener.count > 0) { \
196 assert_listener_msg(_hook_listener.expected == _hook_listener.count, \
197 &_hook_listener, "hook '%s' was called %d times " \
198 "instead of %d", _hook_listener.name, \
199 _hook_listener.count, _hook_listener.expected); \
200 } else { \
201 assert_listener_msg(_hook_listener.count, &_hook_listener, \
202 "hook '%s' was not called (expected %d)", _hook_listener.name, \
203 _hook_listener.expected); \
204 } \
205 } else if (_hook_listener.expected == 0) { \
206 assert_listener_msg(_hook_listener.count == 0, &_hook_listener, \
207 "hook '%s' was called unexpectedly", _hook_listener.name); \
208 } \
209 } while(FALSE)
210
211 /**
212 * Rules regarding payloads/notifies to expect/not expect in a message
213 */
214 struct listener_message_rule_t {
215
216 /**
217 * Whether the payload/notify is expected in the message, FALSE to fail if
218 * it is found
219 */
220 bool expected;
221
222 /**
223 * Payload type to expect/not expect
224 */
225 payload_type_t payload;
226
227 /**
228 * Notify type to expect/not expect (paylod type does not have to be
229 * specified)
230 */
231 notify_type_t notify;
232 };
233
234 /**
235 * Data used to check plaintext messages via listener_t
236 */
237 struct listener_message_assert_t {
238
239 /**
240 * Implemented interface
241 */
242 listener_t listener;
243
244 /**
245 * Original source file
246 */
247 const char *file;
248
249 /**
250 * Source line
251 */
252 int line;
253
254 /**
255 * Whether to check the next inbound or outbound message
256 */
257 bool incoming;
258
259 /**
260 * Payload count to expect (-1 to ignore the count)
261 */
262 int count;
263
264 /**
265 * Payloads to expect or not expect in a message
266 */
267 listener_message_rule_t *rules;
268
269 /**
270 * Number of rules
271 */
272 int num_rules;
273 };
274
275 /**
276 * Implementation of listener_t::message collecting data and asserting
277 * certain things.
278 */
279 bool exchange_test_asserts_message(listener_t *this, ike_sa_t *ike_sa,
280 message_t *message, bool incoming, bool plain);
281
282 /**
283 * Assert that the next in- or outbound plaintext message is empty.
284 *
285 * @param dir IN or OUT to check the next in- or outbound message
286 */
287 #define assert_message_empty(dir) \
288 _assert_payload(#dir, 0)
289
290 /**
291 * Assert that the next in- or outbound plaintext message contains exactly
292 * one payload of the given type.
293 *
294 * @param dir IN or OUT to check the next in- or outbound message
295 * @param expected expected payload type
296 */
297 #define assert_single_payload(dir, expected) \
298 _assert_payload(#dir, 1, { TRUE, expected, 0 })
299
300 /**
301 * Assert that the next in- or outbound plaintext message contains a payload
302 * of the given type.
303 *
304 * @param dir IN or OUT to check the next in- or outbound message
305 * @param expected expected payload type
306 */
307 #define assert_payload(dir, expected) \
308 _assert_payload(#dir, -1, { TRUE, expected, 0 })
309
310 /**
311 * Assert that the next in- or outbound plaintext message contains no payload
312 * of the given type.
313 *
314 * @param dir IN or OUT to check the next in- or outbound message
315 * @param unexpected not expected payload type
316 */
317 #define assert_no_payload(dir, unexpected) \
318 _assert_payload(#dir, -1, { FALSE, unexpected, 0 })
319
320 /**
321 * Assert that the next in- or outbound plaintext message contains exactly
322 * one notify of the given type.
323 *
324 * @param dir IN or OUT to check the next in- or outbound message
325 * @param expected expected notify type
326 */
327 #define assert_single_notify(dir, expected) \
328 _assert_payload(#dir, 1, { TRUE, 0, expected })
329
330 /**
331 * Assert that the next in- or outbound plaintext message contains a notify
332 * of the given type.
333 *
334 * @param dir IN or OUT to check the next in- or outbound message
335 * @param expected expected notify type
336 */
337 #define assert_notify(dir, expected) \
338 _assert_payload(#dir, -1, { TRUE, 0, expected })
339
340 /**
341 * Assert that the next in- or outbound plaintext message does not contain a
342 * notify of the given type.
343 *
344 * @param dir IN or OUT to check the next in- or outbound message
345 * @param unexpected not expected notify type
346 */
347 #define assert_no_notify(dir, unexpected) \
348 _assert_payload(#dir, -1, { FALSE, 0, unexpected })
349
350 #define _assert_payload(dir, c, ...) ({ \
351 listener_message_rule_t _rules[] = { __VA_ARGS__ }; \
352 listener_message_assert_t _listener = { \
353 .listener = { .message = exchange_test_asserts_message, }, \
354 .file = __FILE__, \
355 .line = __LINE__, \
356 .incoming = streq(dir, "IN") ? TRUE : FALSE, \
357 .count = c, \
358 .rules = _rules, \
359 .num_rules = countof(_rules), \
360 }; \
361 exchange_test_helper->add_listener(exchange_test_helper, &_listener.listener); \
362 })
363
364 /**
365 * Data used to check IPsec SAs
366 */
367 struct ipsec_sas_assert_t {
368
369 /**
370 * Original source file
371 */
372 const char *file;
373
374 /**
375 * Source line
376 */
377 int line;
378
379 /**
380 * IKE_SA that installed the IPsec SAs
381 */
382 ike_sa_t *ike_sa;
383
384 /**
385 * SPIs to check
386 */
387 uint32_t *spis;
388
389 /**
390 * Number of SPIs for IPsec SAs to check
391 */
392 int count;
393 };
394
395 /**
396 * Assert that all given IPsec SAs (and only these) are installed for the given
397 * IKE_SA.
398 */
399 void exchange_test_asserts_ipsec_sas(ipsec_sas_assert_t *sas);
400
401 /**
402 * Assert that the IPsec SAs with the given SPIs (and none other) are currently
403 * installed by the given IKE_SA.
404 *
405 * @param sa IKE_SA
406 * @param ... list of SPIs
407 */
408 #define assert_ipsec_sas_installed(sa, ...) ({ \
409 uint32_t _spis[] = { __VA_ARGS__ }; \
410 ipsec_sas_assert_t _sas_assert = { \
411 .file = __FILE__, \
412 .line = __LINE__, \
413 .ike_sa = sa, \
414 .spis = _spis, \
415 .count = countof(_spis), \
416 }; \
417 exchange_test_asserts_ipsec_sas(&_sas_assert); \
418 })
419
420 #endif /** EXCHANGE_TEST_ASSERTS_H_ @}*/