From: Josef 'Jeff' Sipek Date: Fri, 15 Mar 2019 00:30:29 +0000 (-0400) Subject: lib: Add event_flatten() to return a flattened event X-Git-Tag: 2.3.7~153 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=921739d6eebf6a39ed410aafc893079e410abc37;p=thirdparty%2Fdovecot%2Fcore.git lib: Add event_flatten() to return a flattened event --- diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 0bed034a79..3226e3670a 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -345,8 +345,9 @@ test_lib_SOURCES = \ test-connection.c \ test-crc32.c \ test-data-stack.c \ - test-event-log.c \ test-event-filter.c \ + test-event-flatten.c \ + test-event-log.c \ test-failures.c \ test-fd-util.c \ test-file-create-locked.c \ diff --git a/src/lib/lib-event.c b/src/lib/lib-event.c index 20b985db38..a9ff06f075 100644 --- a/src/lib/lib-event.c +++ b/src/lib/lib-event.c @@ -122,6 +122,46 @@ struct event *event_dup(const struct event *source) return ret; } +/* + * Copy the source's categories and fields recursively. + * + * We recurse to the parent before copying this event's data because we may + * be overriding a field. + */ +static void event_flatten_recurse(struct event *dst, struct event *src, + struct event *limit) +{ + if (src->parent != limit) + event_flatten_recurse(dst, src->parent, limit); + + event_copy_categories(dst, src); + event_copy_fields(dst, src); +} + +struct event *event_flatten(struct event *src) +{ + struct event *dst; + + /* If we don't have a parent, we have nothing to flatten. */ + if (src->parent == NULL) + return event_ref(src); + + /* We have to flatten the event. */ + + dst = event_create(NULL); + dst = event_set_name(dst, src->sending_name); + dst = event_set_source(dst, src->source_filename, src->source_linenum, + FALSE); + + event_flatten_recurse(dst, src, NULL); + + dst->tv_created_ioloop = src->tv_created_ioloop; + dst->tv_created = src->tv_created; + dst->tv_last_sent = src->tv_last_sent; + + return dst; +} + #undef event_create struct event *event_create(struct event *parent, const char *source_filename, unsigned int source_linenum) diff --git a/src/lib/lib-event.h b/src/lib/lib-event.h index e598044572..63f7dbb099 100644 --- a/src/lib/lib-event.h +++ b/src/lib/lib-event.h @@ -87,6 +87,11 @@ bool event_has_all_fields(struct event *event, const struct event *other); /* Returns the source event duplicated into a new event. */ struct event *event_dup(const struct event *source); +/* Returns a flattened version of the source event. + Both categories and fields will be flattened. + A new reference to the source event is returned if no flattening was + needed. */ +struct event *event_flatten(struct event *src); /* Copy all categories from source to dest. Only the categories in source event itself are copied. Parent events' categories aren't copied. */ diff --git a/src/lib/test-event-flatten.c b/src/lib/test-event-flatten.c new file mode 100644 index 0000000000..69673ddada --- /dev/null +++ b/src/lib/test-event-flatten.c @@ -0,0 +1,262 @@ +/* Copyright (c) 2019 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" +#include "ioloop.h" +#include "time-util.h" +#include "lib-event-private.h" +#include "failures-private.h" + +#define CHECK_FLATTEN_SAME(e) \ + check_event_same(event_flatten(e), (e)) + +#define CHECK_FLATTEN_DIFF(e, c, nc, f, nf) \ + check_event_diff(event_flatten(e), (e), \ + (c), (nc), \ + (f), (nf)) + +static struct event_category cats[] = { + { .name = "cat0", }, + { .name = "cat1", }, +}; + +static void check_event_diff_cats(struct event_category *const *got, + unsigned int ngot, const char **exp, + unsigned int nexp) +{ + unsigned int i; + + test_assert(ngot == nexp); + + for (i = 0; i < nexp; i++) + test_assert(strcmp(got[i]->name, exp[i]) == 0); +} + +static void check_event_diff_fields(const struct event_field *got, unsigned int ngot, + const struct event_field *exp, unsigned int nexp) +{ + unsigned int i; + + test_assert(ngot == nexp); + + for (i = 0; i < nexp; i++) { + if (got[i].value_type != exp[i].value_type) { + test_assert(FALSE); + continue; + } + + switch (exp[i].value_type) { + case EVENT_FIELD_VALUE_TYPE_STR: + test_assert(strcmp(exp[i].value.str, + got[i].value.str) == 0); + break; + case EVENT_FIELD_VALUE_TYPE_INTMAX: + test_assert(exp[i].value.intmax == got[i].value.intmax); + break; + case EVENT_FIELD_VALUE_TYPE_TIMEVAL: + test_assert(timeval_cmp(&exp[i].value.timeval, + &got[i].value.timeval) == 0); + break; + } + } +} + +static void check_event_diff(struct event *e, struct event *orig, + const char **expected_cats, + unsigned int num_expected_cats, + const struct event_field *expected_fields, + unsigned int num_expected_fields) +{ + struct event_category *const *cats; + const struct event_field *fields; + unsigned int num_cats; + unsigned int num_fields; + + test_assert(e != orig); + test_assert(e->parent == NULL); + + /* different pointers implies different ids */ + test_assert(e->id != orig->id); /* TODO: does this make sense? */ + + test_assert(timeval_cmp(&e->tv_created_ioloop, &orig->tv_created_ioloop) == 0); + test_assert(timeval_cmp(&e->tv_created, &orig->tv_created) == 0); + test_assert(timeval_cmp(&e->tv_last_sent, &orig->tv_last_sent) == 0); + + test_assert(strcmp(e->source_filename, orig->source_filename) == 0); + test_assert(e->source_linenum == orig->source_linenum); + + /* FIXME: check sending name? */ + + cats = event_get_categories(e, &num_cats); + check_event_diff_cats(cats, num_cats, + expected_cats, num_expected_cats); + + fields = event_get_fields(e, &num_fields); + check_event_diff_fields(fields, num_fields, + expected_fields, num_expected_fields); + + event_unref(&e); +} + +static void check_event_same(struct event *e, struct event *orig) +{ + test_assert(e == orig); + + /* the pointers are the same; nothing can possibly differ */ + + event_unref(&e); +} + +static void test_event_flatten_no_parent(void) +{ + struct event *e; + + test_begin("event flatten: no parent"); + + e = event_create(NULL); + + CHECK_FLATTEN_SAME(e); + + event_add_int(e, "abc", 4); + CHECK_FLATTEN_SAME(e); + + event_add_int(e, "def", 2); + CHECK_FLATTEN_SAME(e); + + event_add_str(e, "abc", "foo"); + CHECK_FLATTEN_SAME(e); + + event_add_category(e, &cats[0]); + CHECK_FLATTEN_SAME(e); + + event_unref(&e); + + test_end(); +} + +static void test_event_flatten_one_parent(void) +{ + static const char *exp_1cat[] = { + "cat0", + }; + static const char *exp_2cat[] = { + "cat1", + "cat0", + }; + static struct event_field exp_int = { + .key = "abc", + .value_type = EVENT_FIELD_VALUE_TYPE_INTMAX, + .value.intmax = 42, + }; + static struct event_field exp_2int[2] = { + { + .key = "abc", + .value_type = EVENT_FIELD_VALUE_TYPE_INTMAX, + .value.intmax = 42, + }, + { + .key = "def", + .value_type = EVENT_FIELD_VALUE_TYPE_INTMAX, + .value.intmax = 49, + }, + }; + static struct event_field exp_1str1int[2] = { + { + .key = "abc", + .value_type = EVENT_FIELD_VALUE_TYPE_STR, + .value.str = "foo", + }, + { + .key = "def", + .value_type = EVENT_FIELD_VALUE_TYPE_INTMAX, + .value.intmax = 49, + }, + }; + struct event *parent; + struct event *e; + + test_begin("event flatten: one parent"); + + parent = event_create(NULL); + + e = event_create(parent); + + CHECK_FLATTEN_DIFF(e, NULL, 0, NULL, 0); + + event_add_int(e, "abc", 42); + CHECK_FLATTEN_DIFF(e, NULL, 0, &exp_int, 1); + + event_add_int(e, "def", 49); + CHECK_FLATTEN_DIFF(e, NULL, 0, exp_2int, 2); + + event_add_str(e, "abc", "foo"); + CHECK_FLATTEN_DIFF(e, NULL, 0, exp_1str1int, 2); + + event_add_category(e, &cats[0]); + CHECK_FLATTEN_DIFF(e, exp_1cat, 1, exp_1str1int, 2); + + event_add_category(e, &cats[1]); + CHECK_FLATTEN_DIFF(e, exp_2cat, 2, exp_1str1int, 2); + + event_unref(&e); + event_unref(&parent); + + test_end(); +} + +static void test_event_flatten_override_parent_field(void) +{ + static struct event_field exp_int = { + .key = "abc", + .value_type = EVENT_FIELD_VALUE_TYPE_INTMAX, + .value.intmax = 42, + }; + static struct event_field exp_str = { + .key = "abc", + .value_type = EVENT_FIELD_VALUE_TYPE_STR, + .value.str = "def", + }; + static struct event_field exp_2str[2] = { + { + .key = "abc", + .value_type = EVENT_FIELD_VALUE_TYPE_STR, + .value.str = "def", + }, + { + .key = "foo", + .value_type = EVENT_FIELD_VALUE_TYPE_STR, + .value.str = "bar", + }, + }; + struct event *parent; + struct event *e; + + test_begin("event flatten: override parent field"); + + parent = event_create(NULL); + + event_add_int(parent, "abc", 5); + + e = event_create(parent); + + event_add_int(e, "abc", 42); + + CHECK_FLATTEN_DIFF(e, NULL, 0, &exp_int, 1); + + event_add_str(e, "abc", "def"); + CHECK_FLATTEN_DIFF(e, NULL, 0, &exp_str, 1); + + event_add_str(parent, "foo", "bar"); + CHECK_FLATTEN_DIFF(e, NULL, 0, exp_2str, 2); + + event_unref(&e); + event_unref(&parent); + + test_end(); +} + +void test_event_flatten(void) +{ + test_event_flatten_no_parent(); + test_event_flatten_one_parent(); + test_event_flatten_override_parent_field(); +} diff --git a/src/lib/test-lib.inc b/src/lib/test-lib.inc index 94d3b8105d..0d2f76ecf7 100644 --- a/src/lib/test-lib.inc +++ b/src/lib/test-lib.inc @@ -16,8 +16,9 @@ TEST(test_connection) TEST(test_crc32) TEST(test_data_stack) FATAL(fatal_data_stack) -TEST(test_event_log) TEST(test_event_filter) +TEST(test_event_flatten) +TEST(test_event_log) TEST(test_failures) TEST(test_file_create_locked) TEST(test_guid)