| #!/usr/bin/env python3 |
| # |
| # Copyright 2022 The Fuchsia Authors |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import itertools |
| from dataclasses import dataclass |
| from typing import Any, List, Optional |
| |
| from mobly import asserts, test_runner |
| from mobly.records import TestResultRecord |
| |
| from antlion.controllers.access_point import setup_ap |
| from antlion.controllers.ap_lib import hostapd_constants |
| from antlion.controllers.ap_lib.hostapd_security import Security, SecurityMode |
| from antlion.test_utils.abstract_devices.wlan_device import create_wlan_device |
| from antlion.test_utils.wifi import base_test |
| from antlion.utils import rand_ascii_str |
| |
| # AC Capabilities |
| """ |
| Capabilities Not Supported on Whirlwind: |
| - Supported Channel Width ([VHT160], [VHT160-80PLUS80]): 160mhz and 80+80 |
| unsupported |
| - SU Beamformer [SU-BEAMFORMER] |
| - SU Beamformee [SU-BEAMFORMEE] |
| - MU Beamformer [MU-BEAMFORMER] |
| - MU Beamformee [MU-BEAMFORMEE] |
| - BF Antenna ([BF-ANTENNA-2], [BF-ANTENNA-3], [BF-ANTENNA-4]) |
| - Rx STBC 2, 3, & 4 ([RX-STBC-12],[RX-STBC-123],[RX-STBC-124]) |
| - VHT Link Adaptation ([VHT-LINK-ADAPT2],[VHT-LINK-ADAPT3]) |
| - VHT TXOP Power Save [VHT-TXOP-PS] |
| - HTC-VHT [HTC-VHT] |
| """ |
| VHT_MAX_MPDU_LEN = [ |
| hostapd_constants.AC_CAPABILITY_MAX_MPDU_7991, |
| hostapd_constants.AC_CAPABILITY_MAX_MPDU_11454, |
| "", |
| ] |
| RXLDPC = [hostapd_constants.AC_CAPABILITY_RXLDPC, ""] |
| SHORT_GI_80 = [hostapd_constants.AC_CAPABILITY_SHORT_GI_80, ""] |
| TX_STBC = [hostapd_constants.AC_CAPABILITY_TX_STBC_2BY1, ""] |
| RX_STBC = [hostapd_constants.AC_CAPABILITY_RX_STBC_1, ""] |
| MAX_A_MPDU = [ |
| hostapd_constants.AC_CAPABILITY_MAX_A_MPDU_LEN_EXP0, |
| hostapd_constants.AC_CAPABILITY_MAX_A_MPDU_LEN_EXP1, |
| hostapd_constants.AC_CAPABILITY_MAX_A_MPDU_LEN_EXP2, |
| hostapd_constants.AC_CAPABILITY_MAX_A_MPDU_LEN_EXP3, |
| hostapd_constants.AC_CAPABILITY_MAX_A_MPDU_LEN_EXP4, |
| hostapd_constants.AC_CAPABILITY_MAX_A_MPDU_LEN_EXP5, |
| hostapd_constants.AC_CAPABILITY_MAX_A_MPDU_LEN_EXP6, |
| hostapd_constants.AC_CAPABILITY_MAX_A_MPDU_LEN_EXP7, |
| "", |
| ] |
| RX_ANTENNA = [hostapd_constants.AC_CAPABILITY_RX_ANTENNA_PATTERN, ""] |
| TX_ANTENNA = [hostapd_constants.AC_CAPABILITY_TX_ANTENNA_PATTERN, ""] |
| |
| # Default 11N Capabilities |
| N_CAPABS_40MHZ = [ |
| hostapd_constants.N_CAPABILITY_LDPC, |
| hostapd_constants.N_CAPABILITY_SGI20, |
| hostapd_constants.N_CAPABILITY_RX_STBC1, |
| hostapd_constants.N_CAPABILITY_SGI20, |
| hostapd_constants.N_CAPABILITY_SGI40, |
| hostapd_constants.N_CAPABILITY_MAX_AMSDU_7935, |
| hostapd_constants.N_CAPABILITY_HT40_PLUS, |
| ] |
| |
| N_CAPABS_20MHZ = [ |
| hostapd_constants.N_CAPABILITY_LDPC, |
| hostapd_constants.N_CAPABILITY_SGI20, |
| hostapd_constants.N_CAPABILITY_RX_STBC1, |
| hostapd_constants.N_CAPABILITY_SGI20, |
| hostapd_constants.N_CAPABILITY_MAX_AMSDU_7935, |
| hostapd_constants.N_CAPABILITY_HT20, |
| ] |
| |
| # Default wpa2 profile. |
| WPA2_SECURITY = Security( |
| security_mode=SecurityMode.WPA2, |
| password=rand_ascii_str(20), |
| wpa_cipher=hostapd_constants.WPA2_DEFAULT_CIPER, |
| wpa2_cipher=hostapd_constants.WPA2_DEFAULT_CIPER, |
| ) |
| |
| SECURITIES: List[Security] = [Security(), WPA2_SECURITY] |
| |
| |
| @dataclass |
| class TestParams: |
| security: Security |
| vht_bandwidth_mhz: int |
| # TODO(http://b/290396383): Type AP capabilities as enums |
| n_capabilities: List[Any] |
| ac_capabilities: List[Any] |
| |
| |
| # 6912 test cases |
| class WlanPhyCompliance11ACTest(base_test.WifiBaseTest): |
| """Tests for validating 11ac PHYS. |
| |
| Test Bed Requirement: |
| * One Android device or Fuchsia device |
| * One Access Point |
| """ |
| |
| def __init__(self, controllers): |
| super().__init__(controllers) |
| |
| def setup_generated_tests(self): |
| test_args: List[TestParams] = ( |
| self._generate_20mhz_test_args() |
| + self._generate_40mhz_test_args() |
| + self._generate_80mhz_test_args() |
| ) |
| |
| def generate_test_name(test: TestParams): |
| ret = [] |
| for cap in hostapd_constants.AC_CAPABILITIES_MAPPING.keys(): |
| if cap in test.ac_capabilities: |
| ret.append(hostapd_constants.AC_CAPABILITIES_MAPPING[cap]) |
| return ( |
| f"test_11ac_{test.vht_bandwidth_mhz}mhz_{test.security}_{''.join(ret)}" |
| ) |
| |
| self.generate_tests( |
| test_logic=self.setup_and_connect, |
| name_func=generate_test_name, |
| arg_sets=test_args, |
| ) |
| |
| def setup_class(self): |
| super().setup_class() |
| |
| device_type = self.user_params.get("dut", "fuchsia_devices") |
| if device_type == "fuchsia_devices": |
| self.dut = create_wlan_device(self.fuchsia_devices[0]) |
| elif device_type == "android_devices": |
| self.dut = create_wlan_device(self.android_devices[0]) |
| else: |
| raise ValueError( |
| f'Invalid "dut" type specified in config: "{device_type}".' |
| 'Expected "fuchsia_devices" or "android_devices".' |
| ) |
| |
| self.access_point = self.access_points[0] |
| self.android_devices = getattr(self, "android_devices", []) |
| self.access_point.stop_all_aps() |
| |
| def setup_test(self): |
| for ad in self.android_devices: |
| ad.droid.wakeLockAcquireBright() |
| ad.droid.wakeUpNow() |
| self.dut.wifi_toggle_state(True) |
| |
| def teardown_test(self): |
| for ad in self.android_devices: |
| ad.droid.wakeLockRelease() |
| ad.droid.goToSleepNow() |
| self.dut.turn_location_off_and_scan_toggle_off() |
| self.dut.disconnect() |
| self.dut.reset_wifi() |
| self.download_ap_logs() |
| self.access_point.stop_all_aps() |
| |
| def on_fail(self, record: TestResultRecord): |
| super().on_fail(record) |
| self.access_point.stop_all_aps() |
| |
| def setup_and_connect(self, test: TestParams): |
| """Setup the AP and then attempt to associate a DUT. |
| |
| Args: |
| test: Test parameters |
| """ |
| ssid = rand_ascii_str(20) |
| password: Optional[str] = None |
| target_security = SecurityMode.OPEN |
| if test.security: |
| password = test.security.password |
| target_security = test.security.security_mode |
| |
| setup_ap( |
| access_point=self.access_point, |
| profile_name="whirlwind", |
| mode=hostapd_constants.MODE_11AC_MIXED, |
| channel=36, |
| n_capabilities=test.n_capabilities, |
| ac_capabilities=test.ac_capabilities, |
| force_wmm=True, |
| ssid=ssid, |
| security=test.security, |
| vht_bandwidth=test.vht_bandwidth_mhz, |
| password=password, |
| ) |
| asserts.assert_true( |
| self.dut.associate( |
| ssid, target_pwd=password, target_security=target_security |
| ), |
| "Failed to associate.", |
| ) |
| |
| # 1728 tests |
| def _generate_20mhz_test_args(self) -> List[TestParams]: |
| test_args: List[TestParams] = [] |
| |
| # 864 test cases for open security |
| # 864 test cases for wpa2 security |
| for combination in itertools.product( |
| SECURITIES, |
| VHT_MAX_MPDU_LEN, |
| RXLDPC, |
| RX_STBC, |
| TX_STBC, |
| MAX_A_MPDU, |
| RX_ANTENNA, |
| TX_ANTENNA, |
| ): |
| test_args.append( |
| TestParams( |
| vht_bandwidth_mhz=20, |
| security=combination[0], |
| n_capabilities=N_CAPABS_20MHZ, |
| ac_capabilities=list(combination[1:]), |
| ) |
| ) |
| |
| return test_args |
| |
| # 1728 tests |
| def _generate_40mhz_test_args(self) -> List[TestParams]: |
| test_args: List[TestParams] = [] |
| |
| # 864 test cases for open security |
| # 864 test cases for wpa2 security |
| for combination in itertools.product( |
| SECURITIES, |
| VHT_MAX_MPDU_LEN, |
| RXLDPC, |
| RX_STBC, |
| TX_STBC, |
| MAX_A_MPDU, |
| RX_ANTENNA, |
| TX_ANTENNA, |
| ): |
| test_args.append( |
| TestParams( |
| vht_bandwidth_mhz=40, |
| security=combination[0], |
| n_capabilities=N_CAPABS_40MHZ, |
| ac_capabilities=list(combination[1:]), |
| ) |
| ) |
| |
| return test_args |
| |
| # 3456 tests |
| def _generate_80mhz_test_args(self) -> List[TestParams]: |
| test_args: List[TestParams] = [] |
| |
| # 1728 test cases for open security |
| # 1728 test cases for wpa2 security |
| for combination in itertools.product( |
| SECURITIES, |
| VHT_MAX_MPDU_LEN, |
| RXLDPC, |
| SHORT_GI_80, |
| RX_STBC, |
| TX_STBC, |
| MAX_A_MPDU, |
| RX_ANTENNA, |
| TX_ANTENNA, |
| ): |
| test_args.append( |
| TestParams( |
| vht_bandwidth_mhz=80, |
| security=combination[0], |
| n_capabilities=N_CAPABS_40MHZ, |
| ac_capabilities=list(combination[1:]), |
| ) |
| ) |
| return test_args |
| |
| |
| if __name__ == "__main__": |
| test_runner.main() |