1#!/usr/bin/env python3
2#
3#   Copyright 2020 - The Android Open Source Project
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17import os
18import unittest
19from unittest.mock import patch
20
21from acts.controllers.ap_lib import radvd_constants
22from acts.controllers.ap_lib.radvd import Error
23from acts.controllers.ap_lib.radvd import Radvd
24
25from acts.controllers.ap_lib.radvd_config import RadvdConfig
26
27SEARCH_FILE = ('acts.controllers.utils_lib.commands.shell.'
28               'ShellCommand.search_file')
29DELETE_FILE = ('acts.controllers.utils_lib.commands.shell.ShellCommand.'
30               'delete_file')
31
32CORRECT_COMPLEX_RADVD_CONFIG = ("""interface wlan0 {
33    IgnoreIfMissing on;
34    AdvSendAdvert off;
35    UnicastOnly on;
36    MaxRtrAdvInterval 60;
37    MinRtrAdvInterval 5;
38    MinDelayBetweenRAs 5;
39    AdvManagedFlag off;
40    AdvOtherConfigFlag on;
41    AdvLinkMTU 1400;
42    AdvReachableTime 3600000;
43    AdvRetransTimer 10;
44    AdvCurHopLimit 50;
45    AdvDefaultLifetime 8000;
46    AdvDefaultPreference off;
47    AdvSourceLLAddress on;
48    AdvHomeAgentFlag off;
49    AdvHomeAgentInfo on;
50    HomeAgentLifetime 100;
51    HomeAgentPreference 100;
52    AdvMobRtrSupportFlag off;
53    AdvIntervalOpt on;
54    prefix fd00::/64
55    {
56        AdvOnLink off;
57        AdvAutonomous on;
58        AdvRouterAddr off;
59        AdvValidLifetime 86400;
60        AdvPreferredLifetime 14400;
61        Base6to4Interface NA;
62    };
63    clients
64    {
65        fe80::c66d:3c75:2cec:1d72;
66        fe80::c66d:3c75:2cec:1d73;
67    };
68    route fd00::/64 {
69        AdvRouteLifetime 1024;
70        AdvRoutePreference high;
71    };
72    RDNSS 2401:fa00:480:7a00:4d56:5373:4549:1e29 2401:fa00:480:7a00:4d56:5373:4549:1e30 {
73        AdvRDNSSPreference 8;
74        AdvRDNSSOpen on;
75        AdvRDNSSLifetime 1025;
76    };
77};""".replace("    ", "\t"))
78
79CORRECT_SIMPLE_RADVD_CONFIG = ("""interface wlan0 {
80    AdvSendAdvert on;
81    prefix fd00::/64
82    {
83        AdvOnLink on;
84        AdvAutonomous on;
85    };
86};""".replace("    ", "\t"))
87
88
89def delete_file_mock(file_to_delete):
90    if os.path.exists(file_to_delete):
91        os.remove(file_to_delete)
92
93
94def write_configs_mock(config_file_with_path, output_config):
95    with open(config_file_with_path, 'w+') as config_fileId:
96        config_fileId.write(output_config)
97
98
99class RadvdTest(unittest.TestCase):
100    @patch('acts.controllers.utils_lib.commands.shell.ShellCommand.kill')
101    def test_radvd_ikill(self, kill):
102        kill.return_value = True
103        radvd_mock = Radvd('mock_runner', 'wlan0')
104        self.assertIsNone(radvd_mock.stop())
105
106    @patch('acts.controllers.utils_lib.commands.shell.ShellCommand.is_alive')
107    def test_radvd_is_alive_True(self, is_alive_mock):
108        is_alive_mock.return_value = True
109        radvd_mock = Radvd('mock_runner', 'wlan0')
110        self.assertTrue(radvd_mock.is_alive())
111
112    @patch('acts.controllers.utils_lib.commands.shell.ShellCommand.is_alive')
113    def test_radvd_is_alive_False(self, is_alive_mock):
114        is_alive_mock.return_value = False
115        radvd_mock = Radvd('mock_runner', 'wlan0')
116        self.assertFalse(radvd_mock.is_alive())
117
118    @patch('acts.controllers.ap_lib.radvd.Radvd._scan_for_errors')
119    @patch('acts.controllers.ap_lib.radvd.Radvd.is_alive')
120    def test_wait_for_process_process_alive(self, is_alive_mock,
121                                            _scan_for_errors_mock):
122        is_alive_mock.return_value = True
123        _scan_for_errors_mock.return_value = True
124        radvd_mock = Radvd('mock_runner', 'wlan0')
125        self.assertIsNone(radvd_mock._wait_for_process(timeout=2))
126
127    @patch('acts.controllers.ap_lib.radvd.Radvd.is_alive')
128    @patch(SEARCH_FILE)
129    def test_scan_for_errors_is_dead(self, search_file_mock, is_alive_mock):
130        is_alive_mock.return_value = False
131        search_file_mock.return_value = False
132        radvd_mock = Radvd('mock_runner', 'wlan0')
133        with self.assertRaises(Error) as context:
134            radvd_mock._scan_for_errors(True)
135        self.assertTrue('Radvd failed to start' in str(context.exception))
136
137    @patch('acts.controllers.ap_lib.radvd.Radvd.is_alive')
138    @patch(SEARCH_FILE)
139    def test_scan_for_errors_exited_prematurely(self, search_file_mock,
140                                                is_alive_mock):
141        is_alive_mock.return_value = True
142        search_file_mock.return_value = True
143        radvd_mock = Radvd('mock_runner', 'wlan0')
144        with self.assertRaises(Error) as context:
145            radvd_mock._scan_for_errors(True)
146        self.assertTrue('Radvd exited prematurely.' in str(context.exception))
147
148    @patch('acts.controllers.ap_lib.radvd.Radvd.is_alive')
149    @patch(SEARCH_FILE)
150    def test_scan_for_errors_success(self, search_file_mock, is_alive_mock):
151        is_alive_mock.return_value = True
152        search_file_mock.return_value = False
153        radvd_mock = Radvd('mock_runner', 'wlan0')
154        self.assertIsNone(radvd_mock._scan_for_errors(True))
155
156    @patch(DELETE_FILE)
157    @patch('acts.controllers.utils_lib.commands.shell.ShellCommand.write_file')
158    def test_write_configs_simple(self, write_file, delete_file):
159        delete_file.side_effect = delete_file_mock
160        write_file.side_effect = write_configs_mock
161        basic_radvd_config = RadvdConfig()
162        radvd_mock = Radvd('mock_runner', 'wlan0')
163        radvd_mock._write_configs(basic_radvd_config)
164        radvd_config = radvd_mock._config_file
165        with open(radvd_config, 'r') as radvd_config_fileId:
166            config_data = radvd_config_fileId.read()
167            self.assertTrue(CORRECT_SIMPLE_RADVD_CONFIG == config_data)
168
169    @patch(DELETE_FILE)
170    @patch('acts.controllers.utils_lib.commands.shell.ShellCommand.write_file')
171    def test_write_configs_complex(self, write_file, delete_file):
172        delete_file.side_effect = delete_file_mock
173        write_file.side_effect = write_configs_mock
174        complex_radvd_config = RadvdConfig(
175            clients=['fe80::c66d:3c75:2cec:1d72', 'fe80::c66d:3c75:2cec:1d73'],
176            route=radvd_constants.DEFAULT_PREFIX,
177            rdnss=[
178                '2401:fa00:480:7a00:4d56:5373:4549:1e29',
179                '2401:fa00:480:7a00:4d56:5373:4549:1e30',
180            ],
181            ignore_if_missing=radvd_constants.IGNORE_IF_MISSING_ON,
182            adv_send_advert=radvd_constants.ADV_SEND_ADVERT_OFF,
183            unicast_only=radvd_constants.UNICAST_ONLY_ON,
184            max_rtr_adv_interval=60,
185            min_rtr_adv_interval=5,
186            min_delay_between_ras=5,
187            adv_managed_flag=radvd_constants.ADV_MANAGED_FLAG_OFF,
188            adv_other_config_flag=radvd_constants.ADV_OTHER_CONFIG_FLAG_ON,
189            adv_link_mtu=1400,
190            adv_reachable_time=3600000,
191            adv_retrans_timer=10,
192            adv_cur_hop_limit=50,
193            adv_default_lifetime=8000,
194            adv_default_preference=radvd_constants.ADV_DEFAULT_PREFERENCE_OFF,
195            adv_source_ll_address=radvd_constants.ADV_SOURCE_LL_ADDRESS_ON,
196            adv_home_agent_flag=radvd_constants.ADV_HOME_AGENT_FLAG_OFF,
197            adv_home_agent_info=radvd_constants.ADV_HOME_AGENT_INFO_ON,
198            home_agent_lifetime=100,
199            home_agent_preference=100,
200            adv_mob_rtr_support_flag=radvd_constants.
201            ADV_MOB_RTR_SUPPORT_FLAG_OFF,
202            adv_interval_opt=radvd_constants.ADV_INTERVAL_OPT_ON,
203            adv_on_link=radvd_constants.ADV_ON_LINK_OFF,
204            adv_autonomous=radvd_constants.ADV_AUTONOMOUS_ON,
205            adv_router_addr=radvd_constants.ADV_ROUTER_ADDR_OFF,
206            adv_valid_lifetime=86400,
207            adv_preferred_lifetime=14400,
208            base_6to4_interface='NA',
209            adv_route_lifetime=1024,
210            adv_route_preference=radvd_constants.ADV_ROUTE_PREFERENCE_HIGH,
211            adv_rdnss_preference=8,
212            adv_rdnss_open=radvd_constants.ADV_RDNSS_OPEN_ON,
213            adv_rdnss_lifetime=1025)
214        radvd_mock = Radvd('mock_runner', 'wlan0')
215        radvd_mock._write_configs(complex_radvd_config)
216        radvd_config = radvd_mock._config_file
217        with open(radvd_config, 'r') as radvd_config_fileId:
218            config_data = radvd_config_fileId.read()
219            self.assertTrue(CORRECT_COMPLEX_RADVD_CONFIG == config_data)
220
221
222if __name__ == '__main__':
223    unittest.main()
224