| #!/usr/bin/env python3 |
| # |
| # Copyright 2020 - The Android Open Source Project |
| # |
| # 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 |
| import re |
| |
| from acts import asserts |
| from acts import utils |
| from acts.controllers.access_point import setup_ap |
| from acts.controllers.ap_lib.hostapd_security import Security |
| from acts.controllers.ap_lib import hostapd_constants |
| from acts.controllers.ap_lib import hostapd_config |
| from acts_contrib.test_utils.abstract_devices.wlan_device import create_wlan_device |
| from acts_contrib.test_utils.abstract_devices.wlan_device_lib.AbstractDeviceWlanDeviceBaseTest import AbstractDeviceWlanDeviceBaseTest |
| from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest |
| from acts.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) |
| |
| |
| 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(AbstractDeviceWlanDeviceBaseTest): |
| """Tests for validating 11ac PHYS. |
| |
| Test Bed Requirement: |
| * One Android device or Fuchsia device |
| * One Access Point |
| """ |
| |
| def __init__(self, controllers): |
| WifiBaseTest.__init__(self, controllers) |
| self.tests = [ |
| 'test_11ac_capabilities_20mhz_open', |
| 'test_11ac_capabilities_40mhz_open', |
| 'test_11ac_capabilities_80mhz_open', |
| 'test_11ac_capabilities_20mhz_wpa2', |
| 'test_11ac_capabilities_40mhz_wpa2', |
| 'test_11ac_capabilities_80mhz_wpa2' |
| ] |
| if 'debug_11ac_tests' in self.user_params: |
| self.tests.append('test_11ac_capabilities_debug') |
| |
| def setup_class(self): |
| super().setup_class() |
| if 'dut' in self.user_params: |
| if self.user_params['dut'] == 'fuchsia_devices': |
| self.dut = create_wlan_device(self.fuchsia_devices[0]) |
| elif self.user_params['dut'] == 'android_devices': |
| self.dut = create_wlan_device(self.android_devices[0]) |
| else: |
| raise ValueError('Invalid DUT specified in config. (%s)' % |
| self.user_params['dut']) |
| else: |
| self.dut = create_wlan_device(self.android_devices[0]) |
| |
| 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, test_name, begin_time): |
| super().on_fail(test_name, begin_time) |
| 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.') |
| |
| # 864 test cases |
| def test_11ac_capabilities_20mhz_open(self): |
| test_list = [] |
| for combination in itertools.product(VHT_MAX_MPDU_LEN, RXLDPC, RX_STBC, |
| TX_STBC, MAX_A_MPDU, RX_ANTENNA, |
| TX_ANTENNA): |
| test_list.append({ |
| 'chbw': 20, |
| 'security': None, |
| 'n_capabilities': N_CAPABS_20MHZ, |
| 'ac_capabilities': combination |
| }) |
| self.run_generated_testcases(self.setup_and_connect, |
| settings=test_list, |
| name_func=generate_test_name) |
| |
| # 864 test cases |
| def test_11ac_capabilities_40mhz_open(self): |
| test_list = [] |
| for combination in itertools.product(VHT_MAX_MPDU_LEN, RXLDPC, RX_STBC, |
| TX_STBC, MAX_A_MPDU, RX_ANTENNA, |
| TX_ANTENNA): |
| test_list.append({ |
| 'chbw': 40, |
| 'security': None, |
| 'n_capabilities': N_CAPABS_40MHZ, |
| 'ac_capabilities': combination |
| }) |
| self.run_generated_testcases(self.setup_and_connect, |
| settings=test_list, |
| name_func=generate_test_name) |
| |
| # 1728 test cases |
| def test_11ac_capabilities_80mhz_open(self): |
| test_list = [] |
| for combination in itertools.product(VHT_MAX_MPDU_LEN, RXLDPC, |
| SHORT_GI_80, RX_STBC, TX_STBC, |
| MAX_A_MPDU, RX_ANTENNA, |
| TX_ANTENNA): |
| test_list.append({ |
| 'chbw': 80, |
| 'security': None, |
| 'n_capabilities': N_CAPABS_40MHZ, |
| 'ac_capabilities': combination |
| }) |
| self.run_generated_testcases(self.setup_and_connect, |
| settings=test_list, |
| name_func=generate_test_name) |
| |
| # 864 test cases |
| def test_11ac_capabilities_20mhz_wpa2(self): |
| test_list = [] |
| for combination in itertools.product(VHT_MAX_MPDU_LEN, RXLDPC, RX_STBC, |
| TX_STBC, MAX_A_MPDU, RX_ANTENNA, |
| TX_ANTENNA): |
| test_list.append({ |
| 'chbw': 20, |
| 'security': WPA2_SECURITY, |
| 'n_capabilities': N_CAPABS_20MHZ, |
| 'ac_capabilities': combination |
| }) |
| self.run_generated_testcases(self.setup_and_connect, |
| settings=test_list, |
| name_func=generate_test_name) |
| |
| # 864 test cases |
| def test_11ac_capabilities_40mhz_wpa2(self): |
| test_list = [] |
| for combination in itertools.product(VHT_MAX_MPDU_LEN, RXLDPC, RX_STBC, |
| TX_STBC, MAX_A_MPDU, RX_ANTENNA, |
| TX_ANTENNA): |
| test_list.append({ |
| 'chbw': 40, |
| 'security': WPA2_SECURITY, |
| 'n_capabilities': N_CAPABS_40MHZ, |
| 'ac_capabilities': combination |
| }) |
| self.run_generated_testcases(self.setup_and_connect, |
| settings=test_list, |
| name_func=generate_test_name) |
| |
| # 1728 test cases |
| def test_11ac_capabilities_80mhz_wpa2(self): |
| test_list = [] |
| for combination in itertools.product(VHT_MAX_MPDU_LEN, RXLDPC, |
| SHORT_GI_80, RX_STBC, TX_STBC, |
| MAX_A_MPDU, RX_ANTENNA, |
| TX_ANTENNA): |
| test_list.append({ |
| 'chbw': 80, |
| 'security': WPA2_SECURITY, |
| 'n_capabilities': N_CAPABS_40MHZ, |
| 'ac_capabilities': combination |
| }) |
| self.run_generated_testcases(self.setup_and_connect, |
| settings=test_list, |
| name_func=generate_test_name) |
| |
| def test_11ac_capabilities_debug(self): |
| chbw_sec_capabs = re.compile( |
| r'.*?([0-9]*)mhz.*?(open|wpa2).*?(\[.*\])', re.IGNORECASE) |
| test_list = [] |
| for test_name in self.user_params['debug_11ac_tests']: |
| test_to_run = re.match(chbw_sec_capabs, test_name) |
| chbw = int(test_to_run.group(1)) |
| security = test_to_run.group(2) |
| capabs = test_to_run.group(3) |
| if chbw >= 40: |
| n_capabs = N_CAPABS_40MHZ |
| else: |
| n_capabs = N_CAPABS_20MHZ |
| if security.lower() == 'open': |
| security = None |
| elif security.lower() == 'wpa2': |
| security = WPA2_SECURITY |
| if capabs: |
| ac_capabs_strings = re.findall(r'\[.*?\]', capabs) |
| ac_capabs = [ |
| hostapd_constants.AC_CAPABILITIES_MAPPING_INVERSE[k] |
| for k in ac_capabs_strings |
| ] |
| test_list.append({ |
| 'chbw': chbw, |
| 'security': security, |
| 'n_capabilities': n_capabs, |
| 'ac_capabilities': ac_capabs |
| }) |
| self.run_generated_testcases(self.setup_and_connect, |
| settings=test_list, |
| name_func=generate_test_name) |