blob: 87b07d08cff9441e074e9cd1c565a149ebfbd561 [file] [log] [blame]
Hayden Nix3f2eebf2020-01-14 10:39:21 -08001#!/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
18
19from acts import utils
20from acts.controllers.ap_lib import hostapd_constants
21from acts.controllers.ap_lib import hostapd_config
22from acts.test_utils.abstract_devices.wlan_device import create_wlan_device
23from acts.test_utils.abstract_devices.utils_lib.wlan_utils import validate_setup_ap_and_associate
24from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest
25from acts.utils import rand_ascii_str
26
27# 12, 13 outside the US
28# 14 in Japan, DSSS and CCK only
29CHANNELS_24 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
30
31# 32, 34 for 20 and 40 mhz in Europe
32# 34, 42, 46 have mixed international support
33# 144 is supported by some chips
34CHANNELS_5 = [
35 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128,
36 132, 136, 140, 144, 149, 153, 157, 161, 165
37]
38
39BANDWIDTH_24 = [20, 40]
40BANDWIDTH_5 = [20, 40, 80]
41
42N_CAPABILITIES_DEFAULT = [
43 hostapd_constants.N_CAPABILITY_LDPC, hostapd_constants.N_CAPABILITY_SGI20,
44 hostapd_constants.N_CAPABILITY_SGI40,
45 hostapd_constants.N_CAPABILITY_TX_STBC,
46 hostapd_constants.N_CAPABILITY_RX_STBC1
47]
48
49AC_CAPABILITIES_DEFAULT = [
50 hostapd_constants.AC_CAPABILITY_MAX_MPDU_11454,
51 hostapd_constants.AC_CAPABILITY_RXLDPC,
52 hostapd_constants.AC_CAPABILITY_SHORT_GI_80,
53 hostapd_constants.AC_CAPABILITY_TX_STBC_2BY1,
54 hostapd_constants.AC_CAPABILITY_RX_STBC_1,
55 hostapd_constants.AC_CAPABILITY_MAX_A_MPDU_LEN_EXP7,
56 hostapd_constants.AC_CAPABILITY_RX_ANTENNA_PATTERN,
57 hostapd_constants.AC_CAPABILITY_TX_ANTENNA_PATTERN
58]
59
60
61def generate_test_name(settings):
62 """Generates a string test name based on the channel and band
63
64 Args:
65 settings: A dict with 'channel' and 'bandwidth' keys.
66
67 Returns:
68 A string that represents a test case name.
69 """
70 return 'test_channel_%s_bandwidth_%smhz' % (settings['channel'],
71 settings['bandwidth'])
72
73
74class ChannelSweepTest(WifiBaseTest):
75 """Tests for associating with all 2.5 and 5 channels and bands.
76
77 Testbed Requirement:
78 * One ACTS compatible device (dut)
79 * One Access Point
80 """
81 def __init__(self, controllers):
82 WifiBaseTest.__init__(self, controllers)
83 self.tests = ['test_24ghz_channels', 'test_5ghz_channels']
84 if 'debug_channel_sweep_tests' in self.user_params:
85 self.tests.append('test_channel_sweep_debug')
86
87 def setup_class(self):
88 super().setup_class()
89 if 'dut' in self.user_params:
90 if self.user_params['dut'] == 'fuchsia_devices':
91 self.dut = create_wlan_device(self.fuchsia_devices[0])
92 elif self.user_params['dut'] == 'android_devices':
93 self.dut = create_wlan_device(self.android_devices[0])
94 else:
95 raise ValueError('Invalid DUT specified in config. (%s)' %
96 self.user_params['dut'])
97 else:
98 # Default is an android device, just like the other tests
99 self.dut = create_wlan_device(self.android_devices[0])
100
101 self.android_devices = getattr(self, 'android_devices', [])
102 self.access_point = self.access_points[0]
103 self.access_point.stop_all_aps()
104
105 def setup_test(self):
106 for ad in self.android_devices:
107 ad.droid.wakeLockAcquireBright()
108 ad.droid.wakeUpNow()
109 self.dut.wifi_toggle_state(True)
110
111 def teardown_test(self):
112 for ad in self.android_devices:
113 ad.droid.wakeLockRelease()
114 ad.droid.goToSleepNow()
115 self.dut.turn_location_off_and_scan_toggle_off()
116 self.dut.disconnect()
117 self.dut.reset_wifi()
118 self.access_point.stop_all_aps()
119
120 def on_fail(self, test_name, begin_time):
121 self.dut.take_bug_report(test_name, begin_time)
122 self.dut.get_log(test_name, begin_time)
123
124 def setup_and_connect(self, settings):
125 """Generates a hostapd config based on the provided channel and
126 bandwidth, starts AP with that config, and attempts to associate the
127 dut.
128
129 Args:
130 settings: A dict with 'channel' and 'bandwidth' keys.
131 """
132 channel = settings['channel']
133 bandwidth = settings['bandwidth']
134 if channel > 14:
135 vht_bandwidth = bandwidth
136 else:
137 vht_bandwidth = None
138
139 if bandwidth == 20:
140 n_capabilities = N_CAPABILITIES_DEFAULT + [
141 hostapd_constants.N_CAPABILITY_HT20
142 ]
143 elif bandwidth == 40 or bandwidth == 80:
144 if hostapd_config.ht40_plus_allowed(channel):
145 extended_channel = [hostapd_constants.N_CAPABILITY_HT40_PLUS]
146 elif hostapd_config.ht40_minus_allowed(channel):
147 extended_channel = [hostapd_constants.N_CAPABILITY_HT40_MINUS]
148 else:
149 raise ValueError('Invalid Channel: %s' % channel)
150 n_capabilities = N_CAPABILITIES_DEFAULT + extended_channel
151 else:
152 raise ValueError('Invalid Bandwidth: %s' % bandwidth)
153
154 validate_setup_ap_and_associate(access_point=self.access_point,
155 client=self.dut,
156 profile_name='whirlwind',
157 channel=channel,
158 n_capabilities=n_capabilities,
159 ac_capabilities=None,
160 force_wmm=True,
161 ssid=utils.rand_ascii_str(20),
162 vht_bandwidth=vht_bandwidth)
163
164 def create_test_settings(self, channels, bandwidths):
165 """Creates a list of test configurations to run from the product of the
166 given channels list and bandwidths list.
167
168 Args:
169 channels: A list of ints representing the channels to test.
170 bandwidths: A list of ints representing the bandwidths to test on
171 those channels.
172
173 Returns:
174 A list of dictionaries containing 'channel' and 'bandwidth' keys,
175 one for each test combination to be run.
176 """
177 test_list = []
178 for combination in itertools.product(channels, bandwidths):
179 test_settings = {
180 'channel': combination[0],
181 'bandwidth': combination[1]
182 }
183 test_list.append(test_settings)
184 return test_list
185
186 def test_24ghz_channels(self):
187 """Runs setup_and_connect for 2.4GHz channels on 20 and 40 MHz bands."""
188 test_list = self.create_test_settings(CHANNELS_24, BANDWIDTH_24)
189 self.run_generated_testcases(self.setup_and_connect,
190 settings=test_list,
191 name_func=generate_test_name)
192
193 def test_5ghz_channels(self):
194 """Runs setup_and_connect for 5GHz channels on 20, 40, and 80 MHz bands.
195 """
196 test_list = self.create_test_settings(CHANNELS_5, BANDWIDTH_5)
197 # Channel 165 is 20mhz only
198 test_list.remove({'channel': 165, 'bandwidth': 40})
199 test_list.remove({'channel': 165, 'bandwidth': 80})
200 self.run_generated_testcases(self.setup_and_connect,
201 settings=test_list,
202 name_func=generate_test_name)
203
204 def test_channel_sweep_debug(self):
205 """Runs test cases defined in the ACTS config file for debugging
206 purposes.
207
208 Usage:
209 1. Add 'debug_channel_sweep_tests' to ACTS config with list of
210 tests to run matching pattern:
211 test_channel_<CHANNEL>_bandwidth_<BANDWIDTH>
212 2. Run test_channel_sweep_debug test.
213 """
214 allowed_channels = CHANNELS_24 + CHANNELS_5
215 chan_band_pattern = re.compile(
216 r'.*channel_([0-9]*)_.*bandwidth_([0-9]*)')
217 test_list = []
218 for test_title in self.user_params['debug_channel_sweep_tests']:
219 test = re.match(chan_band_pattern, test_title)
220 if test:
221 channel = int(test.group(1))
222 bandwidth = int(test.group(2))
223 if channel not in allowed_channels:
224 raise ValueError("Invalid channel: %s" % channel)
225 if channel <= 14 and bandwidth not in BANDWIDTH_24:
226 raise ValueError(
227 "Channel %s does not support bandwidth %s" %
228 (channel, bandwidth))
229 test_settings = {'channel': channel, 'bandwidth': bandwidth}
230 test_list.append(test_settings)
231
232 self.run_generated_testcases(self.setup_and_connect,
233 settings=test_list,
234 name_func=generate_test_name)