• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3#   Copyright 2021 - 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 time
18from acts import asserts
19from acts import signals
20from acts.test_decorators import test_tracker_info
21import acts_contrib.test_utils.wifi.wifi_test_utils as wutils
22from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
23from acts.controllers.ap_lib.hostapd_constants import BAND_2G
24from acts.controllers.ap_lib.hostapd_constants import BAND_5G
25from acts.controllers.ap_lib import hostapd_constants
26
27# TODO: Find a better way to get real country code and channels data.
28COUNTRY_5G_NOT_ALLOWED = ["JP", "GB", "DE"]
29WIFI_5G_NON_DFS_CHANNELS = [36, 38, 40, 42, 44, 46, 48, 149, 153, 157, 161, 165]
30WIFI_5G_DFS_CHANNELS = [52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140]
31WIFI_EU_SRD_CHANNELS = [149, 153, 157, 161, 165]
32
33BRIDGED_AP_LAUNCH_INTERVAL_5_SECONDS = 5
34WifiEnums = wutils.WifiEnums
35
36
37class WifiCountrySoftApAcsTest(WifiBaseTest):
38    """WiFi WifiSoftApCountryAcsTest test class.
39
40    Test Bed Requirement:
41        * Android DUT x 1.
42        * OpenWrt x 1.
43    """
44
45    def setup_class(self):
46        super().setup_class()
47
48        self.dut = self.android_devices[0]
49        self.client = self.android_devices[1]
50
51        if "OpenWrtAP" in self.user_params:
52            self.openwrt = self.access_points[0]
53            self.openwrt.log.info("Rebooting OpenWrt")
54            self.openwrt.reboot()
55            self.openwrt.verify_wifi_status(timeout=60)
56
57        req_params = []
58        opt_param = []
59
60        self.unpack_userparams(
61            req_param_names=req_params, opt_param_names=opt_param)
62
63    def setup_test(self):
64        super().setup_test()
65        for ad in self.android_devices:
66            wutils.reset_wifi(ad)
67        wutils.wifi_toggle_state(self.dut, True)
68        wutils.wifi_toggle_state(self.client, True)
69
70    def teardown_test(self):
71        super().teardown_test()
72        if self.dut.droid.wifiIsApEnabled():
73            wutils.stop_wifi_tethering(self.dut)
74
75        for ad in self.android_devices:
76            wutils.reset_wifi(ad)
77            wutils.set_wifi_country_code(
78                ad, wutils.WifiEnums.CountryCode.US)
79
80    def teardown_class(self):
81        super().teardown_class()
82        for ad in self.android_devices:
83            wutils.reset_wifi(ad)
84
85        if "AccessPoint" in self.user_params:
86            del self.user_params["reference_networks"]
87            del self.user_params["open_network"]
88
89    def is_bridgedap_supported(self, *args):
90        return self.dut.droid.wifiIsBridgedApConcurrencySupported()
91
92    def set_country_code_and_verify(self, ad, country_code):
93        """ Set Country Code to DUT.
94
95        Args:
96            ad: An AndroidDevice object.
97            country_code: String; 2 letter ISO country code, e,g,. "US".
98        """
99        wutils.set_wifi_country_code(ad, country_code)
100        # Wi-Fi OFF and ON to make sure country code take effect.
101        wutils.wifi_toggle_state(ad, False)
102        wutils.wifi_toggle_state(ad, True)
103
104        country = ad.droid.wifiGetCountryCode()
105        asserts.assert_true(country == country_code,
106                            "country code {} is not set".format(country_code))
107        ad.log.info("Country code set to : {}".format(country))
108
109    def connect_wifi_network(self, init_sta_band, init_sta_chan):
110        """Enable OpenWrt with a 2G/5G channels and a DUT connect to it.
111
112        Args:
113            init_sta_band: String; "2g" or "5g".
114            init_sta_chan: Integer; use to setup OpenWrt 2G/5G channel.
115
116        Returns:
117            ap_freq: Integer'; represent the frequency of the AP which
118            the DUT connect to.
119        """
120
121        # Enable a Wi-Fi network and DUT connect to it.
122        if init_sta_band == BAND_2G:
123            connect = BAND_2G
124            channel_2g = init_sta_chan
125            channel_5g = hostapd_constants.AP_DEFAULT_CHANNEL_5G
126        elif init_sta_band == BAND_5G:
127            connect = BAND_5G
128            channel_2g = hostapd_constants.AP_DEFAULT_CHANNEL_2G
129            channel_5g = init_sta_chan
130
131        # Enable OpenWrt AP.
132        if "OpenWrtAP" in self.user_params:
133            self.openwrt = self.access_points[0]
134            self.configure_openwrt_ap_and_start(wpa_network=True,
135                                                channel_2g=channel_2g,
136                                                channel_5g=channel_5g)
137            self.ap1_2g = self.wpa_networks[0][BAND_2G]
138            self.ap1_5g = self.wpa_networks[0][BAND_5G]
139
140            self.openwrt.log.info("OpenWrt AP 2G: {}".format(self.ap1_2g))
141            self.openwrt.log.info("OpenWrt AP 5G: {}".format(self.ap1_5g))
142
143        if connect == BAND_2G:
144            wutils.connect_to_wifi_network(self.dut, self.ap1_2g)
145        elif connect == BAND_5G:
146            wutils.connect_to_wifi_network(self.dut, self.ap1_5g)
147
148        ap_freq = self.dut.droid.wifiGetConnectionInfo()["frequency"]
149        self.dut.log.info("DUT connected to AP on freq: {}, chan: {}".
150                          format(ap_freq, WifiEnums.freq_to_channel[ap_freq]))
151        return ap_freq
152
153    def enable_softap(self, ad):
154        """ Enable SoftAp of the DUT
155
156        Args:
157            ad: An AndroidDevice object.
158
159        Returns:
160            (freq1, freq2): Integer; a 2G frequency and a 5G frequency if DUT
161                            support BridgedAp.
162            freq: Integer; a frequency from SoftAp.
163            None, bandwidth: Just a placeholder, won't be used.
164
165        Raises:
166            TestFailure if no BridgedAp instances.
167        """
168        # Enable SoftAp
169        # Create SoftAp config.
170        config = wutils.create_softap_config()
171        # If DUT support BridgedAp, then two BridgedAp instances enabled.
172        if self.dut.droid.wifiIsBridgedApConcurrencySupported():
173            wutils.save_wifi_soft_ap_config(
174                ad,
175                config,
176                bands=[WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G,
177                       WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G_5G])
178        # If DUT does not support BridgedAp, 2G OR 5G SoftAp enabled.
179        else:
180            if self.init_softap_band == BAND_2G:
181                band = WifiEnums.WIFI_CONFIG_SOFTAP_BAND_2G
182            elif self.init_softap_band == BAND_5G:
183                band = WifiEnums.WIFI_CONFIG_SOFTAP_BAND_5G
184            wutils.save_wifi_soft_ap_config(ad, config, band=band)
185        wutils.start_wifi_tethering_saved_config(ad)
186        time.sleep(BRIDGED_AP_LAUNCH_INTERVAL_5_SECONDS)
187
188        # if DUT support BridgedAp:
189        if ad.droid.wifiIsBridgedApConcurrencySupported():
190            callbackId = ad.droid.registerSoftApCallback()
191            infos = wutils.get_current_softap_infos(ad, callbackId, True)
192            ad.droid.unregisterSoftApCallback(callbackId)
193            # if DUT BridgedAp has two instances, return two frequencies.
194            if len(infos) == 2:
195                freq_1 = infos[0]["frequency"]
196                freq_2 = infos[1]["frequency"]
197                return freq_1, freq_2
198            # if DUT BridgedAp has only one instances, return the frequency.
199            elif len(infos) == 1:
200                freq = infos[0]["frequency"]
201                return freq, None
202            else:
203                raise signals.TestFailure("There should be SoftAp instance.")
204        # if DUT does not support BridgedAp:
205        else:
206            # Return SoftAp frequency.
207            callbackId = ad.droid.registerSoftApCallback()
208            freq, bandwidth = wutils.get_current_softap_info(ad, callbackId,
209                                                             True)
210            ad.log.info("SoftAp freq: {}".format(freq))
211            ad.droid.unregisterSoftApCallback(callbackId)
212            return freq, bandwidth
213
214    def collect_acs_failures(self, freq1, freq2, country, init_sta_band,
215                             init_sta_chan, init_softap_band):
216        """ Verify SoftAp ACS rules and return error message when fail.
217
218        Args:
219            freq1: Integer; frequency from SoftAp.
220            freq2: Integer; frequency from SoftAp.
221            country: String; Two letters country code, e.g., "US".
222            init_sta_band: String; "2g" or "5g".
223            init_sta_chan: Integer; use to setup OpenWrt 2G/5G channel.
224            init_softap_band: String: "2g" or "5g".
225
226        Returns: List of string; contains failure messages.
227        """
228        # If DUT support BridgedAp(Dual SoftAp).
229        # Decide which is softap_2g_freq, which is softap_5g_freq
230        self.softap_freq_1 = freq1
231        if self.dut.droid.wifiIsBridgedApConcurrencySupported():
232            self.softap_freq_2 = freq2
233            if self.softap_freq_1 in WifiEnums.ALL_2G_FREQUENCIES:
234                self.softap_2g_freq = self.softap_freq_1
235            elif self.softap_freq_1 in WifiEnums.ALL_5G_FREQUENCIES:
236                self.softap_5g_freq = self.softap_freq_1
237            if self.softap_freq_2 in WifiEnums.ALL_2G_FREQUENCIES:
238                self.softap_2g_freq = self.softap_freq_2
239            elif self.softap_freq_2 in WifiEnums.ALL_5G_FREQUENCIES:
240                self.softap_5g_freq = self.softap_freq_2
241        # If DUT does not support BridgedAp(Dual SoftAp).
242        # Decide the frequency is softap_2g_freq or softap_5g_freq
243        else:
244            if self.softap_freq_1 in WifiEnums.ALL_2G_FREQUENCIES:
245                self.softap_2g_freq = self.softap_freq_1
246            elif self.softap_freq_1 in WifiEnums.ALL_5G_FREQUENCIES:
247                self.softap_5g_freq = self.softap_freq_1
248
249        # Verify ACS when SoftAp 2G enabled.
250        failures = []
251        if init_softap_band == BAND_2G:
252            if init_sta_band == BAND_2G:
253                self.dut.log.info("Verifying 2G SoftAp chan == 2G STA chan")
254                if self.softap_2g_freq != self.actual_sta_freq:
255                    failures.append("Expect 2G SoftAp chan == 2G STA chan")
256            else:
257                self.dut.log.info("Verifying SoftAp still operates on 2G")
258                if self.softap_2g_freq not in WifiEnums.ALL_2G_FREQUENCIES:
259                    failures.append("Expect SoftAp still operates on 2G")
260
261        # Verify ACS when SoftAp 5G enabled.
262        elif init_softap_band == BAND_5G:
263            if (country in COUNTRY_5G_NOT_ALLOWED or
264               init_sta_chan in WIFI_5G_DFS_CHANNELS or
265               init_sta_chan in WIFI_EU_SRD_CHANNELS):
266                self.dut.log.info("Verifying SoftAp fallback to 2G")
267                if self.softap_2g_freq not in WifiEnums.ALL_2G_FREQUENCIES:
268                    failures.append("Expect SoftAp fallback to 2G.")
269            else:
270                if init_sta_band == BAND_2G:
271                    self.dut.log.info("Verifying SoftAp still operates on 5G")
272                    if self.softap_5g_freq not in WifiEnums.ALL_5G_FREQUENCIES:
273                        failures.append("Expect SoftAp still operates on 5G.")
274                elif init_sta_chan in WIFI_5G_NON_DFS_CHANNELS:
275                    self.dut.log.info("Verify 5G SoftAp chan == 5g STA chan")
276                    if self.softap_5g_freq != self.actual_sta_freq:
277                        failures.append("Expect 5G SoftAp chan == 5G STA chan")
278        failures = "\n".join(failures)
279        return failures
280
281    def validate_country_softap_acs(self, country, init_sta_band,
282                                    init_sta_chan, init_softap_band):
283        """ Verify SoftAp ACS on certain country work as expected.
284
285        Steps:
286            Get country, STA band, STA channel from test case name.
287            Set a country code to the DUT.
288            Enable a Wi-Fi network.
289            DUT connects to the Wi-Fi  network.
290            DUT enable SoftAp.
291                P20 and previous
292                    Enable SoftAp (2G OR 5G).
293                P21 and later:
294                    Enable BridgedAp (2G AND 5G)
295            Get SoftAp(or BridgedAp) channel.
296            Get AP channel.
297            Verify Country SoftAp ACS.
298
299        Args:
300            country: String; Two letters country code, e.g., "US".
301            init_sta_band: String; "2g" or "5g".
302            init_sta_chan: Integer; use to setup OpenWrt 2G/5G channel.
303            init_softap_band: String: "2g" or "5g".
304
305        Returns: List of string; contains failure messages.
306         """
307        self.init_softap_band = init_softap_band
308        # Set a country code to the DUT.
309        self.set_country_code_and_verify(self.dut, country)
310        # Get DUT STA frequency.
311        self.actual_sta_freq = self.connect_wifi_network(init_sta_band,
312                                                         init_sta_chan)
313        # DUT Enable SoftAp.
314        freq1, freq2 = self.enable_softap(self.dut)
315        # Verify Country SoftAp ACS.
316        return self.collect_acs_failures(freq1, freq2, country, init_sta_band,
317                                         init_sta_chan, init_softap_band)
318
319    # Tests
320
321    @test_tracker_info(uuid="003c67f7-f4cc-4f04-ab34-28c71a7602d9")
322    def test_country_us_softap_acs_sta_2g_ch_1_softap_2g(self):
323        """Verify SoftAp ACS on STA 2G CH1 and SoftAp 2G in US.
324           Steps: See docstring of validate_country_softap_acs()."""
325        failures = self.validate_country_softap_acs("US", "2g", 1, "2g")
326        asserts.assert_false(failures, str(failures))
327
328    @test_tracker_info(uuid="b3c0a7a4-150f-469c-9191-8d446b2e2593")
329    def test_country_us_softap_acs_sta_5g_ch_36_softap_2g(self):
330        """Verify SoftAp ACS on STA 5G NON-DFS CH36 and SoftAp 2G in US.
331           Steps: See docstring of validate_country_softap_acs()."""
332        failures = self.validate_country_softap_acs("US", "5g", 36, "2g")
333        asserts.assert_false(failures, str(failures))
334
335    @test_tracker_info(uuid="7c660706-e63d-4753-bb6e-dacdf4c36cc0")
336    def test_country_us_softap_acs_sta_5g_ch_132_softap_2g(self):
337        """Verify SoftAp ACS on STA 5G DFS CH52 and SoftAp 2G in US.
338           Steps: See docstring of validate_country_softap_acs()."""
339        failures = self.validate_country_softap_acs("US", "5g", 132, "2g")
340        asserts.assert_false(failures, str(failures))
341
342    @test_tracker_info(uuid="31973348-852e-4cd7-9a72-6e8f333623c5")
343    def test_country_de_softap_acs_sta_5g_ch_161_softap_2g(self):
344        """Verify SoftAp ACS on STA 5G EU SRD CH149 and SoftAp 2G in DE.
345           Steps: See docstring of validate_country_softap_acs()."""
346        failures = self.validate_country_softap_acs("US", "5g", 161, "2g")
347        asserts.assert_false(failures, str(failures))
348
349    @test_tracker_info(uuid="8ebba60c-a32c-46b3-b9da-411b1ef66288")
350    def test_country_us_softap_acs_sta_2g_ch_1_softap_5g(self):
351        """Verify SoftAp ACS on STA 2G CH1 and SoftAp 5G in US.
352           Steps: See docstring of validate_country_softap_acs()."""
353        failures = self.validate_country_softap_acs("US", "2g", 1, "5g")
354        asserts.assert_false(failures, str(failures))
355
356    @test_tracker_info(uuid="503ece09-3030-4a69-ae15-320f5104ddd2")
357    def test_country_us_softap_acs_sta_5g_ch_36_softap_5g(self):
358        """Verify SoftAp ACS on STA 5G NON-DFS CH36 and SoftAp 5G in US.
359           Steps: See docstring of validate_country_softap_acs()."""
360        failures = self.validate_country_softap_acs("US", "5g", 36, "5g")
361        asserts.assert_false(failures, str(failures))
362
363    @test_tracker_info(uuid="35a5f2f5-067d-4d67-aeb8-58fb253f4b97")
364    def test_country_us_softap_acs_sta_5g_ch_132_softap_5g(self):
365        """Verify SoftAp ACS on STA 5G DFS CH52 and SoftAp 5G in US.
366           Steps: See docstring of validate_country_softap_acs()."""
367        failures = self.validate_country_softap_acs("US", "5g", 132, "5g")
368        asserts.assert_false(failures, str(failures))
369
370    @test_tracker_info(uuid="866954a3-72b6-4e7d-853f-9e1659cdf305")
371    def test_country_de_softap_acs_sta_5g_ch_161_softap_5g(self):
372        """Verify SoftAp ACS on STA 5G EU SRD CH149 and SoftAp 5G in DE.
373           Steps: See docstring of validate_country_softap_acs()."""
374        failures = self.validate_country_softap_acs("DE", "5g", 161, "5g")
375        asserts.assert_false(failures, str(failures))
376
377    @test_tracker_info(uuid="866954a3-72b6-4e7d-853f-9e1659cdf305")
378    def test_country_jp_softap_acs_sta_5g_ch_36_softap_5g(self):
379        """Verify SoftAp ACS on STA 5G EU SRD CH149 and SoftAp 5G in DE.
380           Steps: See docstring of validate_country_softap_acs()."""
381        failures = self.validate_country_softap_acs("JP", "5g", 36, "5g")
382        asserts.assert_false(failures, str(failures))
383