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; +}