Skip to content

Commit 5d06469

Browse files
committed
add support for product and version chains
1 parent f642c89 commit 5d06469

3 files changed

Lines changed: 199 additions & 29 deletions

File tree

src/rmq/rmqa/rmqa_rabbitcontextoptions.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,15 @@ class RabbitContextOptions {
8181
/// \param name name of client property to set
8282
/// \param value value of client property
8383
/// NOTE: The following properties are set by default and can be
84-
/// overridden: task, pid, os, os_version, os_patch. The following
85-
/// properties are reserved and cannot be overridden: capabilities,
86-
/// platform, product, version, connection_name
84+
/// overridden: task, pid, os, os_version, os_patch, product, version.
85+
/// If product and version are provided, "product_chain" and
86+
/// "version_chain" fields are automatically populated showing the
87+
/// full library stack (e.g. product_chain="my-wrapper | rmqcpp C++ Client
88+
/// Library", version_chain="1.0.0 | 2.33.0").
89+
/// The following properties are reserved: capabilities, platform,
90+
/// connection_name. The product_chain and version_chain fields are
91+
/// automatically managed by the library stack and should not be set
92+
/// directly by applications.
8793
RabbitContextOptions& setClientProperty(const bsl::string& name,
8894
const rmqt::FieldValue& value);
8995

src/rmq/rmqamqp/rmqamqp_connection.cpp

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,54 @@ const bsl::uint16_t k_HUNG_TIMER_SEC = 60;
8181

8282
BALL_LOG_SET_NAMESPACE_CATEGORY("RMQAMQP.CONNECTION")
8383

84+
void setChainProperties(rmqt::FieldTable& props,
85+
const rmqt::FieldTable& base,
86+
const bsl::string& selfProduct,
87+
const bsl::string& selfVersion)
88+
{
89+
using namespace rmqt;
90+
91+
FieldTable::const_iterator productChainIt = base.find("product_chain");
92+
FieldTable::const_iterator versionChainIt = base.find("version_chain");
93+
FieldTable::const_iterator productIt = base.find("product");
94+
FieldTable::const_iterator versionIt = base.find("version");
95+
96+
if (productChainIt != base.end() &&
97+
productChainIt->second.is<bsl::string>()) {
98+
// Caller provided chains -- append ourselves
99+
props["product_chain"] = FieldValue(
100+
productChainIt->second.the<bsl::string>() + " | " + selfProduct);
101+
props["version_chain"] =
102+
FieldValue((versionChainIt != base.end() &&
103+
versionChainIt->second.is<bsl::string>()
104+
? versionChainIt->second.the<bsl::string>()
105+
: bsl::string("unknown")) +
106+
" | " + selfVersion);
107+
}
108+
else if (productIt != base.end() && productIt->second.is<bsl::string>()) {
109+
// Caller set product/version but no chains -- build from both
110+
props["product_chain"] = FieldValue(
111+
productIt->second.the<bsl::string>() + " | " + selfProduct);
112+
props["version_chain"] = FieldValue(
113+
(versionIt != base.end() && versionIt->second.is<bsl::string>()
114+
? versionIt->second.the<bsl::string>()
115+
: bsl::string("unknown")) +
116+
" | " + selfVersion);
117+
}
118+
else {
119+
// No wrapper -- just ourselves
120+
props["product_chain"] = FieldValue(selfProduct);
121+
props["version_chain"] = FieldValue(selfVersion);
122+
}
123+
124+
if (productIt == base.end()) {
125+
props["product"] = FieldValue(bsl::string(selfProduct));
126+
}
127+
if (versionIt == base.end()) {
128+
props["version"] = FieldValue(bsl::string(selfVersion));
129+
}
130+
}
131+
84132
rmqt::FieldTable generateClientProperties(const rmqt::FieldTable& base,
85133
const bsl::string& connectionName)
86134
{
@@ -98,8 +146,11 @@ rmqt::FieldTable generateClientProperties(const rmqt::FieldTable& base,
98146
props["capabilities"] = FieldValue(capabilities);
99147

100148
props["platform"] = FieldValue(bsl::string(rmqamqpt::Constants::PLATFORM));
101-
props["product"] = FieldValue(bsl::string(rmqamqpt::Constants::PRODUCT));
102-
props["version"] = FieldValue(bsl::string(rmqamqpt::Constants::VERSION));
149+
150+
setChainProperties(props,
151+
base,
152+
bsl::string(rmqamqpt::Constants::PRODUCT),
153+
bsl::string(rmqamqpt::Constants::VERSION));
103154

104155
if (!connectionName.empty()) {
105156
props["connection_name"] = FieldValue(connectionName);

src/tests/rmqamqp/rmqamqp_connection.t.cpp

Lines changed: 137 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ rmqt::FieldTable generateDefaultClientProperties(
9090
rmqt::FieldValue(bsl::string(rmqamqpt::Constants::PRODUCT));
9191
props["version"] =
9292
rmqt::FieldValue(bsl::string(rmqamqpt::Constants::VERSION));
93+
props["product_chain"] =
94+
rmqt::FieldValue(bsl::string(rmqamqpt::Constants::PRODUCT));
95+
props["version_chain"] =
96+
rmqt::FieldValue(bsl::string(rmqamqpt::Constants::VERSION));
9397

9498
if (!connectionName.empty()) {
9599
props["connection_name"] = rmqt::FieldValue(connectionName);
@@ -405,7 +409,7 @@ class ConnectionTests : public ::testing::Test {
405409
, d_sendChannel(bsl::make_shared<MockSendChannel>(d_retryHandlerChannel))
406410
, d_ackQueue(bsl::make_shared<rmqt::ConsumerAckQueue>())
407411
, d_metricPublisher(bsl::make_shared<rmqtestutil::MockMetricPublisher>())
408-
, d_clientProperties(generateDefaultClientProperties())
412+
, d_clientProperties()
409413
, d_factory(bsl::make_shared<ConnectionFactory>(d_resolver,
410414
d_timerFactory,
411415
d_errorCallback,
@@ -679,21 +683,23 @@ TEST_F(ConnectionTests, Handshake)
679683

680684
TEST_F(ConnectionTests, ClientProperties)
681685
{
682-
rmqt::FieldTable overriddenClientProperties =
683-
generateDefaultClientProperties();
684-
overriddenClientProperties["FOO"] =
685-
rmqt::FieldValue(bsl::string("BAR")); // Add one more
686+
rmqt::FieldTable inputClientProperties;
687+
inputClientProperties["FOO"] =
688+
rmqt::FieldValue(bsl::string("BAR")); // Add a custom property
689+
686690
d_factory = bsl::make_shared<ConnectionFactory>(d_resolver,
687691
d_timerFactory,
688692
d_errorCallback,
689693
d_metricPublisher,
690-
overriddenClientProperties,
694+
inputClientProperties,
691695
d_retryHandler,
692696
d_heartbeat,
693697
d_channelFactory);
694698

695-
expectHeaderAndStartFrames(
696-
overriddenClientProperties); // check it's as expected
699+
rmqt::FieldTable expectedProperties =
700+
generateDefaultClientProperties("test-connection");
701+
expectedProperties["FOO"] = rmqt::FieldValue(bsl::string("BAR"));
702+
expectHeaderAndStartFrames(expectedProperties);
697703
expectTuneFrames();
698704
expectOpenFrame();
699705

@@ -709,45 +715,152 @@ TEST_F(ConnectionTests, ClientProperties)
709715
d_eventLoop.run();
710716
}
711717

712-
TEST_F(ConnectionTests, ClientPropertiesCantOverrideReservedOnes)
718+
TEST_F(ConnectionTests, ClientPropertiesCantOverrideConnectionName)
713719
{
714-
rmqt::FieldTable overriddenClientProperties =
715-
generateDefaultClientProperties("my random connection name");
716-
overriddenClientProperties["platform"] = rmqt::FieldValue(
717-
bsl::string("Should get overriden by library")); // Add one more
718-
overriddenClientProperties["product"] = rmqt::FieldValue(
719-
bsl::string("Should get overriden by library")); // Add one more
720-
overriddenClientProperties["version"] = rmqt::FieldValue(
721-
bsl::string("Should get overriden by library")); // Add one more
722-
overriddenClientProperties["connection_name"] = rmqt::FieldValue(
723-
bsl::string("Should get overriden by library")); // Add one more
720+
rmqt::FieldTable inputClientProperties;
721+
inputClientProperties["connection_name"] =
722+
rmqt::FieldValue(bsl::string("Should get overriden by library"));
724723
d_factory = bsl::make_shared<ConnectionFactory>(d_resolver,
725724
d_timerFactory,
726725
d_errorCallback,
727726
d_metricPublisher,
728-
overriddenClientProperties,
727+
inputClientProperties,
729728
d_retryHandler,
730729
d_heartbeat,
731730
d_channelFactory);
732731

733732
expectHeaderAndStartFrames(generateDefaultClientProperties(
734-
"my real connection name")); // despite setting overrides, the library
735-
// has the final say
733+
"my real connection name")); // connection_name is still reserved
736734
expectTuneFrames();
737735
expectOpenFrame();
738736

739737
{
740738
bsl::shared_ptr<rmqamqp::Connection> conn =
741739
createAndStartConnection("my real connection name");
742740

743-
// 1. Handshake up to open with custom client properties
744741
d_eventLoop.run();
745742
d_eventLoop.restart();
746743

747744
expectShutdownCalls();
748745
}
749746

750-
// 2. Shutdown cleanly
747+
d_eventLoop.run();
748+
}
749+
750+
TEST_F(ConnectionTests, ClientPropertiesDefaultsWhenNoneProvided)
751+
{
752+
rmqt::FieldTable emptyClientProperties;
753+
d_factory = bsl::make_shared<ConnectionFactory>(d_resolver,
754+
d_timerFactory,
755+
d_errorCallback,
756+
d_metricPublisher,
757+
emptyClientProperties,
758+
d_retryHandler,
759+
d_heartbeat,
760+
d_channelFactory);
761+
762+
expectHeaderAndStartFrames(
763+
generateDefaultClientProperties("my connection"));
764+
expectTuneFrames();
765+
expectOpenFrame();
766+
767+
{
768+
bsl::shared_ptr<rmqamqp::Connection> conn =
769+
createAndStartConnection("my connection");
770+
771+
d_eventLoop.run();
772+
d_eventLoop.restart();
773+
774+
expectShutdownCalls();
775+
}
776+
777+
d_eventLoop.run();
778+
}
779+
780+
TEST_F(ConnectionTests, ClientPropertiesCanOverrideProductAndVersion)
781+
{
782+
rmqt::FieldTable overriddenClientProperties;
783+
overriddenClientProperties["product"] =
784+
rmqt::FieldValue(bsl::string("xyzlib"));
785+
overriddenClientProperties["version"] =
786+
rmqt::FieldValue(bsl::string("4.5.6"));
787+
d_factory = bsl::make_shared<ConnectionFactory>(d_resolver,
788+
d_timerFactory,
789+
d_errorCallback,
790+
d_metricPublisher,
791+
overriddenClientProperties,
792+
d_retryHandler,
793+
d_heartbeat,
794+
d_channelFactory);
795+
796+
rmqt::FieldTable expectedProperties =
797+
generateDefaultClientProperties("my connection");
798+
expectedProperties["product"] = rmqt::FieldValue(bsl::string("xyzlib"));
799+
expectedProperties["version"] = rmqt::FieldValue(bsl::string("4.5.6"));
800+
expectedProperties["product_chain"] = rmqt::FieldValue(
801+
bsl::string("xyzlib | ") + bsl::string(rmqamqpt::Constants::PRODUCT));
802+
expectedProperties["version_chain"] = rmqt::FieldValue(
803+
bsl::string("4.5.6 | ") + bsl::string(rmqamqpt::Constants::VERSION));
804+
expectHeaderAndStartFrames(expectedProperties);
805+
expectTuneFrames();
806+
expectOpenFrame();
807+
808+
{
809+
bsl::shared_ptr<rmqamqp::Connection> conn =
810+
createAndStartConnection("my connection");
811+
812+
d_eventLoop.run();
813+
d_eventLoop.restart();
814+
815+
expectShutdownCalls();
816+
}
817+
818+
d_eventLoop.run();
819+
}
820+
821+
TEST_F(ConnectionTests, ClientPropertiesWrapperSetsChains)
822+
{
823+
rmqt::FieldTable wrapperClientProperties;
824+
wrapperClientProperties["product"] =
825+
rmqt::FieldValue(bsl::string("rmqcpp-wrapper"));
826+
wrapperClientProperties["version"] = rmqt::FieldValue(bsl::string("1.2.3"));
827+
wrapperClientProperties["product_chain"] =
828+
rmqt::FieldValue(bsl::string("rmqcpp-wrapper"));
829+
wrapperClientProperties["version_chain"] =
830+
rmqt::FieldValue(bsl::string("1.2.3"));
831+
d_factory = bsl::make_shared<ConnectionFactory>(d_resolver,
832+
d_timerFactory,
833+
d_errorCallback,
834+
d_metricPublisher,
835+
wrapperClientProperties,
836+
d_retryHandler,
837+
d_heartbeat,
838+
d_channelFactory);
839+
840+
rmqt::FieldTable expectedProperties =
841+
generateDefaultClientProperties("my connection");
842+
expectedProperties["product"] =
843+
rmqt::FieldValue(bsl::string("rmqcpp-wrapper"));
844+
expectedProperties["version"] = rmqt::FieldValue(bsl::string("1.2.3"));
845+
expectedProperties["product_chain"] =
846+
rmqt::FieldValue(bsl::string("rmqcpp-wrapper | ") +
847+
bsl::string(rmqamqpt::Constants::PRODUCT));
848+
expectedProperties["version_chain"] = rmqt::FieldValue(
849+
bsl::string("1.2.3 | ") + bsl::string(rmqamqpt::Constants::VERSION));
850+
expectHeaderAndStartFrames(expectedProperties);
851+
expectTuneFrames();
852+
expectOpenFrame();
853+
854+
{
855+
bsl::shared_ptr<rmqamqp::Connection> conn =
856+
createAndStartConnection("my connection");
857+
858+
d_eventLoop.run();
859+
d_eventLoop.restart();
860+
861+
expectShutdownCalls();
862+
}
863+
751864
d_eventLoop.run();
752865
}
753866

0 commit comments

Comments
 (0)