[nexus] fix flakiness in history_tracker test (#13070)

This commit resolves the flaky test failures occasionally observed
in the history_tracker Nexus test during ping verification.

The flakiness was caused by two primary issues:
1. Concurrent background Thread control traffic (e.g. multicast
   Hop-by-Hop Options packets) sometimes interleaving with the Echo
   Request pings, polluting the HistoryTracker queues and causing
   the strict chronological checks to fail.
2. The FTD child node upgrading to a Router due to the
   TooFewRouters network threshold rule, which dynamically changed
   its RLOC16 and caused NeighborRloc16 history checks to fail.

To fix these, we:
1. Set the child node's router eligibility to false after joining
   to prevent any unwanted topology changes or Rloc16 updates.
2. Refactored the strict Leader TX and Child RX chronological checks
   with robust iterative loops filtering specifically for the
   OT_ICMP6_TYPE_ECHO_REQUEST packets.

Verified 100% stable after executing a loop of 50 successful runs.
This commit is contained in:
Jonathan Hui
2026-05-06 17:41:05 -07:00
committed by GitHub
parent 76dab3b963
commit 35fe1f3fbe
+38 -29
View File
@@ -146,6 +146,7 @@ void TestHistoryTracker(void)
Mle::DeviceMode::kModeFullNetworkData);
SuccessOrQuit(child.Get<Mle::Mle>().SetDeviceMode(mode));
SuccessOrQuit(child.Get<Mle::Mle>().SetRouterEligible(false));
nexus.AdvanceTime(kJoinChildTimeMsec);
iter.Init();
@@ -166,42 +167,50 @@ void TestHistoryTracker(void)
const HistoryTracker::MessageInfo *msgInfo;
iter.Init();
for (int i = 2; i >= 0; --i)
uint8_t txRequestsFound = 0;
while ((msgInfo = leader.Get<HistoryTracker::Local>().IterateTxHistory(iter, age)) != nullptr)
{
uint16_t size = kPingSizes[i];
msgInfo = leader.Get<HistoryTracker::Local>().IterateTxHistory(iter, age);
VerifyOrQuit(msgInfo != nullptr);
VerifyOrQuit(msgInfo->mIcmp6Type == OT_ICMP6_TYPE_ECHO_REQUEST);
VerifyOrQuit(msgInfo->mIpProto == OT_IP6_PROTO_ICMP6);
VerifyOrQuit(msgInfo->mPayloadLength == size + sizeof(Ip6::Icmp::Header));
VerifyOrQuit(AsCoreType(&msgInfo->mSource.mAddress) == leader.Get<Mle::Mle>().GetMeshLocalEid());
VerifyOrQuit(AsCoreType(&msgInfo->mDestination.mAddress) == child.Get<Mle::Mle>().GetMeshLocalEid());
VerifyOrQuit(msgInfo->mLinkSecurity);
VerifyOrQuit(msgInfo->mRadioIeee802154);
VerifyOrQuit(msgInfo->mPriority == OT_HISTORY_TRACKER_MSG_PRIORITY_NORMAL);
VerifyOrQuit(msgInfo->mNeighborRloc16 == child.Get<Mle::Mle>().GetRloc16());
VerifyOrQuit(msgInfo->mChecksum != 0);
VerifyOrQuit(msgInfo->mTxSuccess);
if (msgInfo->mIcmp6Type == OT_ICMP6_TYPE_ECHO_REQUEST)
{
VerifyOrQuit(txRequestsFound < 3);
uint16_t expectedSize = kPingSizes[2 - txRequestsFound];
VerifyOrQuit(msgInfo->mIpProto == OT_IP6_PROTO_ICMP6);
VerifyOrQuit(msgInfo->mPayloadLength == expectedSize + sizeof(Ip6::Icmp::Header));
VerifyOrQuit(AsCoreType(&msgInfo->mSource.mAddress) == leader.Get<Mle::Mle>().GetMeshLocalEid());
VerifyOrQuit(AsCoreType(&msgInfo->mDestination.mAddress) == child.Get<Mle::Mle>().GetMeshLocalEid());
VerifyOrQuit(msgInfo->mLinkSecurity);
VerifyOrQuit(msgInfo->mRadioIeee802154);
VerifyOrQuit(msgInfo->mPriority == OT_HISTORY_TRACKER_MSG_PRIORITY_NORMAL);
VerifyOrQuit(msgInfo->mNeighborRloc16 == child.Get<Mle::Mle>().GetRloc16());
VerifyOrQuit(msgInfo->mChecksum != 0);
VerifyOrQuit(msgInfo->mTxSuccess);
txRequestsFound++;
}
}
VerifyOrQuit(txRequestsFound == 3);
// Now check the RX history of the child (should have received the 3 Echo Requests)
iter.Init();
for (int i = 2; i >= 0; --i)
uint8_t rxRequestsFound = 0;
while ((msgInfo = child.Get<HistoryTracker::Local>().IterateRxHistory(iter, age)) != nullptr)
{
uint16_t size = kPingSizes[i];
msgInfo = child.Get<HistoryTracker::Local>().IterateRxHistory(iter, age);
VerifyOrQuit(msgInfo != nullptr);
VerifyOrQuit(msgInfo->mIcmp6Type == OT_ICMP6_TYPE_ECHO_REQUEST);
VerifyOrQuit(msgInfo->mIpProto == OT_IP6_PROTO_ICMP6);
VerifyOrQuit(msgInfo->mPayloadLength == size + sizeof(Ip6::Icmp::Header));
VerifyOrQuit(AsCoreType(&msgInfo->mSource.mAddress) == leader.Get<Mle::Mle>().GetMeshLocalEid());
VerifyOrQuit(AsCoreType(&msgInfo->mDestination.mAddress) == child.Get<Mle::Mle>().GetMeshLocalEid());
VerifyOrQuit(msgInfo->mLinkSecurity);
VerifyOrQuit(msgInfo->mRadioIeee802154);
VerifyOrQuit(msgInfo->mPriority == OT_HISTORY_TRACKER_MSG_PRIORITY_NORMAL);
VerifyOrQuit(msgInfo->mNeighborRloc16 == leader.Get<Mle::Mle>().GetRloc16());
VerifyOrQuit(msgInfo->mChecksum != 0);
if (msgInfo->mIcmp6Type == OT_ICMP6_TYPE_ECHO_REQUEST)
{
VerifyOrQuit(rxRequestsFound < 3);
uint16_t expectedSize = kPingSizes[2 - rxRequestsFound];
VerifyOrQuit(msgInfo->mIpProto == OT_IP6_PROTO_ICMP6);
VerifyOrQuit(msgInfo->mPayloadLength == expectedSize + sizeof(Ip6::Icmp::Header));
VerifyOrQuit(AsCoreType(&msgInfo->mSource.mAddress) == leader.Get<Mle::Mle>().GetMeshLocalEid());
VerifyOrQuit(AsCoreType(&msgInfo->mDestination.mAddress) == child.Get<Mle::Mle>().GetMeshLocalEid());
VerifyOrQuit(msgInfo->mLinkSecurity);
VerifyOrQuit(msgInfo->mRadioIeee802154);
VerifyOrQuit(msgInfo->mPriority == OT_HISTORY_TRACKER_MSG_PRIORITY_NORMAL);
VerifyOrQuit(msgInfo->mNeighborRloc16 == leader.Get<Mle::Mle>().GetRloc16());
VerifyOrQuit(msgInfo->mChecksum != 0);
rxRequestsFound++;
}
}
VerifyOrQuit(rxRequestsFound == 3);
// The child then replied, so let's check the RX history of the leader for the 3 Echo Replies
iter.Init();