/src/pigeonhole/src/testsuite/testsuite-log.c
Line | Count | Source |
1 | | /* Copyright (c) Pigeonhole authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "str.h" |
5 | | #include "array.h" |
6 | | |
7 | | #include "sieve-common.h" |
8 | | #include "sieve-stringlist.h" |
9 | | #include "sieve-error-private.h" |
10 | | |
11 | | #include "testsuite-common.h" |
12 | | #include "testsuite-log.h" |
13 | | |
14 | | /* |
15 | | * Configuration |
16 | | */ |
17 | | |
18 | | bool _testsuite_log_stdout = FALSE; |
19 | | |
20 | | /* |
21 | | * Testsuite log error handlers |
22 | | */ |
23 | | |
24 | | struct sieve_error_handler *testsuite_log_ehandler = NULL; |
25 | | struct sieve_error_handler *testsuite_log_main_ehandler = NULL; |
26 | | |
27 | | struct _testsuite_log_message { |
28 | | const char *location; |
29 | | const char *message; |
30 | | }; |
31 | | |
32 | | static pool_t _testsuite_logmsg_pool = NULL; |
33 | | ARRAY(struct _testsuite_log_message) _testsuite_log_errors; |
34 | | ARRAY(struct _testsuite_log_message) _testsuite_log_warnings; |
35 | | ARRAY(struct _testsuite_log_message) _testsuite_log_messages; |
36 | | |
37 | | static inline void |
38 | | _testsuite_stdout_log(const struct sieve_error_params *params, |
39 | | const char *prefix, const char *message) |
40 | 0 | { |
41 | 0 | if (_testsuite_log_stdout) { |
42 | 0 | if (params->location == NULL || *params->location == '\0') { |
43 | 0 | fprintf(stdout, "LOG: %s: %s\n", |
44 | 0 | prefix, message); |
45 | 0 | } else { |
46 | 0 | fprintf(stdout, "LOG: %s: %s: %s\n", |
47 | 0 | params->location, prefix, message); |
48 | 0 | } |
49 | 0 | } |
50 | 0 | } |
51 | | |
52 | | static void |
53 | | _testsuite_log(struct sieve_error_handler *ehandler ATTR_UNUSED, |
54 | | const struct sieve_error_params *params, |
55 | | enum sieve_error_flags flags ATTR_UNUSED, const char *message) |
56 | 0 | { |
57 | 0 | pool_t pool = _testsuite_logmsg_pool; |
58 | 0 | struct _testsuite_log_message msg; |
59 | 0 | const char *prefix; |
60 | |
|
61 | 0 | switch (params->log_type) { |
62 | 0 | case LOG_TYPE_ERROR: |
63 | 0 | prefix = "error"; |
64 | 0 | break; |
65 | 0 | case LOG_TYPE_WARNING: |
66 | 0 | prefix = "warning"; |
67 | 0 | break; |
68 | 0 | case LOG_TYPE_INFO: |
69 | 0 | prefix = "info"; |
70 | 0 | break; |
71 | 0 | case LOG_TYPE_DEBUG: |
72 | 0 | prefix = "debug"; |
73 | 0 | break; |
74 | 0 | default: |
75 | 0 | i_unreached(); |
76 | 0 | } |
77 | | |
78 | 0 | _testsuite_stdout_log(params, prefix, message); |
79 | |
|
80 | 0 | msg.location = p_strdup(pool, params->location); |
81 | 0 | msg.message = p_strdup(pool, message); |
82 | |
|
83 | 0 | switch (params->log_type) { |
84 | 0 | case LOG_TYPE_ERROR: |
85 | 0 | array_append(&_testsuite_log_errors, &msg, 1); |
86 | 0 | break; |
87 | 0 | case LOG_TYPE_WARNING: |
88 | 0 | array_append(&_testsuite_log_warnings, &msg, 1); |
89 | 0 | break; |
90 | 0 | case LOG_TYPE_INFO: |
91 | 0 | array_append(&_testsuite_log_messages, &msg, 1); |
92 | 0 | break; |
93 | 0 | case LOG_TYPE_DEBUG: |
94 | 0 | break; |
95 | 0 | default: |
96 | 0 | i_unreached(); |
97 | 0 | } |
98 | 0 | } |
99 | | |
100 | | static void |
101 | | _testsuite_main_log(struct sieve_error_handler *ehandler, |
102 | | const struct sieve_error_params *params, |
103 | | enum sieve_error_flags flags, const char *message) |
104 | 0 | { |
105 | 0 | if (params->log_type != LOG_TYPE_ERROR) |
106 | 0 | return _testsuite_log(ehandler, params, flags, message); |
107 | | |
108 | 0 | if (testsuite_silent) |
109 | 0 | return; |
110 | 0 | if (params->location == NULL || *params->location == '\0') |
111 | 0 | fprintf(stderr, "error: %s\n", message); |
112 | 0 | else |
113 | 0 | fprintf(stderr, "%s: error: %s\n", params->location, message); |
114 | 0 | } |
115 | | |
116 | | static struct sieve_error_handler *_testsuite_log_ehandler_create(void) |
117 | 0 | { |
118 | 0 | pool_t pool; |
119 | 0 | struct sieve_error_handler *ehandler; |
120 | |
|
121 | 0 | pool = pool_alloconly_create("testsuite_log_ehandler", |
122 | 0 | sizeof(struct sieve_error_handler)); |
123 | 0 | ehandler = p_new(pool, struct sieve_error_handler, 1); |
124 | 0 | sieve_error_handler_init(ehandler, testsuite_sieve_instance, pool, 0); |
125 | |
|
126 | 0 | ehandler->log = _testsuite_log; |
127 | |
|
128 | 0 | return ehandler; |
129 | 0 | } |
130 | | |
131 | | static struct sieve_error_handler *_testsuite_log_main_ehandler_create(void) |
132 | 0 | { |
133 | 0 | pool_t pool; |
134 | 0 | struct sieve_error_handler *ehandler; |
135 | |
|
136 | 0 | pool = pool_alloconly_create("testsuite_log_main_ehandler", |
137 | 0 | sizeof(struct sieve_error_handler)); |
138 | 0 | ehandler = p_new(pool, struct sieve_error_handler, 1); |
139 | 0 | sieve_error_handler_init(ehandler, testsuite_sieve_instance, pool, 0); |
140 | |
|
141 | 0 | ehandler->log = _testsuite_main_log; |
142 | |
|
143 | 0 | return ehandler; |
144 | 0 | } |
145 | | |
146 | | static void ATTR_FORMAT(2, 0) |
147 | | testsuite_error_handler(const struct failure_context *ctx, const char *fmt, |
148 | | va_list args) |
149 | 0 | { |
150 | 0 | struct sieve_error_params params = { |
151 | 0 | .location = NULL, |
152 | 0 | }; |
153 | 0 | pool_t pool = _testsuite_logmsg_pool; |
154 | 0 | struct _testsuite_log_message msg; |
155 | |
|
156 | 0 | i_zero(&msg); |
157 | 0 | switch (ctx->type) { |
158 | 0 | case LOG_TYPE_DEBUG: |
159 | 0 | T_BEGIN { |
160 | 0 | _testsuite_stdout_log(¶ms, "debug", |
161 | 0 | t_strdup_vprintf(fmt, args)); |
162 | 0 | } T_END; |
163 | 0 | break; |
164 | 0 | case LOG_TYPE_INFO: |
165 | 0 | msg.message = p_strdup_vprintf(pool, fmt, args); |
166 | 0 | array_append(&_testsuite_log_messages, &msg, 1); |
167 | |
|
168 | 0 | _testsuite_stdout_log(¶ms, "info", msg.message); |
169 | 0 | break; |
170 | 0 | case LOG_TYPE_WARNING: |
171 | 0 | msg.message = p_strdup_vprintf(pool, fmt, args); |
172 | 0 | array_append(&_testsuite_log_warnings, &msg, 1); |
173 | |
|
174 | 0 | _testsuite_stdout_log(¶ms, "warning", msg.message); |
175 | 0 | break; |
176 | 0 | case LOG_TYPE_ERROR: |
177 | 0 | msg.message = p_strdup_vprintf(pool, fmt, args); |
178 | 0 | array_append(&_testsuite_log_errors, &msg, 1); |
179 | |
|
180 | 0 | _testsuite_stdout_log(¶ms, "error", msg.message); |
181 | 0 | break; |
182 | 0 | default: |
183 | 0 | default_error_handler(ctx, fmt, args); |
184 | 0 | break; |
185 | 0 | } |
186 | 0 | } |
187 | | |
188 | | /* |
189 | | * |
190 | | */ |
191 | | |
192 | | void testsuite_log_clear_messages(void) |
193 | 0 | { |
194 | 0 | if (_testsuite_logmsg_pool != NULL) { |
195 | 0 | if (array_count(&_testsuite_log_errors) == 0) |
196 | 0 | return; |
197 | 0 | pool_unref(&_testsuite_logmsg_pool); |
198 | 0 | } |
199 | | |
200 | 0 | _testsuite_logmsg_pool = |
201 | 0 | pool_alloconly_create("testsuite_log_messages", 8192); |
202 | |
|
203 | 0 | p_array_init(&_testsuite_log_errors, _testsuite_logmsg_pool, 128); |
204 | 0 | p_array_init(&_testsuite_log_warnings, _testsuite_logmsg_pool, 128); |
205 | 0 | p_array_init(&_testsuite_log_messages, _testsuite_logmsg_pool, 128); |
206 | |
|
207 | 0 | sieve_error_handler_reset(testsuite_log_ehandler); |
208 | 0 | } |
209 | | |
210 | | /* |
211 | | * |
212 | | */ |
213 | | |
214 | | void testsuite_log_init(bool log_stdout) |
215 | 0 | { |
216 | 0 | _testsuite_log_stdout = log_stdout; |
217 | |
|
218 | 0 | testsuite_log_ehandler = _testsuite_log_ehandler_create(); |
219 | 0 | sieve_error_handler_accept_infolog(testsuite_log_ehandler, TRUE); |
220 | 0 | sieve_error_handler_accept_debuglog(testsuite_log_ehandler, TRUE); |
221 | |
|
222 | 0 | testsuite_log_main_ehandler = _testsuite_log_main_ehandler_create(); |
223 | 0 | sieve_error_handler_accept_infolog(testsuite_log_main_ehandler, TRUE); |
224 | 0 | sieve_error_handler_accept_debuglog(testsuite_log_main_ehandler, TRUE); |
225 | |
|
226 | 0 | i_set_error_handler(testsuite_error_handler); |
227 | 0 | i_set_info_handler(testsuite_error_handler); |
228 | 0 | i_set_debug_handler(testsuite_error_handler); |
229 | |
|
230 | 0 | testsuite_log_clear_messages(); |
231 | 0 | } |
232 | | |
233 | | void testsuite_log_deinit(void) |
234 | 0 | { |
235 | 0 | sieve_error_handler_unref(&testsuite_log_ehandler); |
236 | 0 | sieve_error_handler_unref(&testsuite_log_main_ehandler); |
237 | |
|
238 | 0 | i_set_error_handler(default_error_handler); |
239 | 0 | i_set_info_handler(default_error_handler); |
240 | 0 | i_set_debug_handler(default_error_handler); |
241 | |
|
242 | 0 | pool_unref(&_testsuite_logmsg_pool); |
243 | 0 | } |
244 | | |
245 | | /* |
246 | | * Log stringlist |
247 | | */ |
248 | | |
249 | | /* Forward declarations */ |
250 | | |
251 | | static int |
252 | | testsuite_log_stringlist_next_item(struct sieve_stringlist *_strlist, |
253 | | string_t **str_r); |
254 | | static void testsuite_log_stringlist_reset(struct sieve_stringlist *_strlist); |
255 | | |
256 | | /* Stringlist object */ |
257 | | |
258 | | struct testsuite_log_stringlist { |
259 | | struct sieve_stringlist strlist; |
260 | | |
261 | | int pos, index; |
262 | | }; |
263 | | |
264 | | struct sieve_stringlist * |
265 | | testsuite_log_stringlist_create(const struct sieve_runtime_env *renv, |
266 | | int index) |
267 | 0 | { |
268 | 0 | struct testsuite_log_stringlist *strlist; |
269 | |
|
270 | 0 | strlist = t_new(struct testsuite_log_stringlist, 1); |
271 | 0 | strlist->strlist.runenv = renv; |
272 | 0 | strlist->strlist.exec_status = SIEVE_EXEC_OK; |
273 | 0 | strlist->strlist.next_item = testsuite_log_stringlist_next_item; |
274 | 0 | strlist->strlist.reset = testsuite_log_stringlist_reset; |
275 | |
|
276 | 0 | strlist->index = index; |
277 | 0 | strlist->pos = 0; |
278 | |
|
279 | 0 | return &strlist->strlist; |
280 | 0 | } |
281 | | |
282 | | static int |
283 | | testsuite_log_stringlist_next_item(struct sieve_stringlist *_strlist, |
284 | | string_t **str_r) |
285 | 0 | { |
286 | 0 | struct testsuite_log_stringlist *strlist = |
287 | 0 | (struct testsuite_log_stringlist *) _strlist; |
288 | 0 | const struct _testsuite_log_message *msg; |
289 | 0 | int pos; |
290 | |
|
291 | 0 | *str_r = NULL; |
292 | |
|
293 | 0 | if (strlist->pos < 0) |
294 | 0 | return 0; |
295 | | |
296 | 0 | if (strlist->index > 0) { |
297 | 0 | pos = strlist->index - 1; |
298 | 0 | strlist->pos = -1; |
299 | 0 | } else { |
300 | 0 | pos = strlist->pos++; |
301 | 0 | } |
302 | |
|
303 | 0 | if (pos >= (int) array_count(&_testsuite_log_errors)) { |
304 | 0 | strlist->pos = -1; |
305 | 0 | return 0; |
306 | 0 | } |
307 | | |
308 | 0 | msg = array_idx(&_testsuite_log_errors, (unsigned int) pos); |
309 | |
|
310 | 0 | *str_r = t_str_new_const(msg->message, strlen(msg->message)); |
311 | 0 | return 1; |
312 | 0 | } |
313 | | |
314 | | static void testsuite_log_stringlist_reset(struct sieve_stringlist *_strlist) |
315 | 0 | { |
316 | 0 | struct testsuite_log_stringlist *strlist = |
317 | 0 | (struct testsuite_log_stringlist *) _strlist; |
318 | |
|
319 | 0 | strlist->pos = 0; |
320 | 0 | } |