From 7e7ae71c8a4f1b78de741dd72cf6518322150bf2 Mon Sep 17 00:00:00 2001 From: Daniel Edwards Date: Thu, 31 Oct 2024 10:40:11 +0100 Subject: [PATCH] config: allow overriding rpc and pub/sub labels (#87) Co-authored-by: Konrad Breitsprecher --- .../ITest_Internals_DataPubSub.cpp | 54 +++++++++ .../ITest_Internals_DataPubSub.hpp | 14 +-- .../IntegrationTests/ITest_Internals_Rpc.cpp | 59 ++++++++++ .../IntegrationTests/ITest_Internals_Rpc.hpp | 18 +-- .../config/ParticipantConfiguration.cpp | 70 ++++++++++++ .../config/ParticipantConfiguration.hpp | 31 ++++++ .../ParticipantConfiguration.schema.json | 37 ++++++ .../ParticipantConfigurationFromXImpl.cpp | 23 ++++ .../config/ParticipantConfiguration_Full.json | 28 +++++ .../config/ParticipantConfiguration_Full.yaml | 16 +++ SilKit/source/config/SilKitYamlHelper.hpp | 12 ++ SilKit/source/config/YamlConversion.cpp | 61 ++++++++++ SilKit/source/config/YamlConversion.hpp | 4 + SilKit/source/config/YamlSchema.cpp | 4 + .../source/core/participant/Participant.hpp | 4 + .../core/participant/Participant_impl.hpp | 105 ++++++++++++------ .../services/logging/SilKitFmtFormatters.hpp | 7 ++ docs/CHANGELOG.rst | 5 + docs/configuration/services-configuration.rst | 37 ++++++ 19 files changed, 537 insertions(+), 52 deletions(-) diff --git a/SilKit/IntegrationTests/ITest_Internals_DataPubSub.cpp b/SilKit/IntegrationTests/ITest_Internals_DataPubSub.cpp index e743ccb0c..5f5287031 100644 --- a/SilKit/IntegrationTests/ITest_Internals_DataPubSub.cpp +++ b/SilKit/IntegrationTests/ITest_Internals_DataPubSub.cpp @@ -501,6 +501,60 @@ TEST_F(ITest_Internals_DataPubSub, test_1pub_1sub_sync_mixed_labels) RunSyncTest(pubsubs); } +// Matching mandatory labels provided by a participant configuration +TEST_F(ITest_Internals_DataPubSub, test_1pub_1sub_sync_label_override) +{ + const uint32_t numMsgToPublish = defaultNumMsgToPublish; + const uint32_t numMsgToReceive = numMsgToPublish; + + auto pub1Config = SilKit::Config::ParticipantConfigurationFromStringImpl(R"( +DataPublishers: + - Name: PubCtrl1 + Labels: + - Key: OverrideKeyA + Value: OverrideValueA + Kind: Optional + - Key: OverrideKeyB + Value: OverrideValueB + Kind: Mandatory +)"); + + auto sub1Config = SilKit::Config::ParticipantConfigurationFromStringImpl(R"( +DataSubscribers: + - Name: SubCtrl1 + Labels: + - Key: OverrideKeyA + Value: OverrideValueA + Kind: Mandatory + - Key: OverrideKeyB + Value: OverrideValueB + Kind: Optional +)"); + + std::vector pubsubs; + pubsubs.push_back({"Pub1", + {{"PubCtrl1", + "TopicA", + {"A"}, + {{"kA", "vA", MatchingLabel::Kind::Mandatory}, {"kB", "vB", MatchingLabel::Kind::Mandatory}}, + 0, + defaultMsgSize, + numMsgToPublish}}, + {}, + pub1Config}); + pubsubs.push_back({"Sub1", + {}, + {{"SubCtrl1", + "TopicA", + {"A"}, + {{"kA", "NOT vA", MatchingLabel::Kind::Mandatory}}, + defaultMsgSize, + numMsgToReceive, + 1}}, + sub1Config}); + + RunSyncTest(pubsubs); +} // Wrong mandatory label value -> Expect no reception TEST_F(ITest_Internals_DataPubSub, test_1pub_1sub_sync_wrong_mandatory_label_value) diff --git a/SilKit/IntegrationTests/ITest_Internals_DataPubSub.hpp b/SilKit/IntegrationTests/ITest_Internals_DataPubSub.hpp index ca2690684..91c8d97c7 100644 --- a/SilKit/IntegrationTests/ITest_Internals_DataPubSub.hpp +++ b/SilKit/IntegrationTests/ITest_Internals_DataPubSub.hpp @@ -184,27 +184,27 @@ class ITest_Internals_DataPubSub : public testing::Test struct PubSubParticipant { PubSubParticipant(const std::string& newName) + : PubSubParticipant(newName, {}, {}) { - name = newName; } PubSubParticipant(const std::string& newName, const std::vector& newDataPublishers, const std::vector& newDataSubscribers, std::shared_ptr newConfig = SilKit::Config::MakeEmptyParticipantConfigurationImpl()) + : config{std::move(newConfig)} + , name{newName} + , dataSubscribers{newDataSubscribers} + , dataPublishers{newDataPublishers} { - config = newConfig; - name = newName; - dataSubscribers = newDataSubscribers; - dataPublishers = newDataPublishers; } - std::shared_ptr config = MakeEmptyParticipantConfigurationImpl(); + std::shared_ptr config; bool delayedDefaultDataHandler = false; std::string name; std::vector dataSubscribers; std::vector dataPublishers; std::unique_ptr participant; - SilKit::Core::IParticipantInternal* participantImpl; + SilKit::Core::IParticipantInternal* participantImpl = nullptr; // Common std::promise participantCreatedPromise; diff --git a/SilKit/IntegrationTests/ITest_Internals_Rpc.cpp b/SilKit/IntegrationTests/ITest_Internals_Rpc.cpp index ea567fb11..1d1825fc8 100644 --- a/SilKit/IntegrationTests/ITest_Internals_Rpc.cpp +++ b/SilKit/IntegrationTests/ITest_Internals_Rpc.cpp @@ -24,6 +24,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "ITest_Internals_Rpc.hpp" +#include "ParticipantConfigurationFromXImpl.hpp" + namespace { //-------------------------------------- @@ -295,6 +297,63 @@ TEST_F(ITest_Internals_Rpc, test_1client_1server_sync_labels) RunSyncTest(rpcs); } +// Matching mandatory and optional labels on both sides provided by a participant configuration +TEST_F(ITest_Internals_Rpc, test_1client_1server_sync_label_override) +{ + const uint32_t numCallsToReceive = defaultNumCalls; + const uint32_t numCallsToReturn = defaultNumCalls; + + auto client1Config = SilKit::Config::ParticipantConfigurationFromStringImpl(R"( +RpcClients: + - Name: ClientCtrl1 + Labels: + - Key: OverrideKeyA + Value: OverrideValueA + Kind: Mandatory + - Key: OverrideKeyB + Value: OverrideValueB + Kind: Optional +)"); + + auto server1Config = SilKit::Config::ParticipantConfigurationFromStringImpl(R"( +RpcServers: + - Name: ServerCtrl1 + Labels: + - Key: OverrideKeyA + Value: OverrideValueA + Kind: Optional + - Key: OverrideKeyB + Value: OverrideValueB + Kind: Mandatory +)"); + + std::vector rpcs; + rpcs.push_back({"Client1", + {}, + {{"ClientCtrl1", + "TestFuncA", + "A", + {{"KeyA", "ValA", SilKit::Services::MatchingLabel::Kind::Mandatory}, + {"KeyB", "ValB", SilKit::Services::MatchingLabel::Kind::Mandatory}}, + defaultMsgSize, + defaultNumCalls, + numCallsToReturn}}, + {"TestFuncA"}, + client1Config}); + rpcs.push_back({"Server1", + {{"ServerCtrl1", + "TestFuncA", + "A", + {{"KeyA", "ValA2", SilKit::Services::MatchingLabel::Kind::Optional}}, + defaultMsgSize, + numCallsToReceive}}, + {}, + {}, + server1Config}); + + RunSyncTest(rpcs); +} + // No communication with server2 (missing mandatory label on client) TEST_F(ITest_Internals_Rpc, test_1client_2server_sync_wrong_mandatory_label) { diff --git a/SilKit/IntegrationTests/ITest_Internals_Rpc.hpp b/SilKit/IntegrationTests/ITest_Internals_Rpc.hpp index 2a00550d4..4919499ab 100644 --- a/SilKit/IntegrationTests/ITest_Internals_Rpc.hpp +++ b/SilKit/IntegrationTests/ITest_Internals_Rpc.hpp @@ -260,22 +260,24 @@ class ITest_Internals_Rpc : public testing::Test struct RpcParticipant { RpcParticipant(const std::string& newName, const std::vector& newExpectedFunctionNames) + : RpcParticipant(newName, {}, {}, newExpectedFunctionNames) { - name = newName; - expectedFunctionNames = newExpectedFunctionNames; } RpcParticipant(const std::string& newName, std::vector newRpcServers, - std::vector newRpcClients, std::vector newExpectedFunctionNames) - : expectedFunctionNames{std::move(newExpectedFunctionNames)} + std::vector newRpcClients, std::vector newExpectedFunctionNames, + std::shared_ptr newConfig = + SilKit::Config::MakeEmptyParticipantConfigurationImpl()) + : config{std::move(newConfig)} + , name{newName} + , expectedFunctionNames{std::move(newExpectedFunctionNames)} { - name = newName; - std::for_each(newRpcServers.begin(), newRpcServers.end(), [this](const auto& info) { AddRpcServer(info); }); std::for_each(newRpcClients.begin(), newRpcClients.end(), [this](const auto& info) { AddRpcClient(info); }); } + std::shared_ptr config; std::string name; std::vector> rpcClients; std::vector> rpcServers; @@ -395,9 +397,7 @@ class ITest_Internals_Rpc : public testing::Test { try { - participant.participant = SilKit::CreateParticipantImpl( - SilKit::Config::MakeParticipantConfigurationWithLoggingImpl(SilKit::Services::Logging::Level::Warn), - participant.name, registryUri); + participant.participant = SilKit::CreateParticipantImpl(participant.config, participant.name, registryUri); participant.participantImpl = dynamic_cast(participant.participant.get()); diff --git a/SilKit/source/config/ParticipantConfiguration.cpp b/SilKit/source/config/ParticipantConfiguration.cpp index 147e4390f..103c6e6e7 100755 --- a/SilKit/source/config/ParticipantConfiguration.cpp +++ b/SilKit/source/config/ParticipantConfiguration.cpp @@ -20,3 +20,73 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "ParticipantConfiguration.hpp" + +#include +#include + +namespace SilKit { +namespace Config { +namespace v1 { + +auto Label::ToPublicApi() const -> SilKit::Services::MatchingLabel +{ + SilKit::Services::MatchingLabel result; + + result.key = key; + result.value = value; + + switch (kind) + { + case Kind::Mandatory: + result.kind = SilKit::Services::MatchingLabel::Kind::Mandatory; + break; + case Kind::Optional: + result.kind = SilKit::Services::MatchingLabel::Kind::Optional; + break; + default: + throw SilKit::ConfigurationError{ + "Invalid SilKit::Config::v1::MatchingLabel::Kind(" + + std::to_string(static_cast>(kind)) + ")"}; + } + + return result; +} + + +auto Label::FromPublicApi(const SilKit::Services::MatchingLabel& label) -> Label +{ + Label result; + + result.key = label.key; + result.value = label.value; + + switch (label.kind) + { + case SilKit::Services::MatchingLabel::Kind::Mandatory: + result.kind = Label::Kind::Mandatory; + break; + case SilKit::Services::MatchingLabel::Kind::Optional: + result.kind = Label::Kind::Optional; + break; + default: + throw SilKit::ConfigurationError{ + "Invalid SilKit::Services::MatchingLabel::Kind(" + + std::to_string(static_cast>(label.kind)) + + ")"}; + } + + return result; +} + + +auto Label::VectorFromPublicApi(const std::vector& labels) -> std::vector