1 /*
2 * Copyright (c) 2002-2016 Balabit
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * As an additional exemption you are allowed to compile & link against the
19 * OpenSSL libraries as published by the OpenSSL project. See the file
20 * COPYING for details.
21 *
22 */
23
24 #include <criterion/criterion.h>
25
26 #include "msg_parse_lib.h"
27 #include "apphook.h"
28 #include "logpipe.h"
29 #include "rcptid.h"
30 #include "libtest/persist_lib.h"
31
32 #include <stdlib.h>
33 #include <glib/gprintf.h>
34
35 MsgFormatOptions parse_options;
36
37 typedef struct _LogMessageTestParams
38 {
39 LogMessage *message;
40 LogMessage *cloned_message;
41 NVHandle nv_handle;
42 NVHandle sd_handle;
43 const gchar *tag_name;
44 } LogMessageTestParams;
45
46 static LogMessage *
_construct_log_message(void)47 _construct_log_message(void)
48 {
49 const gchar *raw_msg = "foo";
50 LogMessage *msg;
51
52 msg = log_msg_new(raw_msg, strlen(raw_msg), &parse_options);
53 log_msg_set_value(msg, LM_V_HOST, raw_msg, -1);
54 return msg;
55 }
56
57 static LogMessage *
_construct_merge_base_message(void)58 _construct_merge_base_message(void)
59 {
60 LogMessage *msg;
61
62 msg = log_msg_new_empty();
63 log_msg_set_value_by_name(msg, "base", "basevalue", -1);
64 log_msg_set_tag_by_name(msg, "basetag");
65 return msg;
66 }
67
68 static LogMessage *
_construct_merged_message(const gchar * name,const gchar * value)69 _construct_merged_message(const gchar *name, const gchar *value)
70 {
71 LogMessage *msg;
72
73 msg = log_msg_new_empty();
74 log_msg_set_value_by_name(msg, name, value, -1);
75 log_msg_set_tag_by_name(msg, "mergedtag");
76 return msg;
77 }
78
79 static void
assert_log_msg_clear_clears_all_properties(LogMessage * message,NVHandle nv_handle,NVHandle sd_handle,const gchar * tag_name)80 assert_log_msg_clear_clears_all_properties(LogMessage *message, NVHandle nv_handle,
81 NVHandle sd_handle, const gchar *tag_name)
82 {
83 message->flags |= LF_LOCAL + LF_UTF8 + LF_INTERNAL + LF_MARK;
84 log_msg_clear(message);
85
86 cr_assert_str_empty(log_msg_get_value(message, nv_handle, NULL),
87 "Message still contains value after log_msg_clear");
88
89 cr_assert_str_empty(log_msg_get_value(message, sd_handle, NULL),
90 "Message still contains sdata value after log_msg_clear");
91
92 cr_assert_null(message->saddr, "Message still contains an saddr after log_msg_clear");
93 cr_assert_not(log_msg_is_tag_by_name(message, tag_name),
94 "Message still contains a valid tag after log_msg_clear");
95 cr_assert((message->flags & LF_LOCAL) == 0, "Message still contains the 'local' flag after log_msg_clear");
96 cr_assert((message->flags & LF_UTF8) == 0, "Message still contains the 'utf8' flag after log_msg_clear");
97 cr_assert((message->flags & LF_MARK) == 0, "Message still contains the 'mark' flag after log_msg_clear");
98 cr_assert((message->flags & LF_INTERNAL) == 0, "Message still contains the 'internal' flag after log_msg_clear");
99 }
100
101 static void
assert_sdata_value_with_seqnum_equals(LogMessage * msg,guint32 seq_num,const gchar * expected)102 assert_sdata_value_with_seqnum_equals(LogMessage *msg, guint32 seq_num, const gchar *expected)
103 {
104 GString *result = g_string_sized_new(0);
105
106 log_msg_append_format_sdata(msg, result, seq_num);
107 cr_assert_str_eq(result->str, expected, "SDATA value does not match, '%s' vs '%s'", expected, result->str);
108 g_string_free(result, TRUE);
109 }
110
111 static void
assert_sdata_value_equals(LogMessage * msg,const gchar * expected)112 assert_sdata_value_equals(LogMessage *msg, const gchar *expected)
113 {
114 assert_sdata_value_with_seqnum_equals(msg, 0, expected);
115 }
116
117 static LogMessageTestParams *
log_message_test_params_new(void)118 log_message_test_params_new(void)
119 {
120 LogMessageTestParams *params = g_new0(LogMessageTestParams, 1);
121
122 params->tag_name = "tag";
123 params->message = _construct_log_message();
124
125 params->nv_handle = log_msg_get_value_handle("foo");
126 params->sd_handle = log_msg_get_value_handle(".SDATA.foo.bar");
127
128 log_msg_set_value(params->message, params->nv_handle, "value", -1);
129 log_msg_set_value(params->message, params->sd_handle, "value", -1);
130 params->message->saddr = g_sockaddr_inet_new("1.2.3.4", 5050);
131 log_msg_set_tag_by_name(params->message, params->tag_name);
132
133 return params;
134 }
135
136 void
log_message_test_params_free(LogMessageTestParams * params)137 log_message_test_params_free(LogMessageTestParams *params)
138 {
139 log_msg_unref(params->message);
140
141 if (params->cloned_message)
142 log_msg_unref(params->cloned_message);
143
144 g_free(params);
145 }
146
147 LogMessage *
log_message_test_params_clone_message(LogMessageTestParams * params)148 log_message_test_params_clone_message(LogMessageTestParams *params)
149 {
150 LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
151 params->cloned_message = log_msg_clone_cow(params->message, &path_options);
152
153 return params->cloned_message;
154 }
155
156
157 void
setup(void)158 setup(void)
159 {
160 app_startup();
161 init_parse_options_and_load_syslogformat(&parse_options);
162 }
163
164 void
teardown(void)165 teardown(void)
166 {
167 deinit_syslogformat_module();
168 app_shutdown();
169 }
170
171 TestSuite(log_message, .init = setup, .fini = teardown);
172
Test(log_message,test_log_message_can_be_created_and_freed)173 Test(log_message, test_log_message_can_be_created_and_freed)
174 {
175 LogMessage *msg = _construct_log_message();
176 log_msg_unref(msg);
177 }
178
Test(log_message,test_log_message_can_be_cleared)179 Test(log_message, test_log_message_can_be_cleared)
180 {
181 LogMessageTestParams *params = log_message_test_params_new();
182
183 log_message_test_params_clone_message(params);
184
185 assert_log_msg_clear_clears_all_properties(params->message, params->nv_handle,
186 params->sd_handle, params->tag_name);
187 assert_log_msg_clear_clears_all_properties(params->cloned_message, params->nv_handle,
188 params->sd_handle, params->tag_name);
189
190 log_message_test_params_free(params);
191 }
192
Test(log_message,test_log_msg_clear_handles_cloned_noninline_tags_properly)193 Test(log_message, test_log_msg_clear_handles_cloned_noninline_tags_properly)
194 {
195 LogMessage *msg = _construct_log_message();
196
197 for (gint i = 0; i < 100; i++)
198 {
199 gchar tag_name[32];
200
201 g_snprintf(tag_name, sizeof(tag_name), "tag%d", i);
202 log_msg_set_tag_by_name(msg, tag_name);
203 }
204
205 LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
206 LogMessage *cloned = log_msg_clone_cow(msg, &path_options);
207
208 log_msg_clear(cloned);
209
210 for (gint i = 0; i < 100; i++)
211 {
212 gchar tag_name[32];
213
214 g_snprintf(tag_name, sizeof(tag_name), "tag%d", i);
215 cr_assert(log_msg_is_tag_by_name(cloned, tag_name) == FALSE);
216 }
217 log_msg_unref(cloned);
218 log_msg_unref(msg);
219
220 }
221
Test(log_message,test_rcptid_is_automatically_assigned_to_a_newly_created_log_message)222 Test(log_message, test_rcptid_is_automatically_assigned_to_a_newly_created_log_message)
223 {
224 LogMessage *msg;
225 PersistState *state = clean_and_create_persist_state_for_test("test_values.persist");
226 rcptid_init(state, TRUE);
227
228 msg = log_msg_new_empty();
229 cr_assert_eq(msg->rcptid, 1, "rcptid is not automatically set");
230 log_msg_unref(msg);
231
232 commit_and_destroy_persist_state(state);
233 rcptid_deinit();
234 }
235
Test(log_message,test_log_message_merge_with_empty_context)236 Test(log_message, test_log_message_merge_with_empty_context)
237 {
238 LogMessageTestParams *params = log_message_test_params_new();
239 LogMessage *context[] = {};
240
241 log_message_test_params_clone_message(params);
242
243 log_msg_merge_context(params->message, context, 0);
244 assert_log_messages_equal(params->message, params->cloned_message);
245
246 log_message_test_params_free(params);
247 }
248
Test(log_message,test_log_message_merge_unset_value)249 Test(log_message, test_log_message_merge_unset_value)
250 {
251 LogMessage *msg;
252 GPtrArray *context = g_ptr_array_sized_new(0);
253
254 msg = _construct_merge_base_message();
255 g_ptr_array_add(context, _construct_merged_message("merged", "mergedvalue"));
256 log_msg_merge_context(msg, (LogMessage **) context->pdata, context->len);
257
258 assert_log_message_value_by_name(msg, "base", "basevalue");
259 assert_log_message_value_by_name(msg, "merged", "mergedvalue");
260 g_ptr_array_foreach(context, (GFunc) log_msg_unref, NULL);
261 g_ptr_array_free(context, TRUE);
262 log_msg_unref(msg);
263 }
264
Test(log_message,test_log_message_merge_doesnt_overwrite_already_set_values)265 Test(log_message, test_log_message_merge_doesnt_overwrite_already_set_values)
266 {
267 LogMessage *msg;
268 GPtrArray *context = g_ptr_array_sized_new(0);
269
270 msg = _construct_merge_base_message();
271 g_ptr_array_add(context, _construct_merged_message("base", "mergedvalue"));
272 log_msg_merge_context(msg, (LogMessage **) context->pdata, context->len);
273
274 assert_log_message_value_by_name(msg, "base", "basevalue");
275 g_ptr_array_foreach(context, (GFunc) log_msg_unref, NULL);
276 g_ptr_array_free(context, TRUE);
277 log_msg_unref(msg);
278 }
279
Test(log_message,test_log_message_merge_merges_the_closest_value_in_the_context)280 Test(log_message, test_log_message_merge_merges_the_closest_value_in_the_context)
281 {
282 LogMessage *msg;
283 GPtrArray *context = g_ptr_array_sized_new(0);
284
285 msg = _construct_merge_base_message();
286 g_ptr_array_add(context, _construct_merged_message("merged", "mergedvalue1"));
287 g_ptr_array_add(context, _construct_merged_message("merged", "mergedvalue2"));
288 log_msg_merge_context(msg, (LogMessage **) context->pdata, context->len);
289
290 assert_log_message_value_by_name(msg, "merged", "mergedvalue2");
291 g_ptr_array_foreach(context, (GFunc) log_msg_unref, NULL);
292 g_ptr_array_free(context, TRUE);
293 log_msg_unref(msg);
294 }
295
Test(log_message,test_log_message_merge_merges_from_all_messages_in_the_context)296 Test(log_message, test_log_message_merge_merges_from_all_messages_in_the_context)
297 {
298 LogMessage *msg;
299 GPtrArray *context = g_ptr_array_sized_new(0);
300
301 msg = _construct_merge_base_message();
302 g_ptr_array_add(context, _construct_merged_message("merged1", "mergedvalue1"));
303 g_ptr_array_add(context, _construct_merged_message("merged2", "mergedvalue2"));
304 g_ptr_array_add(context, _construct_merged_message("merged3", "mergedvalue3"));
305 log_msg_merge_context(msg, (LogMessage **) context->pdata, context->len);
306
307 assert_log_message_value_by_name(msg, "merged1", "mergedvalue1");
308 assert_log_message_value_by_name(msg, "merged2", "mergedvalue2");
309 assert_log_message_value_by_name(msg, "merged3", "mergedvalue3");
310 g_ptr_array_foreach(context, (GFunc) log_msg_unref, NULL);
311 g_ptr_array_free(context, TRUE);
312 log_msg_unref(msg);
313 }
314
Test(log_message,test_log_message_merge_leaves_base_tags_intact)315 Test(log_message, test_log_message_merge_leaves_base_tags_intact)
316 {
317 LogMessage *msg;
318 GPtrArray *context = g_ptr_array_sized_new(0);
319
320 msg = _construct_merge_base_message();
321 g_ptr_array_add(context, _construct_merged_message("merged1", "mergedvalue1"));
322 log_msg_merge_context(msg, (LogMessage **) context->pdata, context->len);
323
324 assert_log_message_has_tag(msg, "basetag");
325 assert_log_message_doesnt_have_tag(msg, "mergedtag");
326 g_ptr_array_foreach(context, (GFunc) log_msg_unref, NULL);
327 g_ptr_array_free(context, TRUE);
328 log_msg_unref(msg);
329 }
330
Test(log_message,test_log_msg_set_value_indirect_with_self_referencing_handle_results_in_a_nonindirect_value)331 Test(log_message, test_log_msg_set_value_indirect_with_self_referencing_handle_results_in_a_nonindirect_value)
332 {
333 LogMessageTestParams *params = log_message_test_params_new();
334 gssize value_len;
335
336 log_msg_set_value_indirect(params->message, params->nv_handle, params->nv_handle, 0, 0, 5);
337 cr_assert_str_eq(log_msg_get_value(params->message, params->nv_handle, &value_len), "value",
338 "indirect self-reference value doesn't match");
339
340 log_message_test_params_free(params);
341 }
342
Test(log_message,test_log_msg_get_value_with_time_related_macro)343 Test(log_message, test_log_msg_get_value_with_time_related_macro)
344 {
345 LogMessage *msg;
346 gssize value_len;
347 NVHandle handle;
348 const char *date_value;
349
350 msg = log_msg_new_empty();
351 msg->timestamps[LM_TS_STAMP].ut_sec = 1389783444;
352 msg->timestamps[LM_TS_STAMP].ut_gmtoff = 3600;
353
354 handle = log_msg_get_value_handle("ISODATE");
355 date_value = log_msg_get_value(msg, handle, &value_len);
356 cr_assert_str_eq(date_value, "2014-01-15T11:57:24+01:00", "ISODATE macro value does not match! value=%s", date_value);
357
358 log_msg_unref(msg);
359 }
360
Test(log_message,test_local_logmsg_created_with_the_right_flags_and_timestamps)361 Test(log_message, test_local_logmsg_created_with_the_right_flags_and_timestamps)
362 {
363 LogMessage *msg = log_msg_new_local();
364
365 gboolean are_equals = unix_time_eq(&msg->timestamps[LM_TS_STAMP], &msg->timestamps[LM_TS_RECVD]);
366
367 cr_assert_neq((msg->flags & LF_LOCAL), 0, "LogMessage created by log_msg_new_local() should have LF_LOCAL flag set");
368 cr_assert(are_equals, "The timestamps in a LogMessage created by log_msg_new_local() should be equals");
369
370 log_msg_unref(msg);
371 }
372
Test(log_message,test_sdata_sanitization)373 Test(log_message, test_sdata_sanitization)
374 {
375 LogMessage *msg;
376 /* These keys looks strange, but JSON object can be parsed to SDATA,
377 * so the key could contain any character, while the specification
378 * does not declare any way to encode the keys, just the values.
379 * The goal is to have a syntactically valid syslog message.
380 *
381 * Block names are sanitized with the same function as the keys,
382 * thus no need for exhaust testing, added just one case to the end
383 * to see if business logic applied. */
384
385 msg = log_msg_new_empty();
386 log_msg_set_value_by_name(msg, ".SDATA.foo.bar[0]", "value[0]", -1);
387 assert_sdata_value_equals(msg, "[foo bar%5B0%5D=\"value[0\\]\"]");
388 log_msg_unref(msg);
389
390 msg = log_msg_new_empty();
391 log_msg_set_value_by_name(msg, ".SDATA.foo.bácsi", "bácsi", -1);
392 assert_sdata_value_equals(msg, "[foo b%C3%A1csi=\"bácsi\"]");
393 log_msg_unref(msg);
394
395 msg = log_msg_new_empty();
396 log_msg_set_value_by_name(msg, ".SDATA.foo.sp ace", "sp ace", -1);
397 assert_sdata_value_equals(msg, "[foo sp%20ace=\"sp ace\"]");
398 log_msg_unref(msg);
399
400 msg = log_msg_new_empty();
401 log_msg_set_value_by_name(msg, ".SDATA.foo.eq=al", "eq=al", -1);
402 assert_sdata_value_equals(msg, "[foo eq%3Dal=\"eq=al\"]");
403 log_msg_unref(msg);
404
405 msg = log_msg_new_empty();
406 log_msg_set_value_by_name(msg, ".SDATA.foo.quo\"te", "quo\"te", -1);
407 assert_sdata_value_equals(msg, "[foo quo%22te=\"quo\\\"te\"]");
408 log_msg_unref(msg);
409
410 msg = log_msg_new_empty();
411 log_msg_set_value_by_name(msg, ".SDATA.fo@o[0].bar", "value", -1);
412 assert_sdata_value_equals(msg, "[fo@o%5B0%5D bar=\"value\"]");
413 log_msg_unref(msg);
414 }
415
Test(log_message,test_sdata_value_is_updated_by_sdata_name_value_pairs)416 Test(log_message, test_sdata_value_is_updated_by_sdata_name_value_pairs)
417 {
418 LogMessage *msg;
419
420 msg = log_msg_new_empty();
421 log_msg_set_value_by_name(msg, ".SDATA.foo.bar1", "value", -1);
422 assert_sdata_value_equals(msg, "[foo bar1=\"value\"]");
423 log_msg_set_value_by_name(msg, ".SDATA.foo.bar2", "value", -1);
424 assert_sdata_value_equals(msg, "[foo bar1=\"value\" bar2=\"value\"]");
425 log_msg_set_value_by_name(msg, ".SDATA.foo.bar3", "value", -1);
426 assert_sdata_value_equals(msg, "[foo bar1=\"value\" bar2=\"value\" bar3=\"value\"]");
427 log_msg_set_value_by_name(msg, ".SDATA.post.value1", "value", -1);
428 assert_sdata_value_equals(msg, "[post value1=\"value\"][foo bar1=\"value\" bar2=\"value\" bar3=\"value\"]");
429 log_msg_set_value_by_name(msg, ".SDATA.post.value2", "value", -1);
430 assert_sdata_value_equals(msg,
431 "[post value1=\"value\" value2=\"value\"][foo bar1=\"value\" bar2=\"value\" bar3=\"value\"]");
432 log_msg_unref(msg);
433 }
434
Test(log_message,test_sdata_seqnum_adds_meta_sequence_id)435 Test(log_message, test_sdata_seqnum_adds_meta_sequence_id)
436 {
437 LogMessage *msg;
438
439 msg = log_msg_new_empty();
440 log_msg_set_value_by_name(msg, ".SDATA.foo.bar1", "value", -1);
441 log_msg_set_value_by_name(msg, ".SDATA.foo.bar2", "value", -1);
442 log_msg_set_value_by_name(msg, ".SDATA.foo.bar3", "value", -1);
443 assert_sdata_value_with_seqnum_equals(msg, 5,
444 "[foo bar1=\"value\" bar2=\"value\" bar3=\"value\"][meta sequenceId=\"5\"]");
445 log_msg_set_value_by_name(msg, ".SDATA.meta.foobar", "value", -1);
446 assert_sdata_value_with_seqnum_equals(msg, 6,
447 "[meta sequenceId=\"6\" foobar=\"value\"][foo bar1=\"value\" bar2=\"value\" bar3=\"value\"]");
448 log_msg_unref(msg);
449 }
450
Test(log_message,test_sdata_value_omits_unset_values)451 Test(log_message, test_sdata_value_omits_unset_values)
452 {
453 LogMessage *msg;
454
455 msg = log_msg_new_empty();
456 log_msg_set_value_by_name(msg, ".SDATA.foo.bar1", "value", -1);
457 log_msg_set_value_by_name(msg, ".SDATA.foo.bar2", "value", -1);
458 log_msg_set_value_by_name(msg, ".SDATA.foo.bar3", "value", -1);
459 assert_sdata_value_equals(msg, "[foo bar1=\"value\" bar2=\"value\" bar3=\"value\"]");
460 log_msg_unset_value_by_name(msg, ".SDATA.foo.bar2");
461 assert_sdata_value_equals(msg, "[foo bar1=\"value\" bar3=\"value\"]");
462 log_msg_unset_value_by_name(msg, ".SDATA.foo.bar1");
463 log_msg_unset_value_by_name(msg, ".SDATA.foo.bar3");
464 assert_sdata_value_equals(msg, "");
465 log_msg_unref(msg);
466 }
467
468 #define DEFUN_KEY_VALUE(name, key, value, size) \
469 gchar name ## _key[size]; \
470 gchar name ## _value[size]; \
471 name ## _key[size-1] = name ## _value[size-1] = 0; \
472 memset(name ## _key, key, sizeof(name ##_key)-1); \
473 memset(name ## _value, value, sizeof(name ##_value)-1); \
474
475
476 typedef struct
477 {
478 gssize nvtable_size_old;
479 gssize nvtable_size_new;
480 gssize msg_size_old;
481 gssize msg_size_new;
482 } sizes_t;
483
484 static sizes_t
add_key_value(LogMessage * msg,gchar * key,gchar * value)485 add_key_value(LogMessage *msg, gchar *key, gchar *value)
486 {
487 sizes_t sizes;
488 sizes.msg_size_old = log_msg_get_size(msg);
489 sizes.nvtable_size_old = nv_table_get_memory_consumption(msg->payload);
490 log_msg_set_value_by_name(msg, key, value, -1);
491 sizes.nvtable_size_new = nv_table_get_memory_consumption(msg->payload);
492 sizes.msg_size_new = log_msg_get_size(msg);
493 return sizes;
494 }
495
496
497 static void
test_with_sdata(LogMessage * msg,guint32 old_msg_size)498 test_with_sdata(LogMessage *msg, guint32 old_msg_size)
499 {
500 sizes_t sizes;
501 gchar key[] = ".SDATA.**";
502 gchar value[] = "AAAAAAA";
503
504 guint32 single_sdata_kv_size;
505 guint32 sdata_payload_array_size;
506
507 const char iter_length = 17;
508
509 for (char i = 0; i < iter_length; i++)
510 {
511 g_sprintf(key, ".SDATA.%02d", i);
512 sizes = add_key_value(msg, key, value);
513
514 single_sdata_kv_size = NV_ENTRY_DIRECT_HDR + NV_TABLE_BOUND(strlen(key)+1 + strlen(value)+1);
515
516 /* i+1 is stored, but the sdata array size is calculated when adding the i-th */
517 sdata_payload_array_size = STRICT_ROUND_TO_NEXT_EIGHT(i) * sizeof(msg->sdata[0]);
518 cr_assert_eq(old_msg_size + (i+1) * single_sdata_kv_size + sdata_payload_array_size, sizes.msg_size_new);
519 }
520 }
521
522 #define SMALL_LENGTH 10
523 #define LARGE_LENGTH 256
524
Test(log_message,test_message_size)525 Test(log_message, test_message_size)
526 {
527 LogMessage *msg = log_msg_new_empty();
528
529 sizes_t sizes;
530
531 DEFUN_KEY_VALUE(small, 'C', 'D', SMALL_LENGTH);
532 sizes = add_key_value(msg, small_key, small_value);
533 // (SMALL_LENGTH-1)*'C'+'\0' + (SMALL_LENGTH-1)*'D'+'\0'
534 guint32 entry_size = NV_ENTRY_DIRECT_HDR + NV_TABLE_BOUND(SMALL_LENGTH + SMALL_LENGTH);
535 cr_assert_eq(sizes.nvtable_size_old + entry_size, sizes.nvtable_size_new);
536 cr_assert_eq(sizes.msg_size_old + entry_size, sizes.msg_size_new); // Size increased because of nvtable
537
538 guint32 msg_size = sizes.msg_size_new;
539 log_msg_set_tag_by_name(msg, "test_tag_storage");
540 cr_assert(log_msg_is_tag_by_name(msg, "test_tag_storage"));
541 cr_assert_eq(msg_size, log_msg_get_size(msg)); // Tag is not increased until tag id 65
542
543 char *tag_name = strdup("00tagname");
544 // (*8 to convert to bits) + no need plus 1 bcause we already added one tag: test_tag_storage
545 for (int i = 0; i < GLIB_SIZEOF_LONG*8; i++)
546 {
547 sprintf(tag_name, "%dtagname", i);
548 log_msg_set_tag_by_name(msg, tag_name);
549 }
550 free(tag_name);
551 cr_assert_eq(msg_size + 2*GLIB_SIZEOF_LONG, log_msg_get_size(msg));
552
553
554 DEFUN_KEY_VALUE(big, 'A', 'B', LARGE_LENGTH);
555 sizes = add_key_value(msg, big_key, big_value); // nvtable is expanded
556 entry_size = NV_ENTRY_DIRECT_HDR + NV_TABLE_BOUND(LARGE_LENGTH + LARGE_LENGTH);
557 cr_assert_eq(sizes.nvtable_size_old + entry_size, sizes.nvtable_size_new); // but only increased by the entry
558 cr_assert_eq(sizes.msg_size_old + entry_size, sizes.msg_size_new); // nvtable is doubled
559
560 test_with_sdata(msg, sizes.msg_size_new);
561
562 log_msg_unref(msg);
563 }
564
565 Test(log_message, when_get_indirect_value_with_null_value_len_abort_instead_of_sigsegv, .signal=SIGABRT)
566 {
567 LogMessageTestParams *params = log_message_test_params_new();
568
569 NVHandle indirect = log_msg_get_value_handle("INDIRECT");
570 log_msg_set_value_indirect(params->message, indirect, params->nv_handle, 0, 0, 5);
571 log_msg_get_value(params->message, indirect, NULL);
572
573 log_message_test_params_free(params);
574 }
575
Test(log_message,test_cow_writing_cloned_message)576 Test(log_message, test_cow_writing_cloned_message)
577 {
578 LogMessage *msg = _construct_log_message();
579 log_msg_set_value_by_name(msg, "orig_name", "orig_value", -1);
580
581 LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
582 LogMessage *cloned = log_msg_clone_cow(msg, &path_options);
583
584 log_msg_set_value_by_name(cloned, "cloned_name", "cloned_value", -1);
585 log_msg_set_value_by_name(cloned, "orig_name", "modified_value", -1);
586
587 cr_assert_str_eq(log_msg_get_value_by_name(msg, "orig_name", NULL), "orig_value",
588 "Modifications on a COW-cloned message should not leak into the original message; actual: %s, expected: %s",
589 log_msg_get_value_by_name(msg, "orig_name", NULL), "orig_value");
590
591 NVHandle cloned_name = log_msg_get_value_handle("cloned_name");
592 gssize value_length;
593 cr_assert_null(log_msg_get_value_if_set(msg, cloned_name, &value_length),
594 "Modifications on a COW-cloned message should not leak into the original message");
595
596 log_msg_unref(cloned);
597 log_msg_unref(msg);
598 }
599
600
Test(log_message,test_cow_make_writable)601 Test(log_message, test_cow_make_writable)
602 {
603 LogMessage *msg = _construct_log_message();
604 log_msg_set_value_by_name(msg, "orig_name", "orig_value", -1);
605
606 log_msg_write_protect(msg);
607 cr_assert(log_msg_is_write_protected(msg));
608
609 LogMessage *orig_msg = log_msg_ref(msg);
610
611 LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
612 log_msg_make_writable(&msg, &path_options);
613
614 log_msg_set_value_by_name(msg, "orig_name2", "orig_value2", -1);
615
616 NVHandle orig_name2 = log_msg_get_value_handle("orig_name2");
617 gssize value_length;
618 cr_assert_null(log_msg_get_value_if_set(orig_msg, orig_name2, &value_length),
619 "Modifications on a COW-cloned message should not leak into the original message");
620
621 log_msg_unref(orig_msg);
622 log_msg_unref(msg);
623 }
624
Test(log_message,test_cow_unset_value)625 Test(log_message, test_cow_unset_value)
626 {
627 LogMessage *msg = _construct_log_message();
628 log_msg_set_value_by_name(msg, "orig_name", "orig_value", -1);
629 log_msg_write_protect(msg);
630
631 LogMessage *orig_msg = log_msg_ref(msg);
632
633 LogPathOptions path_options = LOG_PATH_OPTIONS_INIT;
634 log_msg_make_writable(&msg, &path_options);
635
636 log_msg_unset_value_by_name(msg, "orig_name");
637
638 cr_assert_str_eq(log_msg_get_value_by_name(orig_msg, "orig_name", NULL), "orig_value",
639 "Unsetting a value in a COW-cloned message should not unset the value in the original message; actual: %s, expected: %s",
640 log_msg_get_value_by_name(orig_msg, "orig_name", NULL), "orig_value");
641
642 log_msg_unref(orig_msg);
643 log_msg_unref(msg);
644 }
645