From 10d7496c60664701e70d7f31f6e58f948a1cee0c Mon Sep 17 00:00:00 2001 From: Takahiro Yamashita Date: Sat, 6 May 2023 13:53:04 +0900 Subject: [PATCH] grep: add common grep APIs Signed-off-by: Takahiro Yamashita --- include/fluent-bit/flb_grep.h | 69 +++++ src/CMakeLists.txt | 1 + src/flb_grep.c | 260 ++++++++++++++++++ tests/internal/CMakeLists.txt | 1 + tests/internal/grep.c | 496 ++++++++++++++++++++++++++++++++++ 5 files changed, 827 insertions(+) create mode 100644 include/fluent-bit/flb_grep.h create mode 100644 src/flb_grep.c create mode 100644 tests/internal/grep.c diff --git a/include/fluent-bit/flb_grep.h b/include/fluent-bit/flb_grep.h new file mode 100644 index 00000000000..7688cee215a --- /dev/null +++ b/include/fluent-bit/flb_grep.h @@ -0,0 +1,69 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLB_GREP_H +#define FLB_GREP_H + +#include +#include +#include + +/* rule types */ +enum flb_grep_rule_type{ + FLB_GREP_NO_RULE, + FLB_GREP_REGEX, + FLB_GREP_EXCLUDE +}; + +/* actions */ +enum flb_grep_action{ + FLB_GREP_RET_KEEP, + FLB_GREP_RET_EXCLUDE +}; + +enum flb_grep_logical_op{ + FLB_GREP_LOGICAL_OP_LEGACY, + FLB_GREP_LOGICAL_OP_OR, + FLB_GREP_LOGICAL_OP_AND +}; + +struct flb_grep_rule +{ + int type; + flb_sds_t field; + char *regex_pattern; + struct flb_regex *regex; + struct flb_record_accessor *ra; + struct mk_list _head; +}; + + +struct flb_grep { + enum flb_grep_rule_type first_rule; + enum flb_grep_logical_op op; + struct mk_list rules; /* flb_grep_rule list */ +}; + + +int flb_grep_filter(msgpack_object map, struct flb_grep *grep_ctx); +int flb_grep_set_rule_str(struct flb_grep *ctx, enum flb_grep_rule_type type, char *rule_str); +struct flb_grep *flb_grep_create(enum flb_grep_logical_op op); +int flb_grep_destroy(struct flb_grep *grep_ctx); + +#endif /* FLB_GREP_H */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 06a206dd445..0bb29748861 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -77,6 +77,7 @@ set(src flb_log_event_encoder_dynamic_field.c flb_processor.c flb_reload.c + flb_grep.c ) # Config format diff --git a/src/flb_grep.c b/src/flb_grep.c new file mode 100644 index 00000000000..7bbed4fe2f0 --- /dev/null +++ b/src/flb_grep.c @@ -0,0 +1,260 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +/* Fluent Bit + * ========== + * Copyright (C) 2015-2023 The Fluent Bit Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +static int flb_grep_delete_rules(struct mk_list *rules) +{ + struct mk_list *tmp; + struct mk_list *head; + struct flb_grep_rule *rule; + + if (rules == NULL) { + return 0; + } + + mk_list_foreach_safe(head, tmp, rules) { + rule = mk_list_entry(head, struct flb_grep_rule, _head); + flb_sds_destroy(rule->field); + flb_free(rule->regex_pattern); + flb_ra_destroy(rule->ra); + flb_regex_destroy(rule->regex); + mk_list_del(&rule->_head); + flb_free(rule); + } + return 0; +} + +int flb_grep_destroy(struct flb_grep *grep_ctx) +{ + int ret; + + if (grep_ctx == NULL) { + return 0; + } + + ret = flb_grep_delete_rules(&grep_ctx->rules); + flb_free(grep_ctx); + + return ret; +} + + +static int is_valid_rule_type(struct flb_grep *grep_ctx, enum flb_grep_rule_type type) +{ + if (type == FLB_GREP_NO_RULE) { + flb_error("%s: invalid type", __FUNCTION__); + return -1; + } + + if (grep_ctx->op != FLB_GREP_LOGICAL_OP_LEGACY) { + /* 'AND'/'OR' case */ + if (grep_ctx->first_rule != FLB_GREP_NO_RULE /* 2+ rules */ + && grep_ctx->first_rule != type) { + flb_error("Both 'regex' and 'exclude' are set."); + return FLB_FALSE; + } + } + + return FLB_TRUE; +} + +/* + * rule_str format is "KEY REGEX" . + * e.g. hostname *.com + */ +int flb_grep_set_rule_str(struct flb_grep *grep_ctx, enum flb_grep_rule_type type, char *rule_str) +{ + flb_sds_t tmp; + struct mk_list *split; + struct flb_split_entry *sentry; + struct flb_grep_rule *rule = NULL; + + if (grep_ctx == NULL || rule_str == NULL) { + flb_error("%s: input error", __FUNCTION__); + return -1; + } + + if (is_valid_rule_type(grep_ctx, type) != FLB_TRUE) { + return -1; + } + + rule = flb_malloc(sizeof(struct flb_grep_rule)); + if (rule == NULL) { + flb_errno(); + return -1; + } + rule->type = type; + if (grep_ctx->first_rule == FLB_GREP_NO_RULE) { + grep_ctx->first_rule = type; + } + + /* As a value we expect a pair of field name and a regular expression */ + split = flb_utils_split(rule_str, ' ', 1); + if (mk_list_size(split) != 2) { + flb_error("invalid regex, expected field and regular expression"); + flb_free(rule); + flb_utils_split_free(split); + return -1; + } + /* Get first value (field) */ + sentry = mk_list_entry_first(split, struct flb_split_entry, _head); + if (*sentry->value == '$') { + rule->field = flb_sds_create_len(sentry->value, sentry->len); + } + else { + rule->field = flb_sds_create_size(sentry->len + 2); + tmp = flb_sds_cat(rule->field, "$", 1); + rule->field = tmp; + + tmp = flb_sds_cat(rule->field, sentry->value, sentry->len); + rule->field = tmp; + } + + /* Get remaining content (regular expression) */ + sentry = mk_list_entry_last(split, struct flb_split_entry, _head); + rule->regex_pattern = flb_strndup(sentry->value, sentry->len); + if (rule->regex_pattern == NULL) { + flb_errno(); + flb_free(rule); + flb_utils_split_free(split); + return -1; + } + + /* Release split */ + flb_utils_split_free(split); + + /* Create a record accessor context for this rule */ + rule->ra = flb_ra_create(rule->field, FLB_FALSE); + if (!rule->ra) { + flb_error("invalid record accessor? '%s'", rule->field); + flb_free(rule); + return -1; + } + + /* Convert string to regex pattern */ + rule->regex = flb_regex_create(rule->regex_pattern); + if (!rule->regex) { + flb_error("could not compile regex pattern '%s'", + rule->regex_pattern); + flb_free(rule); + return -1; + } + + /* Link to parent list */ + mk_list_add(&rule->_head, &grep_ctx->rules); + + return 0; +} + +struct flb_grep *flb_grep_create(enum flb_grep_logical_op op) +{ + struct flb_grep *ctx = NULL; + + ctx = flb_calloc(1, sizeof(struct flb_grep)); + if (ctx == NULL) { + return NULL; + } + + ctx->first_rule = FLB_GREP_NO_RULE; + ctx->op = op; + mk_list_init(&ctx->rules); + + return ctx; +} + +static int flb_grep_filter_legacy(msgpack_object map, + struct flb_grep *grep_ctx) +{ + ssize_t ret; + struct mk_list *head; + struct flb_grep_rule *rule; + + /* For each rule, validate against map fields */ + mk_list_foreach(head, &grep_ctx->rules) { + rule = mk_list_entry(head, struct flb_grep_rule, _head); + + ret = flb_ra_regex_match(rule->ra, map, rule->regex, NULL); + if (ret <= 0) { /* no match */ + if (rule->type == FLB_GREP_REGEX) { + return FLB_GREP_RET_EXCLUDE; + } + } + else { + if (rule->type == FLB_GREP_EXCLUDE) { + return FLB_GREP_RET_EXCLUDE; + } + else { + return FLB_GREP_RET_KEEP; + } + } + } + + return FLB_GREP_RET_KEEP; +} + +static int flb_grep_filter_data_and_or(msgpack_object map, struct flb_grep *ctx) +{ + ssize_t ra_ret; + int found = FLB_FALSE; + struct mk_list *head; + struct flb_grep_rule *rule; + + /* For each rule, validate against map fields */ + mk_list_foreach(head, &ctx->rules) { + found = FLB_FALSE; + rule = mk_list_entry(head, struct flb_grep_rule, _head); + + ra_ret = flb_ra_regex_match(rule->ra, map, rule->regex, NULL); + if (ra_ret > 0) { + found = FLB_TRUE; + } + + if (ctx->op == FLB_GREP_LOGICAL_OP_OR && found == FLB_TRUE) { + /* OR case: One rule is matched. */ + goto grep_filter_data_and_or_end; + } + else if (ctx->op == FLB_GREP_LOGICAL_OP_AND && found == FLB_FALSE) { + /* AND case: One rule is not matched */ + goto grep_filter_data_and_or_end; + } + } + + grep_filter_data_and_or_end: + if (rule->type == FLB_GREP_REGEX) { + return found ? FLB_GREP_RET_KEEP : FLB_GREP_RET_EXCLUDE; + } + + /* rule is exclude */ + return found ? FLB_GREP_RET_EXCLUDE : FLB_GREP_RET_KEEP; +} + +int flb_grep_filter(msgpack_object map, struct flb_grep *grep_ctx) +{ + if (grep_ctx->op == FLB_GREP_LOGICAL_OP_LEGACY) { + return flb_grep_filter_legacy(map, grep_ctx); + } + return flb_grep_filter_data_and_or(map, grep_ctx); +} diff --git a/tests/internal/CMakeLists.txt b/tests/internal/CMakeLists.txt index b92b999cec3..1dd823f86bb 100644 --- a/tests/internal/CMakeLists.txt +++ b/tests/internal/CMakeLists.txt @@ -39,6 +39,7 @@ set(UNIT_TESTS_FILES env.c log.c processor.c + grep.c ) # Config format diff --git a/tests/internal/grep.c b/tests/internal/grep.c new file mode 100644 index 00000000000..bdab9d84344 --- /dev/null +++ b/tests/internal/grep.c @@ -0,0 +1,496 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +#include +#include +#include +#include + +#include "flb_tests_internal.h" + +void create_destroy() +{ + int ret; + struct flb_grep *grep; + + /* legacy */ + grep = flb_grep_create(FLB_GREP_LOGICAL_OP_LEGACY); + if (!TEST_CHECK(grep != NULL)) { + TEST_MSG("flb_grep_create failed. op is legacy"); + return; + } + ret = flb_grep_destroy(grep); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("flb_grep_destroy failed. ret=%d op is legacy", ret); + } + + /* or */ + grep = flb_grep_create(FLB_GREP_LOGICAL_OP_OR); + if (!TEST_CHECK(grep != NULL)) { + TEST_MSG("flb_grep_create failed. op is or"); + return; + } + ret = flb_grep_destroy(grep); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("flb_grep_destroy failed. ret=%d op is or", ret); + } + + /* and */ + grep = flb_grep_create(FLB_GREP_LOGICAL_OP_AND); + if (!TEST_CHECK(grep != NULL)) { + TEST_MSG("flb_grep_create failed. op is and"); + return; + } + ret = flb_grep_destroy(grep); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("flb_grep_destroy failed. ret=%d op is and", ret); + } +} + + +struct test_grep +{ + char *out_buf; + size_t out_size; + msgpack_unpacked result; +}; + +static struct test_grep* test_grep_create(char *json) +{ + int ret; + int type; + struct test_grep *test_grep; + + if (!TEST_CHECK(json != NULL)) { + TEST_MSG("json is NULL"); + return NULL; + } + + test_grep = flb_calloc(1, sizeof(struct test_grep)); + if (!TEST_CHECK(test_grep != NULL)) { + TEST_MSG("calloc failed"); + return NULL; + } + + ret = flb_pack_json(json, strlen(json), &test_grep->out_buf, &test_grep->out_size, + &type, NULL); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("flb_pack_json failed"); + flb_free(test_grep); + return NULL; + } + + msgpack_unpacked_init(&test_grep->result); + + return test_grep; +} + +static int test_grep_destroy(struct test_grep* test_grep) +{ + flb_free(test_grep->out_buf); + msgpack_unpacked_destroy(&test_grep->result); + flb_free(test_grep); + return 0; +} + +static const char* grep_action_str(int ret) +{ + switch (ret) { + case FLB_GREP_RET_KEEP: + return "FLB_GREP_RET_KEEP"; + break; + case FLB_GREP_RET_EXCLUDE: + return "FLB_GREP_RET_EXCLUDE"; + break; + default: + return "unknown value"; + } + return NULL; +} + +static const char* grep_op_str(int ret) +{ + switch (ret) { + case FLB_GREP_LOGICAL_OP_LEGACY: + return "Legacy"; + break; + case FLB_GREP_LOGICAL_OP_OR: + return "Or"; + break; + case FLB_GREP_LOGICAL_OP_AND: + return "And"; + break; + default: + return "unknown value"; + } + return NULL; +} + +static int test_grep_simple(enum flb_grep_logical_op op, char *json, + enum flb_grep_rule_type type, char *rule, + int expect) +{ + int ret; + size_t off = 0; + struct flb_grep *grep; + struct test_grep *test_grep; + + grep = flb_grep_create(op); + if (!TEST_CHECK(grep != NULL)) { + TEST_MSG("flb_grep_create failed. op is %s", grep_op_str(op)); + return -1; + } + + ret = flb_grep_set_rule_str(grep, type, rule); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("flb_grep_set_rule_str failed"); + flb_grep_destroy(grep); + return -1; + } + + test_grep = test_grep_create(json); + if (!TEST_CHECK(test_grep != NULL)) { + TEST_MSG("test_grep_create failed"); + flb_grep_destroy(grep); + return -1; + } + + msgpack_unpack_next(&test_grep->result, test_grep->out_buf, test_grep->out_size, &off); + ret = flb_grep_filter(test_grep->result.data, grep); + if (!TEST_CHECK(ret == expect)) { + TEST_MSG("test_grep_filter failed. ret=%s", grep_action_str(ret)); + test_grep_destroy(test_grep); + flb_grep_destroy(grep); + return -1; + } + + test_grep_destroy(test_grep); + ret = flb_grep_destroy(grep); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("flb_grep_destroy failed"); + return -1; + } + + return 0; +} + +void legacy_regex_match() +{ + test_grep_simple(FLB_GREP_LOGICAL_OP_LEGACY, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_REGEX, "key match", FLB_GREP_RET_KEEP); +} + +void legacy_regex_unmatch() +{ + test_grep_simple(FLB_GREP_LOGICAL_OP_LEGACY, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_REGEX, "key unmatch", FLB_GREP_RET_EXCLUDE); +} + +void legacy_exclude_match() +{ + test_grep_simple(FLB_GREP_LOGICAL_OP_LEGACY, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_EXCLUDE, "key match", FLB_GREP_RET_EXCLUDE); +} + +void legacy_exclude_unmatch() +{ + test_grep_simple(FLB_GREP_LOGICAL_OP_LEGACY, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_EXCLUDE, "key unmatch", FLB_GREP_RET_KEEP); +} + +void or_regex_match() +{ + test_grep_simple(FLB_GREP_LOGICAL_OP_OR, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_REGEX, "key match", FLB_GREP_RET_KEEP); +} + +void or_regex_unmatch() +{ + test_grep_simple(FLB_GREP_LOGICAL_OP_OR, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_REGEX, "key unmatch", FLB_GREP_RET_EXCLUDE); +} + +void or_exclude_match() +{ + test_grep_simple(FLB_GREP_LOGICAL_OP_OR, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_EXCLUDE, "key match", FLB_GREP_RET_EXCLUDE); +} + +void or_exclude_unmatch() +{ + test_grep_simple(FLB_GREP_LOGICAL_OP_OR, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_EXCLUDE, "key unmatch", FLB_GREP_RET_KEEP); +} + + +void and_regex_match() +{ + test_grep_simple(FLB_GREP_LOGICAL_OP_AND, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_REGEX, "key match", FLB_GREP_RET_KEEP); +} + +void and_regex_unmatch() +{ + test_grep_simple(FLB_GREP_LOGICAL_OP_AND, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_REGEX, "key unmatch", FLB_GREP_RET_EXCLUDE); +} + +void and_exclude_match() +{ + test_grep_simple(FLB_GREP_LOGICAL_OP_AND, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_EXCLUDE, "key match", FLB_GREP_RET_EXCLUDE); +} + +void and_exclude_unmatch() +{ + test_grep_simple(FLB_GREP_LOGICAL_OP_AND, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_EXCLUDE, "key unmatch", FLB_GREP_RET_KEEP); +} + +void or_regex_exclude_rules() +{ + int ret; + struct flb_grep *grep; + + grep = flb_grep_create(FLB_GREP_LOGICAL_OP_OR); + if (!TEST_CHECK(grep != NULL)) { + TEST_MSG("flb_grep_create failed. op is Or"); + return; + } + + ret = flb_grep_set_rule_str(grep, FLB_GREP_EXCLUDE, "key unmatch"); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("flb_grep_set_rule_str failed"); + flb_grep_destroy(grep); + return; + } + + /* Error! */ + ret = flb_grep_set_rule_str(grep, FLB_GREP_REGEX, "key match"); + if (!TEST_CHECK(ret != 0)) { + TEST_MSG("flb_grep_set_rule_str failed"); + flb_grep_destroy(grep); + return; + } + ret = flb_grep_destroy(grep); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("flb_grep_destroy failed"); + return; + } +} + +void and_regex_exclude_rules() +{ + int ret; + struct flb_grep *grep; + + grep = flb_grep_create(FLB_GREP_LOGICAL_OP_AND); + if (!TEST_CHECK(grep != NULL)) { + TEST_MSG("flb_grep_create failed. op is And"); + return; + } + + ret = flb_grep_set_rule_str(grep, FLB_GREP_EXCLUDE, "key unmatch"); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("flb_grep_set_rule_str failed"); + flb_grep_destroy(grep); + return; + } + + /* Error! */ + ret = flb_grep_set_rule_str(grep, FLB_GREP_REGEX, "key match"); + if (!TEST_CHECK(ret != 0)) { + TEST_MSG("flb_grep_set_rule_str failed"); + flb_grep_destroy(grep); + return; + } + ret = flb_grep_destroy(grep); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("flb_grep_destroy failed"); + return; + } +} + +struct str_list { + size_t size; + char **lists; +}; + +int test_grep_multi_rules(enum flb_grep_logical_op op, char *json, + enum flb_grep_rule_type type, struct str_list *list, + int expect) +{ + int ret; + size_t i; + size_t off = 0; + struct flb_grep *grep; + struct test_grep *test_grep; + + grep = flb_grep_create(op); + if (!TEST_CHECK(grep != NULL)) { + TEST_MSG("flb_grep_create failed. op is %s", grep_op_str(op)); + return -1; + } + + for (i=0; isize; i++) { + ret = flb_grep_set_rule_str(grep, type, list->lists[i]); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("%zd : flb_grep_set_rule_str failed", i); + flb_grep_destroy(grep); + return -1; + } + } + + test_grep = test_grep_create(json); + if (!TEST_CHECK(test_grep != NULL)) { + TEST_MSG("test_grep_create failed"); + flb_grep_destroy(grep); + return -1; + } + + msgpack_unpack_next(&test_grep->result, test_grep->out_buf, test_grep->out_size, &off); + ret = flb_grep_filter(test_grep->result.data, grep); + if (!TEST_CHECK(ret == expect)) { + TEST_MSG("test_grep_filter failed. ret=%s", grep_action_str(ret)); + test_grep_destroy(test_grep); + flb_grep_destroy(grep); + return -1; + } + + test_grep_destroy(test_grep); + ret = flb_grep_destroy(grep); + if (!TEST_CHECK(ret == 0)) { + TEST_MSG("flb_grep_destroy failed"); + return -1; + } + + return 0; +} + +void or_regexs_match(){ + char *rules[] = {"aa bb", "cc dd", "key match"}; + struct str_list rule_list = { + .size = sizeof(rules)/sizeof(char*), + .lists = &rules[0], + }; + + test_grep_multi_rules(FLB_GREP_LOGICAL_OP_OR, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_REGEX, &rule_list, FLB_GREP_RET_KEEP); +} + +void or_regexs_unmatch(){ + char *rules[] = {"aa bb", "cc dd", "key unmatch"}; + struct str_list rule_list = { + .size = sizeof(rules)/sizeof(char*), + .lists = &rules[0], + }; + + test_grep_multi_rules(FLB_GREP_LOGICAL_OP_OR, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_REGEX, &rule_list, FLB_GREP_RET_EXCLUDE); +} + +void or_excludes_match(){ + char *rules[] = {"aa bb", "cc dd", "key match"}; + struct str_list rule_list = { + .size = sizeof(rules)/sizeof(char*), + .lists = &rules[0], + }; + + test_grep_multi_rules(FLB_GREP_LOGICAL_OP_OR, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_EXCLUDE, &rule_list, FLB_GREP_RET_EXCLUDE); +} + +void or_excludes_unmatch(){ + char *rules[] = {"aa bb", "cc dd", "key unmatch"}; + struct str_list rule_list = { + .size = sizeof(rules)/sizeof(char*), + .lists = &rules[0], + }; + + test_grep_multi_rules(FLB_GREP_LOGICAL_OP_OR, "{\"key\":\"match\", \"hoge\":\"aaa\"}", + FLB_GREP_EXCLUDE, &rule_list, FLB_GREP_RET_KEEP); +} + +void and_regexs_match(){ + char *rules[] = {"aa bb", "cc dd", "key match"}; + struct str_list rule_list = { + .size = sizeof(rules)/sizeof(char*), + .lists = &rules[0], + }; + + test_grep_multi_rules(FLB_GREP_LOGICAL_OP_AND, + "{\"key\":\"match\", \"cc\":\"dd\", \"aa\":\"bb\"}", + FLB_GREP_REGEX, &rule_list, FLB_GREP_RET_KEEP); +} + +void and_regexs_unmatch(){ + char *rules[] = {"aa bb", "cc dd", "key unmatch"}; + struct str_list rule_list = { + .size = sizeof(rules)/sizeof(char*), + .lists = &rules[0], + }; + test_grep_multi_rules(FLB_GREP_LOGICAL_OP_AND, + "{\"key\":\"match\", \"cc\":\"dd\", \"aa\":\"bb\"}", + FLB_GREP_REGEX, &rule_list, FLB_GREP_RET_EXCLUDE); +} + +void and_excludes_match(){ + char *rules[] = {"aa bb", "cc dd", "key match"}; + struct str_list rule_list = { + .size = sizeof(rules)/sizeof(char*), + .lists = &rules[0], + }; + + test_grep_multi_rules(FLB_GREP_LOGICAL_OP_AND, + "{\"key\":\"match\", \"cc\":\"dd\", \"aa\":\"bb\"}", + FLB_GREP_EXCLUDE, &rule_list, FLB_GREP_RET_EXCLUDE); +} + +void and_excludes_unmatch(){ + char *rules[] = {"aa bb", "cc dd", "key unmatch"}; + struct str_list rule_list = { + .size = sizeof(rules)/sizeof(char*), + .lists = &rules[0], + }; + + test_grep_multi_rules(FLB_GREP_LOGICAL_OP_AND, + "{\"key\":\"match\", \"cc\":\"dd\", \"aa\":\"bb\"}", + FLB_GREP_EXCLUDE, &rule_list, FLB_GREP_RET_KEEP); +} + +TEST_LIST = { + {"create_destroy", create_destroy}, + + /* legacy */ + {"legacy_regex_match", legacy_regex_match}, + {"legacy_regex_unmatch", legacy_regex_unmatch}, + {"legacy_exclude_match", legacy_exclude_match}, + {"legacy_exclude_unmatch", legacy_exclude_unmatch}, + + /* OR */ + {"or_regex_match", or_regex_match}, + {"or_regex_unmatch", or_regex_unmatch}, + {"or_exclude_match", or_exclude_match}, + {"or_exclude_unmatch", or_exclude_unmatch}, + + {"or_regexs_match", or_regexs_match}, + {"or_regexs_unmatch", or_regexs_unmatch}, + {"or_excludes_match", or_excludes_match}, + {"or_excludes_unmatch", or_excludes_unmatch}, + + /* AND */ + {"and_regex_match", and_regex_match}, + {"and_regex_unmatch", and_regex_unmatch}, + {"and_exclude_match", and_exclude_match}, + {"and_exclude_unmatch", and_exclude_unmatch}, + + {"and_regexs_match", and_regexs_match}, + {"and_regexs_unmatch", and_regexs_unmatch}, + {"and_excludes_match", and_excludes_match}, + {"and_excludes_unmatch", and_excludes_unmatch}, + + /* error case */ + {"or_regex_exclude_rules", or_regex_exclude_rules}, + {"and_regex_exclude_rules", and_regex_exclude_rules}, + + { 0 } +};