• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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