2 * Copyright (C) 2016-2017 Tobias Brunner
4 * Copyright (C) secunet Security Networks AG
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 * Special assertions using listener_t etc.
20 * @defgroup exchange_test_asserts exchange_test_asserts
21 * @{ @ingroup test_utils_c
24 #ifndef EXCHANGE_TEST_ASSERTS_H_
25 #define EXCHANGE_TEST_ASSERTS_H_
27 #include <bus/listeners/listener.h>
29 typedef struct listener_hook_assert_t listener_hook_assert_t
;
30 typedef struct listener_message_assert_t listener_message_assert_t
;
31 typedef struct listener_message_rule_t listener_message_rule_t
;
32 typedef struct ipsec_sas_assert_t ipsec_sas_assert_t
;
34 struct listener_hook_assert_t
{
37 * Implemented interface
42 * Original source file
57 * Expected number of calls (-1 to ignore)
62 * Number of times the hook was called
67 * Expected updown result
72 * Initiator/Inbound SPIs to expect in rekey event
74 uint64_t spi_old
, spi_new
;
78 * Basic callback for methods on listener_t, counting the number of calls.
80 bool exchange_test_asserts_hook(listener_t
*this);
83 * Implementation of listener_t::ike_updown.
85 bool exchange_test_asserts_ike_updown(listener_t
*this, ike_sa_t
*ike_sa
,
89 * Implementation of listener_t::child_updown.
91 bool exchange_test_asserts_child_updown(listener_t
*this, ike_sa_t
*ike_sa
,
92 child_sa_t
*child_sa
, bool up
);
95 * Implementation of listener_t::ike_rekey.
97 bool exchange_test_asserts_ike_rekey(listener_t
*this, ike_sa_t
*old
,
101 * Implementation of listener_t::child_rekey.
103 bool exchange_test_asserts_child_rekey(listener_t
*this, ike_sa_t
*ike_sa
,
104 child_sa_t
*old
, child_sa_t
*new);
107 * Check if a statement evaluates to TRUE, use original source file and line
108 * in the error message if not.
110 * @param x statement to evaluate
111 * @param l listener providing original source file and line
112 * @param fmt printf format string
113 * @param ... arguments for fmt
115 #define assert_listener_msg(x, l, fmt, ...) ({ \
116 test_fail_if_worker_failed(); \
119 test_fail_msg((l)->file, (l)->line, "%s: " fmt, #x, ##__VA_ARGS__); \
124 * Initialize an assertion that enforces that the given hook was called.
125 * Must be matched by a call to assert_hook().
127 * @param name name of the hook
129 #define assert_hook_called(name) \
130 _assert_hook_init(name, exchange_test_asserts_hook, .expected = 1)
133 * Initialize an assertion that enforces that the given hook was not called.
134 * Must be matched by a call to assert_hook().
136 * @param name name of the hook
138 #define assert_hook_not_called(name) \
139 _assert_hook_init(name, exchange_test_asserts_hook, .expected = 0)
142 * Initialize an assertion that enforces that the given updown hook was called
143 * with the expected result.
144 * Must be matched by a call to assert_hook().
146 * @param name name of the hook
147 * @param e whether to expect up in the hook to be TRUE or not
149 #define assert_hook_updown(name, e) \
150 _assert_hook_init(name, \
151 streq(#name, "ike_updown") ? (void*)exchange_test_asserts_ike_updown \
152 : (void*)exchange_test_asserts_child_updown, \
158 * Initialize an assertion that enforces that the given rekey hook was called
159 * with the SAs with the matching initiator/inbound SPIs.
160 * Must be matched by a call to assert_hook().
162 * @param name name of the hook
163 * @param old SPI of the old SA
164 * @param new SPI of the new SA
166 #define assert_hook_rekey(name, old, new) \
167 _assert_hook_init(name, \
168 streq(#name, "ike_rekey") ? (void*)exchange_test_asserts_ike_rekey \
169 : (void*)exchange_test_asserts_child_rekey, \
176 * Initialize assertions against invocations of listener_t hooks. Each call
177 * must be matched by a call to assert_hook().
179 #define _assert_hook_init(n, callback, ...) \
181 listener_hook_assert_t _hook_listener = { \
182 .listener = { .n = (void*)callback, }, \
188 exchange_test_helper->add_listener(exchange_test_helper, &_hook_listener.listener)
191 * Enforce the most recently initialized hook assertion.
193 #define assert_hook() \
194 charon->bus->remove_listener(charon->bus, &_hook_listener.listener); \
195 if (_hook_listener.expected > 0) { \
196 if (_hook_listener.count > 0) { \
197 assert_listener_msg(_hook_listener.expected == _hook_listener.count, \
198 &_hook_listener, "hook '%s' was called %d times " \
199 "instead of %d", _hook_listener.name, \
200 _hook_listener.count, _hook_listener.expected); \
202 assert_listener_msg(_hook_listener.count, &_hook_listener, \
203 "hook '%s' was not called (expected %d)", _hook_listener.name, \
204 _hook_listener.expected); \
206 } else if (_hook_listener.expected == 0) { \
207 assert_listener_msg(_hook_listener.count == 0, &_hook_listener, \
208 "hook '%s' was called unexpectedly", _hook_listener.name); \
213 * Rules regarding payloads/notifies to expect/not expect in a message
215 struct listener_message_rule_t
{
218 * Whether the payload/notify is expected in the message, FALSE to fail if
224 * Payload type to expect/not expect
226 payload_type_t payload
;
229 * Notify type to expect/not expect (payload type does not have to be
232 notify_type_t notify
;
236 * Data used to check plaintext messages via listener_t
238 struct listener_message_assert_t
{
241 * Implemented interface
246 * Original source file
256 * Whether to check the next inbound or outbound message
261 * Payload count to expect (-1 to ignore the count)
266 * Payloads to expect or not expect in a message
268 listener_message_rule_t
*rules
;
277 * Implementation of listener_t::message collecting data and asserting
280 bool exchange_test_asserts_message(listener_t
*this, ike_sa_t
*ike_sa
,
281 message_t
*message
, bool incoming
, bool plain
);
284 * Assert that the next in- or outbound plaintext message is empty.
286 * @param dir IN or OUT to check the next in- or outbound message
288 #define assert_message_empty(dir) \
289 _assert_payload(#dir, 0)
292 * Assert that the next in- or outbound plaintext message contains exactly
293 * one payload of the given type.
295 * @param dir IN or OUT to check the next in- or outbound message
296 * @param expected expected payload type
298 #define assert_single_payload(dir, expected) \
299 _assert_payload(#dir, 1, { TRUE, expected, 0 })
302 * Assert that the next in- or outbound plaintext message contains a payload
305 * @param dir IN or OUT to check the next in- or outbound message
306 * @param expected expected payload type
308 #define assert_payload(dir, expected) \
309 _assert_payload(#dir, -1, { TRUE, expected, 0 })
312 * Assert that the next in- or outbound plaintext message contains no payload
315 * @param dir IN or OUT to check the next in- or outbound message
316 * @param unexpected not expected payload type
318 #define assert_no_payload(dir, unexpected) \
319 _assert_payload(#dir, -1, { FALSE, unexpected, 0 })
322 * Assert that the next in- or outbound plaintext message contains exactly
323 * one notify of the given type.
325 * @param dir IN or OUT to check the next in- or outbound message
326 * @param expected expected notify type
328 #define assert_single_notify(dir, expected) \
329 _assert_payload(#dir, 1, { TRUE, 0, expected })
332 * Assert that the next in- or outbound plaintext message contains a notify
335 * @param dir IN or OUT to check the next in- or outbound message
336 * @param expected expected notify type
338 #define assert_notify(dir, expected) \
339 _assert_payload(#dir, -1, { TRUE, 0, expected })
342 * Assert that the next in- or outbound plaintext message does not contain a
343 * notify of the given type.
345 * @param dir IN or OUT to check the next in- or outbound message
346 * @param unexpected not expected notify type
348 #define assert_no_notify(dir, unexpected) \
349 _assert_payload(#dir, -1, { FALSE, 0, unexpected })
351 #define _assert_payload(dir, c, ...) ({ \
352 listener_message_rule_t _rules[] = { __VA_ARGS__ }; \
353 listener_message_assert_t _listener = { \
354 .listener = { .message = exchange_test_asserts_message, }, \
357 .incoming = streq(dir, "IN") ? TRUE : FALSE, \
360 .num_rules = countof(_rules), \
362 exchange_test_helper->add_listener(exchange_test_helper, &_listener.listener); \
366 * Data used to check IPsec SAs
368 struct ipsec_sas_assert_t
{
371 * Original source file
381 * IKE_SA that installed the IPsec SAs
391 * Number of SPIs for IPsec SAs to check
397 * Assert that all given IPsec SAs (and only these) are installed for the given
400 void exchange_test_asserts_ipsec_sas(ipsec_sas_assert_t
*sas
);
403 * Assert that the IPsec SAs with the given SPIs (and none other) are currently
404 * installed by the given IKE_SA.
407 * @param ... list of SPIs
409 #define assert_ipsec_sas_installed(sa, ...) ({ \
410 uint32_t _spis[] = { __VA_ARGS__ }; \
411 ipsec_sas_assert_t _sas_assert = { \
416 .count = countof(_spis), \
418 exchange_test_asserts_ipsec_sas(&_sas_assert); \
421 #endif /** EXCHANGE_TEST_ASSERTS_H_ @}*/