Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

utility: convert typed_config to factory config #10418

Merged
merged 2 commits into from
Mar 18, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion source/common/config/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,6 @@ class Utility {

/**
* Translate a nested config into a proto message provided by the implementation factory.
* @param extension_name name of extension corresponding to config.
* @param enclosing_message proto that contains a field 'config'. Note: the enclosing proto is
* provided because for statically registered implementations, a custom config is generally
* optional, which means the conversion must be done conditionally.
Expand All @@ -269,6 +268,30 @@ class Utility {
return config;
}

/**
* Translate the typed any field into a proto message provided by the implementation factory.
* @param typed_config typed configuration.
* @param validation_visitor message validation visitor instance.
* @param factory implementation factory with the method 'createEmptyConfigProto' to produce a
* proto to be filled with the translated configuration.
*/
template <class Factory>
static ProtobufTypes::MessagePtr
translateAnyToFactoryConfig(const ProtobufWkt::Any& typed_config,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this looks clean. Are there some existing sites that we should refactor to use this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't do a thorough search but I guess existing proto should include the deprecated config field. Otherwise, this function should exist for converting the typed config to factory configuration.

We could replace all the translateToFactoryConfig with translateAnyToFactoryConfig because the config field is deprecated. It will break the compatibility.

ProtobufMessage::ValidationVisitor& validation_visitor,
Factory& factory) {
ProtobufTypes::MessagePtr config = factory.createEmptyConfigProto();

// Fail in an obvious way if a plugin does not return a proto.
RELEASE_ASSERT(config != nullptr, "");

// Check that the config type is not google.protobuf.Empty
RELEASE_ASSERT(config->GetDescriptor()->full_name() != "google.protobuf.Empty", "");

translateOpaqueConfig(typed_config, ProtobufWkt::Struct(), validation_visitor, *config);
return config;
}

/**
* Truncates the message to a length less than default GRPC trailers size limit (by default 8KiB).
*/
Expand Down
37 changes: 37 additions & 0 deletions test/common/config/utility_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "common/config/well_known_names.h"
#include "common/protobuf/protobuf.h"

#include "test/mocks/config/mocks.h"
#include "test/mocks/grpc/mocks.h"
#include "test/mocks/local_info/mocks.h"
#include "test/mocks/stats/mocks.h"
Expand Down Expand Up @@ -287,6 +288,42 @@ TEST(UtilityTest, AnyWrongType) {
R"(Unable to unpack as google.protobuf.Timestamp: \[type.googleapis.com/google.protobuf.Duration\] .*)");
}

TEST(UtilityTest, TranslateAnyWrongToFactoryConfig) {
ProtobufWkt::Duration source_duration;
source_duration.set_seconds(42);
ProtobufWkt::Any typed_config;
typed_config.PackFrom(source_duration);

MockTypedFactory factory;
EXPECT_CALL(factory, createEmptyConfigProto()).WillOnce(Invoke([]() -> ProtobufTypes::MessagePtr {
return ProtobufTypes::MessagePtr{new ProtobufWkt::Timestamp()};
}));

EXPECT_THROW_WITH_REGEX(
Utility::translateAnyToFactoryConfig(typed_config,
ProtobufMessage::getStrictValidationVisitor(), factory),
EnvoyException,
R"(Unable to unpack as google.protobuf.Timestamp: \[type.googleapis.com/google.protobuf.Duration\] .*)");
}

TEST(UtilityTest, TranslateAnyToFactoryConfig) {
ProtobufWkt::Duration source_duration;
source_duration.set_seconds(42);
ProtobufWkt::Any typed_config;
typed_config.PackFrom(source_duration);

MockTypedFactory factory;
EXPECT_CALL(factory, createEmptyConfigProto()).WillOnce(Invoke([]() -> ProtobufTypes::MessagePtr {
return ProtobufTypes::MessagePtr{new ProtobufWkt::Duration()};
}));

const auto& config =
dynamic_cast<const ProtobufWkt::Duration&>(*Utility::translateAnyToFactoryConfig(
typed_config, ProtobufMessage::getStrictValidationVisitor(), factory));

EXPECT_EQ(config.seconds(), 42);
}

void packTypedStructIntoAny(ProtobufWkt::Any& typed_config, const Protobuf::Message& inner) {
udpa::type::v1::TypedStruct typed_struct;
(*typed_struct.mutable_type_url()) =
Expand Down
1 change: 1 addition & 0 deletions test/mocks/config/mocks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@ MockSubscriptionCallbacks::MockSubscriptionCallbacks() {

MockSubscriptionCallbacks::~MockSubscriptionCallbacks() = default;

MockTypedFactory::~MockTypedFactory() = default;
} // namespace Config
} // namespace Envoy
11 changes: 11 additions & 0 deletions test/mocks/config/mocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "envoy/config/endpoint/v3/endpoint.pb.h"
#include "envoy/config/grpc_mux.h"
#include "envoy/config/subscription.h"
#include "envoy/config/typed_config.h"
#include "envoy/service/discovery/v3/discovery.pb.h"

#include "common/config/config_provider_impl.h"
Expand Down Expand Up @@ -119,5 +120,15 @@ class MockConfigProviderManager : public ConfigProviderManager {
const Envoy::Config::ConfigProviderManager::OptionalArg& optarg));
};

class MockTypedFactory : public TypedFactory {
public:
~MockTypedFactory() override;

MOCK_METHOD(ProtobufTypes::MessagePtr, createEmptyConfigProto, ());
MOCK_METHOD(std::string, configType, ());
MOCK_METHOD(std::string, name, (), (const));
MOCK_METHOD(std::string, category, (), (const));
};

} // namespace Config
} // namespace Envoy