#include #include #include "envoy/config/common/matcher/v3/matcher.pb.validate.h" #include "envoy/config/core/v3/extension.pb.h" #include "envoy/matcher/matcher.h" #include "envoy/registry/registry.h" #include "common/matcher/list_matcher.h" #include "common/matcher/matcher.h" #include "common/protobuf/utility.h" #include "test/common/matcher/test_utility.h" #include "test/test_common/registry.h" #include "test/test_common/utility.h" #include "gtest/gtest.h" namespace Envoy { namespace Matcher { class MatcherTest : public ::testing::Test { public: MatcherTest() : inject_action_(action_factory_) {} StringActionFactory action_factory_; Registry::InjectFactory inject_action_; }; TEST_F(MatcherTest, TestMatcher) { const std::string yaml = R"EOF( matcher_tree: input: name: outer_input typed_config: "@type": type.googleapis.com/google.protobuf.StringValue exact_match_map: map: value: matcher: matcher_list: matchers: - on_match: action: name: test_action typed_config: "@type": type.googleapis.com/google.protobuf.StringValue value: match!! predicate: single_predicate: input: name: inner_input typed_config: "@type": type.googleapis.com/google.protobuf.StringValue value_match: exact: foo )EOF"; envoy::config::common::matcher::v3::Matcher matcher; MessageUtil::loadFromYaml(yaml, matcher, ProtobufMessage::getStrictValidationVisitor()); TestUtility::validate(matcher); MatchTreeFactory factory(ProtobufMessage::getStrictValidationVisitor()); auto outer_factory = TestDataInputFactory("outer_input", "value"); auto inner_factory = TestDataInputFactory("inner_input", "foo"); auto match_tree = factory.create(matcher); const auto result = match_tree->match(TestData()); EXPECT_EQ(result.match_state_, MatchState::MatchComplete); EXPECT_TRUE(result.on_match_.has_value()); EXPECT_NE(result.on_match_->action_cb_, nullptr); } TEST_F(MatcherTest, CustomMatcher) { const std::string yaml = R"EOF( matcher_list: matchers: - on_match: action: name: test_action typed_config: "@type": type.googleapis.com/google.protobuf.StringValue value: match!! predicate: single_predicate: input: name: inner_input typed_config: "@type": type.googleapis.com/google.protobuf.StringValue custom_match: name: never_match typed_config: {} )EOF"; envoy::config::common::matcher::v3::Matcher matcher; MessageUtil::loadFromYaml(yaml, matcher, ProtobufMessage::getStrictValidationVisitor()); TestUtility::validate(matcher); MatchTreeFactory factory(ProtobufMessage::getStrictValidationVisitor()); auto inner_factory = TestDataInputFactory("inner_input", "foo"); NeverMatchFactory match_factory; auto match_tree = factory.create(matcher); const auto result = match_tree->match(TestData()); EXPECT_EQ(result.match_state_, MatchState::MatchComplete); EXPECT_FALSE(result.on_match_.has_value()); } TEST_F(MatcherTest, TestAndMatcher) { const std::string yaml = R"EOF( matcher_tree: input: name: outer_input typed_config: "@type": type.googleapis.com/google.protobuf.StringValue exact_match_map: map: value: matcher: matcher_list: matchers: - on_match: action: name: test_action typed_config: "@type": type.googleapis.com/google.protobuf.StringValue value: match!! predicate: and_matcher: predicate: - single_predicate: input: name: inner_input typed_config: "@type": type.googleapis.com/google.protobuf.StringValue value_match: exact: foo - single_predicate: input: name: inner_input typed_config: "@type": type.googleapis.com/google.protobuf.StringValue value_match: exact: foo )EOF"; envoy::config::common::matcher::v3::Matcher matcher; MessageUtil::loadFromYaml(yaml, matcher, ProtobufMessage::getStrictValidationVisitor()); TestUtility::validate(matcher); MatchTreeFactory factory(ProtobufMessage::getStrictValidationVisitor()); auto outer_factory = TestDataInputFactory("outer_input", "value"); auto inner_factory = TestDataInputFactory("inner_input", "foo"); auto match_tree = factory.create(matcher); const auto result = match_tree->match(TestData()); EXPECT_EQ(result.match_state_, MatchState::MatchComplete); EXPECT_TRUE(result.on_match_.has_value()); EXPECT_NE(result.on_match_->action_cb_, nullptr); } TEST_F(MatcherTest, TestOrMatcher) { const std::string yaml = R"EOF( matcher_tree: input: name: outer_input typed_config: "@type": type.googleapis.com/google.protobuf.StringValue exact_match_map: map: value: matcher: matcher_list: matchers: - on_match: action: name: test_action typed_config: "@type": type.googleapis.com/google.protobuf.StringValue value: match!! predicate: or_matcher: predicate: - single_predicate: input: name: inner_input typed_config: "@type": type.googleapis.com/google.protobuf.StringValue value_match: exact: foo - single_predicate: input: name: inner_input typed_config: "@type": type.googleapis.com/google.protobuf.StringValue value_match: exact: foo )EOF"; envoy::config::common::matcher::v3::Matcher matcher; MessageUtil::loadFromYaml(yaml, matcher, ProtobufMessage::getStrictValidationVisitor()); TestUtility::validate(matcher); MatchTreeFactory factory(ProtobufMessage::getStrictValidationVisitor()); auto outer_factory = TestDataInputFactory("outer_input", "value"); auto inner_factory = TestDataInputFactory("inner_input", "foo"); auto match_tree = factory.create(matcher); const auto result = match_tree->match(TestData()); EXPECT_EQ(result.match_state_, MatchState::MatchComplete); EXPECT_TRUE(result.on_match_.has_value()); EXPECT_NE(result.on_match_->action_cb_, nullptr); } TEST_F(MatcherTest, TestRecursiveMatcher) { const std::string yaml = R"EOF( matcher_list: matchers: - on_match: matcher: matcher_list: matchers: - on_match: action: name: test_action typed_config: "@type": type.googleapis.com/google.protobuf.StringValue value: match!! predicate: single_predicate: input: name: inner_input typed_config: "@type": type.googleapis.com/google.protobuf.StringValue value_match: exact: foo predicate: single_predicate: input: name: inner_input typed_config: "@type": type.googleapis.com/google.protobuf.StringValue value_match: exact: foo )EOF"; envoy::config::common::matcher::v3::Matcher matcher; MessageUtil::loadFromYaml(yaml, matcher, ProtobufMessage::getStrictValidationVisitor()); TestUtility::validate(matcher); MatchTreeFactory factory(ProtobufMessage::getStrictValidationVisitor()); auto outer_factory = TestDataInputFactory("outer_input", "value"); auto inner_factory = TestDataInputFactory("inner_input", "foo"); auto match_tree = factory.create(matcher); const auto result = match_tree->match(TestData()); EXPECT_EQ(result.match_state_, MatchState::MatchComplete); EXPECT_TRUE(result.on_match_.has_value()); EXPECT_EQ(result.on_match_->action_cb_, nullptr); const auto recursive_result = evaluateMatch(*match_tree, TestData()); EXPECT_EQ(recursive_result.match_state_, MatchState::MatchComplete); EXPECT_NE(recursive_result.result_, nullptr); } TEST_F(MatcherTest, RecursiveMatcherNoMatch) { ListMatcher matcher(absl::nullopt); matcher.addMatcher(createSingleMatcher(absl::nullopt, [](auto) { return false; }), stringOnMatch("match")); const auto recursive_result = evaluateMatch(matcher, TestData()); EXPECT_EQ(recursive_result.match_state_, MatchState::MatchComplete); EXPECT_EQ(recursive_result.result_, nullptr); } TEST_F(MatcherTest, RecursiveMatcherCannotMatch) { ListMatcher matcher(absl::nullopt); matcher.addMatcher(createSingleMatcher( absl::nullopt, [](auto) { return false; }, DataInputGetResult::DataAvailability::NotAvailable), stringOnMatch("match")); const auto recursive_result = evaluateMatch(matcher, TestData()); EXPECT_EQ(recursive_result.match_state_, MatchState::UnableToMatch); EXPECT_EQ(recursive_result.result_, nullptr); } } // namespace Matcher } // namespace Envoy