Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
cmake_minimum_required(VERSION 3.25)
project(rmq LANGUAGES C CXX)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

option(ENABLE_COMPRESSION "Enable zstd compression support" ON)

set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
Expand Down
16 changes: 16 additions & 0 deletions cmake/Findlibpcre2-8.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Bridge module: bde's bdlConfig.cmake expects find_package(libpcre2-8),
# but vcpkg's pcre2 port provides find_package(pcre2) with target PCRE2::8BIT.
find_package(pcre2 CONFIG REQUIRED)

if (TARGET PCRE2::8BIT AND NOT TARGET libpcre2-8::libpcre2-8)
# Resolve PCRE2::8BIT to its underlying IMPORTED target before aliasing,
# matching the approach used by the BDE vcpkg port.
get_target_property(_pcre2_actual PCRE2::8BIT ALIASED_TARGET)
if (_pcre2_actual)
add_library(libpcre2-8::libpcre2-8 ALIAS "${_pcre2_actual}")
else()
add_library(libpcre2-8::libpcre2-8 ALIAS PCRE2::8BIT)
endif()
endif()

set(libpcre2-8_FOUND TRUE)
12 changes: 9 additions & 3 deletions src/rmq/rmqa/rmqa_rabbitcontextoptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,15 @@ class RabbitContextOptions {
/// \param name name of client property to set
/// \param value value of client property
/// NOTE: The following properties are set by default and can be
/// overridden: task, pid, os, os_version, os_patch. The following
/// properties are reserved and cannot be overridden: capabilities,
/// platform, product, version, connection_name
/// overridden: task, pid, os, os_version, os_patch, product, version.
/// If product and version are provided, "product_chain" and
/// "version_chain" fields are automatically populated showing the
/// full library stack (e.g. product_chain="my-wrapper | rmqcpp C++ Client
/// Library", version_chain="1.0.0 | 2.33.0").
/// The following properties are reserved: capabilities, platform,
/// connection_name. The product_chain and version_chain fields are
/// automatically managed by the library stack and should not be set
/// directly by applications.
RabbitContextOptions& setClientProperty(const bsl::string& name,
const rmqt::FieldValue& value);

Expand Down
55 changes: 53 additions & 2 deletions src/rmq/rmqamqp/rmqamqp_connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,54 @@ const bsl::uint16_t k_HUNG_TIMER_SEC = 60;

BALL_LOG_SET_NAMESPACE_CATEGORY("RMQAMQP.CONNECTION")

void setChainProperties(rmqt::FieldTable& props,
const rmqt::FieldTable& base,
const bsl::string& selfProduct,
const bsl::string& selfVersion)
{
using namespace rmqt;

FieldTable::const_iterator productChainIt = base.find("product_chain");
FieldTable::const_iterator versionChainIt = base.find("version_chain");
FieldTable::const_iterator productIt = base.find("product");
FieldTable::const_iterator versionIt = base.find("version");

if (productChainIt != base.end() &&
productChainIt->second.is<bsl::string>()) {
// Caller provided chains -- append ourselves
props["product_chain"] = FieldValue(
productChainIt->second.the<bsl::string>() + " | " + selfProduct);
props["version_chain"] =
FieldValue((versionChainIt != base.end() &&
versionChainIt->second.is<bsl::string>()
? versionChainIt->second.the<bsl::string>()
: bsl::string("unknown")) +
" | " + selfVersion);
}
else if (productIt != base.end() && productIt->second.is<bsl::string>()) {
// Caller set product/version but no chains -- build from both
props["product_chain"] = FieldValue(
productIt->second.the<bsl::string>() + " | " + selfProduct);
props["version_chain"] = FieldValue(
(versionIt != base.end() && versionIt->second.is<bsl::string>()
? versionIt->second.the<bsl::string>()
: bsl::string("unknown")) +
" | " + selfVersion);
}
else {
// No wrapper -- just ourselves
props["product_chain"] = FieldValue(selfProduct);
props["version_chain"] = FieldValue(selfVersion);
}

if (productIt == base.end()) {
props["product"] = FieldValue(bsl::string(selfProduct));
}
if (versionIt == base.end()) {
props["version"] = FieldValue(bsl::string(selfVersion));
}
}

rmqt::FieldTable generateClientProperties(const rmqt::FieldTable& base,
const bsl::string& connectionName)
{
Expand All @@ -98,8 +146,11 @@ rmqt::FieldTable generateClientProperties(const rmqt::FieldTable& base,
props["capabilities"] = FieldValue(capabilities);

props["platform"] = FieldValue(bsl::string(rmqamqpt::Constants::PLATFORM));
props["product"] = FieldValue(bsl::string(rmqamqpt::Constants::PRODUCT));
props["version"] = FieldValue(bsl::string(rmqamqpt::Constants::VERSION));

setChainProperties(props,
base,
bsl::string(rmqamqpt::Constants::PRODUCT),
bsl::string(rmqamqpt::Constants::VERSION));

if (!connectionName.empty()) {
props["connection_name"] = FieldValue(connectionName);
Expand Down
161 changes: 137 additions & 24 deletions src/tests/rmqamqp/rmqamqp_connection.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ rmqt::FieldTable generateDefaultClientProperties(
rmqt::FieldValue(bsl::string(rmqamqpt::Constants::PRODUCT));
props["version"] =
rmqt::FieldValue(bsl::string(rmqamqpt::Constants::VERSION));
props["product_chain"] =
rmqt::FieldValue(bsl::string(rmqamqpt::Constants::PRODUCT));
props["version_chain"] =
rmqt::FieldValue(bsl::string(rmqamqpt::Constants::VERSION));

if (!connectionName.empty()) {
props["connection_name"] = rmqt::FieldValue(connectionName);
Expand Down Expand Up @@ -405,7 +409,7 @@ class ConnectionTests : public ::testing::Test {
, d_sendChannel(bsl::make_shared<MockSendChannel>(d_retryHandlerChannel))
, d_ackQueue(bsl::make_shared<rmqt::ConsumerAckQueue>())
, d_metricPublisher(bsl::make_shared<rmqtestutil::MockMetricPublisher>())
, d_clientProperties(generateDefaultClientProperties())
, d_clientProperties()
, d_factory(bsl::make_shared<ConnectionFactory>(d_resolver,
d_timerFactory,
d_errorCallback,
Expand Down Expand Up @@ -679,21 +683,23 @@ TEST_F(ConnectionTests, Handshake)

TEST_F(ConnectionTests, ClientProperties)
{
rmqt::FieldTable overriddenClientProperties =
generateDefaultClientProperties();
overriddenClientProperties["FOO"] =
rmqt::FieldValue(bsl::string("BAR")); // Add one more
rmqt::FieldTable inputClientProperties;
inputClientProperties["FOO"] =
rmqt::FieldValue(bsl::string("BAR")); // Add a custom property

d_factory = bsl::make_shared<ConnectionFactory>(d_resolver,
d_timerFactory,
d_errorCallback,
d_metricPublisher,
overriddenClientProperties,
inputClientProperties,
d_retryHandler,
d_heartbeat,
d_channelFactory);

expectHeaderAndStartFrames(
overriddenClientProperties); // check it's as expected
rmqt::FieldTable expectedProperties =
generateDefaultClientProperties("test-connection");
expectedProperties["FOO"] = rmqt::FieldValue(bsl::string("BAR"));
expectHeaderAndStartFrames(expectedProperties);
expectTuneFrames();
expectOpenFrame();

Expand All @@ -709,45 +715,152 @@ TEST_F(ConnectionTests, ClientProperties)
d_eventLoop.run();
}

TEST_F(ConnectionTests, ClientPropertiesCantOverrideReservedOnes)
TEST_F(ConnectionTests, ClientPropertiesCantOverrideConnectionName)
{
rmqt::FieldTable overriddenClientProperties =
generateDefaultClientProperties("my random connection name");
overriddenClientProperties["platform"] = rmqt::FieldValue(
bsl::string("Should get overriden by library")); // Add one more
overriddenClientProperties["product"] = rmqt::FieldValue(
bsl::string("Should get overriden by library")); // Add one more
overriddenClientProperties["version"] = rmqt::FieldValue(
bsl::string("Should get overriden by library")); // Add one more
overriddenClientProperties["connection_name"] = rmqt::FieldValue(
bsl::string("Should get overriden by library")); // Add one more
rmqt::FieldTable inputClientProperties;
inputClientProperties["connection_name"] =
rmqt::FieldValue(bsl::string("Should get overriden by library"));
d_factory = bsl::make_shared<ConnectionFactory>(d_resolver,
d_timerFactory,
d_errorCallback,
d_metricPublisher,
overriddenClientProperties,
inputClientProperties,
d_retryHandler,
d_heartbeat,
d_channelFactory);

expectHeaderAndStartFrames(generateDefaultClientProperties(
"my real connection name")); // despite setting overrides, the library
// has the final say
"my real connection name")); // connection_name is still reserved
expectTuneFrames();
expectOpenFrame();

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

// 1. Handshake up to open with custom client properties
d_eventLoop.run();
d_eventLoop.restart();

expectShutdownCalls();
}

// 2. Shutdown cleanly
d_eventLoop.run();
}

TEST_F(ConnectionTests, ClientPropertiesDefaultsWhenNoneProvided)
{
rmqt::FieldTable emptyClientProperties;
d_factory = bsl::make_shared<ConnectionFactory>(d_resolver,
d_timerFactory,
d_errorCallback,
d_metricPublisher,
emptyClientProperties,
d_retryHandler,
d_heartbeat,
d_channelFactory);

expectHeaderAndStartFrames(
generateDefaultClientProperties("my connection"));
expectTuneFrames();
expectOpenFrame();

{
bsl::shared_ptr<rmqamqp::Connection> conn =
createAndStartConnection("my connection");

d_eventLoop.run();
d_eventLoop.restart();

expectShutdownCalls();
}

d_eventLoop.run();
}

TEST_F(ConnectionTests, ClientPropertiesCanOverrideProductAndVersion)
{
rmqt::FieldTable overriddenClientProperties;
overriddenClientProperties["product"] =
rmqt::FieldValue(bsl::string("xyzlib"));
overriddenClientProperties["version"] =
rmqt::FieldValue(bsl::string("4.5.6"));
d_factory = bsl::make_shared<ConnectionFactory>(d_resolver,
d_timerFactory,
d_errorCallback,
d_metricPublisher,
overriddenClientProperties,
d_retryHandler,
d_heartbeat,
d_channelFactory);

rmqt::FieldTable expectedProperties =
generateDefaultClientProperties("my connection");
expectedProperties["product"] = rmqt::FieldValue(bsl::string("xyzlib"));
expectedProperties["version"] = rmqt::FieldValue(bsl::string("4.5.6"));
expectedProperties["product_chain"] = rmqt::FieldValue(
bsl::string("xyzlib | ") + bsl::string(rmqamqpt::Constants::PRODUCT));
expectedProperties["version_chain"] = rmqt::FieldValue(
bsl::string("4.5.6 | ") + bsl::string(rmqamqpt::Constants::VERSION));
expectHeaderAndStartFrames(expectedProperties);
expectTuneFrames();
expectOpenFrame();

{
bsl::shared_ptr<rmqamqp::Connection> conn =
createAndStartConnection("my connection");

d_eventLoop.run();
d_eventLoop.restart();

expectShutdownCalls();
}

d_eventLoop.run();
}

TEST_F(ConnectionTests, ClientPropertiesWrapperSetsChains)
{
rmqt::FieldTable wrapperClientProperties;
wrapperClientProperties["product"] =
rmqt::FieldValue(bsl::string("rmqcpp-wrapper"));
wrapperClientProperties["version"] = rmqt::FieldValue(bsl::string("1.2.3"));
wrapperClientProperties["product_chain"] =
rmqt::FieldValue(bsl::string("rmqcpp-wrapper"));
wrapperClientProperties["version_chain"] =
rmqt::FieldValue(bsl::string("1.2.3"));
d_factory = bsl::make_shared<ConnectionFactory>(d_resolver,
d_timerFactory,
d_errorCallback,
d_metricPublisher,
wrapperClientProperties,
d_retryHandler,
d_heartbeat,
d_channelFactory);

rmqt::FieldTable expectedProperties =
generateDefaultClientProperties("my connection");
expectedProperties["product"] =
rmqt::FieldValue(bsl::string("rmqcpp-wrapper"));
expectedProperties["version"] = rmqt::FieldValue(bsl::string("1.2.3"));
expectedProperties["product_chain"] =
rmqt::FieldValue(bsl::string("rmqcpp-wrapper | ") +
bsl::string(rmqamqpt::Constants::PRODUCT));
expectedProperties["version_chain"] = rmqt::FieldValue(
bsl::string("1.2.3 | ") + bsl::string(rmqamqpt::Constants::VERSION));
expectHeaderAndStartFrames(expectedProperties);
expectTuneFrames();
expectOpenFrame();

{
bsl::shared_ptr<rmqamqp::Connection> conn =
createAndStartConnection("my connection");

d_eventLoop.run();
d_eventLoop.restart();

expectShutdownCalls();
}

d_eventLoop.run();
}

Expand Down
1 change: 1 addition & 0 deletions vcpkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"openssl",
"gtest",
"bde",
"pcre2",
"zstd"
]
}
Loading