|
14 | 14 |
|
15 | 15 | #include "BlackboxTests.hpp" |
16 | 16 |
|
| 17 | +#include <atomic> |
| 18 | +#include <memory> |
| 19 | + |
| 20 | +#include <fastdds/dds/core/policy/ParameterTypes.hpp> |
| 21 | +#include <fastdds/dds/topic/TypeSupport.hpp> |
17 | 22 | #include <fastdds/rtps/common/CDRMessage_t.hpp> |
| 23 | +#include <fastdds/rtps/common/InstanceHandle.hpp> |
| 24 | +#include <fastdds/rtps/common/SerializedPayload.hpp> |
18 | 25 | #include <fastdds/rtps/transport/test_UDPv4TransportDescriptor.hpp> |
19 | 26 |
|
| 27 | +#include "../types/HelloWorldPubSubTypes.hpp" |
| 28 | +#include "../types/KeyedHelloWorldPubSubTypes.hpp" |
20 | 29 | #include "../utils/filter_helpers.hpp" |
21 | 30 | #include "PubSubReader.hpp" |
22 | 31 | #include "PubSubWriter.hpp" |
| 32 | +#include "UDPMessageSender.hpp" |
23 | 33 |
|
24 | 34 | TEST(KeyedTopic, RegistrationNonKeyedFail) |
25 | 35 | { |
@@ -287,6 +297,144 @@ TEST(KeyedTopic, DataWriterAlwaysSendTheSerializedKeyViaInlineQoS) |
287 | 297 | EXPECT_TRUE(writer_sends_pid_key_hash); |
288 | 298 | } |
289 | 299 |
|
| 300 | +// Check that compute_key is called with a key-only payload when KEY_HASH is not present |
| 301 | +TEST(KeyedTopic, key_only_payload) |
| 302 | +{ |
| 303 | + using namespace eprosima::fastdds::dds; |
| 304 | + using namespace eprosima::fastdds::rtps; |
| 305 | + |
| 306 | + struct TestTypeSupport : public KeyedHelloWorldPubSubType |
| 307 | + { |
| 308 | + typedef KeyedHelloWorldPubSubType::type type; |
| 309 | + |
| 310 | + bool compute_key( |
| 311 | + eprosima::fastdds::rtps::SerializedPayload_t& payload, |
| 312 | + eprosima::fastdds::rtps::InstanceHandle_t& ihandle, |
| 313 | + bool force_md5 = false) override |
| 314 | + { |
| 315 | + if (payload.is_serialized_key) |
| 316 | + { |
| 317 | + // Count the number of times compute_key is called with a key-only payload |
| 318 | + key_only_payload_count++; |
| 319 | + } |
| 320 | + |
| 321 | + return KeyedHelloWorldPubSubType::compute_key(payload, ihandle, force_md5); |
| 322 | + } |
| 323 | + |
| 324 | + bool compute_key( |
| 325 | + const void* const data, |
| 326 | + eprosima::fastdds::rtps::InstanceHandle_t& ihandle, |
| 327 | + bool force_md5 = false) override |
| 328 | + { |
| 329 | + return KeyedHelloWorldPubSubType::compute_key(data, ihandle, force_md5); |
| 330 | + } |
| 331 | + |
| 332 | + std::atomic<uint32_t> key_only_payload_count{ 0 }; |
| 333 | + }; |
| 334 | + |
| 335 | + // Force using UDP transport |
| 336 | + auto udp_transport = std::make_shared<UDPv4TransportDescriptor>(); |
| 337 | + |
| 338 | + PubSubWriter<TestTypeSupport> writer(TEST_TOPIC_NAME); |
| 339 | + PubSubReader<TestTypeSupport> reader(TEST_TOPIC_NAME); |
| 340 | + |
| 341 | + // Set custom reader locator so we can send hand-crafted data to a known location |
| 342 | + Locator_t reader_locator; |
| 343 | + ASSERT_TRUE(IPLocator::setIPv4(reader_locator, "127.0.0.1")); |
| 344 | + reader_locator.port = 7000; |
| 345 | + reader.add_to_unicast_locator_list("127.0.0.1", 7000); |
| 346 | + |
| 347 | + reader.disable_builtin_transport(). |
| 348 | + add_user_transport_to_pparams(udp_transport). |
| 349 | + init(); |
| 350 | + ASSERT_TRUE(reader.isInitialized()); |
| 351 | + |
| 352 | + writer.disable_builtin_transport(). |
| 353 | + add_user_transport_to_pparams(udp_transport). |
| 354 | + init(); |
| 355 | + ASSERT_TRUE(writer.isInitialized()); |
| 356 | + |
| 357 | + // Wait for discovery. |
| 358 | + writer.wait_discovery(); |
| 359 | + reader.wait_discovery(); |
| 360 | + |
| 361 | + auto data = default_keyedhelloworld_data_generator(2); |
| 362 | + reader.startReception(data); |
| 363 | + // Send data |
| 364 | + writer.send(data); |
| 365 | + EXPECT_TRUE(data.empty()); |
| 366 | + reader.block_for_all(); |
| 367 | + |
| 368 | + // Check that compute_key was not called with a key-only payload |
| 369 | + auto ts = std::dynamic_pointer_cast<TestTypeSupport>(reader.get_type_support()); |
| 370 | + ASSERT_TRUE(ts != nullptr); |
| 371 | + EXPECT_EQ(ts->key_only_payload_count.load(), 0u); |
| 372 | + |
| 373 | + struct KeyOnlyPayloadPacket |
| 374 | + { |
| 375 | + std::array<char, 4> rtps_id{ {'R', 'T', 'P', 'S'} }; |
| 376 | + std::array<uint8_t, 2> protocol_version{ {2, 3} }; |
| 377 | + std::array<uint8_t, 2> vendor_id{ {0x01, 0x0F} }; |
| 378 | + GuidPrefix_t sender_prefix{}; |
| 379 | + |
| 380 | + struct DataSubMsg |
| 381 | + { |
| 382 | + struct Header |
| 383 | + { |
| 384 | + uint8_t submessage_id = 0x15; |
| 385 | +#if FASTDDS_IS_BIG_ENDIAN_TARGET |
| 386 | + uint8_t flags = 0x08; |
| 387 | +#else |
| 388 | + uint8_t flags = 0x09; |
| 389 | +#endif // FASTDDS_IS_BIG_ENDIAN_TARGET |
| 390 | + uint16_t octets_to_next_header = 28; |
| 391 | + uint16_t extra_flags = 0; |
| 392 | + uint16_t octets_to_inline_qos = 16; |
| 393 | + EntityId_t reader_id{}; |
| 394 | + EntityId_t writer_id{}; |
| 395 | + SequenceNumber_t sn{ 3 }; |
| 396 | + }; |
| 397 | + |
| 398 | + struct SerializedData |
| 399 | + { |
| 400 | + uint16_t encapsulation; |
| 401 | + uint16_t encapsulation_opts; |
| 402 | + uint8_t data[4] = {0x01, 0x00, 0x00, 0x00}; |
| 403 | + }; |
| 404 | + |
| 405 | + Header header; |
| 406 | + SerializedData payload; |
| 407 | + } |
| 408 | + data; |
| 409 | + }; |
| 410 | + |
| 411 | + UDPMessageSender fake_msg_sender; |
| 412 | + |
| 413 | + // Send hand-crafted data |
| 414 | + { |
| 415 | + auto writer_guid = writer.datawriter_guid(); |
| 416 | + |
| 417 | + KeyOnlyPayloadPacket key_only_packet{}; |
| 418 | + key_only_packet.sender_prefix = writer_guid.guidPrefix; |
| 419 | + key_only_packet.data.header.writer_id = writer_guid.entityId; |
| 420 | + key_only_packet.data.header.reader_id = reader.datareader_guid().entityId; |
| 421 | + key_only_packet.data.payload.encapsulation = CDR_LE; |
| 422 | + |
| 423 | + CDRMessage_t msg(0); |
| 424 | + uint32_t msg_len = static_cast<uint32_t>(sizeof(key_only_packet)); |
| 425 | + msg.init(reinterpret_cast<octet*>(&key_only_packet), msg_len); |
| 426 | + msg.length = msg_len; |
| 427 | + msg.pos = msg_len; |
| 428 | + fake_msg_sender.send(msg, reader_locator); |
| 429 | + } |
| 430 | + |
| 431 | + // Wait for key-only compute key to be called |
| 432 | + while (ts->key_only_payload_count.load() <= 0) |
| 433 | + { |
| 434 | + std::this_thread::sleep_for(std::chrono::milliseconds(10)); |
| 435 | + } |
| 436 | +} |
| 437 | + |
290 | 438 | /* Uncomment when DDS API supports NO_WRITERS_ALIVE |
291 | 439 | TEST(KeyedTopic, WriteSamplesBestEffort) |
292 | 440 | { |
|
0 commit comments