| #!/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 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 |
| 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=hostapd_constants.WPA2_STRING, |
| password=rand_ascii_str(20), |
| wpa_cipher=hostapd_constants.WPA2_DEFAULT_CIPER, |
| wpa2_cipher=hostapd_constants.WPA2_DEFAULT_CIPER, |
| ) |
| |
| SECURITIES = [None, WPA2_SECURITY] |
| |
| |
| def generate_test_name(settings): |
| """Generates a test name string based on the ac_capabilities for |
| a test case. |
| |
| Args: |
| settings: a dict with the test settings (bandwidth, security, ac_capabs) |
| |
| Returns: |
| A string test case name |
| """ |
| chbw = settings["chbw"] |
| sec = "wpa2" if settings["security"] else "open" |
| ret = [] |
| for cap in hostapd_constants.AC_CAPABILITIES_MAPPING.keys(): |
| if cap in settings["ac_capabilities"]: |
| ret.append(hostapd_constants.AC_CAPABILITIES_MAPPING[cap]) |
| return "test_11ac_%smhz_%s_%s" % (chbw, sec, "".join(ret)) |
| |
| |
| # 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 = ( |
| self._generate_20mhz_test_args() |
| + self._generate_40mhz_test_args() |
| + self._generate_80mhz_test_args() |
| ) |
| 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, ap_settings): |
| """Uses ap_settings to set up ap and then attempts to associate a DUT. |
| |
| Args: |
| ap_settings: a dict containing test case settings, including |
| bandwidth, security, n_capabilities, and ac_capabilities |
| |
| """ |
| ssid = rand_ascii_str(20) |
| security = ap_settings["security"] |
| chbw = ap_settings["chbw"] |
| password = None |
| target_security = None |
| if security: |
| password = security.password |
| target_security = security.security_mode_string |
| n_capabilities = ap_settings["n_capabilities"] |
| ac_capabilities = ap_settings["ac_capabilities"] |
| |
| setup_ap( |
| access_point=self.access_point, |
| profile_name="whirlwind", |
| mode=hostapd_constants.MODE_11AC_MIXED, |
| channel=36, |
| n_capabilities=n_capabilities, |
| ac_capabilities=ac_capabilities, |
| force_wmm=True, |
| ssid=ssid, |
| security=security, |
| vht_bandwidth=chbw, |
| 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): |
| test_args = [] |
| |
| # 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, |
| ): |
| security = combination[0] |
| ac_capabilities = combination[1:] |
| test_args.append( |
| ( |
| { |
| "chbw": 20, |
| "security": security, |
| "n_capabilities": N_CAPABS_20MHZ, |
| "ac_capabilities": ac_capabilities, |
| }, |
| ) |
| ) |
| |
| return test_args |
| |
| # 1728 tests |
| def _generate_40mhz_test_args(self): |
| test_args = [] |
| |
| # 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, |
| ): |
| security = combination[0] |
| ac_capabilities = combination[1:] |
| test_args.append( |
| ( |
| { |
| "chbw": 40, |
| "security": security, |
| "n_capabilities": N_CAPABS_40MHZ, |
| "ac_capabilities": ac_capabilities, |
| }, |
| ) |
| ) |
| |
| return test_args |
| |
| # 3456 tests |
| def _generate_80mhz_test_args(self): |
| test_args = [] |
| |
| # 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, |
| ): |
| security = combination[0] |
| ac_capabilities = combination[1:] |
| test_args.append( |
| ( |
| { |
| "chbw": 80, |
| "security": security, |
| "n_capabilities": N_CAPABS_40MHZ, |
| "ac_capabilities": ac_capabilities, |
| }, |
| ) |
| ) |
| return test_args |
| |
| |
| if __name__ == "__main__": |
| test_runner.main() |