From 5fad120d9b29fcd79c3ab0f303cc0ee752eb7c63 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Fri, 17 Apr 2026 11:22:46 -0700 Subject: [PATCH] [tests] remove redundant MLE and connectivity tests (#12909) The following test scripts in tests/scripts/thread-cert are now redundant as their functionality is sufficiently covered by the Nexus test framework: - test_detach.py: Covered by Nexus MLE synchronization and parent selection tests. - test_router_upgrade.py: Covered by 5.1.x Nexus router attachment tests. Nexus tests are preferred for these scenarios as they execute in a single process using virtual time, providing faster and more reliable verification than the traditional multi-process simulation scripts. --- tests/scripts/thread-cert/test_detach.py | 184 ------------------ .../thread-cert/test_router_upgrade.py | 99 ---------- 2 files changed, 283 deletions(-) delete mode 100755 tests/scripts/thread-cert/test_detach.py delete mode 100755 tests/scripts/thread-cert/test_router_upgrade.py diff --git a/tests/scripts/thread-cert/test_detach.py b/tests/scripts/thread-cert/test_detach.py deleted file mode 100755 index 39f380130..000000000 --- a/tests/scripts/thread-cert/test_detach.py +++ /dev/null @@ -1,184 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2022, 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. -# - -import unittest - -import thread_cert -import config -from pktverify.consts import MLE_CHILD_UPDATE_REQUEST, TIMEOUT_TLV, ADDR_REL_URI -from pktverify.packet_verifier import PacketVerifier - -# Test description: -# This test verifies that detaching function can send correct "goodbye" messages. -# -# Topology: -# -# CHILD_1 ----- ROUTER_1 ----- LEADER -# -# - -LEADER = 1 -ROUTER_1 = 2 -CHILD_1 = 3 - - -class TestDetach(thread_cert.TestCase): - USE_MESSAGE_FACTORY = False - SUPPORT_NCP = False - - TOPOLOGY = { - LEADER: { - 'name': 'Leader', - 'allowlist': [ROUTER_1], - 'mode': 'rdn', - }, - ROUTER_1: { - 'name': 'Router_1', - 'allowlist': [LEADER, CHILD_1], - 'mode': 'rdn', - }, - CHILD_1: { - 'name': 'Child_1', - 'is_mtd': True, - 'allowlist': [ROUTER_1], - 'mode': '-', - 'timeout': 10, - }, - } - - def test(self): - leader = self.nodes[LEADER] - router1 = self.nodes[ROUTER_1] - child1 = self.nodes[CHILD_1] - - leader.start() - self.simulator.go(config.LEADER_STARTUP_DELAY) - self.assertEqual(leader.get_state(), 'leader') - - router1.start() - self.simulator.go(config.ROUTER_STARTUP_DELAY) - self.assertEqual(router1.get_state(), 'router') - router1_rloc16 = router1.get_addr16() - self.assertTrue(list(filter(lambda x: x[1]['rloc16'] == router1_rloc16, leader.router_table().items()))) - - self.collect_rloc16s() - - child1.start() - self.simulator.go(7) - self.assertEqual(child1.get_state(), 'child') - child_table = router1.get_child_table() - self.assertEqual(len(child_table), 1) - self.assertEqual(child_table[1]['timeout'], 10) - - child1.detach() - self.assertEqual(child1.get_state(), 'disabled') - self.simulator.go(2) # The router processes its child table every second; wait 2s to be safe. - self.assertFalse(router1.get_child_table()) - - router1.detach() - self.assertEqual(router1.get_state(), 'disabled') - self.assertFalse(list(filter(lambda x: x[1]['rloc16'] == router1_rloc16, leader.router_table().items()))) - - router1.start() - self.simulator.go(config.ROUTER_STARTUP_DELAY) - self.assertEqual(router1.get_state(), 'router') - - child1.start() - self.simulator.go(7) - self.assertEqual(child1.get_state(), 'child') - child_table = router1.get_child_table() - self.assertEqual(len(child_table), 1) - self.assertEqual(child_table[2]['timeout'], 10) - - router1.thread_stop() - self.assertEqual(router1.get_state(), 'disabled') - child1.detach() - self.assertEqual(child1.get_state(), 'disabled') - - router1.start() - self.simulator.go(config.ROUTER_STARTUP_DELAY) - self.assertEqual(router1.get_state(), 'router') - - child1.start() - self.simulator.go(7) - self.assertEqual(child1.get_state(), 'child') - - leader.detach() - self.assertEqual(leader.get_state(), 'disabled') - - self.assertTrue(child1.ping(router1.get_mleid(), timeout=20)) - - router1.detach() - self.assertEqual(router1.get_state(), 'disabled') - - leader.detach() - self.assertEqual(leader.get_state(), 'disabled') - - leader.start() - self.assertEqual(leader.get_state(), 'detached') - leader.detach() - self.assertEqual(leader.get_state(), 'disabled') - - leader.start() - self.simulator.go(config.LEADER_RESET_DELAY / 2) - self.assertEqual(leader.get_state(), 'detached') - self.simulator.go(config.LEADER_RESET_DELAY / 2) - self.assertEqual(leader.get_state(), 'leader') - router1.start() - self.simulator.go(config.ROUTER_RESET_DELAY) - self.assertEqual(router1.get_state(), 'router') - - leader.thread_stop() - router1.detach(is_async=True) - self.assertEqual(router1.get_state(), 'router') - router1.thread_stop() - self.assertEqual(router1.get_state(), 'disabled') - router1.detach() - self.assertEqual(router1.get_state(), 'disabled') - - def verify(self, pv: PacketVerifier): - pkts = pv.pkts - pv.summary.show() - - leader = pv.vars['Leader'] - router1 = pv.vars['Router_1'] - child1 = pv.vars['Child_1'] - leader_rloc16 = pv.vars['Leader_RLOC16'] - - pkts.filter_wpan_src64(child1).filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).filter_wpan_dst64( - router1).must_next().must_verify(lambda p: TIMEOUT_TLV in set(p.mle.tlv.type) and p.mle.tlv.timeout == 0) - pkts.filter_wpan_src64(router1).filter_coap_request(ADDR_REL_URI).filter_wpan_dst16(leader_rloc16).must_next() - pkts.filter_wpan_src64(child1).filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).filter_wpan_dst64( - router1).must_next().must_verify(lambda p: TIMEOUT_TLV in set(p.mle.tlv.type) and p.mle.tlv.timeout == 0) - pkts.filter_wpan_src64(leader).filter_coap_request(ADDR_REL_URI).must_not_next() - pkts.filter_wpan_src64(router1).filter_coap_request(ADDR_REL_URI).filter_wpan_dst16(leader_rloc16).must_next() - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/scripts/thread-cert/test_router_upgrade.py b/tests/scripts/thread-cert/test_router_upgrade.py deleted file mode 100755 index a9c1e1a34..000000000 --- a/tests/scripts/thread-cert/test_router_upgrade.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2022, 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. -# - -import unittest - -import config -import mle -import network_layer -import thread_cert - -LEADER = 1 -REED = 2 - -RSSI_LOW = -95 -RSSI_HIGH = -45 - -ROUTER_UPGRADE_DELAY = 150 - -# Test Purpose and Description: -# ----------------------------- -# The purpose of this test case is to show that a REED does not -# upgrade to router if it does not have a neighbor with link margin -# above threshold. -# -# Test Topology: -# ------------- -# Leader -# | -# REED -# -# DUT Types: -# ---------- -# Leader -# REED - - -class TestRouterUpgrade(thread_cert.TestCase): - USE_MESSAGE_FACTORY = False - - TOPOLOGY = { - LEADER: { - 'name': 'LEADER', - 'mode': 'rdn', - 'allowlist': [REED] - }, - REED: { - 'name': 'REED', - 'mode': 'rdn', - 'allowlist': [LEADER] - }, - } - - def test(self): - self.nodes[LEADER].start() - self.simulator.go(config.LEADER_STARTUP_DELAY) - self.assertEqual(self.nodes[LEADER].get_state(), 'leader') - - self.nodes[REED].add_allowlist(self.nodes[LEADER].get_addr64(), rssi=RSSI_LOW) - self.nodes[REED].enable_allowlist() - - self.nodes[REED].start() - self.simulator.go(ROUTER_UPGRADE_DELAY) - self.assertEqual(self.nodes[REED].get_state(), 'child') - - self.nodes[REED].add_allowlist(self.nodes[LEADER].get_addr64(), rssi=RSSI_HIGH) - self.nodes[REED].enable_allowlist() - - self.simulator.go(ROUTER_UPGRADE_DELAY) - self.assertEqual(self.nodes[REED].get_state(), 'router') - - -if __name__ == '__main__': - unittest.main()