1#!/usr/bin/env python3 2# 3# Copyright 2016 - 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 logging 18import time 19import unittest 20 21import mock 22 23from acts import utils 24from acts import signals 25from acts.controllers.adb_lib.error import AdbError 26from acts.controllers.android_device import AndroidDevice 27from acts.controllers.fuchsia_device import FuchsiaDevice 28from acts.controllers.utils_lib.ssh.connection import SshConnection 29from acts.libs.proc import job 30 31PROVISIONED_STATE_GOOD = 1 32 33MOCK_IP_ADDRESSES = """eno1 100.127.110.79 34eno1 2401:fa00:480:7a00:8d4f:85ff:cc5c:787e 35eno1 2401:fa00:480:7a00:459:b993:fcbf:1419 36eno1 fe80::c66d:3c75:2cec:1d72 37enx00e04c000d06 192.168.42.220 38enx00e04c000d06 fe80::2c68:f1b7:eaaa:52e7""" 39 40MOCK_IFCONFIG_OUTPUT = """eno1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 41 inet 100.127.110.79 netmask 255.255.255.0 broadcast 100.127.110.255 42 inet6 2401:fa00:480:7a00:8d4f:85ff:cc5c:787e prefixlen 64 scopeid 0x0<global> 43 inet6 fe80::c66d:3c75:2cec:1d72 prefixlen 64 scopeid 0x20<link> 44 inet6 2401:fa00:480:7a00:459:b993:fcbf:1419 prefixlen 64 scopeid 0x0<global> 45 ether 54:b2:03:13:36:05 txqueuelen 1000 (Ethernet) 46 RX packets 32943262 bytes 13324306863 (13.3 GB) 47 RX errors 669 dropped 0 overruns 0 frame 669 48 TX packets 4778580 bytes 3012041798 (3.0 GB) 49 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 50 device interrupt 16 memory 0xdf200000-df220000 51 52enx00e04c000d06: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 53 inet 192.168.42.220 netmask 255.255.255.0 broadcast 192.168.42.255 54 inet6 fe80::2c68:f1b7:eaaa:52e7 prefixlen 64 scopeid 0x20<link> 55 ether 00:e0:4c:00:0d:06 txqueuelen 1000 (Ethernet) 56 RX packets 10212416 bytes 3204008175 (3.2 GB) 57 RX errors 0 dropped 0 overruns 0 frame 0 58 TX packets 9868425 bytes 5641667955 (5.6 GB) 59 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 60 61lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 62 inet 127.0.0.1 netmask 255.0.0.0 63 inet6 ::1 prefixlen 128 scopeid 0x10<host> 64 loop txqueuelen 1000 (Local Loopback) 65 RX packets 42779835 bytes 6144028882 (6.1 GB) 66 RX errors 0 dropped 0 overruns 0 frame 0 67 TX packets 42779835 bytes 6144028882 (6.1 GB) 68 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 69 70""" 71 72FUCHSIA_INTERFACES = { 73 'id': 74 '1', 75 'result': [{ 76 'features': 77 4, 78 'filepath': 79 '[none]', 80 'id': 81 1, 82 'ipv4_addresses': [[127, 0, 0, 1]], 83 'ipv6_addresses': [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]], 84 'is_administrative_status_enabled': 85 True, 86 'is_physical_status_up': 87 True, 88 'mac': [0, 0, 0, 0, 0, 0], 89 'mtu': 90 65536, 91 'name': 92 'lo', 93 'topopath': 94 'loopback' 95 }, { 96 'features': 97 0, 98 'filepath': 99 '/dev/class/ethernet/000', 100 'id': 101 2, 102 'ipv4_addresses': [[100, 127, 110, 79]], 103 'ipv6_addresses': 104 [[254, 128, 0, 0, 0, 0, 0, 0, 198, 109, 60, 117, 44, 236, 29, 114], 105 [36, 1, 250, 0, 4, 128, 122, 0, 141, 79, 133, 255, 204, 92, 120, 126], 106 [36, 1, 250, 0, 4, 128, 122, 0, 4, 89, 185, 147, 252, 191, 20, 25]], 107 'is_administrative_status_enabled': 108 True, 109 'is_physical_status_up': 110 True, 111 'mac': [0, 224, 76, 5, 76, 229], 112 'mtu': 113 1514, 114 'name': 115 'eno1', 116 'topopath': 117 '@/dev/xhci/xhci/usb-bus/001/001/ifc-000/usb-cdc-ecm/ethernet' 118 }, { 119 'features': 120 1, 121 'filepath': 122 '/dev/class/ethernet/001', 123 'id': 124 3, 125 'ipv4_addresses': [], 126 'ipv6_addresses': 127 [[254, 128, 0, 0, 0, 0, 0, 0, 96, 255, 93, 96, 52, 253, 253, 243], 128 [254, 128, 0, 0, 0, 0, 0, 0, 70, 7, 11, 255, 254, 118, 126, 192]], 129 'is_administrative_status_enabled': 130 False, 131 'is_physical_status_up': 132 False, 133 'mac': [68, 7, 11, 118, 126, 192], 134 'mtu': 135 1500, 136 'name': 137 'wlanxc0', 138 'topopath': 139 '@/dev/wifi/wlanphy/wlanif-client/wlan-ethernet/ethernet' 140 }], 141 'error': 142 None 143} 144 145CORRECT_FULL_IP_LIST = { 146 'ipv4_private': [], 147 'ipv4_public': ['100.127.110.79'], 148 'ipv6_link_local': ['fe80::c66d:3c75:2cec:1d72'], 149 'ipv6_private_local': [], 150 'ipv6_public': [ 151 '2401:fa00:480:7a00:8d4f:85ff:cc5c:787e', 152 '2401:fa00:480:7a00:459:b993:fcbf:1419' 153 ] 154} 155 156CORRECT_EMPTY_IP_LIST = { 157 'ipv4_private': [], 158 'ipv4_public': [], 159 'ipv6_link_local': [], 160 'ipv6_private_local': [], 161 'ipv6_public': [] 162} 163 164FUCHSIA_INIT_SERVER = ('acts.controllers.fuchsia_device.FuchsiaDevice.' 165 'init_server_connection') 166FUCHSIA_SET_CONTROL_PATH_CONFIG = ('acts.controllers.fuchsia_device.' 167 'FuchsiaDevice._set_control_path_config') 168FUCHSIA_START_SERVICES = ('acts.controllers.fuchsia_device.FuchsiaDevice.' 169 'start_services') 170FUCHSIA_NETSTACK_LIST_INTERFACES = ( 171 'acts.controllers.' 172 'fuchsia_lib.netstack.netstack_lib.' 173 'FuchsiaNetstackLib.netstackListInterfaces') 174FUCHSIA_INIT_NETSTACK = ('acts.controllers.fuchsia_lib.netstack.' 175 'netstack_lib.FuchsiaNetstackLib.init') 176 177 178class ByPassSetupWizardTests(unittest.TestCase): 179 """This test class for unit testing acts.utils.bypass_setup_wizard.""" 180 def test_start_standing_subproc(self): 181 with self.assertRaisesRegex(utils.ActsUtilsError, 182 'Process .* has terminated'): 183 utils.start_standing_subprocess('sleep 0', check_health_delay=0.1) 184 185 def test_stop_standing_subproc(self): 186 p = utils.start_standing_subprocess('sleep 0') 187 time.sleep(0.1) 188 with self.assertRaisesRegex(utils.ActsUtilsError, 189 'Process .* has terminated'): 190 utils.stop_standing_subprocess(p) 191 192 @mock.patch('time.sleep') 193 def test_bypass_setup_wizard_no_complications(self, _): 194 ad = mock.Mock() 195 ad.adb.shell.side_effect = [ 196 # Return value for SetupWizardExitActivity 197 BypassSetupWizardReturn.NO_COMPLICATIONS, 198 # Return value for device_provisioned 199 PROVISIONED_STATE_GOOD, 200 ] 201 ad.adb.return_state = BypassSetupWizardReturn.NO_COMPLICATIONS 202 self.assertTrue(utils.bypass_setup_wizard(ad)) 203 self.assertFalse( 204 ad.adb.root_adb.called, 205 'The root command should not be called if there are no ' 206 'complications.') 207 208 @mock.patch('time.sleep') 209 def test_bypass_setup_wizard_unrecognized_error(self, _): 210 ad = mock.Mock() 211 ad.adb.shell.side_effect = [ 212 # Return value for SetupWizardExitActivity 213 BypassSetupWizardReturn.UNRECOGNIZED_ERR, 214 # Return value for device_provisioned 215 PROVISIONED_STATE_GOOD, 216 ] 217 with self.assertRaises(AdbError): 218 utils.bypass_setup_wizard(ad) 219 self.assertFalse( 220 ad.adb.root_adb.called, 221 'The root command should not be called if we do not have a ' 222 'codepath for recovering from the failure.') 223 224 @mock.patch('time.sleep') 225 def test_bypass_setup_wizard_need_root_access(self, _): 226 ad = mock.Mock() 227 ad.adb.shell.side_effect = [ 228 # Return value for SetupWizardExitActivity 229 BypassSetupWizardReturn.ROOT_ADB_NO_COMP, 230 # Return value for rooting the device 231 BypassSetupWizardReturn.NO_COMPLICATIONS, 232 # Return value for device_provisioned 233 PROVISIONED_STATE_GOOD 234 ] 235 236 utils.bypass_setup_wizard(ad) 237 238 self.assertTrue( 239 ad.adb.root_adb_called, 240 'The command required root access, but the device was never ' 241 'rooted.') 242 243 @mock.patch('time.sleep') 244 def test_bypass_setup_wizard_need_root_already_skipped(self, _): 245 ad = mock.Mock() 246 ad.adb.shell.side_effect = [ 247 # Return value for SetupWizardExitActivity 248 BypassSetupWizardReturn.ROOT_ADB_SKIPPED, 249 # Return value for SetupWizardExitActivity after root 250 BypassSetupWizardReturn.ALREADY_BYPASSED, 251 # Return value for device_provisioned 252 PROVISIONED_STATE_GOOD 253 ] 254 self.assertTrue(utils.bypass_setup_wizard(ad)) 255 self.assertTrue(ad.adb.root_adb_called) 256 257 @mock.patch('time.sleep') 258 def test_bypass_setup_wizard_root_access_still_fails(self, _): 259 ad = mock.Mock() 260 ad.adb.shell.side_effect = [ 261 # Return value for SetupWizardExitActivity 262 BypassSetupWizardReturn.ROOT_ADB_FAILS, 263 # Return value for SetupWizardExitActivity after root 264 BypassSetupWizardReturn.UNRECOGNIZED_ERR, 265 # Return value for device_provisioned 266 PROVISIONED_STATE_GOOD 267 ] 268 269 with self.assertRaises(AdbError): 270 utils.bypass_setup_wizard(ad) 271 self.assertTrue(ad.adb.root_adb_called) 272 273 274class BypassSetupWizardReturn: 275 # No complications. Bypass works the first time without issues. 276 NO_COMPLICATIONS = ( 277 'Starting: Intent { cmp=com.google.android.setupwizard/' 278 '.SetupWizardExitActivity }') 279 280 # Fail with doesn't need to be skipped/was skipped already. 281 ALREADY_BYPASSED = AdbError('', 'ADB_CMD_OUTPUT:0', 'Error type 3\n' 282 'Error: Activity class', 1) 283 # Fail with different error. 284 UNRECOGNIZED_ERR = AdbError('', 'ADB_CMD_OUTPUT:0', 'Error type 4\n' 285 'Error: Activity class', 0) 286 # Fail, get root access, then no complications arise. 287 ROOT_ADB_NO_COMP = AdbError( 288 '', 'ADB_CMD_OUTPUT:255', 'Security exception: Permission Denial: ' 289 'starting Intent { flg=0x10000000 ' 290 'cmp=com.google.android.setupwizard/' 291 '.SetupWizardExitActivity } from null ' 292 '(pid=5045, uid=2000) not exported from uid ' 293 '10000', 0) 294 # Even with root access, the bypass setup wizard doesn't need to be skipped. 295 ROOT_ADB_SKIPPED = AdbError( 296 '', 'ADB_CMD_OUTPUT:255', 'Security exception: Permission Denial: ' 297 'starting Intent { flg=0x10000000 ' 298 'cmp=com.google.android.setupwizard/' 299 '.SetupWizardExitActivity } from null ' 300 '(pid=5045, uid=2000) not exported from ' 301 'uid 10000', 0) 302 # Even with root access, the bypass setup wizard fails 303 ROOT_ADB_FAILS = AdbError( 304 '', 'ADB_CMD_OUTPUT:255', 305 'Security exception: Permission Denial: starting Intent { ' 306 'flg=0x10000000 cmp=com.google.android.setupwizard/' 307 '.SetupWizardExitActivity } from null (pid=5045, uid=2000) not ' 308 'exported from uid 10000', 0) 309 310 311class ConcurrentActionsTest(unittest.TestCase): 312 """Tests acts.utils.run_concurrent_actions and related functions.""" 313 @staticmethod 314 def function_returns_passed_in_arg(arg): 315 return arg 316 317 @staticmethod 318 def function_raises_passed_in_exception_type(exception_type): 319 raise exception_type 320 321 def test_run_concurrent_actions_no_raise_returns_proper_return_values( 322 self): 323 """Tests run_concurrent_actions_no_raise returns in the correct order. 324 325 Each function passed into run_concurrent_actions_no_raise returns the 326 values returned from each individual callable in the order passed in. 327 """ 328 ret_values = utils.run_concurrent_actions_no_raise( 329 lambda: self.function_returns_passed_in_arg('ARG1'), 330 lambda: self.function_returns_passed_in_arg('ARG2'), 331 lambda: self.function_returns_passed_in_arg('ARG3')) 332 333 self.assertEqual(len(ret_values), 3) 334 self.assertEqual(ret_values[0], 'ARG1') 335 self.assertEqual(ret_values[1], 'ARG2') 336 self.assertEqual(ret_values[2], 'ARG3') 337 338 def test_run_concurrent_actions_no_raise_returns_raised_exceptions(self): 339 """Tests run_concurrent_actions_no_raise returns raised exceptions. 340 341 Instead of allowing raised exceptions to be raised in the main thread, 342 this function should capture the exception and return them in the slot 343 the return value should have been returned in. 344 """ 345 ret_values = utils.run_concurrent_actions_no_raise( 346 lambda: self.function_raises_passed_in_exception_type(IndexError), 347 lambda: self.function_raises_passed_in_exception_type(KeyError)) 348 349 self.assertEqual(len(ret_values), 2) 350 self.assertEqual(ret_values[0].__class__, IndexError) 351 self.assertEqual(ret_values[1].__class__, KeyError) 352 353 def test_run_concurrent_actions_returns_proper_return_values(self): 354 """Tests run_concurrent_actions returns in the correct order. 355 356 Each function passed into run_concurrent_actions returns the values 357 returned from each individual callable in the order passed in. 358 """ 359 360 ret_values = utils.run_concurrent_actions( 361 lambda: self.function_returns_passed_in_arg('ARG1'), 362 lambda: self.function_returns_passed_in_arg('ARG2'), 363 lambda: self.function_returns_passed_in_arg('ARG3')) 364 365 self.assertEqual(len(ret_values), 3) 366 self.assertEqual(ret_values[0], 'ARG1') 367 self.assertEqual(ret_values[1], 'ARG2') 368 self.assertEqual(ret_values[2], 'ARG3') 369 370 def test_run_concurrent_actions_raises_exceptions(self): 371 """Tests run_concurrent_actions raises exceptions from given actions.""" 372 with self.assertRaises(KeyError): 373 utils.run_concurrent_actions( 374 lambda: self.function_returns_passed_in_arg('ARG1'), lambda: 375 self.function_raises_passed_in_exception_type(KeyError)) 376 377 def test_test_concurrent_actions_raises_non_test_failure(self): 378 """Tests test_concurrent_actions raises the given exception.""" 379 with self.assertRaises(KeyError): 380 utils.test_concurrent_actions( 381 lambda: self.function_raises_passed_in_exception_type(KeyError 382 ), 383 failure_exceptions=signals.TestFailure) 384 385 def test_test_concurrent_actions_raises_test_failure(self): 386 """Tests test_concurrent_actions raises the given exception.""" 387 with self.assertRaises(signals.TestFailure): 388 utils.test_concurrent_actions( 389 lambda: self.function_raises_passed_in_exception_type(KeyError 390 ), 391 failure_exceptions=KeyError) 392 393 394class SuppressLogOutputTest(unittest.TestCase): 395 """Tests SuppressLogOutput""" 396 def test_suppress_log_output(self): 397 """Tests that the SuppressLogOutput context manager removes handlers 398 of the specified levels upon entry and re-adds handlers upon exit. 399 """ 400 handlers = [ 401 logging.NullHandler(level=lvl) 402 for lvl in (logging.DEBUG, logging.INFO, logging.ERROR) 403 ] 404 log = logging.getLogger('test_log') 405 for handler in handlers: 406 log.addHandler(handler) 407 with utils.SuppressLogOutput(log, [logging.INFO, logging.ERROR]): 408 self.assertTrue( 409 any(handler.level == logging.DEBUG 410 for handler in log.handlers)) 411 self.assertFalse( 412 any(handler.level in (logging.INFO, logging.ERROR) 413 for handler in log.handlers)) 414 self.assertCountEqual(handlers, log.handlers) 415 416 417class IpAddressUtilTest(unittest.TestCase): 418 def test_positive_ipv4_normal_address(self): 419 ip_address = "192.168.1.123" 420 self.assertTrue(utils.is_valid_ipv4_address(ip_address)) 421 422 def test_positive_ipv4_any_address(self): 423 ip_address = "0.0.0.0" 424 self.assertTrue(utils.is_valid_ipv4_address(ip_address)) 425 426 def test_positive_ipv4_broadcast(self): 427 ip_address = "255.255.255.0" 428 self.assertTrue(utils.is_valid_ipv4_address(ip_address)) 429 430 def test_negative_ipv4_with_ipv6_address(self): 431 ip_address = "fe80::f693:9fff:fef4:1ac" 432 self.assertFalse(utils.is_valid_ipv4_address(ip_address)) 433 434 def test_negative_ipv4_with_invalid_string(self): 435 ip_address = "fdsafdsafdsafdsf" 436 self.assertFalse(utils.is_valid_ipv4_address(ip_address)) 437 438 def test_negative_ipv4_with_invalid_number(self): 439 ip_address = "192.168.500.123" 440 self.assertFalse(utils.is_valid_ipv4_address(ip_address)) 441 442 def test_positive_ipv6(self): 443 ip_address = 'fe80::f693:9fff:fef4:1ac' 444 self.assertTrue(utils.is_valid_ipv6_address(ip_address)) 445 446 def test_positive_ipv6_link_local(self): 447 ip_address = 'fe80::' 448 self.assertTrue(utils.is_valid_ipv6_address(ip_address)) 449 450 def test_negative_ipv6_with_ipv4_address(self): 451 ip_address = '192.168.1.123' 452 self.assertFalse(utils.is_valid_ipv6_address(ip_address)) 453 454 def test_negative_ipv6_invalid_characters(self): 455 ip_address = 'fe80:jkyr:f693:9fff:fef4:1ac' 456 self.assertFalse(utils.is_valid_ipv6_address(ip_address)) 457 458 def test_negative_ipv6_invalid_string(self): 459 ip_address = 'fdsafdsafdsafdsf' 460 self.assertFalse(utils.is_valid_ipv6_address(ip_address)) 461 462 @mock.patch('acts.libs.proc.job.run') 463 def test_local_get_interface_ip_addresses_full(self, job_mock): 464 job_mock.side_effect = [ 465 job.Result(stdout=bytes(MOCK_IP_ADDRESSES, 'utf-8'), 466 encoding='utf-8'), 467 job.Result(stdout=bytes(MOCK_IFCONFIG_OUTPUT, 'utf-8'), 468 encoding='utf-8') 469 ] 470 self.assertEqual(utils.get_interface_ip_addresses(job, 'eno1'), 471 CORRECT_FULL_IP_LIST) 472 473 @mock.patch('acts.libs.proc.job.run') 474 def test_local_get_interface_ip_addresses_empty(self, job_mock): 475 job_mock.side_effect = [ 476 job.Result(stdout=bytes(MOCK_IP_ADDRESSES, 'utf-8'), 477 encoding='utf-8'), 478 job.Result(stdout=bytes(MOCK_IFCONFIG_OUTPUT, 'utf-8'), 479 encoding='utf-8') 480 ] 481 self.assertEqual(utils.get_interface_ip_addresses(job, 'wlan1'), 482 CORRECT_EMPTY_IP_LIST) 483 484 @mock.patch('acts.controllers.utils_lib.ssh.connection.SshConnection.run') 485 def test_ssh_get_interface_ip_addresses_full(self, ssh_mock): 486 ssh_mock.side_effect = [ 487 job.Result(stdout=bytes(MOCK_IP_ADDRESSES, 'utf-8'), 488 encoding='utf-8'), 489 job.Result(stdout=bytes(MOCK_IFCONFIG_OUTPUT, 'utf-8'), 490 encoding='utf-8') 491 ] 492 self.assertEqual( 493 utils.get_interface_ip_addresses(SshConnection('mock_settings'), 494 'eno1'), CORRECT_FULL_IP_LIST) 495 496 @mock.patch('acts.controllers.utils_lib.ssh.connection.SshConnection.run') 497 def test_ssh_get_interface_ip_addresses_empty(self, ssh_mock): 498 ssh_mock.side_effect = [ 499 job.Result(stdout=bytes(MOCK_IP_ADDRESSES, 'utf-8'), 500 encoding='utf-8'), 501 job.Result(stdout=bytes(MOCK_IFCONFIG_OUTPUT, 'utf-8'), 502 encoding='utf-8') 503 ] 504 self.assertEqual( 505 utils.get_interface_ip_addresses(SshConnection('mock_settings'), 506 'wlan1'), CORRECT_EMPTY_IP_LIST) 507 508 @mock.patch('acts.controllers.adb.AdbProxy') 509 @mock.patch.object(AndroidDevice, 'is_bootloader', return_value=True) 510 def test_android_get_interface_ip_addresses_full(self, is_bootloader, 511 adb_mock): 512 adb_mock().shell.side_effect = [ 513 MOCK_IP_ADDRESSES, MOCK_IFCONFIG_OUTPUT 514 ] 515 self.assertEqual( 516 utils.get_interface_ip_addresses(AndroidDevice(), 'eno1'), 517 CORRECT_FULL_IP_LIST) 518 519 @mock.patch('acts.controllers.adb.AdbProxy') 520 @mock.patch.object(AndroidDevice, 'is_bootloader', return_value=True) 521 def test_android_get_interface_ip_addresses_empty(self, is_bootloader, 522 adb_mock): 523 adb_mock().shell.side_effect = [ 524 MOCK_IP_ADDRESSES, MOCK_IFCONFIG_OUTPUT 525 ] 526 self.assertEqual( 527 utils.get_interface_ip_addresses(AndroidDevice(), 'wlan1'), 528 CORRECT_EMPTY_IP_LIST) 529 530 @mock.patch(FUCHSIA_INIT_SERVER) 531 @mock.patch(FUCHSIA_SET_CONTROL_PATH_CONFIG) 532 @mock.patch(FUCHSIA_START_SERVICES) 533 @mock.patch(FUCHSIA_NETSTACK_LIST_INTERFACES) 534 @mock.patch(FUCHSIA_INIT_NETSTACK) 535 def test_fuchsia_get_interface_ip_addresses_full(self, init_mock, 536 list_interfaces_mock, 537 start_services_mock, 538 control_path_mock, 539 fuchsia_device_mock): 540 init_mock.return_value = None 541 list_interfaces_mock.return_value = FUCHSIA_INTERFACES 542 fuchsia_device_mock.return_value = None 543 self.assertEqual( 544 utils.get_interface_ip_addresses( 545 FuchsiaDevice({'ip': '192.168.1.1'}), 'eno1'), 546 CORRECT_FULL_IP_LIST) 547 548 @mock.patch(FUCHSIA_INIT_SERVER) 549 @mock.patch(FUCHSIA_SET_CONTROL_PATH_CONFIG) 550 @mock.patch(FUCHSIA_START_SERVICES) 551 @mock.patch(FUCHSIA_NETSTACK_LIST_INTERFACES) 552 @mock.patch(FUCHSIA_INIT_NETSTACK) 553 def test_fuchsia_get_interface_ip_addresses_empty(self, init_mock, 554 list_interfaces_mock, 555 start_services_mock, 556 control_path_mock, 557 fuchsia_device_mock): 558 init_mock.return_value = None 559 list_interfaces_mock.return_value = FUCHSIA_INTERFACES 560 fuchsia_device_mock.return_value = None 561 self.assertEqual( 562 utils.get_interface_ip_addresses( 563 FuchsiaDevice({'ip': '192.168.1.1'}), 'wlan1'), 564 CORRECT_EMPTY_IP_LIST) 565 566 567if __name__ == '__main__': 568 unittest.main() 569