• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 itertools
18import os
19import time
20
21from multiprocessing import Process
22
23from acts import asserts
24from acts import context
25from acts import utils
26from acts.controllers import iperf_client
27from acts.controllers import iperf_server
28from acts.controllers import pdu
29from acts.controllers.access_point import setup_ap
30from acts.controllers.ap_lib import hostapd_constants
31from acts.controllers.ap_lib.hostapd_security import Security
32from acts.controllers.ap_lib.hostapd_utils import generate_random_password
33from acts.controllers.ap_lib.radvd import Radvd
34from acts.controllers.ap_lib import radvd_constants
35from acts.controllers.ap_lib.radvd_config import RadvdConfig
36from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device
37from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
38
39# Constants, for readibility
40AP = 'ap'
41DUT = 'dut'
42SOFT = 'soft'
43HARD = 'hard'
44BAND_2G = '2g'
45BAND_5G = '5g'
46BANDS = [BAND_2G, BAND_5G]
47IPV4 = 'ipv4'
48IPV6 = 'ipv6'
49DUAL_IPV4_IPV6 = {IPV4: True, IPV6: True}
50IPV4_ONLY = {IPV4: True, IPV6: False}
51IPV6_ONLY = {IPV4: False, IPV6: True}
52INTERRUPTS = [True, False]
53DEFAULT_IPERF_TIMEOUT = 30
54
55DUT_NETWORK_CONNECTION_TIMEOUT = 60
56DUT_IP_ADDRESS_TIMEOUT = 15
57
58# Constants for Custom Reboot Tests
59ALL = 'all'
60BOTH = 'both'
61
62CUSTOM_TEST_REBOOT_DEVICES = {AP: [AP], DUT: [DUT], ALL: [AP, DUT]}
63CUSTOM_TEST_REBOOT_TYPES = {SOFT: [SOFT], HARD: [HARD], ALL: [SOFT, HARD]}
64CUSTOM_TEST_BANDS = {
65    BAND_2G: [BAND_2G],
66    BAND_5G: [BAND_5G],
67    ALL: [BAND_2G, BAND_5G]
68}
69CUSTOM_TEST_IP_VERSIONS = {
70    IPV4: [IPV4_ONLY],
71    IPV6: [IPV6_ONLY],
72    BOTH: [DUAL_IPV4_IPV6],
73    ALL: [IPV4_ONLY, IPV6_ONLY, DUAL_IPV4_IPV6]
74}
75CUSTOM_TEST_INTERRUPTS = {'true': [True], 'false': [False], ALL: [True, False]}
76
77
78def create_custom_test_name(reboot_device, reboot_type, band, ip_version,
79                            interrupt, iterations):
80    """Creates custom base test name, from custom test parameters"""
81    return ('test_custom_reboot_device_%s_type_%s_band_%s_ip_version_%s%s_with'
82            '_%s_iterations_each' %
83            (reboot_device, reboot_type, band, ip_version,
84             '_interrupt' if interrupt else '', iterations))
85
86
87def create_custom_subtest_name(settings):
88    """Creates custom subtest name, from subtest parameters."""
89    ipv4_str = '_ipv4' if settings[IPV4] else ''
90    ipv6_str = '_ipv6' if settings[IPV6] else ''
91    return 'test_custom_%s_reboot_%s_band_%s%s%s%s%s_with_%s_iterations' % (
92        settings['reboot_type'], settings['reboot_device'], settings['band'],
93        ipv4_str, ipv6_str, '_interrupt' if settings['interrupt'] else '',
94        '_%s' % settings['security_mode'] if settings['security_mode'] else '',
95        settings['iterations'])
96
97
98def get_test_name(settings):
99    """Returns test_name from custom generated subtest settings."""
100    return settings['test_name']
101
102
103class WlanRebootTest(WifiBaseTest):
104    """Tests wlan reconnects in different reboot scenarios.
105
106    Testbed Requirement:
107    * One ACTS compatible device (dut)
108    * One Whirlwind Access Point (will also serve as iperf server)
109    * One PduDevice
110    """
111    def __init__(self, controllers):
112        WifiBaseTest.__init__(self, controllers)
113
114    def setup_class(self):
115        super().setup_class()
116        self.android_devices = getattr(self, 'android_devices', [])
117        self.fuchsia_devices = getattr(self, 'fuchsia_devices', [])
118
119        if 'dut' in self.user_params:
120            if self.user_params['dut'] == 'fuchsia_devices':
121                self.dut = create_wlan_device(self.fuchsia_devices[0])
122            elif self.user_params['dut'] == 'android_devices':
123                self.dut = create_wlan_device(self.android_devices[0])
124            else:
125                raise ValueError('Invalid DUT specified in config. (%s)' %
126                                 self.user_params['dut'])
127        else:
128            # Default is an android device, just like the other tests
129            self.dut = create_wlan_device(self.android_devices[0])
130
131        self.access_point = self.access_points[0]
132
133        # Times (in seconds) to wait for DUT network connection and assigning an
134        # ip address to the wlan interface.
135        self.wlan_reboot_test_params = self.user_params.get(
136            'wlan_reboot_test_params', {})
137        self.dut_network_connection_timeout = self.wlan_reboot_test_params.get(
138            'dut_network_connection_timeout', DUT_NETWORK_CONNECTION_TIMEOUT)
139        self.dut_ip_address_timeout = self.wlan_reboot_test_params.get(
140            'dut_ip_address_timeout', DUT_IP_ADDRESS_TIMEOUT)
141        self.skip_iperf = self.wlan_reboot_test_params.get('skip_iperf', False)
142
143        self.iperf_server_on_ap = None
144        self.iperf_client_on_dut = None
145        if not self.skip_iperf:
146            try:
147                self.iperf_client_on_dut = self.iperf_clients[0]
148            except AttributeError:
149                self.iperf_client_on_dut = self.dut.create_iperf_client()
150        else:
151            self.log.info(
152                'Skipping iperf throughput validation as requested by ACTS '
153                'config')
154
155        self.router_adv_daemon = None
156
157    def setup_test(self):
158        self.access_point.stop_all_aps()
159        if self.router_adv_daemon:
160            self.router_adv_daemon.stop()
161        self.dut.wifi_toggle_state(True)
162        for ad in self.android_devices:
163            ad.droid.wakeLockAcquireBright()
164            ad.droid.wakeUpNow()
165        self.dut.disconnect()
166        self.router_adv_daemon = None
167        self.ssid = utils.rand_ascii_str(hostapd_constants.AP_SSID_LENGTH_2G)
168
169    def teardown_test(self):
170        self.access_point.stop_all_aps()
171        if self.router_adv_daemon:
172            self.router_adv_daemon.stop()
173            self.router_adv_daemon = None
174        self.dut.disconnect()
175        for ad in self.android_devices:
176            ad.droid.wakeLockRelease()
177            ad.droid.goToSleepNow()
178        self.dut.turn_location_off_and_scan_toggle_off()
179        self.dut.reset_wifi()
180
181    def on_fail(self, test_name, begin_time):
182        self.dut.take_bug_report(test_name, begin_time)
183        self.dut.get_log(test_name, begin_time)
184
185    def setup_ap(self,
186                 ssid,
187                 band,
188                 ipv4=True,
189                 ipv6=False,
190                 security_mode=None,
191                 password=None):
192        """Setup ap with basic config.
193
194        Args:
195            ssid: string, ssid to setup on ap
196            band: string ('2g' or '5g') of band to setup.
197            ipv4: True if using ipv4 (dhcp), else False.
198            ipv6: True if using ipv6 (radvd), else False.
199        """
200        # TODO(fxb/63719): Add varying AP parameters
201        security_profile = None
202        if security_mode:
203            security_profile = Security(security_mode=security_mode,
204                                        password=password)
205        if band == BAND_2G:
206            setup_ap(access_point=self.access_point,
207                     profile_name='whirlwind',
208                     channel=11,
209                     ssid=ssid,
210                     security=security_profile)
211        elif band == BAND_5G:
212            setup_ap(access_point=self.access_point,
213                     profile_name='whirlwind',
214                     channel=36,
215                     ssid=ssid,
216                     security=security_profile)
217
218        if not ipv4:
219            self.access_point.stop_dhcp()
220        if ipv6:
221            radvd_config = RadvdConfig(
222                prefix='fd00::/64',
223                adv_send_advert=radvd_constants.ADV_SEND_ADVERT_ON,
224                adv_on_link=radvd_constants.ADV_ON_LINK_ON,
225                adv_autonomous=radvd_constants.ADV_AUTONOMOUS_ON)
226
227            if band == BAND_2G:
228                self.router_adv_daemon = Radvd(self.access_point.ssh,
229                                               self.access_point.wlan_2g)
230            elif band == BAND_5G:
231                self.router_adv_daemon = Radvd(self.access_point.ssh,
232                                               self.access_point.wlan_5g)
233            self.router_adv_daemon.start(radvd_config)
234
235        self.log.info('Network (SSID: %s) is up.' % ssid)
236
237    def wait_until_dut_gets_ipv4_addr(self, interface):
238        """Checks if device has an ipv4 private address. Sleeps 1 second between
239        retries.
240
241        Args:
242            interface: string, name of interface from which to get ipv4 address.
243
244        Raises:
245            ConnectionError, if DUT does not have an ipv4 address after all
246            timeout.
247        """
248        self.log.info(
249            'Checking if DUT has received an ipv4 addr. Will retry for %s '
250            'seconds.' % self.dut_ip_address_timeout)
251        timeout = time.time() + self.dut_ip_address_timeout
252        while time.time() < timeout:
253            ip_addrs = self.dut.get_interface_ip_addresses(interface)
254
255            if len(ip_addrs['ipv4_private']) > 0:
256                self.log.info('DUT has an ipv4 address: %s' %
257                              ip_addrs['ipv4_private'][0])
258                break
259            else:
260                self.log.debug(
261                    'DUT does not yet have an ipv4 address...retrying in 1 '
262                    'second.')
263                time.sleep(1)
264        else:
265            raise ConnectionError('DUT failed to get an ipv4 address.')
266
267    def wait_until_dut_gets_ipv6_addr(self, interface):
268        """Checks if device has an ipv6 private local address. Sleeps 1 second
269        between retries.
270
271        Args:
272            interface: string, name of interface from which to get ipv6 address.
273
274        Raises:
275            ConnectionError, if DUT does not have an ipv6 address after all
276            timeout.
277        """
278        self.log.info(
279            'Checking if DUT has received an ipv6 addr. Will retry for %s '
280            'seconds.' % self.dut_ip_address_timeout)
281        timeout = time.time() + self.dut_ip_address_timeout
282        while time.time() < timeout:
283            ip_addrs = self.dut.get_interface_ip_addresses(interface)
284            if len(ip_addrs['ipv6_private_local']) > 0:
285                self.log.info('DUT has an ipv6 private local address: %s' %
286                              ip_addrs['ipv6_private_local'][0])
287                break
288            else:
289                self.log.debug(
290                    'DUT does not yet have an ipv6 address...retrying in 1 '
291                    'second.')
292                time.sleep(1)
293        else:
294            raise ConnectionError('DUT failed to get an ipv6 address.')
295
296    def setup_iperf_server_on_ap(self, band):
297        """Configures iperf server based on the tests band.
298
299        Args:
300            band: string ('2g' or '5g') of band to setup.
301        """
302        if band == BAND_2G:
303            return iperf_server.IPerfServerOverSsh(
304                self.user_params['AccessPoint'][0]['ssh_config'],
305                5201,
306                test_interface=self.access_point.wlan_2g)
307        elif band == BAND_5G:
308            return iperf_server.IPerfServerOverSsh(
309                self.user_params['AccessPoint'][0]['ssh_config'],
310                5201,
311                test_interface=self.access_point.wlan_5g)
312
313    def get_iperf_server_address(self, iperf_server_on_ap, ip_version):
314        """Retrieves the ip address of the iperf server.
315
316        Args:
317            iperf_server_on_ap: IPerfServer object, linked to AP
318            ip_version: string, the ip version (ipv4 or ipv6)
319
320        Returns:
321            String, the ip address of the iperf_server
322        """
323        iperf_server_addresses = iperf_server_on_ap.get_interface_ip_addresses(
324            iperf_server_on_ap.test_interface)
325        if ip_version == IPV4:
326            iperf_server_ip_address = (
327                iperf_server_addresses['ipv4_private'][0])
328        elif ip_version == IPV6:
329            if iperf_server_addresses['ipv6_private_local']:
330                iperf_server_ip_address = (
331                    iperf_server_addresses['ipv6_private_local'][0])
332            else:
333                iperf_server_ip_address = (
334                    '%s%%%s' % (iperf_server_addresses['ipv6_link_local'][0],
335                                self.iperf_client_on_dut.test_interface))
336        else:
337            raise ValueError('Invalid IP version: %s' % ip_version)
338
339        return iperf_server_ip_address
340
341    def verify_traffic_between_dut_and_ap(self,
342                                          iperf_server_on_ap,
343                                          iperf_client_on_dut,
344                                          ip_version=IPV4):
345        """Runs IPerf traffic from the iperf client (dut) and the iperf
346        server (and vice versa) and verifies traffic was able to pass
347        successfully.
348
349        Args:
350            iperf_server_on_ap: IPerfServer object, linked to AP
351            iperf_client_on_dut: IPerfClient object, linked to DUT
352            ip_version: string, the ip version (ipv4 or ipv6)
353
354        Raises:
355            ValueError, if invalid ip_version is passed.
356            ConnectionError, if traffic is not passed successfully in both
357                directions.
358        """
359        dut_ip_addresses = self.dut.get_interface_ip_addresses(
360            iperf_client_on_dut.test_interface)
361
362        iperf_server_ip_address = self.get_iperf_server_address(
363            iperf_server_on_ap, ip_version)
364
365        self.log.info(
366            'Attempting to pass traffic from DUT to IPerf server (%s).' %
367            iperf_server_ip_address)
368        tx_file = iperf_client_on_dut.start(iperf_server_ip_address,
369                                            '-i 1 -t 3 -J',
370                                            'reboot_tx',
371                                            timeout=DEFAULT_IPERF_TIMEOUT)
372        tx_results = iperf_server.IPerfResult(tx_file)
373        if not tx_results.avg_receive_rate or tx_results.avg_receive_rate == 0:
374            raise ConnectionError(
375                'Failed to pass IPerf traffic from DUT to server (%s). TX '
376                'Average Receive Rate: %s' %
377                (iperf_server_ip_address, tx_results.avg_receive_rate))
378        else:
379            self.log.info(
380                'Success: Traffic passed from DUT to IPerf server (%s).' %
381                iperf_server_ip_address)
382        self.log.info(
383            'Attempting to pass traffic from IPerf server (%s) to DUT.' %
384            iperf_server_ip_address)
385        rx_file = iperf_client_on_dut.start(iperf_server_ip_address,
386                                            '-i 1 -t 3 -R -J',
387                                            'reboot_rx',
388                                            timeout=DEFAULT_IPERF_TIMEOUT)
389        rx_results = iperf_server.IPerfResult(rx_file)
390        if not rx_results.avg_receive_rate or rx_results.avg_receive_rate == 0:
391            raise ConnectionError(
392                'Failed to pass IPerf traffic from server (%s) to DUT. RX '
393                'Average Receive Rate: %s' %
394                (iperf_server_ip_address, rx_results.avg_receive_rate))
395        else:
396            self.log.info(
397                'Success: Traffic passed from IPerf server (%s) to DUT.' %
398                iperf_server_ip_address)
399
400    def start_dut_ping_process(self, iperf_server_on_ap, ip_version=IPV4):
401        """Creates a  process that pings the AP from the DUT.
402
403        Runs in parallel for 15 seconds, so it can be interrupted by a reboot.
404        Sleeps for a few seconds to ensure pings have started.
405
406        Args:
407            iperf_server_on_ap: IPerfServer object, linked to AP
408            ip_version: string, the ip version (ipv4 or ipv6)
409        """
410        ap_address = self.get_iperf_server_address(iperf_server_on_ap,
411                                                   ip_version)
412        if ap_address:
413            self.log.info(
414                'Starting ping process to %s in parallel. Logs from this '
415                'process will be suppressed, since it will be intentionally '
416                'interrupted.' % ap_address)
417            ping_proc = Process(target=self.dut.ping,
418                                args=[ap_address],
419                                kwargs={'count': 15})
420            with utils.SuppressLogOutput():
421                ping_proc.start()
422            # Allow for a few seconds of pinging before allowing it to be
423            # interrupted.
424            time.sleep(3)
425        else:
426            raise ConnectionError('Failed to retrieve APs iperf address.')
427
428    def prepare_dut_for_reconnection(self):
429        """Perform any actions to ready DUT for reconnection.
430
431        These actions will vary depending on the DUT. eg. android devices may
432        need to be woken up, ambient devices should not require any interaction,
433        etc.
434        """
435        self.dut.wifi_toggle_state(True)
436        for ad in self.android_devices:
437            ad.droid.wakeUpNow()
438
439    def wait_for_dut_network_connection(self, ssid):
440        """Checks if device is connected to given network. Sleeps 1 second
441        between retries.
442
443        Args:
444            ssid: string of ssid
445        Raises:
446            ConnectionError, if DUT is not connected after all timeout.
447        """
448        self.log.info(
449            'Checking if DUT is connected to %s network. Will retry for %s '
450            'seconds.' % (ssid, self.dut_network_connection_timeout))
451        timeout = time.time() + self.dut_network_connection_timeout
452        while time.time() < timeout:
453            try:
454                is_connected = self.dut.is_connected(ssid=ssid)
455            except Exception as err:
456                self.log.debug('SL4* call failed. Retrying in 1 second.')
457                is_connected = False
458            finally:
459                if is_connected:
460                    self.log.info('Success: DUT has connected.')
461                    break
462                else:
463                    self.log.debug(
464                        'DUT not connected to network %s...retrying in 1 second.'
465                        % ssid)
466                    time.sleep(1)
467        else:
468            raise ConnectionError('DUT failed to connect to the network.')
469
470    def write_csv_time_to_reconnect(self, test_name, time_to_reconnect):
471        """Writes the time to reconnect to a csv file.
472        Args:
473            test_name: the name of the test case
474            time_to_reconnect: the time from when the rebooted device came back
475                up to when it reassociated (or 'FAIL'), if it failed to
476                reconnect.
477        """
478        log_context = context.get_current_context()
479        log_path = os.path.join(log_context.get_base_output_path(),
480                                'WlanRebootTest/')
481        csv_file_name = '%stime_to_reconnect.csv' % log_path
482        self.log.info('Writing to %s' % csv_file_name)
483        with open(csv_file_name, 'a') as csv_file:
484            csv_file.write('%s,%s\n' % (test_name, time_to_reconnect))
485
486    def log_and_continue(self, run, time_to_reconnect=None, error=None):
487        """Writes the time to reconnect to the csv file before continuing, used
488        in stress tests runs.
489
490        Args:
491            time_to_reconnect: the time from when the rebooted device came back
492                ip to when reassociation occurred.
493            run: the run number in a looped stress tested.,
494            error: string, error message to log before continuing with the test
495        """
496        if error:
497            self.log.info(
498                'Device failed to reconnect to network %s on run %s. Error: %s'
499                % (self.ssid, run, error))
500            self.write_csv_time_to_reconnect(
501                '%s_run_%s' % (self.test_name, run), 'FAIL')
502
503        else:
504            self.log.info(
505                'Device successfully reconnected to network %s after %s seconds'
506                ' on run %s.' % (self.ssid, time_to_reconnect, run))
507            self.write_csv_time_to_reconnect(
508                '%s_run_%s' % (self.test_name, run), time_to_reconnect)
509
510    def run_reboot_test(self, settings):
511        """Runs a reboot test based on a given config.
512            1. Setups up a network, associates the dut, and saves the network.
513            2. Verifies the dut receives ip address(es).
514            3. Verifies traffic between DUT and AP (IPerf client and server).
515            4. Reboots (hard or soft) the device (dut or ap).
516                - If the ap was rebooted, setup the same network again.
517            5. Wait for reassociation or timeout.
518            6. If reassocation occurs:
519                - Verifies the dut receives ip address(es).
520                - Verifies traffic between DUT and AP (IPerf client and server).
521            7. Logs time to reconnect (or failure to reconnect)
522            8. If stress testing, repeats steps 4 - 7 for N iterations.
523
524        Args:
525            settings: dictionary containing the following values:
526                reboot_device: string ('dut' or 'ap') of the device to reboot.
527                reboot_type: string ('soft' or 'hard') of how to reboot the
528                    reboot_device.
529                band: string ('2g' or '5g') of band to setup.
530                ipv4: True if using ipv4 (dhcp), else False.
531                ipv6: True if using ipv6 (radvd), else False.
532
533                Optional:
534                    interrupt: if True, the DUT will be pinging the AP in a
535                        parallel process when the reboot occurs. This is used to
536                        compare reconnect times when idle to active.
537                    test_name: name of the test, used when stress testing.
538                    iterations: number of times to perform test, used when stress
539                        testing.
540
541        Raises:
542            ValueError, if ipv4 and ipv6 are both False
543            ValueError, if band is not '2g' or '5g'
544            ValueError, if reboot_device is not 'dut' or 'ap'
545            ValueError, if reboot_type is not 'soft' or 'hard'
546
547        """
548        iterations = settings.get('iterations', 1)
549        passed_count = 0
550        ipv4 = settings.get('ipv4', None)
551        ipv6 = settings.get('ipv6', None)
552        reboot_device = settings['reboot_device']
553        reboot_type = settings['reboot_type']
554        band = settings['band']
555        security_mode = settings.get('security_mode', None)
556        password = settings.get('password', None)
557        if security_mode:
558            if security_mode.lower() == 'open':
559                security_mode = None
560            elif not password:
561                password = generate_random_password(
562                    security_mode=security_mode)
563        interrupt = settings.get('interrupt', None)
564        # Skip hard reboots if no PDU present
565        asserts.skip_if(
566            reboot_type == HARD
567            and len(self.user_params.get('PduDevice', [])) < 1,
568            'Hard reboots require a PDU device.')
569        # Skip DUT reboot w/ interrupt tests, since they are not more helpful
570        # and may cause threading issues.
571        asserts.skip_if(
572            (reboot_device == DUT) and interrupt,
573            'Stream interrupts for DUT reboots are prone to threading issues '
574            'and are not supported.')
575
576        # Validate test settings.
577        if not ipv4 and not ipv6:
578            raise ValueError('Either ipv4, ipv6, or both must be True.')
579        if reboot_device != DUT and reboot_device != AP:
580            raise ValueError('Invalid reboot device: %s' % reboot_device)
581        if reboot_type != SOFT and reboot_type != HARD:
582            raise ValueError('Invalid reboot type: %s' % reboot_type)
583        if band != BAND_2G and band != BAND_5G:
584            raise ValueError('Invalid band: %s' % band)
585
586        self.setup_ap(self.ssid, band, ipv4, ipv6, security_mode, password)
587        if not self.dut.associate(
588                self.ssid,
589                target_security=hostapd_constants.
590                SECURITY_STRING_TO_DEFAULT_TARGET_SECURITY.get(security_mode),
591                target_pwd=password):
592            raise EnvironmentError('Initial network connection failed.')
593
594        if not self.skip_iperf:
595            dut_test_interface = self.iperf_client_on_dut.test_interface
596            if ipv4:
597                self.wait_until_dut_gets_ipv4_addr(dut_test_interface)
598            if ipv6:
599                self.wait_until_dut_gets_ipv6_addr(dut_test_interface)
600
601            self.iperf_server_on_ap = self.setup_iperf_server_on_ap(band)
602            self.iperf_server_on_ap.start()
603
604            if ipv4:
605                self.verify_traffic_between_dut_and_ap(
606                    self.iperf_server_on_ap, self.iperf_client_on_dut)
607            if ipv6:
608                self.verify_traffic_between_dut_and_ap(
609                    self.iperf_server_on_ap,
610                    self.iperf_client_on_dut,
611                    ip_version=IPV6)
612
613        # Looping reboots for stress testing
614        for run in range(iterations):
615            run += 1
616            self.log.info('Starting run %s of %s.' % (run, iterations))
617
618            # Ping from DUT to AP during AP reboot
619            if interrupt:
620                if ipv4:
621                    self.start_dut_ping_process(self.iperf_server_on_ap)
622                if ipv6:
623                    self.start_dut_ping_process(self.iperf_server_on_ap,
624                                                ip_version=IPV6)
625
626            # DUT reboots
627            if reboot_device == DUT:
628                if not self.skip_iperf and type(
629                        self.iperf_client_on_dut
630                ) == iperf_client.IPerfClientOverSsh:
631                    self.iperf_client_on_dut.close_ssh()
632                if reboot_type == SOFT:
633                    self.dut.device.reboot()
634                elif reboot_type == HARD:
635                    self.dut.hard_power_cycle(self.pdu_devices)
636
637            # AP reboots
638            elif reboot_device == AP:
639                if reboot_type == SOFT:
640                    self.log.info('Cleanly stopping ap.')
641                    self.access_point.stop_all_aps()
642                elif reboot_type == HARD:
643                    if not self.skip_iperf:
644                        self.iperf_server_on_ap.close_ssh()
645                    self.access_point.hard_power_cycle(self.pdu_devices)
646                self.setup_ap(self.ssid, band, ipv4, ipv6, security_mode,
647                              password)
648
649            self.prepare_dut_for_reconnection()
650            uptime = time.time()
651            try:
652                self.wait_for_dut_network_connection(self.ssid)
653                time_to_reconnect = time.time() - uptime
654
655                if not self.skip_iperf:
656                    if ipv4:
657                        self.wait_until_dut_gets_ipv4_addr(dut_test_interface)
658                    if ipv6:
659                        self.wait_until_dut_gets_ipv6_addr(dut_test_interface)
660
661                    self.iperf_server_on_ap.start()
662
663                    if ipv4:
664                        self.verify_traffic_between_dut_and_ap(
665                            self.iperf_server_on_ap, self.iperf_client_on_dut)
666                    if ipv6:
667                        self.verify_traffic_between_dut_and_ap(
668                            self.iperf_server_on_ap,
669                            self.iperf_client_on_dut,
670                            ip_version=IPV6)
671
672            except ConnectionError as err:
673                self.log_and_continue(run, error=err)
674            else:
675                passed_count += 1
676                self.log_and_continue(run, time_to_reconnect=time_to_reconnect)
677
678        if passed_count == iterations:
679            asserts.explicit_pass(
680                'Test Summary: device successfully reconnected to network %s '
681                '%s/%s times.' % (self.ssid, passed_count, iterations))
682
683        else:
684            asserts.fail(
685                'Test Summary: device failed reconnection test. Reconnected to '
686                'network %s %s/%s times.' %
687                (self.ssid, passed_count, iterations))
688
689# Open Network DUT Soft Reboots (requires a DUT and Whirlwind)
690
691    def test_soft_reboot_dut_ipv4_2g(self):
692        settings = {
693            'reboot_device': DUT,
694            'reboot_type': SOFT,
695            'ipv4': True,
696            'band': BAND_2G,
697        }
698        self.run_reboot_test(settings)
699
700    def test_soft_reboot_dut_ipv4_5g(self):
701        settings = {
702            'reboot_device': DUT,
703            'reboot_type': SOFT,
704            'ipv4': True,
705            'band': BAND_5G,
706        }
707        self.run_reboot_test(settings)
708
709    def test_soft_reboot_dut_ipv6_2g(self):
710        settings = {
711            'reboot_device': DUT,
712            'reboot_type': SOFT,
713            'ipv6': True,
714            'band': BAND_2G,
715        }
716        self.run_reboot_test(settings)
717
718    def test_soft_reboot_dut_ipv6_5g(self):
719        settings = {
720            'reboot_device': DUT,
721            'reboot_type': SOFT,
722            'ipv6': True,
723            'band': BAND_5G,
724        }
725        self.run_reboot_test(settings)
726
727    def test_soft_reboot_dut_ipv4_ipv6_2g(self):
728        settings = {
729            'reboot_device': DUT,
730            'reboot_type': SOFT,
731            'ipv4': True,
732            'ipv6': True,
733            'band': BAND_2G,
734        }
735        self.run_reboot_test(settings)
736
737    def test_soft_reboot_dut_ipv4_ipv6_5g(self):
738        settings = {
739            'reboot_device': DUT,
740            'reboot_type': SOFT,
741            'ipv4': True,
742            'ipv6': True,
743            'band': BAND_5G,
744        }
745        self.run_reboot_test(settings)
746
747# Open Network DUT Hard Reboots (requires a DUT, Whirlwind, and PDU)
748
749    def test_hard_reboot_dut_ipv4_2g(self):
750        settings = {
751            'reboot_device': DUT,
752            'reboot_type': HARD,
753            'ipv4': True,
754            'band': BAND_2G,
755        }
756        self.run_reboot_test(settings)
757
758    def test_hard_reboot_dut_ipv4_5g(self):
759        settings = {
760            'reboot_device': DUT,
761            'reboot_type': HARD,
762            'ipv4': True,
763            'band': BAND_5G,
764        }
765        self.run_reboot_test(settings)
766
767    def test_hard_reboot_dut_ipv6_2g(self):
768        settings = {
769            'reboot_device': DUT,
770            'reboot_type': HARD,
771            'ipv6': True,
772            'band': BAND_2G,
773        }
774        self.run_reboot_test(settings)
775
776    def test_hard_reboot_dut_ipv6_5g(self):
777        settings = {
778            'reboot_device': DUT,
779            'reboot_type': HARD,
780            'ipv6': True,
781            'band': BAND_5G,
782        }
783        self.run_reboot_test(settings)
784
785    def test_hard_reboot_dut_ipv4_ipv6_2g(self):
786        settings = {
787            'reboot_device': DUT,
788            'reboot_type': HARD,
789            'ipv4': True,
790            'ipv6': True,
791            'band': BAND_2G,
792        }
793        self.run_reboot_test(settings)
794
795    def test_hard_reboot_dut_ipv4_ipv6_5g(self):
796        settings = {
797            'reboot_device': DUT,
798            'reboot_type': HARD,
799            'ipv4': True,
800            'ipv6': True,
801            'band': BAND_5G,
802        }
803        self.run_reboot_test(settings)
804
805# Open Network AP Soft Reboots (requires a DUT and Whirlwind)
806
807    def test_soft_reboot_ap_ipv4_2g(self):
808        settings = {
809            'reboot_device': AP,
810            'reboot_type': SOFT,
811            'ipv4': True,
812            'band': BAND_2G,
813        }
814        self.run_reboot_test(settings)
815
816    def test_soft_reboot_ap_ipv4_5g(self):
817        settings = {
818            'reboot_device': AP,
819            'reboot_type': SOFT,
820            'ipv4': True,
821            'band': BAND_5G,
822        }
823        self.run_reboot_test(settings)
824
825    def test_soft_reboot_ap_ipv6_2g(self):
826        settings = {
827            'reboot_device': AP,
828            'reboot_type': SOFT,
829            'ipv6': True,
830            'band': BAND_2G,
831        }
832        self.run_reboot_test(settings)
833
834    def test_soft_reboot_ap_ipv6_5g(self):
835        settings = {
836            'reboot_device': AP,
837            'reboot_type': SOFT,
838            'ipv6': True,
839            'band': BAND_5G,
840        }
841        self.run_reboot_test(settings)
842
843    def test_soft_reboot_ap_ipv4_ipv6_2g(self):
844        settings = {
845            'reboot_device': AP,
846            'reboot_type': SOFT,
847            'ipv4': True,
848            'ipv6': True,
849            'band': BAND_2G,
850        }
851        self.run_reboot_test(settings)
852
853    def test_soft_reboot_ap_ipv4_ipv6_5g(self):
854        settings = {
855            'reboot_device': AP,
856            'reboot_type': SOFT,
857            'ipv4': True,
858            'ipv6': True,
859            'band': BAND_5G,
860        }
861        self.run_reboot_test(settings)
862
863# Open Network AP Soft Reboots (requires a DUT and Whirlwind) with traffic
864# interruption.
865
866    def test_soft_reboot_ap_ipv4_2g_interrupt(self):
867        settings = {
868            'reboot_device': AP,
869            'reboot_type': SOFT,
870            'ipv4': True,
871            'band': BAND_2G,
872            'interrupt': True
873        }
874        self.run_reboot_test(settings)
875
876    def test_soft_reboot_ap_ipv4_5g_interrupt(self):
877        settings = {
878            'reboot_device': AP,
879            'reboot_type': SOFT,
880            'ipv4': True,
881            'band': BAND_5G,
882            'interrupt': True
883        }
884        self.run_reboot_test(settings)
885
886    def test_soft_reboot_ap_ipv6_2g_interrupt(self):
887        settings = {
888            'reboot_device': AP,
889            'reboot_type': SOFT,
890            'ipv6': True,
891            'band': BAND_2G,
892            'interrupt': True
893        }
894        self.run_reboot_test(settings)
895
896    def test_soft_reboot_ap_ipv6_5g_interrupt(self):
897        settings = {
898            'reboot_device': AP,
899            'reboot_type': SOFT,
900            'ipv6': True,
901            'band': BAND_5G,
902            'interrupt': True
903        }
904        self.run_reboot_test(settings)
905
906    def test_soft_reboot_ap_ipv4_ipv6_2g_interrupt(self):
907        settings = {
908            'reboot_device': AP,
909            'reboot_type': SOFT,
910            'ipv4': True,
911            'ipv6': True,
912            'band': BAND_2G,
913            'interrupt': True
914        }
915        self.run_reboot_test(settings)
916
917    def test_soft_reboot_ap_ipv4_ipv6_5g_interrupt(self):
918        settings = {
919            'reboot_device': AP,
920            'reboot_type': SOFT,
921            'ipv4': True,
922            'ipv6': True,
923            'band': BAND_5G,
924            'interrupt': True
925        }
926        self.run_reboot_test(settings)
927
928# Open Network AP Hard Reboot (requires a DUT, Whirlwind, and PDU)
929
930    def test_hard_reboot_ap_ipv4_2g(self):
931        settings = {
932            'reboot_device': AP,
933            'reboot_type': HARD,
934            'ipv4': True,
935            'band': BAND_2G,
936        }
937        self.run_reboot_test(settings)
938
939    def test_hard_reboot_ap_ipv4_5g(self):
940        settings = {
941            'reboot_device': AP,
942            'reboot_type': HARD,
943            'ipv4': True,
944            'band': BAND_5G,
945        }
946        self.run_reboot_test(settings)
947
948    def test_hard_reboot_ap_ipv6_2g(self):
949        settings = {
950            'reboot_device': AP,
951            'reboot_type': HARD,
952            'ipv6': True,
953            'band': BAND_2G,
954        }
955        self.run_reboot_test(settings)
956
957    def test_hard_reboot_ap_ipv6_5g(self):
958        settings = {
959            'reboot_device': AP,
960            'reboot_type': HARD,
961            'ipv6': True,
962            'band': BAND_5G,
963        }
964        self.run_reboot_test(settings)
965
966    def test_hard_reboot_ap_ipv4_ipv6_2g(self):
967        settings = {
968            'reboot_device': AP,
969            'reboot_type': HARD,
970            'ipv4': True,
971            'ipv6': True,
972            'band': BAND_2G,
973        }
974        self.run_reboot_test(settings)
975
976    def test_hard_reboot_ap_ipv4_ipv6_5g(self):
977        settings = {
978            'reboot_device': AP,
979            'reboot_type': HARD,
980            'ipv4': True,
981            'ipv6': True,
982            'band': BAND_5G,
983        }
984        self.run_reboot_test(settings)
985
986# Open Network AP Hard Reboot (requires a DUT, Whirlwind, and PDU) with traffic
987# interruptions.
988
989    def test_hard_reboot_ap_ipv4_2g_interrupt(self):
990        settings = {
991            'reboot_device': AP,
992            'reboot_type': HARD,
993            'ipv4': True,
994            'band': BAND_2G,
995            'interrupt': True
996        }
997        self.run_reboot_test(settings)
998
999    def test_hard_reboot_ap_ipv4_5g_interrupt(self):
1000        settings = {
1001            'reboot_device': AP,
1002            'reboot_type': HARD,
1003            'ipv4': True,
1004            'band': BAND_5G,
1005            'interrupt': True
1006        }
1007        self.run_reboot_test(settings)
1008
1009    def test_hard_reboot_ap_ipv6_2g_interrupt(self):
1010        settings = {
1011            'reboot_device': AP,
1012            'reboot_type': HARD,
1013            'ipv6': True,
1014            'band': BAND_2G,
1015            'interrupt': True
1016        }
1017        self.run_reboot_test(settings)
1018
1019    def test_hard_reboot_ap_ipv6_5g_interrupt(self):
1020        settings = {
1021            'reboot_device': AP,
1022            'reboot_type': HARD,
1023            'ipv6': True,
1024            'band': BAND_5G,
1025            'interrupt': True
1026        }
1027        self.run_reboot_test(settings)
1028
1029    def test_hard_reboot_ap_ipv4_ipv6_2g_interrupt(self):
1030        settings = {
1031            'reboot_device': AP,
1032            'reboot_type': HARD,
1033            'ipv4': True,
1034            'ipv6': True,
1035            'band': BAND_2G,
1036            'interrupt': True
1037        }
1038        self.run_reboot_test(settings)
1039
1040    def test_hard_reboot_ap_ipv4_ipv6_5g_interrupt(self):
1041        settings = {
1042            'reboot_device': AP,
1043            'reboot_type': HARD,
1044            'ipv4': True,
1045            'ipv6': True,
1046            'band': BAND_5G,
1047            'interrupt': True
1048        }
1049        self.run_reboot_test(settings)
1050
1051# WPA2 DUT Soft Reboots (requires a DUT and Whirlwind)
1052
1053    def test_soft_reboot_dut_ipv4_2g_wpa2(self):
1054        settings = {
1055            'reboot_device': DUT,
1056            'reboot_type': SOFT,
1057            'ipv4': True,
1058            'band': BAND_2G,
1059            'security_mode': hostapd_constants.WPA2_STRING
1060        }
1061        self.run_reboot_test(settings)
1062
1063    def test_soft_reboot_dut_ipv4_5g_wpa2(self):
1064        settings = {
1065            'reboot_device': DUT,
1066            'reboot_type': SOFT,
1067            'ipv4': True,
1068            'band': BAND_5G,
1069            'security_mode': hostapd_constants.WPA2_STRING
1070        }
1071        self.run_reboot_test(settings)
1072
1073    def test_soft_reboot_dut_ipv6_2g_wpa2(self):
1074        settings = {
1075            'reboot_device': DUT,
1076            'reboot_type': SOFT,
1077            'ipv6': True,
1078            'band': BAND_2G,
1079            'security_mode': hostapd_constants.WPA2_STRING
1080        }
1081        self.run_reboot_test(settings)
1082
1083    def test_soft_reboot_dut_ipv6_5g_wpa2(self):
1084        settings = {
1085            'reboot_device': DUT,
1086            'reboot_type': SOFT,
1087            'ipv6': True,
1088            'band': BAND_5G,
1089            'security_mode': hostapd_constants.WPA2_STRING
1090        }
1091        self.run_reboot_test(settings)
1092
1093    def test_soft_reboot_dut_ipv4_ipv6_2g_wpa2(self):
1094        settings = {
1095            'reboot_device': DUT,
1096            'reboot_type': SOFT,
1097            'ipv4': True,
1098            'ipv6': True,
1099            'band': BAND_2G,
1100            'security_mode': hostapd_constants.WPA2_STRING
1101        }
1102        self.run_reboot_test(settings)
1103
1104    def test_soft_reboot_dut_ipv4_ipv6_5g_wpa2(self):
1105        settings = {
1106            'reboot_device': DUT,
1107            'reboot_type': SOFT,
1108            'ipv4': True,
1109            'ipv6': True,
1110            'band': BAND_5G,
1111            'security_mode': hostapd_constants.WPA2_STRING
1112        }
1113        self.run_reboot_test(settings)
1114
1115# WPA2 Network DUT Hard Reboots (requires a DUT, Whirlwind, and PDU)
1116
1117    def test_hard_reboot_dut_ipv4_2g_wpa2(self):
1118        settings = {
1119            'reboot_device': DUT,
1120            'reboot_type': HARD,
1121            'ipv4': True,
1122            'band': BAND_2G,
1123            'security_mode': hostapd_constants.WPA2_STRING
1124        }
1125        self.run_reboot_test(settings)
1126
1127    def test_hard_reboot_dut_ipv4_5g_wpa2(self):
1128        settings = {
1129            'reboot_device': DUT,
1130            'reboot_type': HARD,
1131            'ipv4': True,
1132            'band': BAND_5G,
1133            'security_mode': hostapd_constants.WPA2_STRING
1134        }
1135        self.run_reboot_test(settings)
1136
1137    def test_hard_reboot_dut_ipv6_2g_wpa2(self):
1138        settings = {
1139            'reboot_device': DUT,
1140            'reboot_type': HARD,
1141            'ipv6': True,
1142            'band': BAND_2G,
1143            'security_mode': hostapd_constants.WPA2_STRING
1144        }
1145        self.run_reboot_test(settings)
1146
1147    def test_hard_reboot_dut_ipv6_5g_wpa2(self):
1148        settings = {
1149            'reboot_device': DUT,
1150            'reboot_type': HARD,
1151            'ipv6': True,
1152            'band': BAND_5G,
1153            'security_mode': hostapd_constants.WPA2_STRING
1154        }
1155        self.run_reboot_test(settings)
1156
1157    def test_hard_reboot_dut_ipv4_ipv6_2g_wpa2(self):
1158        settings = {
1159            'reboot_device': DUT,
1160            'reboot_type': HARD,
1161            'ipv4': True,
1162            'ipv6': True,
1163            'band': BAND_2G,
1164            'security_mode': hostapd_constants.WPA2_STRING
1165        }
1166        self.run_reboot_test(settings)
1167
1168    def test_hard_reboot_dut_ipv4_ipv6_5g_wpa2(self):
1169        settings = {
1170            'reboot_device': DUT,
1171            'reboot_type': HARD,
1172            'ipv4': True,
1173            'ipv6': True,
1174            'band': BAND_5G,
1175            'security_mode': hostapd_constants.WPA2_STRING
1176        }
1177        self.run_reboot_test(settings)
1178
1179# WPA2 Network AP Soft Reboots (requires a DUT and Whirlwind)
1180
1181    def test_soft_reboot_ap_ipv4_2g_wpa2(self):
1182        settings = {
1183            'reboot_device': AP,
1184            'reboot_type': SOFT,
1185            'ipv4': True,
1186            'band': BAND_2G,
1187            'security_mode': hostapd_constants.WPA2_STRING
1188        }
1189        self.run_reboot_test(settings)
1190
1191    def test_soft_reboot_ap_ipv4_5g_wpa2(self):
1192        settings = {
1193            'reboot_device': AP,
1194            'reboot_type': SOFT,
1195            'ipv4': True,
1196            'band': BAND_5G,
1197            'security_mode': hostapd_constants.WPA2_STRING
1198        }
1199        self.run_reboot_test(settings)
1200
1201    def test_soft_reboot_ap_ipv6_2g_wpa2(self):
1202        settings = {
1203            'reboot_device': AP,
1204            'reboot_type': SOFT,
1205            'ipv6': True,
1206            'band': BAND_2G,
1207            'security_mode': hostapd_constants.WPA2_STRING
1208        }
1209        self.run_reboot_test(settings)
1210
1211    def test_soft_reboot_ap_ipv6_5g_wpa2(self):
1212        settings = {
1213            'reboot_device': AP,
1214            'reboot_type': SOFT,
1215            'ipv6': True,
1216            'band': BAND_5G,
1217            'security_mode': hostapd_constants.WPA2_STRING
1218        }
1219        self.run_reboot_test(settings)
1220
1221    def test_soft_reboot_ap_ipv4_ipv6_2g_wpa2(self):
1222        settings = {
1223            'reboot_device': AP,
1224            'reboot_type': SOFT,
1225            'ipv4': True,
1226            'ipv6': True,
1227            'band': BAND_2G,
1228            'security_mode': hostapd_constants.WPA2_STRING
1229        }
1230        self.run_reboot_test(settings)
1231
1232    def test_soft_reboot_ap_ipv4_ipv6_5g_wpa2(self):
1233        settings = {
1234            'reboot_device': AP,
1235            'reboot_type': SOFT,
1236            'ipv4': True,
1237            'ipv6': True,
1238            'band': BAND_5G,
1239            'security_mode': hostapd_constants.WPA2_STRING
1240        }
1241        self.run_reboot_test(settings)
1242
1243# WPA2 Network AP Hard Reboot (requires a DUT, Whirlwind, and PDU)
1244
1245    def test_hard_reboot_ap_ipv4_2g_wpa2(self):
1246        settings = {
1247            'reboot_device': AP,
1248            'reboot_type': HARD,
1249            'ipv4': True,
1250            'band': BAND_2G,
1251            'security_mode': hostapd_constants.WPA2_STRING
1252        }
1253        self.run_reboot_test(settings)
1254
1255    def test_hard_reboot_ap_ipv4_5g_wpa2(self):
1256        settings = {
1257            'reboot_device': AP,
1258            'reboot_type': HARD,
1259            'ipv4': True,
1260            'band': BAND_5G,
1261            'security_mode': hostapd_constants.WPA2_STRING
1262        }
1263        self.run_reboot_test(settings)
1264
1265    def test_hard_reboot_ap_ipv6_2g_wpa2(self):
1266        settings = {
1267            'reboot_device': AP,
1268            'reboot_type': HARD,
1269            'ipv6': True,
1270            'band': BAND_2G,
1271            'security_mode': hostapd_constants.WPA2_STRING
1272        }
1273        self.run_reboot_test(settings)
1274
1275    def test_hard_reboot_ap_ipv6_5g_wpa2(self):
1276        settings = {
1277            'reboot_device': AP,
1278            'reboot_type': HARD,
1279            'ipv6': True,
1280            'band': BAND_5G,
1281            'security_mode': hostapd_constants.WPA2_STRING
1282        }
1283        self.run_reboot_test(settings)
1284
1285    def test_hard_reboot_ap_ipv4_ipv6_2g_wpa2(self):
1286        settings = {
1287            'reboot_device': AP,
1288            'reboot_type': HARD,
1289            'ipv4': True,
1290            'ipv6': True,
1291            'band': BAND_2G,
1292            'security_mode': hostapd_constants.WPA2_STRING
1293        }
1294        self.run_reboot_test(settings)
1295
1296    def test_hard_reboot_ap_ipv4_ipv6_5g_wpa2(self):
1297        settings = {
1298            'reboot_device': AP,
1299            'reboot_type': HARD,
1300            'ipv4': True,
1301            'ipv6': True,
1302            'band': BAND_5G,
1303            'security_mode': hostapd_constants.WPA2_STRING
1304        }
1305        self.run_reboot_test(settings)
1306
1307# WPA3 DUT Soft Reboots (requires a DUT and Whirlwind)
1308
1309    def test_soft_reboot_dut_ipv4_2g_wpa3(self):
1310        settings = {
1311            'reboot_device': DUT,
1312            'reboot_type': SOFT,
1313            'ipv4': True,
1314            'band': BAND_2G,
1315            'security_mode': hostapd_constants.WPA3_STRING
1316        }
1317        self.run_reboot_test(settings)
1318
1319    def test_soft_reboot_dut_ipv4_5g_wpa3(self):
1320        settings = {
1321            'reboot_device': DUT,
1322            'reboot_type': SOFT,
1323            'ipv4': True,
1324            'band': BAND_5G,
1325            'security_mode': hostapd_constants.WPA3_STRING
1326        }
1327        self.run_reboot_test(settings)
1328
1329    def test_soft_reboot_dut_ipv6_2g_wpa3(self):
1330        settings = {
1331            'reboot_device': DUT,
1332            'reboot_type': SOFT,
1333            'ipv6': True,
1334            'band': BAND_2G,
1335            'security_mode': hostapd_constants.WPA3_STRING
1336        }
1337        self.run_reboot_test(settings)
1338
1339    def test_soft_reboot_dut_ipv6_5g_wpa3(self):
1340        settings = {
1341            'reboot_device': DUT,
1342            'reboot_type': SOFT,
1343            'ipv6': True,
1344            'band': BAND_5G,
1345            'security_mode': hostapd_constants.WPA3_STRING
1346        }
1347        self.run_reboot_test(settings)
1348
1349    def test_soft_reboot_dut_ipv4_ipv6_2g_wpa3(self):
1350        settings = {
1351            'reboot_device': DUT,
1352            'reboot_type': SOFT,
1353            'ipv4': True,
1354            'ipv6': True,
1355            'band': BAND_2G,
1356            'security_mode': hostapd_constants.WPA3_STRING
1357        }
1358        self.run_reboot_test(settings)
1359
1360    def test_soft_reboot_dut_ipv4_ipv6_5g_wpa3(self):
1361        settings = {
1362            'reboot_device': DUT,
1363            'reboot_type': SOFT,
1364            'ipv4': True,
1365            'ipv6': True,
1366            'band': BAND_5G,
1367            'security_mode': hostapd_constants.WPA3_STRING
1368        }
1369        self.run_reboot_test(settings)
1370
1371# WPA3 Network DUT Hard Reboots (requires a DUT, Whirlwind, and PDU)
1372
1373    def test_hard_reboot_dut_ipv4_2g_wpa3(self):
1374        settings = {
1375            'reboot_device': DUT,
1376            'reboot_type': HARD,
1377            'ipv4': True,
1378            'band': BAND_2G,
1379            'security_mode': hostapd_constants.WPA3_STRING
1380        }
1381        self.run_reboot_test(settings)
1382
1383    def test_hard_reboot_dut_ipv4_5g_wpa3(self):
1384        settings = {
1385            'reboot_device': DUT,
1386            'reboot_type': HARD,
1387            'ipv4': True,
1388            'band': BAND_5G,
1389            'security_mode': hostapd_constants.WPA3_STRING
1390        }
1391        self.run_reboot_test(settings)
1392
1393    def test_hard_reboot_dut_ipv6_2g_wpa3(self):
1394        settings = {
1395            'reboot_device': DUT,
1396            'reboot_type': HARD,
1397            'ipv6': True,
1398            'band': BAND_2G,
1399            'security_mode': hostapd_constants.WPA3_STRING
1400        }
1401        self.run_reboot_test(settings)
1402
1403    def test_hard_reboot_dut_ipv6_5g_wpa3(self):
1404        settings = {
1405            'reboot_device': DUT,
1406            'reboot_type': HARD,
1407            'ipv6': True,
1408            'band': BAND_5G,
1409            'security_mode': hostapd_constants.WPA3_STRING
1410        }
1411        self.run_reboot_test(settings)
1412
1413    def test_hard_reboot_dut_ipv4_ipv6_2g_wpa3(self):
1414        settings = {
1415            'reboot_device': DUT,
1416            'reboot_type': HARD,
1417            'ipv4': True,
1418            'ipv6': True,
1419            'band': BAND_2G,
1420            'security_mode': hostapd_constants.WPA3_STRING
1421        }
1422        self.run_reboot_test(settings)
1423
1424    def test_hard_reboot_dut_ipv4_ipv6_5g_wpa3(self):
1425        settings = {
1426            'reboot_device': DUT,
1427            'reboot_type': HARD,
1428            'ipv4': True,
1429            'ipv6': True,
1430            'band': BAND_5G,
1431            'security_mode': hostapd_constants.WPA3_STRING
1432        }
1433        self.run_reboot_test(settings)
1434
1435# WPA3 Network AP Soft Reboots (requires a DUT and Whirlwind)
1436
1437    def test_soft_reboot_ap_ipv4_2g_wpa3(self):
1438        settings = {
1439            'reboot_device': AP,
1440            'reboot_type': SOFT,
1441            'ipv4': True,
1442            'band': BAND_2G,
1443            'security_mode': hostapd_constants.WPA3_STRING
1444        }
1445        self.run_reboot_test(settings)
1446
1447    def test_soft_reboot_ap_ipv4_5g_wpa3(self):
1448        settings = {
1449            'reboot_device': AP,
1450            'reboot_type': SOFT,
1451            'ipv4': True,
1452            'band': BAND_5G,
1453            'security_mode': hostapd_constants.WPA3_STRING
1454        }
1455        self.run_reboot_test(settings)
1456
1457    def test_soft_reboot_ap_ipv6_2g_wpa3(self):
1458        settings = {
1459            'reboot_device': AP,
1460            'reboot_type': SOFT,
1461            'ipv6': True,
1462            'band': BAND_2G,
1463            'security_mode': hostapd_constants.WPA3_STRING
1464        }
1465        self.run_reboot_test(settings)
1466
1467    def test_soft_reboot_ap_ipv6_5g_wpa3(self):
1468        settings = {
1469            'reboot_device': AP,
1470            'reboot_type': SOFT,
1471            'ipv6': True,
1472            'band': BAND_5G,
1473            'security_mode': hostapd_constants.WPA3_STRING
1474        }
1475        self.run_reboot_test(settings)
1476
1477    def test_soft_reboot_ap_ipv4_ipv6_2g_wpa3(self):
1478        settings = {
1479            'reboot_device': AP,
1480            'reboot_type': SOFT,
1481            'ipv4': True,
1482            'ipv6': True,
1483            'band': BAND_2G,
1484            'security_mode': hostapd_constants.WPA3_STRING
1485        }
1486        self.run_reboot_test(settings)
1487
1488    def test_soft_reboot_ap_ipv4_ipv6_5g_wpa3(self):
1489        settings = {
1490            'reboot_device': AP,
1491            'reboot_type': SOFT,
1492            'ipv4': True,
1493            'ipv6': True,
1494            'band': BAND_5G,
1495            'security_mode': hostapd_constants.WPA3_STRING
1496        }
1497        self.run_reboot_test(settings)
1498
1499
1500# WPA3 Network AP Hard Reboot (requires a DUT, Whirlwind, and PDU)
1501
1502    def test_hard_reboot_ap_ipv4_2g_wpa3(self):
1503        settings = {
1504            'reboot_device': AP,
1505            'reboot_type': HARD,
1506            'ipv4': True,
1507            'band': BAND_2G,
1508            'security_mode': hostapd_constants.WPA3_STRING
1509        }
1510        self.run_reboot_test(settings)
1511
1512    def test_hard_reboot_ap_ipv4_5g_wpa3(self):
1513        settings = {
1514            'reboot_device': AP,
1515            'reboot_type': HARD,
1516            'ipv4': True,
1517            'band': BAND_5G,
1518            'security_mode': hostapd_constants.WPA3_STRING
1519        }
1520        self.run_reboot_test(settings)
1521
1522    def test_hard_reboot_ap_ipv6_2g_wpa3(self):
1523        settings = {
1524            'reboot_device': AP,
1525            'reboot_type': HARD,
1526            'ipv6': True,
1527            'band': BAND_2G,
1528            'security_mode': hostapd_constants.WPA3_STRING
1529        }
1530        self.run_reboot_test(settings)
1531
1532    def test_hard_reboot_ap_ipv6_5g_wpa3(self):
1533        settings = {
1534            'reboot_device': AP,
1535            'reboot_type': HARD,
1536            'ipv6': True,
1537            'band': BAND_5G,
1538            'security_mode': hostapd_constants.WPA3_STRING
1539        }
1540        self.run_reboot_test(settings)
1541
1542    def test_hard_reboot_ap_ipv4_ipv6_2g_wpa3(self):
1543        settings = {
1544            'reboot_device': AP,
1545            'reboot_type': HARD,
1546            'ipv4': True,
1547            'ipv6': True,
1548            'band': BAND_2G,
1549            'security_mode': hostapd_constants.WPA3_STRING
1550        }
1551        self.run_reboot_test(settings)
1552
1553    def test_hard_reboot_ap_ipv4_ipv6_5g_wpa3(self):
1554        settings = {
1555            'reboot_device': AP,
1556            'reboot_type': HARD,
1557            'ipv4': True,
1558            'ipv6': True,
1559            'band': BAND_5G,
1560            'security_mode': hostapd_constants.WPA3_STRING
1561        }
1562        self.run_reboot_test(settings)
1563
1564    def test_custom_reboots(self):
1565        """Used to create custom reboot tests from ACTS config. Can be
1566        individual tests or permutation sets (i.e. setting "all" for a
1567        test param will run a test with every permutation).
1568
1569        Parameters:
1570            reboot_device: string - "ap", "dut", or "all"
1571            reboot_type: string - "soft", "hard", or "all"
1572            band: string, "2g" - "5g", "all"
1573            ip_version: string - "ipv4", "ipv6", "both", or "all"
1574            interrupt: bool - whether to have traffic flowing at reboot
1575            security_modes: optional, string or list - "open", "wep", "wpa",
1576                "wpa2", "wpa/wpa2", "wpa3", "wpa2/wpa3"
1577            iterations: int - number of iterations for each test
1578            test_name: string (optional, one will be generated)
1579
1580        Example:
1581        "wlan_reboot_test_params": {
1582            "test_custom_reboots": [
1583                {
1584                    "test_name": "test_custom_soft_reboot_dut_2g_dual_ip_open",
1585                    "reboot_device": "dut",
1586                    "reboot_type": "soft",
1587                    "band": "2g",
1588                    "ip_version": "both"
1589                },
1590                {
1591                    "reboot_device": "all",
1592                    "reboot_type": "hard",
1593                    "band": "all",
1594                    "ip_version": ipv4",
1595                    "security_modes": "wpa2",
1596                    "iterations": 10
1597                },
1598                {
1599                    "test_name": "test_custom_hard_reboot_dut_open_and_wpa3",
1600                    "reboot_device": "dut",
1601                    "reboot_type": "hard",
1602                    "band": "5g",
1603                    "ip_version": "ipv4",
1604                    "security_modes": ["open", "wpa3"]
1605                }
1606            ]
1607        }
1608
1609        The first example runs a single DUT soft reboot test with a 2.4GHz
1610        network and dual ipv4/ipv6.
1611
1612        The second example runs 4 tests, each with 10 iterations. It runs hard
1613        reboots with ipv4 for the permutations of DUT/AP and 2.4GHz/5GHz.
1614
1615        The third example runs two tests, both hard reboots of the DUT with 5g
1616        and ipv4 only, one with open security and one with WPA3.
1617        """
1618        asserts.skip_if(
1619            'test_custom_reboots' not in self.wlan_reboot_test_params,
1620            'No custom reboots provided in ACTS config.')
1621        test_list = []
1622        for test in self.wlan_reboot_test_params['test_custom_reboots']:
1623            # Ensure required params are present
1624            try:
1625                reboot_device = test['reboot_device'].lower()
1626                reboot_type = test['reboot_type'].lower()
1627                band = test['band'].lower()
1628                ip_version = test['ip_version'].lower()
1629            except KeyError as err:
1630                raise AttributeError(
1631                    'Must provide reboot_type, reboot_device, ip_version, and '
1632                    'band (optionally interrupt and iterations) in custom test '
1633                    'config. See test_custom_reboots docstring for details. '
1634                    'Err: %s' % err)
1635            security_modes = test.get('security_modes', 'open')
1636            interrupt = str(test.get('interrupt', False)).lower()
1637            iterations = test.get('iterations', 1)
1638
1639            # Validate parameters and convert to lists (for permutations)
1640            try:
1641                reboot_devices = CUSTOM_TEST_REBOOT_DEVICES[reboot_device]
1642                reboot_types = CUSTOM_TEST_REBOOT_TYPES[reboot_type]
1643                bands = CUSTOM_TEST_BANDS[band]
1644                ip_versions = CUSTOM_TEST_IP_VERSIONS[ip_version]
1645                interrupts = CUSTOM_TEST_INTERRUPTS[interrupt]
1646                if isinstance(security_modes, str):
1647                    security_modes = [security_modes]
1648
1649            except KeyError as err:
1650                raise AttributeError(
1651                    'Invalid custom test parameter provided. Err: %s' % err)
1652
1653            # Generate base test name if one is not present
1654            if 'test_name' in test:
1655                test_name = test['test_name']
1656            else:
1657                test_name = create_custom_test_name(reboot_device, reboot_type,
1658                                                    band, ip_version,
1659                                                    interrupt, iterations)
1660
1661            test_settings = {
1662                'test_name': test_name,
1663                'reboot_devices': reboot_devices,
1664                'reboot_types': reboot_types,
1665                'bands': bands,
1666                'ip_versions': ip_versions,
1667                'security_modes': security_modes,
1668                'interrupts': interrupts,
1669                'iterations': iterations
1670            }
1671            test_list.append(test_settings)
1672
1673        # Run all permutations of the test settings
1674        self.run_generated_testcases(self.run_custom_test_permutations,
1675                                     test_list,
1676                                     name_func=get_test_name)
1677
1678    def run_custom_test_permutations(self, settings):
1679        """Runs a custom reboot subtest for each permutation of the provided
1680        test parameters."""
1681        test_list = []
1682        for combination in itertools.product(
1683                settings['reboot_devices'],
1684                settings['reboot_types'],
1685                settings['bands'],
1686                settings['ip_versions'],
1687                settings['security_modes'],
1688                settings['interrupts'],
1689        ):
1690            test_settings = {
1691                'reboot_device': combination[0],
1692                'reboot_type': combination[1],
1693                'band': combination[2],
1694                'ipv4': combination[3][IPV4],
1695                'ipv6': combination[3][IPV6],
1696                'security_mode': combination[4],
1697                'interrupt': combination[5],
1698                'iterations': settings['iterations']
1699            }
1700            test_list.append(test_settings)
1701        self.run_generated_testcases(self.run_reboot_test,
1702                                     test_list,
1703                                     name_func=create_custom_subtest_name)
1704