From f4f13b6d5bfe44543ed8b7c6bb03ce3657a89fc6 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Sat, 25 Apr 2026 10:22:06 -0700 Subject: [PATCH] [nexus] add test for `OT_MLE_LONG_ROUTES` feature (#12956) This commit adds a new Nexus test to verify the functionality of the MLE long routes experimental feature, which allows path costs to exceed the standard limit of 15. The new test `TestLongRoutes` in `test_long_routes.cpp` forms a topology consisting of a leader and a chain of 25 routers. It then validates that the path cost from the last router in the chain to the leader is correctly reported as 25 using `GetPathCostToLeader()`. Supporting changes include: - Updating `build.sh` to support a `long_routes` build target that enables `OT_MLE_LONG_ROUTES`. - Adding the `long_routes` test to `CMakeLists.txt` with the appropriate labels. - Introducing a new GitHub workflow job `nexus-long-routes-tests` in `nexus.yml` to automate the execution of this test. --- .github/workflows/nexus.yml | 29 ++++++++++ tests/nexus/CMakeLists.txt | 3 + tests/nexus/build.sh | 8 +++ tests/nexus/test_long_routes.cpp | 95 ++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 tests/nexus/test_long_routes.cpp diff --git a/.github/workflows/nexus.yml b/.github/workflows/nexus.yml index d1d6416cd..73dbc6aac 100644 --- a/.github/workflows/nexus.yml +++ b/.github/workflows/nexus.yml @@ -107,6 +107,35 @@ jobs: run: | cd build/nexus && ctest -L trel --output-on-failure + nexus-long-routes-tests: + name: nexus-long-routes-tests + runs-on: ubuntu-24.04 + steps: + - name: Harden Runner + uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2 + with: + egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs + + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + submodules: recursive + + - name: Bootstrap + env: + PR_BODY: "${{ github.event.pull_request.body }}" + run: | + sudo apt-get update + sudo apt-get --no-install-recommends install -y ninja-build lcov + + - name: Build Nexus + run: | + mkdir -p build/nexus + top_builddir=build/nexus ./tests/nexus/build.sh long_routes + + - name: Run LONG_ROUTES Tests + run: | + cd build/nexus && ctest -L long_routes --output-on-failure + nexus-grpc-tests: name: nexus-grpc-tests runs-on: ubuntu-24.04 diff --git a/tests/nexus/CMakeLists.txt b/tests/nexus/CMakeLists.txt index dbd5f1c96..7c6a2b97b 100644 --- a/tests/nexus/CMakeLists.txt +++ b/tests/nexus/CMakeLists.txt @@ -423,6 +423,9 @@ ot_nexus_test(zero_len_external_route "core;nexus") # Trel ot_nexus_test(trel "trel;nexus") +# Long-routes +ot_nexus_test(long_routes "long_routes;nexus") + # Grpc if(OT_NEXUS_GRPC) ot_nexus_test(grpc "core;nexus") diff --git a/tests/nexus/build.sh b/tests/nexus/build.sh index 8a5463206..d99e9a5ec 100755 --- a/tests/nexus/build.sh +++ b/tests/nexus/build.sh @@ -44,6 +44,8 @@ else top_builddir=. fi +long_routes=OFF + case $1 in trel) fifteenfour=OFF @@ -53,6 +55,11 @@ case $1 in fifteenfour=ON wasm=ON ;; + long_routes) + fifteenfour=ON + wasm=OFF + long_routes=ON + ;; *) fifteenfour=ON wasm=OFF @@ -73,6 +80,7 @@ CMAKE_ARGS=( -DOT_APP_NCP=OFF -DOT_APP_RCP=OFF -DOT_15_4="${fifteenfour}" + -DOT_MLE_LONG_ROUTES="${long_routes}" -DOT_PROJECT_CONFIG="${top_srcdir}/tests/nexus/openthread-core-nexus-config.h" ) diff --git a/tests/nexus/test_long_routes.cpp b/tests/nexus/test_long_routes.cpp new file mode 100644 index 000000000..a345bd7d2 --- /dev/null +++ b/tests/nexus/test_long_routes.cpp @@ -0,0 +1,95 @@ +/* + * 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 { + +#if OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE + +void TestLongRoutes(void) +{ + static constexpr uint16_t kNumRouters = 25; + + Core nexus; + Node &leader = nexus.CreateNode(); + Node *routers[kNumRouters]; + + Log("---------------------------------------------------------------------------------------"); + Log("TestLongRoutes"); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Log("Form topology - long chain of routers"); + + leader.Form(); + nexus.AdvanceTime(100 * 1000); + VerifyOrQuit(leader.Get().IsLeader()); + + routers[0] = &nexus.CreateNode(); + AllowLinkBetween(leader, *routers[0]); + routers[0]->Join(leader, Node::kAsFtd); + + for (uint16_t i = 1; i < kNumRouters; i++) + { + Log("Router %u", i); + + routers[i] = &nexus.CreateNode(); + AllowLinkBetween(*routers[i], *routers[i - 1]); + routers[i]->Join(*routers[i - 1], Node::kAsFtd); + nexus.AdvanceTime(20 * 1000); + + VerifyOrQuit(routers[i - 1]->Get().IsRouter()); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Log("Check the path cost from last router to leader"); + + VerifyOrQuit(routers[kNumRouters - 1]->Get().GetPathCostToLeader() == kNumRouters); +} + +#endif // OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE + +} // namespace Nexus +} // namespace ot + +int main(void) +{ +#if OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE + ot::Nexus::TestLongRoutes(); + printf("All tests passed\n"); +#else + printf("OPENTHREAD_CONFIG_MLE_LONG_ROUTES_ENABLE is not enabled, test is skipped\n"); +#endif + return 0; +}