From: Mozejko, MarcinX Date: Tue, 16 Oct 2018 11:27:42 +0000 (+0100) Subject: logparser plugin: Add unit tests X-Git-Tag: collectd-5.11.0~18^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9c10ab1f6154a469f0754178f6e0d8224f37ce5d;p=thirdparty%2Fcollectd.git logparser plugin: Add unit tests Change-Id: I193aa776d6fbc1e31690db96d85143707823fbe1 Signed-off-by: Mozejko, MarcinX --- diff --git a/Makefile.am b/Makefile.am index b14d50cfa..f2f01cd0f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1225,6 +1225,19 @@ logparser_la_SOURCES = src/logparser.c \ src/utils_latency_config.c src/utils_latency_config.h logparser_la_CPPFLAGS = $(AM_CPPFLAGS) logparser_la_LDFLAGS = $(PLUGIN_LDFLAGS) -lm + +test_plugin_logparser_SOURCES = src/logparser_test.c \ + src/utils_message_parser.c \ + src/utils_tail_match.c src/utils_tail_match.h \ + src/utils_tail.c src/utils_tail.h \ + src/utils_match.c src/utils_match.h \ + src/daemon/configfile.c \ + src/daemon/types_list.c +test_plugin_logparser_CPPFLAGS = $(AM_CPPFLAGS) +test_plugin_logparser_LDFLAGS = $(PLUGIN_LDFLAGS) +test_plugin_logparser_LDADD = liboconfig.la libplugin_mock.la liblatency.la +check_PROGRAMS += test_plugin_logparser +TESTS += test_plugin_logparser endif if BUILD_PLUGIN_LOG_LOGSTASH diff --git a/src/logparser.c b/src/logparser.c index 056aae34d..303eb8d7c 100644 --- a/src/logparser.c +++ b/src/logparser.c @@ -670,15 +670,21 @@ static int logparser_shutdown(void) { if (parser->job != NULL) message_parser_cleanup(parser->job); - for (size_t j = 0; j < parser->patterns_len; j++) + for (size_t j = 0; j < parser->patterns_len; j++) { if (parser->patterns[j].free_user_data != NULL) parser->patterns[j].free_user_data(parser->patterns[j].user_data); + sfree(parser->patterns[j].name); + sfree(parser->patterns[j].regex); + sfree(parser->patterns[j].excluderegex); + } + sfree(parser->patterns); sfree(parser->filename); sfree(parser->def_plugin_inst); sfree(parser->def_type); sfree(parser->def_type_inst); + sfree(parser->name); } sfree(logparser_ctx.parsers); diff --git a/src/logparser_test.c b/src/logparser_test.c new file mode 100644 index 000000000..908b3eaa4 --- /dev/null +++ b/src/logparser_test.c @@ -0,0 +1,448 @@ +/** + * collectd - src/logparser_test.c + * + * Copyright(c) 2018 Intel Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Marcin Mozejko + * Adrian Boczkowski + **/ + +#include "logparser.c" +#include "testing.h" + +DEF_TEST(init) { + logparser_ctx.parsers_len = 3; + logparser_ctx.parsers = calloc(3, sizeof(log_parser_t)); + + logparser_ctx.parsers[0].filename = "test_filename0"; + logparser_ctx.parsers[0].patterns_len = 3; + logparser_ctx.parsers[0].patterns = calloc(3, sizeof(message_pattern_t)); + logparser_ctx.parsers[0].patterns[0].regex = "test_regex00"; + logparser_ctx.parsers[0].patterns[0].excluderegex = "exclude_regex00"; + logparser_ctx.parsers[0].patterns[0].is_mandatory = true; + logparser_ctx.parsers[0].patterns[0].submatch_idx = 1; + logparser_ctx.parsers[0].patterns[0].name = "test_name00"; + logparser_ctx.parsers[0].patterns[1].regex = "test_regex01"; + logparser_ctx.parsers[0].patterns[1].excluderegex = "exclude_regex01"; + logparser_ctx.parsers[0].patterns[1].is_mandatory = true; + logparser_ctx.parsers[0].patterns[1].submatch_idx = 1; + logparser_ctx.parsers[0].patterns[1].name = "test_name01"; + logparser_ctx.parsers[0].patterns[2].regex = "test_regex02"; + logparser_ctx.parsers[0].patterns[2].excluderegex = "exclude_regex02"; + logparser_ctx.parsers[0].patterns[2].is_mandatory = true; + logparser_ctx.parsers[0].patterns[2].submatch_idx = 1; + logparser_ctx.parsers[0].patterns[2].name = "test_name02"; + + logparser_ctx.parsers[1].filename = "test_filename1"; + logparser_ctx.parsers[1].patterns_len = 3; + logparser_ctx.parsers[1].patterns = calloc(3, sizeof(message_pattern_t)); + logparser_ctx.parsers[1].patterns[0].regex = "test_regex10"; + logparser_ctx.parsers[1].patterns[0].excluderegex = "exclude_regex10"; + logparser_ctx.parsers[1].patterns[0].is_mandatory = true; + logparser_ctx.parsers[1].patterns[0].submatch_idx = 1; + logparser_ctx.parsers[1].patterns[0].name = "test_name10"; + logparser_ctx.parsers[1].patterns[1].regex = "test_regex11"; + logparser_ctx.parsers[1].patterns[1].excluderegex = "exclude_regex11"; + logparser_ctx.parsers[1].patterns[1].is_mandatory = true; + logparser_ctx.parsers[1].patterns[1].submatch_idx = 1; + logparser_ctx.parsers[1].patterns[1].name = "test_name11"; + logparser_ctx.parsers[1].patterns[2].regex = "test_regex12"; + logparser_ctx.parsers[1].patterns[2].excluderegex = "exclude_regex12"; + logparser_ctx.parsers[1].patterns[2].is_mandatory = true; + logparser_ctx.parsers[1].patterns[2].submatch_idx = 1; + logparser_ctx.parsers[1].patterns[2].name = "test_name12"; + + logparser_ctx.parsers[2].filename = "test_filename2"; + logparser_ctx.parsers[2].patterns_len = 3; + logparser_ctx.parsers[2].patterns = calloc(3, sizeof(message_pattern_t)); + logparser_ctx.parsers[2].patterns[0].regex = "test_regex20"; + logparser_ctx.parsers[2].patterns[0].excluderegex = "exclude_regex20"; + logparser_ctx.parsers[2].patterns[0].is_mandatory = true; + logparser_ctx.parsers[2].patterns[0].submatch_idx = 1; + logparser_ctx.parsers[2].patterns[0].name = "test_name20"; + logparser_ctx.parsers[2].patterns[1].regex = "test_regex21"; + logparser_ctx.parsers[2].patterns[1].excluderegex = "exclude_regex21"; + logparser_ctx.parsers[2].patterns[1].is_mandatory = true; + logparser_ctx.parsers[2].patterns[1].submatch_idx = 1; + logparser_ctx.parsers[2].patterns[1].name = "test_name21"; + logparser_ctx.parsers[2].patterns[2].regex = "test_regex22"; + logparser_ctx.parsers[2].patterns[2].excluderegex = "exclude_regex22"; + logparser_ctx.parsers[2].patterns[2].is_mandatory = true; + logparser_ctx.parsers[2].patterns[2].submatch_idx = 1; + logparser_ctx.parsers[2].patterns[2].name = "test_name22"; + + int ret = logparser_init(); + sfree(logparser_ctx.parsers[0].patterns); + sfree(logparser_ctx.parsers[1].patterns); + sfree(logparser_ctx.parsers[2].patterns); + message_parser_cleanup(logparser_ctx.parsers[0].job); + message_parser_cleanup(logparser_ctx.parsers[1].job); + message_parser_cleanup(logparser_ctx.parsers[2].job); + sfree(logparser_ctx.parsers); + logparser_ctx.parsers_len = 0; + EXPECT_EQ_INT(0, ret); + + return 0; +} + +DEF_TEST(free_user_data) { + message_item_user_data_t *user_data = calloc(1, sizeof(*user_data)); + + user_data->infos_len = 4; + user_data->infos[0].type = MSG_ITEM_SEVERITY; + user_data->infos[0].val.severity = NOTIF_OKAY; + user_data->infos[1].type = MSG_ITEM_PLUGIN_INST; + user_data->infos[1].val.str_override = strdup("test_plugin_inst"); + user_data->infos[2].type = MSG_ITEM_TYPE; + user_data->infos[2].val.str_override = strdup("test_type"); + user_data->infos[3].type = MSG_ITEM_TYPE_INST; + user_data->infos[3].val.str_override = strdup("test_type_inst"); + logparser_free_user_data(user_data); + + return 0; +} + +DEF_TEST(config_logfile) { + oconfig_item_t *logfile_ci = calloc(1, sizeof(*logfile_ci)); + assert(logfile_ci != NULL); + logfile_ci->key = "Logfile"; + + logfile_ci->values_num = 1; + logfile_ci->values = + calloc(logfile_ci->values_num, sizeof(*logfile_ci->values)); + assert(logfile_ci->values != NULL); + logfile_ci->values->type = OCONFIG_TYPE_STRING; + logfile_ci->values->value.string = "/path/to/a/file"; + + logfile_ci->children_num = 2; + logfile_ci->children = + calloc(logfile_ci->children_num, sizeof(*logfile_ci->children)); + assert(logfile_ci->children != NULL); + + oconfig_item_t *first_full_read_ci = &logfile_ci->children[0]; + first_full_read_ci->key = "FirstFullRead"; + + first_full_read_ci->values_num = 1; + first_full_read_ci->values = calloc(first_full_read_ci->values_num, + sizeof(*first_full_read_ci->values)); + assert(first_full_read_ci->values != NULL); + first_full_read_ci->values->type = OCONFIG_TYPE_BOOLEAN; + first_full_read_ci->values->value.boolean = true; + + oconfig_item_t *msg_ci = &logfile_ci->children[1]; + msg_ci->key = "Message"; + + msg_ci->values_num = 1; + msg_ci->values = calloc(msg_ci->values_num, sizeof(*msg_ci->values)); + assert(msg_ci->values != NULL); + msg_ci->values->type = OCONFIG_TYPE_STRING; + msg_ci->values->value.string = "msg-name"; + + msg_ci->children_num = 6; + msg_ci->children = calloc(msg_ci->children_num, sizeof(*msg_ci->children)); + assert(msg_ci->children != NULL); + + oconfig_item_t *def_plugin_inst_ci = &msg_ci->children[0]; + def_plugin_inst_ci->key = "DefaultPluginInstance"; + def_plugin_inst_ci->values_num = 1; + def_plugin_inst_ci->values = calloc(def_plugin_inst_ci->values_num, + sizeof(*def_plugin_inst_ci->values)); + assert(def_plugin_inst_ci->values != NULL); + def_plugin_inst_ci->values->type = OCONFIG_TYPE_STRING; + def_plugin_inst_ci->values->value.string = "test_default_plugin_instance_1"; + + oconfig_item_t *def_type_ci = &msg_ci->children[1]; + def_type_ci->key = "DefaultType"; + def_type_ci->values_num = 1; + def_type_ci->values = + calloc(def_type_ci->values_num, sizeof(*def_type_ci->values)); + assert(def_type_ci->values != NULL); + def_type_ci->values->type = OCONFIG_TYPE_STRING; + def_type_ci->values->value.string = "test_default_type_1"; + + oconfig_item_t *def_type_inst_ci = &msg_ci->children[2]; + def_type_inst_ci->key = "DefaultTypeInstance"; + def_type_inst_ci->values_num = 1; + def_type_inst_ci->values = + calloc(def_type_inst_ci->values_num, sizeof(*def_type_inst_ci->values)); + assert(def_type_inst_ci->values != NULL); + def_type_inst_ci->values->type = OCONFIG_TYPE_STRING; + def_type_inst_ci->values->value.string = "test_default_type_instance_1"; + + oconfig_item_t *def_severity_ci = &msg_ci->children[3]; + def_severity_ci->key = "DefaultSeverity"; + def_severity_ci->values_num = 1; + def_severity_ci->values = + calloc(def_severity_ci->values_num, sizeof(*def_severity_ci->values)); + assert(def_severity_ci->values != NULL); + def_severity_ci->values->type = OCONFIG_TYPE_STRING; + def_severity_ci->values->value.string = "OK"; + + oconfig_item_t *match1_ci = &msg_ci->children[4]; + assert(match1_ci != NULL); + match1_ci->key = "Match"; + match1_ci->values_num = 1; + match1_ci->values = calloc(match1_ci->values_num, sizeof(*match1_ci->values)); + assert(match1_ci->values != NULL); + match1_ci->values->type = OCONFIG_TYPE_STRING; + match1_ci->values->value.string = "test_match_1"; + + match1_ci->children_num = 6; + match1_ci->children = + calloc(match1_ci->children_num, sizeof(*match1_ci->children)); + assert(match1_ci->children != NULL); + + oconfig_item_t *regex1_ci = &match1_ci->children[0]; + regex1_ci->key = "Regex"; + regex1_ci->values_num = 1; + regex1_ci->values = calloc(regex1_ci->values_num, sizeof(*regex1_ci->values)); + assert(regex1_ci->values != NULL); + regex1_ci->values->type = OCONFIG_TYPE_STRING; + regex1_ci->values->value.string = "test_regex_1"; + + oconfig_item_t *submatch_idx1_ci = &match1_ci->children[1]; + submatch_idx1_ci->key = "SubmatchIdx"; + submatch_idx1_ci->values_num = 1; + submatch_idx1_ci->values = + calloc(submatch_idx1_ci->values_num, sizeof(*submatch_idx1_ci->values)); + assert(submatch_idx1_ci->values != NULL); + submatch_idx1_ci->values->type = OCONFIG_TYPE_NUMBER; + submatch_idx1_ci->values->value.number = 15; + + oconfig_item_t *is_mandatory1_ci = &match1_ci->children[2]; + is_mandatory1_ci->key = "IsMandatory"; + is_mandatory1_ci->values_num = 1; + is_mandatory1_ci->values = + calloc(is_mandatory1_ci->values_num, sizeof(*is_mandatory1_ci->values)); + assert(is_mandatory1_ci->values != NULL); + is_mandatory1_ci->values->type = OCONFIG_TYPE_BOOLEAN; + is_mandatory1_ci->values->value.boolean = false; + + oconfig_item_t *severity1_ci = &match1_ci->children[3]; + severity1_ci->key = "Severity"; + severity1_ci->values_num = 1; + severity1_ci->values = + calloc(severity1_ci->values_num, sizeof(*severity1_ci->values)); + assert(severity1_ci->values != NULL); + severity1_ci->values->type = OCONFIG_TYPE_STRING; + severity1_ci->values->value.string = "failure"; + + oconfig_item_t *type_inst1_ci = &match1_ci->children[4]; + type_inst1_ci->key = "TypeInstance"; + type_inst1_ci->values_num = 1; + type_inst1_ci->values = + calloc(type_inst1_ci->values_num, sizeof(*type_inst1_ci->values)); + assert(type_inst1_ci->values != NULL); + type_inst1_ci->values->type = OCONFIG_TYPE_STRING; + type_inst1_ci->values->value.string = "test_type_instance_1"; + + oconfig_item_t *plugin_inst1_ci = &match1_ci->children[5]; + plugin_inst1_ci->key = "PluginInstance"; + plugin_inst1_ci->values_num = 1; + plugin_inst1_ci->values = + calloc(plugin_inst1_ci->values_num, sizeof(*plugin_inst1_ci->values)); + assert(plugin_inst1_ci->values != NULL); + plugin_inst1_ci->values->type = OCONFIG_TYPE_STRING; + plugin_inst1_ci->values->value.string = "test_plugin_instance_1"; + + oconfig_item_t *match2_ci = &msg_ci->children[5]; + assert(match2_ci != NULL); + match2_ci->key = "Match"; + match2_ci->values_num = 1; + match2_ci->values = calloc(match2_ci->values_num, sizeof(*match2_ci->values)); + assert(match2_ci->values != NULL); + match2_ci->values->type = OCONFIG_TYPE_STRING; + match2_ci->values->value.string = "test_match_2"; + + match2_ci->children_num = 6; + match2_ci->children = + calloc(match2_ci->children_num, sizeof(*match2_ci->children)); + assert(match2_ci->children != NULL); + + oconfig_item_t *regex2_ci = &match2_ci->children[0]; + regex2_ci->key = "Regex"; + regex2_ci->values_num = 1; + regex2_ci->values = calloc(regex2_ci->values_num, sizeof(*regex2_ci->values)); + assert(regex2_ci->values != NULL); + regex2_ci->values->type = OCONFIG_TYPE_STRING; + regex2_ci->values->value.string = "test_regex_2"; + + oconfig_item_t *submatch_idx2_ci = &match2_ci->children[1]; + submatch_idx2_ci->key = "SubmatchIdx"; + submatch_idx2_ci->values_num = 1; + submatch_idx2_ci->values = + calloc(submatch_idx2_ci->values_num, sizeof(*submatch_idx2_ci->values)); + assert(submatch_idx2_ci->values != NULL); + submatch_idx2_ci->values->type = OCONFIG_TYPE_NUMBER; + submatch_idx2_ci->values->value.number = 8; + + oconfig_item_t *is_mandatory2_ci = &match2_ci->children[2]; + is_mandatory2_ci->key = "IsMandatory"; + is_mandatory2_ci->values_num = 1; + is_mandatory2_ci->values = + calloc(is_mandatory2_ci->values_num, sizeof(*is_mandatory2_ci->values)); + assert(is_mandatory2_ci->values != NULL); + is_mandatory2_ci->values->type = OCONFIG_TYPE_BOOLEAN; + is_mandatory2_ci->values->value.boolean = true; + + oconfig_item_t *severity2_ci = &match2_ci->children[3]; + severity2_ci->key = "Severity"; + severity2_ci->values_num = 1; + severity2_ci->values = + calloc(severity2_ci->values_num, sizeof(*severity2_ci->values)); + assert(severity2_ci->values != NULL); + severity2_ci->values->type = OCONFIG_TYPE_STRING; + severity2_ci->values->value.string = "warning"; + + oconfig_item_t *type_inst2_ci = &match2_ci->children[4]; + type_inst2_ci->key = "TypeInstance"; + type_inst2_ci->values_num = 1; + type_inst2_ci->values = + calloc(type_inst2_ci->values_num, sizeof(*type_inst2_ci->values)); + assert(type_inst2_ci->values != NULL); + type_inst2_ci->values->type = OCONFIG_TYPE_STRING; + type_inst2_ci->values->value.string = "test_type_instance_2"; + + oconfig_item_t *plugin_inst2_ci = &match2_ci->children[5]; + plugin_inst2_ci->key = "PluginInstance"; + plugin_inst2_ci->values_num = 1; + plugin_inst2_ci->values = + calloc(plugin_inst2_ci->values_num, sizeof(*plugin_inst2_ci->values)); + assert(plugin_inst2_ci->values != NULL); + plugin_inst2_ci->values->type = OCONFIG_TYPE_STRING; + plugin_inst2_ci->values->value.string = "test_plugin_instance_2"; + + int ret = logparser_config_logfile(logfile_ci); + EXPECT_EQ_INT(0, ret); + + EXPECT_EQ_INT(1, logparser_ctx.parsers_len); + + log_parser_t *parser = &logparser_ctx.parsers[0]; + + EXPECT_EQ_INT(1, parser->first_read); + EXPECT_EQ_STR("/path/to/a/file", parser->filename); + EXPECT_EQ_STR("test_default_plugin_instance_1", parser->def_plugin_inst); + EXPECT_EQ_INT(NOTIF_OKAY, parser->def_severity); + EXPECT_EQ_STR("test_default_type_1", parser->def_type); + EXPECT_EQ_STR("test_default_type_instance_1", parser->def_type_inst); + EXPECT_EQ_INT(2, parser->patterns_len); + + message_pattern_t *pattern = &logparser_ctx.parsers[0].patterns[0]; + EXPECT_EQ_STR("test_regex_1", pattern->regex); + EXPECT_EQ_INT(0, pattern->is_mandatory); + EXPECT_EQ_INT(15, pattern->submatch_idx); + EXPECT_EQ_STR("test_match_1", pattern->name); + + message_item_user_data_t *user_data = pattern->user_data; + EXPECT_EQ_INT(3, user_data->infos_len); + for (size_t i = 0; i < user_data->infos_len; ++i) { + switch (user_data->infos[i].type) { + case MSG_ITEM_PLUGIN_INST: + EXPECT_EQ_STR("test_plugin_instance_1", + user_data->infos[i].val.str_override); + break; + case MSG_ITEM_TYPE_INST: + EXPECT_EQ_STR("test_type_instance_1", + user_data->infos[i].val.str_override); + break; + case MSG_ITEM_SEVERITY: + EXPECT_EQ_INT(NOTIF_FAILURE, user_data->infos[i].val.severity); + break; + default: + OK1(false, "Unknown message item"); + } + } + + pattern = &logparser_ctx.parsers[0].patterns[1]; + EXPECT_EQ_STR("test_regex_2", pattern->regex); + EXPECT_EQ_INT(1, pattern->is_mandatory); + EXPECT_EQ_INT(8, pattern->submatch_idx); + EXPECT_EQ_STR("test_match_2", pattern->name); + + user_data = pattern->user_data; + EXPECT_EQ_INT(3, user_data->infos_len); + for (size_t i = 0; i < user_data->infos_len; ++i) { + switch (user_data->infos[i].type) { + case MSG_ITEM_PLUGIN_INST: + EXPECT_EQ_STR("test_plugin_instance_2", + user_data->infos[i].val.str_override); + break; + case MSG_ITEM_TYPE_INST: + EXPECT_EQ_STR("test_type_instance_2", + user_data->infos[i].val.str_override); + break; + case MSG_ITEM_SEVERITY: + EXPECT_EQ_INT(NOTIF_WARNING, user_data->infos[i].val.severity); + break; + default: + OK1(false, "Unknown message item"); + } + } + + sfree(regex1_ci->values); + sfree(submatch_idx1_ci->values); + sfree(is_mandatory1_ci->values); + sfree(severity1_ci->values); + sfree(type_inst1_ci->values); + sfree(plugin_inst1_ci->values); + + sfree(regex2_ci->values); + sfree(submatch_idx2_ci->values); + sfree(is_mandatory2_ci->values); + sfree(severity2_ci->values); + sfree(type_inst2_ci->values); + sfree(plugin_inst2_ci->values); + + sfree(match2_ci->children); + sfree(match2_ci->values); + + sfree(match1_ci->children); + sfree(match1_ci->values); + + sfree(def_plugin_inst_ci->values); + sfree(def_type_ci->values); + sfree(def_type_inst_ci->values); + sfree(def_severity_ci->values); + + sfree(msg_ci->children); + sfree(msg_ci->values); + + sfree(first_full_read_ci->values); + + sfree(logfile_ci->children); + sfree(logfile_ci->values); + + sfree(logfile_ci); + + logparser_shutdown(); + + return 0; +} + +int main(void) { + + RUN_TEST(init); + RUN_TEST(free_user_data); + RUN_TEST(config_logfile); + + END_TEST; +}