From 758a9a90c15331fbfd093f23170454c5a2fbf903 Mon Sep 17 00:00:00 2001 From: Snow Pettersen Date: Thu, 1 Apr 2021 12:05:13 -0400 Subject: [PATCH] matching: add support for generic inputs and add environment variable input (#15410) Adds support for a "generic input" extension point that allows specifying inputs that are not dependent on protocol data. Adds an environment variable generic input that allows matching on the value of an environment variable. Signed-off-by: Snow Pettersen --- CODEOWNERS | 2 + api/BUILD | 1 + .../config/common/matcher/v3/matcher.proto | 1 + .../common/matcher/v4alpha/matcher.proto | 1 + .../environment_variable/v3/BUILD | 9 ++++ .../environment_variable/v3/input.proto | 22 ++++++++ api/versioning/BUILD | 1 + bazel/envoy_library.bzl | 1 + .../common_messages/common_messages.rst | 1 + generated_api_shadow/BUILD | 1 + .../config/common/matcher/v3/matcher.proto | 1 + .../common/matcher/v4alpha/matcher.proto | 1 + .../environment_variable/v3/BUILD | 9 ++++ .../environment_variable/v3/input.proto | 22 ++++++++ include/envoy/matcher/matcher.h | 29 +++++++++- source/common/matcher/matcher.h | 32 +++++++++-- source/extensions/extensions_build_config.bzl | 6 +++ .../common_inputs/environment_variable/BUILD | 34 ++++++++++++ .../environment_variable/config.cc | 39 ++++++++++++++ .../environment_variable/config.h | 35 ++++++++++++ .../environment_variable/input.h | 24 +++++++++ test/common/matcher/matcher_test.cc | 35 ++++++++++++ test/common/matcher/test_utility.h | 29 ++++++++++ .../common_inputs/environment_variable/BUILD | 31 +++++++++++ .../environment_variable/config_test.cc | 53 +++++++++++++++++++ .../environment_variable/input_test.cc | 26 +++++++++ 26 files changed, 442 insertions(+), 4 deletions(-) create mode 100644 api/envoy/extensions/matching/common_inputs/environment_variable/v3/BUILD create mode 100644 api/envoy/extensions/matching/common_inputs/environment_variable/v3/input.proto create mode 100644 generated_api_shadow/envoy/extensions/matching/common_inputs/environment_variable/v3/BUILD create mode 100644 generated_api_shadow/envoy/extensions/matching/common_inputs/environment_variable/v3/input.proto create mode 100644 source/extensions/matching/common_inputs/environment_variable/BUILD create mode 100644 source/extensions/matching/common_inputs/environment_variable/config.cc create mode 100644 source/extensions/matching/common_inputs/environment_variable/config.h create mode 100644 source/extensions/matching/common_inputs/environment_variable/input.h create mode 100644 test/extensions/matching/common_inputs/environment_variable/BUILD create mode 100644 test/extensions/matching/common_inputs/environment_variable/config_test.cc create mode 100644 test/extensions/matching/common_inputs/environment_variable/input_test.cc diff --git a/CODEOWNERS b/CODEOWNERS index ff73c10d891c..22712ae47fce 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -166,6 +166,8 @@ extensions/filters/http/oauth2 @rgs1 @derekargueta @snowp /*/extensions/rate_limit_descriptors/expr @kyessenov @lizan # hash input matcher /*/extensions/matching/input_matchers/consistent_hashing @snowp @donyu +# environment generic input +/*/extensions/matching/common_inputs/environment @snowp @donyu # user space socket pair and event /*/extensions/io_socket/user_space @lambdai @antoniovicente # Default UUID4 request ID extension diff --git a/api/BUILD b/api/BUILD index 0167c8a69dd2..7077b21ab0b3 100644 --- a/api/BUILD +++ b/api/BUILD @@ -246,6 +246,7 @@ proto_library( "//envoy/extensions/internal_redirect/allow_listed_routes/v3:pkg", "//envoy/extensions/internal_redirect/previous_routes/v3:pkg", "//envoy/extensions/internal_redirect/safe_cross_scheme/v3:pkg", + "//envoy/extensions/matching/common_inputs/environment_variable/v3:pkg", "//envoy/extensions/matching/input_matchers/consistent_hashing/v3:pkg", "//envoy/extensions/network/socket_interface/v3:pkg", "//envoy/extensions/rate_limit_descriptors/expr/v3:pkg", diff --git a/api/envoy/config/common/matcher/v3/matcher.proto b/api/envoy/config/common/matcher/v3/matcher.proto index aa49132ce990..f9a4aafa945e 100644 --- a/api/envoy/config/common/matcher/v3/matcher.proto +++ b/api/envoy/config/common/matcher/v3/matcher.proto @@ -50,6 +50,7 @@ message Matcher { // Predicate for a single input field. message SinglePredicate { // Protocol-specific specification of input field to match on. + // [#extension-category: envoy.matching.common_inputs] core.v3.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; oneof matcher { diff --git a/api/envoy/config/common/matcher/v4alpha/matcher.proto b/api/envoy/config/common/matcher/v4alpha/matcher.proto index 586a4a920154..7747157a24dc 100644 --- a/api/envoy/config/common/matcher/v4alpha/matcher.proto +++ b/api/envoy/config/common/matcher/v4alpha/matcher.proto @@ -66,6 +66,7 @@ message Matcher { "envoy.config.common.matcher.v3.Matcher.MatcherList.Predicate.SinglePredicate"; // Protocol-specific specification of input field to match on. + // [#extension-category: envoy.matching.common_inputs] core.v4alpha.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; oneof matcher { diff --git a/api/envoy/extensions/matching/common_inputs/environment_variable/v3/BUILD b/api/envoy/extensions/matching/common_inputs/environment_variable/v3/BUILD new file mode 100644 index 000000000000..ee92fb652582 --- /dev/null +++ b/api/envoy/extensions/matching/common_inputs/environment_variable/v3/BUILD @@ -0,0 +1,9 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"], +) diff --git a/api/envoy/extensions/matching/common_inputs/environment_variable/v3/input.proto b/api/envoy/extensions/matching/common_inputs/environment_variable/v3/input.proto new file mode 100644 index 000000000000..13db7227c640 --- /dev/null +++ b/api/envoy/extensions/matching/common_inputs/environment_variable/v3/input.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +package envoy.extensions.matching.common_inputs.environment_variable.v3; + +import "udpa/annotations/migrate.proto"; +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.matching.common_inputs.environment_variable.v3"; +option java_outer_classname = "InputProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Environment Variable Input] +// [#extension: envoy.matching.common_inputs.environment_variable] + +// Reads an environment variable to provide an input for matching. +message Config { + // Name of the environment variable to read from. + string name = 1 [(validate.rules).string = {min_len: 1}]; +} diff --git a/api/versioning/BUILD b/api/versioning/BUILD index 1be50dfd0f6f..17c30b1501c9 100644 --- a/api/versioning/BUILD +++ b/api/versioning/BUILD @@ -129,6 +129,7 @@ proto_library( "//envoy/extensions/internal_redirect/allow_listed_routes/v3:pkg", "//envoy/extensions/internal_redirect/previous_routes/v3:pkg", "//envoy/extensions/internal_redirect/safe_cross_scheme/v3:pkg", + "//envoy/extensions/matching/common_inputs/environment_variable/v3:pkg", "//envoy/extensions/matching/input_matchers/consistent_hashing/v3:pkg", "//envoy/extensions/network/socket_interface/v3:pkg", "//envoy/extensions/rate_limit_descriptors/expr/v3:pkg", diff --git a/bazel/envoy_library.bzl b/bazel/envoy_library.bzl index e0c27f3bd971..f239dd3487ec 100644 --- a/bazel/envoy_library.bzl +++ b/bazel/envoy_library.bzl @@ -83,6 +83,7 @@ EXTENSION_CATEGORIES = [ "envoy.http.stateful_header_formatters", "envoy.internal_redirect_predicates", "envoy.io_socket", + "envoy.matching.common_inputs", "envoy.matching.input_matchers", "envoy.rate_limit_descriptors", "envoy.request_id", diff --git a/docs/root/api-v3/common_messages/common_messages.rst b/docs/root/api-v3/common_messages/common_messages.rst index 9c385fb26d9e..843154a3bb9e 100644 --- a/docs/root/api-v3/common_messages/common_messages.rst +++ b/docs/root/api-v3/common_messages/common_messages.rst @@ -26,3 +26,4 @@ Common messages ../extensions/filters/common/dependency/v3/dependency.proto ../extensions/filters/common/matcher/action/v3/skip_action.proto ../extensions/matching/input_matchers/consistent_hashing/v3/consistent_hashing.proto + ../extensions/matching/common_inputs/environment_variable/v3/input.proto diff --git a/generated_api_shadow/BUILD b/generated_api_shadow/BUILD index 0167c8a69dd2..7077b21ab0b3 100644 --- a/generated_api_shadow/BUILD +++ b/generated_api_shadow/BUILD @@ -246,6 +246,7 @@ proto_library( "//envoy/extensions/internal_redirect/allow_listed_routes/v3:pkg", "//envoy/extensions/internal_redirect/previous_routes/v3:pkg", "//envoy/extensions/internal_redirect/safe_cross_scheme/v3:pkg", + "//envoy/extensions/matching/common_inputs/environment_variable/v3:pkg", "//envoy/extensions/matching/input_matchers/consistent_hashing/v3:pkg", "//envoy/extensions/network/socket_interface/v3:pkg", "//envoy/extensions/rate_limit_descriptors/expr/v3:pkg", diff --git a/generated_api_shadow/envoy/config/common/matcher/v3/matcher.proto b/generated_api_shadow/envoy/config/common/matcher/v3/matcher.proto index aa49132ce990..f9a4aafa945e 100644 --- a/generated_api_shadow/envoy/config/common/matcher/v3/matcher.proto +++ b/generated_api_shadow/envoy/config/common/matcher/v3/matcher.proto @@ -50,6 +50,7 @@ message Matcher { // Predicate for a single input field. message SinglePredicate { // Protocol-specific specification of input field to match on. + // [#extension-category: envoy.matching.common_inputs] core.v3.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; oneof matcher { diff --git a/generated_api_shadow/envoy/config/common/matcher/v4alpha/matcher.proto b/generated_api_shadow/envoy/config/common/matcher/v4alpha/matcher.proto index 586a4a920154..7747157a24dc 100644 --- a/generated_api_shadow/envoy/config/common/matcher/v4alpha/matcher.proto +++ b/generated_api_shadow/envoy/config/common/matcher/v4alpha/matcher.proto @@ -66,6 +66,7 @@ message Matcher { "envoy.config.common.matcher.v3.Matcher.MatcherList.Predicate.SinglePredicate"; // Protocol-specific specification of input field to match on. + // [#extension-category: envoy.matching.common_inputs] core.v4alpha.TypedExtensionConfig input = 1 [(validate.rules).message = {required: true}]; oneof matcher { diff --git a/generated_api_shadow/envoy/extensions/matching/common_inputs/environment_variable/v3/BUILD b/generated_api_shadow/envoy/extensions/matching/common_inputs/environment_variable/v3/BUILD new file mode 100644 index 000000000000..ee92fb652582 --- /dev/null +++ b/generated_api_shadow/envoy/extensions/matching/common_inputs/environment_variable/v3/BUILD @@ -0,0 +1,9 @@ +# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py. + +load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package") + +licenses(["notice"]) # Apache 2 + +api_proto_package( + deps = ["@com_github_cncf_udpa//udpa/annotations:pkg"], +) diff --git a/generated_api_shadow/envoy/extensions/matching/common_inputs/environment_variable/v3/input.proto b/generated_api_shadow/envoy/extensions/matching/common_inputs/environment_variable/v3/input.proto new file mode 100644 index 000000000000..13db7227c640 --- /dev/null +++ b/generated_api_shadow/envoy/extensions/matching/common_inputs/environment_variable/v3/input.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +package envoy.extensions.matching.common_inputs.environment_variable.v3; + +import "udpa/annotations/migrate.proto"; +import "udpa/annotations/status.proto"; +import "udpa/annotations/versioning.proto"; +import "validate/validate.proto"; + +option java_package = "io.envoyproxy.envoy.extensions.matching.common_inputs.environment_variable.v3"; +option java_outer_classname = "InputProto"; +option java_multiple_files = true; +option (udpa.annotations.file_status).package_version_status = ACTIVE; + +// [#protodoc-title: Environment Variable Input] +// [#extension: envoy.matching.common_inputs.environment_variable] + +// Reads an environment variable to provide an input for matching. +message Config { + // Name of the environment variable to read from. + string name = 1 [(validate.rules).string = {min_len: 1}]; +} diff --git a/include/envoy/matcher/matcher.h b/include/envoy/matcher/matcher.h index fc6e335d7b07..529683a65fa6 100644 --- a/include/envoy/matcher/matcher.h +++ b/include/envoy/matcher/matcher.h @@ -201,7 +201,8 @@ struct DataInputGetResult { }; /** - * Interface for types providing a way to extract a string from the DataType to perform matching on. + * Interface for types providing a way to extract a string from the DataType to perform matching + * on. */ template class DataInput { public: @@ -236,5 +237,31 @@ template class DataInputFactory : public Config::TypedFactory { } }; +/** + * Interface for types providing a way to use a string for matching without depending on protocol + * data. As a result, these can be used for all protocols. + */ +class CommonProtocolInput { +public: + virtual ~CommonProtocolInput() = default; + virtual absl::optional get() PURE; +}; +using CommonProtocolInputPtr = std::unique_ptr; + +/** + * Factory for CommonProtocolInput. + */ +class CommonProtocolInputFactory : public Config::TypedFactory { +public: + /** + * Creates a CommonProtocolInput from the provided config. + */ + virtual CommonProtocolInputPtr + createCommonProtocolInput(const Protobuf::Message& config, + Server::Configuration::FactoryContext& factory_context) PURE; + + std::string category() const override { return "envoy.matching.common_inputs"; } +}; + } // namespace Matcher } // namespace Envoy diff --git a/source/common/matcher/matcher.h b/source/common/matcher/matcher.h index 400da9d5386c..e2f41d27ad2a 100644 --- a/source/common/matcher/matcher.h +++ b/source/common/matcher/matcher.h @@ -155,12 +155,38 @@ template class MatchTreeFactory { return absl::nullopt; } + // Wrapper around a CommonProtocolInput that allows it to be used as a DataInput. + class CommonProtocolInputWrapper : public DataInput { + public: + explicit CommonProtocolInputWrapper(CommonProtocolInputPtr&& common_protocol_input) + : common_protocol_input_(std::move(common_protocol_input)) {} + + DataInputGetResult get(const DataType&) override { + return DataInputGetResult{DataInputGetResult::DataAvailability::AllDataAvailable, + common_protocol_input_->get()}; + } + + private: + const CommonProtocolInputPtr common_protocol_input_; + }; + DataInputPtr createDataInput(const envoy::config::core::v3::TypedExtensionConfig& config) { - auto& factory = Config::Utility::getAndCheckFactory>(config); + auto* factory = Config::Utility::getFactory>(config); + if (factory != nullptr) { + ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig( + config.typed_config(), factory_context_.messageValidationVisitor(), *factory); + return factory->createDataInput(*message, factory_context_); + } + + // If the provided config doesn't match a typed input, assume that this is one of the common + // inputs. + auto& common_input_factory = + Config::Utility::getAndCheckFactory(config); ProtobufTypes::MessagePtr message = Config::Utility::translateAnyToFactoryConfig( - config.typed_config(), factory_context_.messageValidationVisitor(), factory); - return factory.createDataInput(*message, factory_context_); + config.typed_config(), factory_context_.messageValidationVisitor(), common_input_factory); + return std::make_unique( + common_input_factory.createCommonProtocolInput(*message, factory_context_)); } InputMatcherPtr createInputMatcher( diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index ade157cf6f2f..4e8e2adc7c80 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -53,6 +53,12 @@ EXTENSIONS = { "envoy.matching.input_matchers.consistent_hashing": "//source/extensions/matching/input_matchers/consistent_hashing:config", + # + # Generic Inputs + # + + "envoy.matching.common_inputs.environment_variable": "//source/extensions/matching/common_inputs/environment_variable:config", + # # HTTP filters # diff --git a/source/extensions/matching/common_inputs/environment_variable/BUILD b/source/extensions/matching/common_inputs/environment_variable/BUILD new file mode 100644 index 000000000000..cf54b92130a8 --- /dev/null +++ b/source/extensions/matching/common_inputs/environment_variable/BUILD @@ -0,0 +1,34 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_extension", + "envoy_cc_library", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_library( + name = "input_lib", + hdrs = ["input.h"], + deps = [ + "//include/envoy/matcher:matcher_interface", + "//source/common/common:hash_lib", + ], +) + +envoy_cc_extension( + name = "config", + srcs = ["config.cc"], + hdrs = ["config.h"], + category = "envoy.matching.common_inputs", + security_posture = "robust_to_untrusted_downstream", + deps = [ + ":input_lib", + "//include/envoy/matcher:matcher_interface", + "//include/envoy/registry", + "//include/envoy/server:factory_context_interface", + "@envoy_api//envoy/extensions/matching/common_inputs/environment_variable/v3:pkg_cc_proto", + ], +) diff --git a/source/extensions/matching/common_inputs/environment_variable/config.cc b/source/extensions/matching/common_inputs/environment_variable/config.cc new file mode 100644 index 000000000000..a7716e0b0748 --- /dev/null +++ b/source/extensions/matching/common_inputs/environment_variable/config.cc @@ -0,0 +1,39 @@ +#include "extensions/matching/common_inputs/environment_variable/config.h" + +#include + +#include "envoy/matcher/matcher.h" + +namespace Envoy { +namespace Extensions { +namespace Matching { +namespace CommonInputs { +namespace EnvironmentVariable { + +Envoy::Matcher::CommonProtocolInputPtr +Config::createCommonProtocolInput(const Protobuf::Message& config, + Server::Configuration::FactoryContext& factory_context) { + const auto& environment_config = MessageUtil::downcastAndValidate< + const envoy::extensions::matching::common_inputs::environment_variable::v3::Config&>( + config, factory_context.messageValidationVisitor()); + + // We read the env variable at construction time to avoid repeat lookups. + // This assumes that the environment remains stable during the process lifetime. + auto* value = getenv(environment_config.name().data()); + if (value != nullptr) { + return std::make_unique(std::string(value)); + } + + return std::make_unique(absl::nullopt); +} + +/** + * Static registration for the environment data input. @see RegisterFactory. + */ +REGISTER_FACTORY(Config, Envoy::Matcher::CommonProtocolInputFactory); + +} // namespace EnvironmentVariable +} // namespace CommonInputs +} // namespace Matching +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/matching/common_inputs/environment_variable/config.h b/source/extensions/matching/common_inputs/environment_variable/config.h new file mode 100644 index 000000000000..a583785a3101 --- /dev/null +++ b/source/extensions/matching/common_inputs/environment_variable/config.h @@ -0,0 +1,35 @@ +#pragma once + +#include "envoy/extensions/matching/common_inputs/environment_variable/v3/input.pb.h" +#include "envoy/extensions/matching/common_inputs/environment_variable/v3/input.pb.validate.h" +#include "envoy/matcher/matcher.h" +#include "envoy/server/factory_context.h" + +#include "common/protobuf/utility.h" + +#include "extensions/matching/common_inputs/environment_variable/input.h" + +namespace Envoy { +namespace Extensions { +namespace Matching { +namespace CommonInputs { +namespace EnvironmentVariable { + +class Config : public Envoy::Matcher::CommonProtocolInputFactory { +public: + Envoy::Matcher::CommonProtocolInputPtr + createCommonProtocolInput(const Protobuf::Message& config, + Server::Configuration::FactoryContext& factory_context) override; + + std::string name() const override { return "envoy.matching.common_inputs.environment_variable"; } + + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique< + envoy::extensions::matching::common_inputs::environment_variable::v3::Config>(); + } +}; +} // namespace EnvironmentVariable +} // namespace CommonInputs +} // namespace Matching +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/matching/common_inputs/environment_variable/input.h b/source/extensions/matching/common_inputs/environment_variable/input.h new file mode 100644 index 000000000000..240869d9c9d0 --- /dev/null +++ b/source/extensions/matching/common_inputs/environment_variable/input.h @@ -0,0 +1,24 @@ +#pragma once + +#include "envoy/matcher/matcher.h" + +namespace Envoy { +namespace Extensions { +namespace Matching { +namespace CommonInputs { +namespace EnvironmentVariable { + +class Input : public Matcher::CommonProtocolInput { +public: + explicit Input(absl::optional&& value) : storage_(std::move(value)) {} + + absl::optional get() override { return storage_; } + +private: + const absl::optional storage_; +}; +} // namespace EnvironmentVariable +} // namespace CommonInputs +} // namespace Matching +} // namespace Extensions +} // namespace Envoy diff --git a/test/common/matcher/matcher_test.cc b/test/common/matcher/matcher_test.cc index d9ccf93ada19..415394fea295 100644 --- a/test/common/matcher/matcher_test.cc +++ b/test/common/matcher/matcher_test.cc @@ -75,6 +75,41 @@ TEST_F(MatcherTest, TestMatcher) { EXPECT_NE(result.on_match_->action_cb_, nullptr); } +TEST_F(MatcherTest, CustomGenericInput) { + 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: generic + 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(factory_context_); + + auto common_input_factory = TestCommonProtocolInputFactory("generic", "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: diff --git a/test/common/matcher/test_utility.h b/test/common/matcher/test_utility.h index 9aa0acec2482..76cccbe548f9 100644 --- a/test/common/matcher/test_utility.h +++ b/test/common/matcher/test_utility.h @@ -16,6 +16,35 @@ struct TestData { static absl::string_view name() { return "test"; } }; +// A CommonProtocolInput that returns the configured value every time. +struct CommonProtocolTestInput : public CommonProtocolInput { + explicit CommonProtocolTestInput(const std::string& data) : data_(data) {} + absl::optional get() override { return data_; } + + const std::string data_; +}; +class TestCommonProtocolInputFactory : public CommonProtocolInputFactory { +public: + TestCommonProtocolInputFactory(absl::string_view factory_name, absl::string_view data) + : factory_name_(std::string(factory_name)), value_(std::string(data)), injection_(*this) {} + + CommonProtocolInputPtr + createCommonProtocolInput(const Protobuf::Message&, + Server::Configuration::FactoryContext&) override { + return std::make_unique(value_); + } + + ProtobufTypes::MessagePtr createEmptyConfigProto() override { + return std::make_unique(); + } + std::string name() const override { return factory_name_; } + +private: + const std::string factory_name_; + const std::string value_; + Registry::InjectFactory injection_; +}; + // A DataInput that returns the configured value every time. struct TestInput : public DataInput { explicit TestInput(DataInputGetResult result) : result_(result) {} diff --git a/test/extensions/matching/common_inputs/environment_variable/BUILD b/test/extensions/matching/common_inputs/environment_variable/BUILD new file mode 100644 index 000000000000..e688a7dcb792 --- /dev/null +++ b/test/extensions/matching/common_inputs/environment_variable/BUILD @@ -0,0 +1,31 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_package", +) +load( + "//test/extensions:extensions_build_system.bzl", + "envoy_extension_cc_test", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_extension_cc_test( + name = "config_test", + srcs = ["config_test.cc"], + extension_name = "envoy.matching.common_inputs.environment_variable", + deps = [ + "//source/extensions/matching/common_inputs/environment_variable:config", + "//test/mocks/server:factory_context_mocks", + ], +) + +envoy_extension_cc_test( + name = "input_test", + srcs = ["input_test.cc"], + extension_name = "envoy.matching.common_inputs.environment_variable", + deps = [ + "//source/extensions/matching/common_inputs/environment_variable:input_lib", + ], +) diff --git a/test/extensions/matching/common_inputs/environment_variable/config_test.cc b/test/extensions/matching/common_inputs/environment_variable/config_test.cc new file mode 100644 index 000000000000..f8a697979c9e --- /dev/null +++ b/test/extensions/matching/common_inputs/environment_variable/config_test.cc @@ -0,0 +1,53 @@ +#include "common/config/utility.h" + +#include "extensions/matching/common_inputs/environment_variable/config.h" + +#include "test/mocks/server/factory_context.h" +#include "test/test_common/environment.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace Matching { +namespace CommonInputs { +namespace EnvironmentVariable { + +TEST(ConfigTest, TestConfig) { + NiceMock context; + + const std::string yaml_string = R"EOF( + name: hashing + typed_config: + "@type": type.googleapis.com/envoy.extensions.matching.common_inputs.environment_variable.v3.Config + name: foo +)EOF"; + + envoy::config::core::v3::TypedExtensionConfig config; + TestUtility::loadFromYaml(yaml_string, config); + + Config factory; + auto message = Envoy::Config::Utility::translateAnyToFactoryConfig( + config.typed_config(), ProtobufMessage::getStrictValidationVisitor(), factory); + + { + auto input = factory.createCommonProtocolInput(*message, context); + EXPECT_NE(nullptr, input); + EXPECT_EQ(input->get(), absl::nullopt); + } + + TestEnvironment::setEnvVar("foo", "bar", 1); + { + auto input = factory.createCommonProtocolInput(*message, context); + EXPECT_NE(nullptr, input); + EXPECT_EQ(input->get(), absl::make_optional("bar")); + } + + TestEnvironment::unsetEnvVar("foo"); +} + +} // namespace EnvironmentVariable +} // namespace CommonInputs +} // namespace Matching +} // namespace Extensions +} // namespace Envoy diff --git a/test/extensions/matching/common_inputs/environment_variable/input_test.cc b/test/extensions/matching/common_inputs/environment_variable/input_test.cc new file mode 100644 index 000000000000..7c0bcc9768c1 --- /dev/null +++ b/test/extensions/matching/common_inputs/environment_variable/input_test.cc @@ -0,0 +1,26 @@ +#include "extensions/matching/common_inputs/environment_variable/input.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace Extensions { +namespace Matching { +namespace CommonInputs { +namespace EnvironmentVariable { + +TEST(InputTest, BasicUsage) { + { + Input input("foo"); + ASSERT_TRUE(input.get().has_value()); + EXPECT_EQ(input.get().value(), "foo"); + } + + Input input("foo"); + ASSERT_TRUE(input.get().has_value()); + EXPECT_EQ(input.get().value(), "foo"); +} +} // namespace EnvironmentVariable +} // namespace CommonInputs +} // namespace Matching +} // namespace Extensions +} // namespace Envoy