@@ -1315,6 +1315,98 @@ TEST_P(Security, RemoveParticipantProxyDataonSecurityManagerLeaseExpired_validat
13151315
13161316}
13171317
1318+ // Regression test for secure PDP liveliness maintenance without user traffic.
1319+ TEST (Security, SecureParticipantsDoNotLoseDiscoveryWithoutUserTraffic)
1320+ {
1321+ PubSubReader<HelloWorldPubSubType> reader (" HelloWorldTopic_secure_participant_liveliness" );
1322+ PubSubWriter<HelloWorldPubSubType> writer (" HelloWorldTopic_secure_participant_liveliness" );
1323+ const auto idle_timeout = std::chrono::seconds (6 );
1324+ const auto data_timeout = std::chrono::seconds (10 );
1325+ // Keep the lease short so loss of secure PDP liveliness shows up quickly
1326+ const auto lease_duration = eprosima::fastdds::dds::Duration_t (3 , 0 );
1327+ const auto announcement_period = eprosima::fastdds::dds::Duration_t (1 , 0 );
1328+ // Use UDP transport to later block the fallback participant DATA(P) traffic
1329+ auto reader_transport = std::make_shared<test_UDPv4TransportDescriptor>();
1330+ auto writer_transport = std::make_shared<test_UDPv4TransportDescriptor>();
1331+
1332+ const std::string governance_file (" governance_helloworld_all_enable.smime" );
1333+ const std::string permissions_file (" permissions_helloworld.smime" );
1334+
1335+ CommonPermissionsConfigure (reader, writer, governance_file, permissions_file);
1336+ // Force the test through UDP to avoid local shortcuts masking the secure discovery behavior
1337+ reader.disable_builtin_transport ().add_user_transport_to_pparams (reader_transport);
1338+ writer.disable_builtin_transport ().add_user_transport_to_pparams (writer_transport);
1339+
1340+ // Two secure participants that authenticate, discover each other, and exchange user data
1341+ reader.lease_duration (lease_duration, announcement_period)
1342+ .history_depth (10 )
1343+ .reliability (eprosima::fastdds::dds::RELIABLE_RELIABILITY_QOS )
1344+ .init ();
1345+ ASSERT_TRUE (reader.isInitialized ());
1346+
1347+ writer.lease_duration (lease_duration, announcement_period)
1348+ .history_depth (10 )
1349+ .reliability (eprosima::fastdds::dds::RELIABLE_RELIABILITY_QOS )
1350+ .init ();
1351+ ASSERT_TRUE (writer.isInitialized ());
1352+
1353+ reader.wait_authorized ();
1354+ writer.wait_authorized ();
1355+
1356+ // Wait until both endpoints are matched
1357+ reader.wait_discovery ();
1358+ writer.wait_discovery ();
1359+
1360+ // Verify discovery state stayed stable
1361+ auto assert_still_discovered = [&reader, &writer]()
1362+ {
1363+ ASSERT_TRUE (reader.is_matched ());
1364+ ASSERT_TRUE (writer.is_matched ());
1365+ ASSERT_EQ (reader.get_matched (), 1u );
1366+ ASSERT_EQ (writer.get_matched (), 1u );
1367+
1368+ const auto reader_status = reader.get_subscription_matched_status ();
1369+ const auto writer_status = writer.get_publication_matched_status ();
1370+ ASSERT_EQ (reader_status.total_count , 1 );
1371+ ASSERT_EQ (writer_status.total_count , 1 );
1372+ };
1373+
1374+ // Check the secure participants must not be undiscovered just because user traffic stops
1375+ auto assert_idle_period_keeps_discovery = [&reader, &writer, &idle_timeout, &assert_still_discovered]()
1376+ {
1377+ ASSERT_FALSE (reader.wait_participant_undiscovery (idle_timeout));
1378+ ASSERT_FALSE (writer.wait_participant_undiscovery (idle_timeout));
1379+
1380+ assert_still_discovered ();
1381+ };
1382+
1383+ // Discovery is only useful if data can still flow after the idle window
1384+ auto assert_data_flow = [&reader, &writer, &data_timeout, &assert_still_discovered]()
1385+ {
1386+ auto data = default_helloworld_data_generator (2 );
1387+
1388+ reader.startReception (data);
1389+ writer.send (data);
1390+
1391+ ASSERT_TRUE (data.empty ());
1392+ ASSERT_EQ (reader.block_for_all (data_timeout), 2u );
1393+ assert_still_discovered ();
1394+ };
1395+
1396+ ASSERT_NO_FATAL_FAILURE (assert_still_discovered ());
1397+
1398+ // After the secure PDP endpoints are established, stop the unprotected participant DATA(P)
1399+ // traffic, to depend on the secure liveliness maintenance path
1400+ reader_transport->test_transport_options ->always_drop_participant_builtin_topic_data = true ;
1401+ writer_transport->test_transport_options ->always_drop_participant_builtin_topic_data = true ;
1402+
1403+ // Exercise the idle scenario twice to catch both immediate loss and unstable recovery/rematch behavior
1404+ ASSERT_NO_FATAL_FAILURE (assert_idle_period_keeps_discovery ());
1405+ ASSERT_NO_FATAL_FAILURE (assert_data_flow ());
1406+ ASSERT_NO_FATAL_FAILURE (assert_idle_period_keeps_discovery ());
1407+ ASSERT_NO_FATAL_FAILURE (assert_data_flow ());
1408+ }
1409+
13181410TEST (Security, AllowUnauthenticatedParticipants_EntityCreationFailsIfRTPSProtectionIsNotNONE)
13191411{
13201412 PubSubReader<HelloWorldPubSubType> reader (" HelloWorldTopic" );
0 commit comments