From fe3594e4e63a835c2a9ce650503d7325b502daf1 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 30 Apr 2026 16:30:26 -0700 Subject: [PATCH] [tests] add nexus test for FED rx-only link establishment (#13019) This commit adds a new Nexus test `TestFedRxOnlyLinkEstablishment` to verify that a Full End Device (FED) successfully establishes rx-only links with all its neighboring routers in the network. The test forms a topology with a leader and 15 routers, then adds an FED child. It uses the `NeighborTable` callback to track the addition of routers to the FED's neighbor table and ensures that it eventually establishes links with all available neighboring routers. --- tests/nexus/CMakeLists.txt | 1 + .../test_fed_rx_only_link_establishment.cpp | 130 ++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 tests/nexus/test_fed_rx_only_link_establishment.cpp diff --git a/tests/nexus/CMakeLists.txt b/tests/nexus/CMakeLists.txt index a5ccd17b2..74066031c 100644 --- a/tests/nexus/CMakeLists.txt +++ b/tests/nexus/CMakeLists.txt @@ -400,6 +400,7 @@ ot_nexus_test(dnssd "core;nexus") ot_nexus_test(dns_client_config_auto_start "core;nexus") ot_nexus_test(dnssd_name_with_special_chars "core;nexus") ot_nexus_test(dtls "core;nexus") +ot_nexus_test(fed_rx_only_link_establishment "core;nexus") ot_nexus_test(form_join "core;nexus") ot_nexus_test(ipv6_fragmentation "core;nexus") ot_nexus_test(ipv6_source_selection "core;nexus") diff --git a/tests/nexus/test_fed_rx_only_link_establishment.cpp b/tests/nexus/test_fed_rx_only_link_establishment.cpp new file mode 100644 index 000000000..e715684f1 --- /dev/null +++ b/tests/nexus/test_fed_rx_only_link_establishment.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2026, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "platform/nexus_core.hpp" +#include "platform/nexus_node.hpp" + +namespace ot { +namespace Nexus { + +static uint8_t sRxOnlyNeighborCount = 0; + +static void HandleNeighborTableChanged(otNeighborTableEvent aEvent, const otNeighborTableEntryInfo *aEntryInfo) +{ + VerifyOrQuit(static_cast(aEvent) == NeighborTable::kRouterAdded); + VerifyOrQuit(aEntryInfo != nullptr); + + Log(" Neighbor Table Event ROUTER_ADDED -> rloc16: 0x%04x", aEntryInfo->mInfo.mRouter.mRloc16); + sRxOnlyNeighborCount++; +} + +void TestFedRxOnlyLinkEstablishment(void) +{ + static constexpr uint16_t kNumRouters = 15; + + Core nexus; + Node &leader = nexus.CreateNode(); + Node *routers[kNumRouters]; + Node *fed; + + Log("---------------------------------------------------------------------------------------"); + Log("TestFedRxOnlyLinkEstablishment"); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Log("Form topology - leader + %u routers", kNumRouters); + + leader.Form(); + nexus.AdvanceTime(100 * Time::kOneSecondInMsec); + VerifyOrQuit(leader.Get().IsLeader()); + + for (uint16_t i = 0; i < kNumRouters; i++) + { + Node &router = nexus.CreateNode(); + + router.Join(leader, Node::kAsFtd); + nexus.AdvanceTime(300 * Time::kOneSecondInMsec); + VerifyOrQuit(router.Get().IsRouter()); + routers[i] = &router; + + Log("Router %-2u -> rloc16: 0x%04x", i, router.Get().GetRloc16()); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Log("Check Active Router Count on all routers"); + + nexus.AdvanceTime(300 * Time::kOneSecondInMsec); + + VerifyOrQuit(leader.Get().GetActiveRouterCount() == kNumRouters + 1); + + for (const Node *router : routers) + { + VerifyOrQuit(router->Get().GetActiveRouterCount() == kNumRouters + 1); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Log("Add an FED child to the network"); + + fed = &nexus.CreateNode(); + fed->Get().RegisterCallback(HandleNeighborTableChanged); + + fed->Join(leader, Node::kAsFed); + nexus.AdvanceTime(2 * Time::kOneSecondInMsec); + VerifyOrQuit(fed->Get().IsChild()); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Log("Check that the FED successfully establishes link (rx-only) with all neighboring routers"); + + VerifyOrQuit(fed->Get().GetActiveRouterCount() == kNumRouters + 1); + + for (uint16_t i = 0; i < 45; i++) + { + nexus.AdvanceTime(2 * Time::kOneMinuteInMsec); + + if (sRxOnlyNeighborCount == kNumRouters) + { + break; + } + } + + VerifyOrQuit(sRxOnlyNeighborCount == kNumRouters); +} + +} // namespace Nexus +} // namespace ot + +int main(void) +{ + ot::Nexus::TestFedRxOnlyLinkEstablishment(); + printf("All tests passed\n"); + + return 0; +}