1 /* Copyright (c) 2015-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 #include "lib/log/log.h"
5 #include "test/log_test_helpers.h"
8 * \file log_test_helpers.c
9 * \brief Code to check for expected log messages during testing.
12 static void mock_saving_logv(int severity
, log_domain_mask_t domain
,
13 const char *funcname
, const char *suffix
,
14 const char *format
, va_list ap
)
18 * Smartlist of all the logs we've received since we last set up
21 static smartlist_t
*saved_logs
= NULL
;
23 /** Boolean: should we also send messages to the test-runner? */
24 static int echo_to_real_logs
= 1;
26 /** Record logs at this level or more severe */
27 static int record_logs_at_level
= LOG_ERR
;
29 static int saved_log_level
= 0;
32 * As setup_capture_of_logs, but do not relay log messages into the main
35 * Avoid using this function; use setup_capture_of_logs() instead if you
36 * can. If you must use this function, then make sure you detect any
37 * unexpected log messages, and treat them as test failures. */
39 setup_full_capture_of_logs(int new_level
)
41 setup_capture_of_logs(new_level
);
42 echo_to_real_logs
= 0;
46 * Temporarily capture all the messages logged at severity <b>new_level</b> or
49 * This function does not prevent messages from being sent to the main
53 setup_capture_of_logs(int new_level
)
55 if (saved_log_level
== 0) {
56 saved_log_level
= log_global_min_severity_
;
61 /* Only change the log_global_min_severity_ if we're making things _more_
62 * verbose. Otherwise we could prevent real log messages that the test-
65 if (log_global_min_severity_
< new_level
)
66 log_global_min_severity_
= new_level
;
68 record_logs_at_level
= new_level
;
69 mock_clean_saved_logs();
70 saved_logs
= smartlist_new();
71 MOCK(logv
, mock_saving_logv
);
72 echo_to_real_logs
= 1;
76 * Undo setup_capture_of_logs().
78 * This function is safe to call more than once.
81 teardown_capture_of_logs(void)
85 log_global_min_severity_
= saved_log_level
;
87 mock_clean_saved_logs();
91 * Clear all messages in mock_saved_logs()
94 mock_clean_saved_logs(void)
98 SMARTLIST_FOREACH(saved_logs
, mock_saved_log_entry_t
*, m
,
99 { tor_free(m
->generated_msg
); tor_free(m
); });
100 smartlist_free(saved_logs
);
105 * Return a list of all the messages captured since the last
106 * setup_[full_]capture_of_logs() call. Each log call is recorded as a
107 * mock_saved_log_entry_t.
110 mock_saved_logs(void)
116 mock_saved_log_n_entries(void)
118 return saved_logs
? smartlist_len(saved_logs
) : 0;
122 * Return true iff there is a message recorded by log capture
123 * that is exactly equal to <b>msg</b>
126 mock_saved_log_has_message(const char *msg
)
129 SMARTLIST_FOREACH(saved_logs
, mock_saved_log_entry_t
*, m
,
131 if (msg
&& m
->generated_msg
&&
132 !strcmp(msg
, m
->generated_msg
)) {
142 * Return true iff there is a message recorded by log capture
143 * that contains <b>msg</b> as a substring.
146 mock_saved_log_has_message_containing(const char *msg
)
149 SMARTLIST_FOREACH(saved_logs
, mock_saved_log_entry_t
*, m
,
151 if (msg
&& m
->generated_msg
&&
152 strstr(m
->generated_msg
, msg
)) {
162 * Return true iff there is not a message recorded by log capture
163 * that contains <b>msg</b> as a substring.
166 mock_saved_log_has_message_not_containing(const char *msg
)
170 saved_logs
, mock_saved_log_entry_t
*, m
,
172 if (msg
&& m
->generated_msg
&& strstr(m
->generated_msg
, msg
))
181 /** Return true iff the saved logs have any messages with <b>severity</b> */
183 mock_saved_log_has_severity(int severity
)
187 SMARTLIST_FOREACH(saved_logs
, mock_saved_log_entry_t
*, m
,
189 if (m
->severity
== severity
) {
198 /** Return true iff the the saved logs have at lease one message */
200 mock_saved_log_has_entry(void)
203 return smartlist_len(saved_logs
) > 0;
208 /* Replacement for logv: record the log message, and (maybe) send it
209 * into the logging system again.
212 mock_saving_logv(int severity
, log_domain_mask_t domain
,
213 const char *funcname
, const char *suffix
,
214 const char *format
, va_list ap
)
216 char *buf
= tor_malloc_zero(10240);
218 n
= tor_vsnprintf(buf
,10240,format
,ap
);
219 tor_assert(n
< 10240-1);
223 if (echo_to_real_logs
) {
224 tor_log(severity
, domain
|LD_NO_MOCK
, "%s", buf
);
227 if (severity
> record_logs_at_level
) {
233 saved_logs
= smartlist_new();
235 mock_saved_log_entry_t
*e
= tor_malloc_zero(sizeof(mock_saved_log_entry_t
));
236 e
->severity
= severity
;
237 e
->funcname
= funcname
;
240 e
->generated_msg
= tor_strdup(buf
);
243 smartlist_add(saved_logs
, e
);
247 mock_dump_saved_logs(void)
249 if (saved_logs
== NULL
) {
250 puts(" Captured logs: NULL");
254 puts(" Captured logs:");
255 SMARTLIST_FOREACH_BEGIN(saved_logs
, const mock_saved_log_entry_t
*, m
) {
256 printf("% 5d. %s: %s\n", m_sl_idx
+ 1,
257 log_level_to_string(m
->severity
),
258 escaped(m
->generated_msg
));
259 } SMARTLIST_FOREACH_END(m
);