1#!/usr/bin/env python3 2# 3# Copyright (c) 2024, The OpenThread Authors. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 3. Neither the name of the copyright holder nor the 14# names of its contributors may be used to endorse or promote products 15# derived from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28 29from cli import verify 30from cli import verify_within 31import cli 32import time 33 34# ----------------------------------------------------------------------------------------------------------------------- 35# Test description: 36# 37# Validate parent search on FTD child (FED/REED). 38# 39# Topology: 40# 41# The link between `r1` and `fed` is configured to be poor, ensuring 42# `fed` will search for a new parent. `r2` is configured with 43# `set_child_max(1)`, allowing only one child. `c2` is already 44# attached to `r2`, preventing `r2` from accepting `fed` as a child. 45# Later, `r3` is added to the network, and the test validates that 46# `fed` successfully switches to `r3` as its parent. 47# 48# 49# r1 ---- r2 r3 -- r1 -- r2 50# . | \ | 51# . | ==> \ | 52# fed c2 fed c2 53 54test_name = __file__[:-3] if __file__.endswith('.py') else __file__ 55print('-' * 120) 56print('Starting \'{}\''.format(test_name)) 57 58# ----------------------------------------------------------------------------------------------------------------------- 59# Creating `cli.Node` instances 60 61speedup = 40 62cli.Node.set_time_speedup_factor(speedup) 63 64fed = cli.Node() 65r1 = cli.Node() 66r2 = cli.Node() 67c2 = cli.Node() 68r3 = cli.Node() 69 70# ----------------------------------------------------------------------------------------------------------------------- 71# Test Implementation 72 73r1.set_macfilter_lqi_to_node(fed, 1) 74fed.set_macfilter_lqi_to_node(r1, 1) 75 76r1.allowlist_node(fed) 77r1.allowlist_node(r2) 78r1.allowlist_node(r3) 79 80r2.allowlist_node(fed) 81r2.allowlist_node(r1) 82r2.allowlist_node(c2) 83r2.allowlist_node(r3) 84 85c2.allowlist_node(r2) 86 87# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 88# `r2` is allowed to have one child only (`c2`) 89 90r2.set_child_max(1) 91verify(int(r2.get_child_max()) == 1) 92 93# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 94# Form the network. 95 96r1.form('fed-prnt-srch') 97fed.join(r1, cli.JOIN_TYPE_REED) 98r2.join(r1) 99c2.join(r2, cli.JOIN_TYPE_END_DEVICE) 100 101verify(r1.get_state() == 'leader') 102verify(fed.get_state() == 'child') 103verify(r2.get_state() == 'router') 104verify(c2.get_state() == 'child') 105 106# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 107# Check that `c2` is attached to `r2`. 108 109info = c2.get_parent_info() 110verify(int(info['Rloc'], 16) == int(r2.get_rloc16(), 16)) 111 112# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 113# Check that `fed` is attached to `r1` and has poor link quality. 114 115info = fed.get_parent_info() 116verify(int(info['Rloc'], 16) == int(r1.get_rloc16(), 16)) 117verify(int(info['Link Quality In']) == 1) 118verify(int(info['Link Quality Out']) == 1) 119 120verify(int(cli.Node.parse_list(fed.get_mle_counter())['Better Parent Attach Attempts']) == 0) 121 122# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 123# The `toranj` config sets `PARENT_SEARCH_CHECK_INTERVAL` to 120 seconds. 124 125time.sleep(130 / speedup) 126 127# Verify that parent search mechanism did trigger an attach attempt on 128# `fed`. 129 130verify(int(cli.Node.parse_list(fed.get_mle_counter())['Better Parent Attach Attempts']) == 1) 131 132# Since `r2` can have one child only and already has `c2`, the attach 133# attempt should fail and `fed` should still have `r1` as its 134# parent. 135 136info = fed.get_parent_info() 137verify(int(info['Rloc'], 16) == int(r1.get_rloc16(), 16)) 138 139# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 140# Ensure that `fed` does not initiate any further attach attempts, as 141# the only available parent (`r2`) should be in the "reselect timeout" 142# period. This should prevent `fed` from attempting to attach to `r2`. 143 144time.sleep(150 / speedup) 145 146verify(int(cli.Node.parse_list(fed.get_mle_counter())['Better Parent Attach Attempts']) == 1) 147 148# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 149# Add `r3` to the network and wait for `PARENT_SEARCH_CHECK_INTERVAL`. 150# This should trigger a parent search on `fed`. Validate that 151# `fed` successfully switches to `r3` as its new parent. 152 153r3.join(r1) 154verify(r3.get_state() == 'router') 155 156time.sleep(130 / speedup) 157 158counters = cli.Node.parse_list(fed.get_mle_counter()) 159verify(int(counters['Better Parent Attach Attempts']) == 2) 160verify(int(counters['Parent Changes']) == 1) 161 162info = fed.get_parent_info() 163verify(int(info['Rloc'], 16) == int(r3.get_rloc16(), 16)) 164verify(int(info['Link Quality In']) == 3) 165verify(int(info['Link Quality Out']) == 3) 166 167# ----------------------------------------------------------------------------------------------------------------------- 168# Test finished 169 170cli.Node.finalize_all_nodes() 171 172print('\'{}\' passed.'.format(test_name)) 173