xref: /aosp_15_r20/external/openthread/tests/toranj/cli/test-024-mle-adv-imax-change.py (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1#!/usr/bin/env python3
2#
3#  Copyright (c) 2023, 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 changes to `IntervalMax` for MLE Advertisement Trickle Timer based on number of
38# router neighbors of the device.
39#
40
41test_name = __file__[:-3] if __file__.endswith('.py') else __file__
42print('-' * 120)
43print('Starting \'{}\''.format(test_name))
44
45# -----------------------------------------------------------------------------------------------------------------------
46# Creating `cli.Node` instances
47
48speedup = 20
49cli.Node.set_time_speedup_factor(speedup)
50
51leader = cli.Node()
52routers = []
53for num in range(0, 9):
54    routers.append(cli.Node())
55
56# -----------------------------------------------------------------------------------------------------------------------
57# Test Implementation
58
59leader.form('mle-adv-imax')
60
61verify(leader.get_state() == 'leader')
62
63# The Imax is determined as `Clamp((n + 1) * 4, 12, 32)` with `n` as
64# number of router neighbors with link quality 2 or higher
65
66verify(int(leader.get_mle_adv_imax()) == 12000)
67
68expected_neighbor_count = 0
69
70
71def check_leader_has_expected_number_of_neighbors():
72    verify(len(leader.get_neighbor_table()) == expected_neighbor_count)
73
74
75# Add two routers one by one and check that Imax
76# remains at 12 seconds.
77
78for num in range(0, 2):
79    r = routers[num]
80
81    r.join(leader)
82    verify(r.get_state() == 'router')
83
84    expected_neighbor_count += 1
85    verify_within(check_leader_has_expected_number_of_neighbors, 10)
86
87    verify(int(leader.get_mle_adv_imax()) == 12000)
88
89# Adding the third router, we should see Imax increasing
90# to 16 seconds.
91
92r = routers[2]
93r.join(leader)
94verify(r.get_state() == 'router')
95
96expected_neighbor_count += 1
97verify_within(check_leader_has_expected_number_of_neighbors, 10)
98
99verify(int(leader.get_mle_adv_imax()) == 16000)
100
101# Adding a neighbor with poor link quality which should not
102# count.
103
104r_poor_lqi = routers[3]
105leader.set_macfilter_lqi_to_node(r_poor_lqi, 1)
106
107r_poor_lqi.join(leader)
108verify(r_poor_lqi.get_state() == 'router')
109
110expected_neighbor_count += 1
111verify_within(check_leader_has_expected_number_of_neighbors, 10)
112verify(int(leader.get_mle_adv_imax()) == 16000)
113
114expected_imax = 16000
115
116# Add four new routers one by one and check that Imax is
117# increased by 4 second for each new router neighbor up to
118# 32 seconds.
119
120for num in range(4, 8):
121    r = routers[num]
122
123    r.join(leader)
124    verify(r.get_state() == 'router')
125
126    expected_neighbor_count += 1
127    verify_within(check_leader_has_expected_number_of_neighbors, 10)
128    expected_imax += 4000
129    verify(int(leader.get_mle_adv_imax()) == expected_imax)
130
131# Check that Imax does not increase beyond 32 seconds.
132
133r = routers[8]
134
135r.join(leader)
136verify(r.get_state() == 'router')
137
138expected_neighbor_count += 1
139verify_within(check_leader_has_expected_number_of_neighbors, 10)
140
141verify(int(leader.get_mle_adv_imax()) == 32000)
142
143# Check that all routers see each other as neighbor and they are all also
144# using 32 seconds as Imax.
145
146
147def check_all_routers_have_expected_number_of_neighbors():
148    for r in routers:
149        verify(len(r.get_neighbor_table()) == expected_neighbor_count)
150
151
152verify_within(check_all_routers_have_expected_number_of_neighbors, 10)
153
154for r in routers:
155    verify(int(r.get_mle_adv_imax()) == 32000)
156
157# -----------------------------------------------------------------------------------------------------------------------
158# Test finished
159
160cli.Node.finalize_all_nodes()
161
162print('\'{}\' passed.'.format(test_name))
163