• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3.4
2#
3#   Copyright 2016 - 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
18import queue
19import time
20import traceback
21
22from acts import asserts
23from acts import utils
24from acts.test_decorators import test_tracker_info
25from acts.test_utils.wifi import wifi_constants
26from acts.test_utils.wifi import wifi_test_utils as wutils
27from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest
28
29SCANTIME = 10000  #framework support only 10s as minimum scan interval
30NUMBSSIDPERSCAN = 8
31EVENT_TAG = "WifiScannerScan"
32SCAN_TIME_PASSIVE = 47  # dwell time plus 2ms
33SCAN_TIME_ACTIVE = 32  # dwell time plus 2ms
34SHORT_TIMEOUT = 30
35NETWORK_ID_ERROR = "Network don't have ID"
36NETWORK_ERROR = "Device is not connected to reference network"
37INVALID_RESULT = "Test fail because scan result reported are not valid"
38EMPTY_RESULT = "Test fail because empty scan result reported"
39KEY_RET = "ResultElapsedRealtime"
40ATTENUATOR = 0
41
42class WifiScannerScanError(Exception):
43    pass
44
45
46class WifiScannerScanTest(WifiBaseTest):
47    def __init__(self, configs):
48        super().__init__(configs)
49        self.enable_packet_log = True
50        # TODO(angli): Remove this list.
51        # There are order dependencies among these tests so we'll have to leave
52        # it here for now. :(
53        self.tests = (
54            "test_available_channels_band_1",
55            "test_available_channels_band_2",
56            "test_available_channels_band_3",
57            "test_available_channels_band_4",
58            "test_available_channels_band_6",
59            "test_available_channels_band_7",
60            "test_wifi_scanner_single_scan_channel_sanity",
61            "test_wifi_scanner_with_wifi_off",
62            "test_single_scan_report_each_scan_for_channels_with_enumerated_params",
63            "test_single_scan_report_each_scan_for_band_with_enumerated_params",
64            "test_single_scan_report_full_scan_for_channels_with_enumerated_params",
65            "test_single_scan_report_full_scan_for_band_with_enumerated_params",
66            "test_single_scan_while_pno",
67            "test_wifi_scanner_single_scan_in_isolated",
68            "test_wifi_scanner_with_invalid_numBssidsPerScan",
69            "test_wifi_scanner_dual_radio_low_latency",
70            "test_wifi_scanner_dual_radio_low_power",
71            "test_wifi_scanner_dual_radio_high_accuracy")
72
73    def setup_class(self):
74        super().setup_class()
75        self.dut = self.android_devices[0]
76        wutils.wifi_test_device_init(self.dut)
77        req_params = ("run_extended_test", "ping_addr", "dbs_supported_models")
78        opt_param = ["reference_networks"]
79        self.unpack_userparams(
80            req_param_names=req_params, opt_param_names=opt_param)
81
82        if "AccessPoint" in self.user_params:
83            self.legacy_configure_ap_and_start(ap_count=2, mirror_ap=False)
84
85        self.leeway = 10
86        self.stime_channel = SCAN_TIME_PASSIVE
87        self.default_scan_setting = {
88            "band": wutils.WifiEnums.WIFI_BAND_BOTH,
89            "periodInMs": SCANTIME,
90            "reportEvents": wutils.WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN
91        }
92        self.default_batch_scan_setting = {
93            "band": wutils.WifiEnums.WIFI_BAND_BOTH,
94            "periodInMs": SCANTIME,
95            "reportEvents": wutils.WifiEnums.REPORT_EVENT_AFTER_BUFFER_FULL
96        }
97        self.log.debug("Run extended test: {}".format(self.run_extended_test))
98        self.wifi_chs = wutils.WifiChannelUS(self.dut.model)
99        self.attenuators = wutils.group_attenuators(self.attenuators)
100        self.attenuators[0].set_atten(0)
101        self.attenuators[1].set_atten(0)
102
103    def teardown_test(self):
104        super().teardown_test()
105        self.log.debug("Shut down all wifi scanner activities.")
106        self.dut.droid.wifiScannerShutdown()
107
108    def teardown_class(self):
109        if "AccessPoint" in self.user_params:
110            del self.user_params["reference_networks"]
111            del self.user_params["open_network"]
112
113    """ Helper Functions Begin """
114
115    def wifi_generate_scanner_scan_settings(self, extended, scan_type,
116                                            report_result):
117        """Generates all the combinations of different scan setting parameters.
118
119        Args:
120          extended: True for extended setting
121          scan_type: key for type of scan
122          report_result: event type of report scan results
123
124        Returns:
125          A list of dictionaries each representing a set of scan settings.
126        """
127        base_scan_time = [SCANTIME * 2]
128        if scan_type == "band":
129            scan_types_setting = [wutils.WifiEnums.WIFI_BAND_BOTH]
130        else:
131            scan_types_setting = [self.wifi_chs.MIX_CHANNEL_SCAN]
132        num_of_bssid = [NUMBSSIDPERSCAN * 4]
133        max_scan_cache = [0]
134        if extended:
135            base_scan_time.append(SCANTIME)
136            if scan_type == "band":
137                scan_types_setting.extend(
138                    [wutils.WifiEnums.WIFI_BAND_24_GHZ,
139                     wutils.WifiEnums.WIFI_BAND_5_GHZ_WITH_DFS,
140                     wutils.WifiEnums.WIFI_BAND_BOTH_WITH_DFS])
141            else:
142                scan_types_setting.extend(
143                    [self.wifi_chs.NONE_DFS_5G_FREQUENCIES, self.wifi_chs.
144                     ALL_2G_FREQUENCIES, self.wifi_chs.DFS_5G_FREQUENCIES,
145                     self.wifi_chs.ALL_5G_FREQUENCIES])
146            num_of_bssid.append(NUMBSSIDPERSCAN * 3)
147            max_scan_cache.append(5)
148            # Generate all the combinations of report types and scan types
149        if report_result == wutils.WifiEnums.REPORT_EVENT_FULL_SCAN_RESULT:
150            report_types = {"reportEvents": report_result}
151            setting_combinations = list(itertools.product(scan_types_setting,
152                                                          base_scan_time))
153            # Create scan setting strings based on the combinations
154            scan_settings = []
155            for combo in setting_combinations:
156                s = dict(report_types)
157                s[scan_type] = combo[0]
158                s["periodInMs"] = combo[1]
159                scan_settings.append(s)
160        else:
161            report_types = {"reportEvents": report_result}
162            setting_combinations = list(
163                itertools.product(scan_types_setting, base_scan_time,
164                                  num_of_bssid, max_scan_cache))
165            # Create scan setting strings based on the combinations
166            scan_settings = []
167            for combo in setting_combinations:
168                s = dict(report_types)
169                s[scan_type] = combo[0]
170                s["periodInMs"] = combo[1]
171                s["numBssidsPerScan"] = combo[2]
172                s["maxScansToCache"] = combo[3]
173                scan_settings.append(s)
174        return scan_settings
175
176    def proces_and_valid_batch_scan_result(self, scan_resutls, scan_rt,
177                                           result_rt, scan_setting):
178        """This function process scan results and validate against settings used
179        while starting the scan.
180
181        There are two steps for the verification. First it checks that all the
182        wifi networks in results are of the correct frequencies set by scan setting
183        params. Then it checks that the delta between the batch of scan results less
184        than the time required for scanning channel set by scan setting params.
185
186        Args:
187            scan_results: scan results reported.
188            scan_rt: Elapsed real time on start scan.
189            result_rt: Elapsed ral time on results reported.
190            scan_setting: The params for the single scan.
191
192        Returns:
193            bssids: total number of bssids scan result have
194            validity: True if the all scan result are valid.
195        """
196        bssids = 0
197        validity = True
198        scan_time_mic = 0
199        scan_channels = []
200        scan_time, scan_channels = wutils.get_scan_time_and_channels(
201            self.wifi_chs, scan_setting, self.stime_channel)
202        scan_time_mic = scan_time * 1000
203        for i, batch in enumerate(scan_resutls, start=1):
204            asserts.assert_true(
205                batch["ScanResults"],
206                "At least one scan result is required to validate")
207            max_scan_interval = batch["ScanResults"][0][
208                "timestamp"] + scan_time_mic
209            self.log.debug("max_scan_interval: %s", max_scan_interval)
210            for result in batch["ScanResults"]:
211                # Though the tests are run in shield box, there are leakes
212                # from outside environment. This would ignore any such SSIDs
213                ssid = result["SSID"]
214                if not ssid.startswith("2g_") or not ssid.startswith("5g_"):
215                    continue
216                if (result["frequency"] not in scan_channels or
217                        result["timestamp"] > max_scan_interval or
218                        result["timestamp"] < scan_rt * 1000 or
219                        result["timestamp"] > result_rt * 1000):
220                    self.log.error("Result didn't match requirement: %s",
221                                   result)
222                    validity = False
223            self.log.info("Number of scan result in batch %s: %s", i,
224                          len(batch["ScanResults"]))
225            bssids += len(batch["ScanResults"])
226        return bssids, validity
227
228    def pop_scan_result_events(self, event_name):
229        """Function to pop all the scan result events.
230
231        Args:
232            event_name: event name.
233
234        Returns:
235            results: list  of scan result reported in events
236        """
237        results = []
238        try:
239            events = self.dut.ed.pop_all(event_name)
240            for event in events:
241                results.append(event["data"]["Results"])
242        except queue.Empty as error:
243            self.log.debug("Number of Full scan results %s", len(results))
244        return results
245
246    def wifi_scanner_single_scan(self, scan_setting):
247        """Common logic for an enumerated wifi scanner single scan test case.
248
249         1. Start WifiScanner single scan for scan_setting.
250         2. Wait for the scan result event, wait time depend on scan settings
251            parameter.
252         3. Verify that scan results match with scan settings parameters.
253         4. Also verify that only one scan result event trigger.
254
255        Args:
256            scan_setting: The params for the single scan.
257        """
258        data = wutils.start_wifi_single_scan(self.dut, scan_setting)
259        idx = data["Index"]
260        scan_rt = data["ScanElapsedRealtime"]
261        self.log.info(
262            "Wifi single shot scan started index: %s at real time: %s", idx,
263            scan_rt)
264        results = []
265        #generating event wait time from scan setting plus leeway
266        scan_time, scan_channels = wutils.get_scan_time_and_channels(
267            self.wifi_chs, scan_setting, self.stime_channel)
268        wait_time = int(scan_time / 1000) + self.leeway
269        validity = False
270        #track number of result received
271        result_received = 0
272        try:
273            for snumber in range(1, 3):
274                event_name = "{}{}onResults".format(EVENT_TAG, idx)
275                self.log.debug("Waiting for event: %s for time %s", event_name,
276                               wait_time)
277                event = self.dut.ed.pop_event(event_name, wait_time)
278                self.log.debug("Event received: %s", event)
279                results = event["data"]["Results"]
280                result_received += 1
281                bssids, validity = self.proces_and_valid_batch_scan_result(
282                    results, scan_rt, event["data"][KEY_RET], scan_setting)
283                asserts.assert_equal(
284                    len(results), 1,
285                    "Test fail because number of scan result %s" %
286                    len(results))
287                asserts.assert_true(bssids > 0, EMPTY_RESULT)
288                asserts.assert_true(validity, INVALID_RESULT)
289                self.log.info("Scan number Buckets: %s\nTotal BSSID: %s",
290                              len(results), bssids)
291        except queue.Empty as error:
292            asserts.assert_true(
293                result_received >= 1,
294                "Event did not triggered for single shot {}".format(error))
295        finally:
296            self.dut.droid.wifiScannerStopScan(idx)
297            #For single shot number of result received and length of result should be one
298            asserts.assert_true(
299                result_received == 1,
300                "Test fail because received result {}".format(result_received))
301
302    def wifi_scanner_single_scan_full(self, scan_setting):
303        """Common logic for single scan test case for full scan result.
304
305        1. Start WifiScanner single scan with scan_setting for full scan result.
306        2. Wait for the scan result event, wait time depend on scan settings
307           parameter.
308        3. Pop all full scan result events occurred earlier.
309        4. Verify that full scan results match with normal scan results.
310        5. If the scan type is included in scan_setting, verify that the
311           radioChainInfos length.
312
313        Args:
314            scan_setting: The parameters for the single scan.
315        """
316        self.dut.ed.clear_all_events()
317        data = wutils.start_wifi_single_scan(self.dut, scan_setting)
318        idx = data["Index"]
319        scan_rt = data["ScanElapsedRealtime"]
320        self.log.info("Wifi single shot scan started with index: %s", idx)
321        #generating event wait time from scan setting plus leeway
322        scan_time, scan_channels = wutils.get_scan_time_and_channels(
323            self.wifi_chs, scan_setting, self.stime_channel)
324        wait_time = int(scan_time / 1000) + self.leeway
325        results = []
326        validity = False
327        try:
328            event_name = "%s%sonResults" % (EVENT_TAG, idx)
329            self.log.debug("Waiting for event: %s for time %s", event_name,
330                           wait_time)
331            event = self.dut.ed.pop_event(event_name, wait_time)
332            self.log.info("Event received: %s", event)
333            bssids, validity = (self.proces_and_valid_batch_scan_result(
334                event["data"]["Results"], scan_rt, event["data"][KEY_RET],
335                scan_setting))
336            asserts.assert_true(bssids > 0, EMPTY_RESULT)
337            asserts.assert_true(validity, INVALID_RESULT)
338            event_name = "{}{}onFullResult".format(EVENT_TAG, idx)
339            results = self.pop_scan_result_events(event_name)
340            asserts.assert_true(
341                len(results) >= bssids,
342                "Full single shot result don't match {}".format(len(results)))
343            if 'type' in scan_setting.keys():
344                for item in results:
345                    self.verify_radio_chain_length(scan_setting['type'], item)
346        except queue.Empty as error:
347            raise AssertionError(
348                "Event did not triggered for single shot {}".format(error))
349        finally:
350            self.dut.droid.wifiScannerStopScan(idx)
351
352    def verify_radio_chain_length(self, scan_setting_type, scan_result):
353        llen = len(scan_result[0]["radioChainInfos"])
354        if scan_setting_type == wutils.WifiEnums.SCAN_TYPE_LOW_LATENCY \
355            or scan_setting_type == wutils.WifiEnums.SCAN_TYPE_LOW_POWER:
356            asserts.assert_true(llen == 1,
357                                "radioChainInfos len expected:{} "
358                                "actual:{}".format(1, llen))
359        else:
360            asserts.assert_true(llen == 2,
361                                "radioChainInfos len expected:{} "
362                                "actual:{}".format(2, llen))
363
364    def wifi_scanner_batch_scan_full(self, scan_setting):
365        """Common logic for batch scan test case for full scan result.
366
367        1. Start WifiScanner batch scan with scan_setting for full scan result.
368        2. Wait for the scan result event, wait time depend on scan settings
369           parameter.
370        3. Pop all full scan result events occurred earlier.
371        4. Verify that full scan results match with scan results.
372
373        Args:
374            scan_setting: The params for the batch scan.
375        """
376        self.dut.ed.clear_all_events()
377        data = wutils.start_wifi_background_scan(self.dut, scan_setting)
378        idx = data["Index"]
379        scan_rt = data["ScanElapsedRealtime"]
380        self.log.info("Wifi batch shot scan started with index: %s", idx)
381        #generating event wait time from scan setting plus leeway
382        scan_time, scan_channels = wutils.get_scan_time_and_channels(
383            self.wifi_chs, scan_setting, self.stime_channel)
384        # multiply scan period by two to account for scheduler changing period
385        scan_time += scan_setting[
386            'periodInMs'] * 2  #add scan period delay for next cycle
387        wait_time = scan_time / 1000 + self.leeway
388        validity = False
389        try:
390            for snumber in range(1, 3):
391                results = []
392                event_name = "%s%sonResults" % (EVENT_TAG, idx)
393                self.log.debug("Waiting for event: %s for time %s", event_name,
394                               wait_time)
395                event = self.dut.ed.pop_event(event_name, wait_time)
396                self.log.debug("Event received: %s", event)
397                bssids, validity = self.proces_and_valid_batch_scan_result(
398                    event["data"]["Results"], scan_rt, event["data"][KEY_RET],
399                    scan_setting)
400                event_name = "%s%sonFullResult" % (EVENT_TAG, idx)
401                results = self.pop_scan_result_events(event_name)
402                asserts.assert_true(
403                    len(results) >= bssids,
404                    "Full single shot result don't match %s" % len(results))
405                asserts.assert_true(bssids > 0, EMPTY_RESULT)
406                asserts.assert_true(validity, INVALID_RESULT)
407        except queue.Empty as error:
408            raise AssertionError("Event did not triggered for batch scan %s" %
409                                 error)
410        finally:
411            self.dut.droid.wifiScannerStopBackgroundScan(idx)
412            self.dut.ed.clear_all_events()
413
414    def wifi_scanner_batch_scan(self, scan_setting):
415        """Common logic for an enumerated wifi scanner batch scan test case.
416
417        1. Start WifiScanner batch scan for given scan_setting.
418        2. Wait for the scan result event, wait time depend on scan settings
419           parameter.
420        3. Verify that scan results match with scan settings parameters.
421        4. Also verify that multiple scan result events trigger.
422
423        Args:
424            scan_setting: The parameters for the batch scan.
425        """
426        data = wutils.start_wifi_background_scan(self.dut, scan_setting)
427        idx = data["Index"]
428        scan_rt = data["ScanElapsedRealtime"]
429        self.log.info(
430            "Wifi background scan started with index: %s real time %s", idx,
431            scan_rt)
432        scan_time, scan_channels = wutils.get_scan_time_and_channels(
433            self.wifi_chs, scan_setting, self.stime_channel)
434        #generating event wait time from scan setting plus leeway
435        time_cache = 0
436        number_bucket = 1  #bucket for Report result on each scan
437        check_get_result = False
438        if scan_setting[
439                'reportEvents'] == wutils.WifiEnums.REPORT_EVENT_AFTER_BUFFER_FULL:
440            check_get_result = True
441            if ('maxScansToCache' in scan_setting and
442                    scan_setting['maxScansToCache'] != 0):
443                time_cache = (scan_setting['maxScansToCache'] *
444                              scan_setting['periodInMs'])
445                number_bucket = scan_setting['maxScansToCache']
446            else:
447                time_cache = 10 * scan_setting['periodInMs'
448                                               ]  #10 as default max scan cache
449                number_bucket = 10
450        else:
451            time_cache = scan_setting[
452                'periodInMs'
453            ]  #need while waiting for seconds resutls
454        # multiply cache time by two to account for scheduler changing period
455        wait_time = (time_cache * 2 + scan_time) / 1000 + self.leeway
456        validity = False
457        try:
458            for snumber in range(1, 3):
459                event_name = "%s%sonResults" % (EVENT_TAG, idx)
460                self.log.info("Waiting for event: %s for time %s", event_name,
461                              wait_time)
462                event = self.dut.ed.pop_event(event_name, wait_time)
463                self.log.debug("Event received: %s", event)
464                results = event["data"]["Results"]
465                bssids, validity = (self.proces_and_valid_batch_scan_result(
466                    results, scan_rt, event["data"][KEY_RET], scan_setting))
467                self.log.info("Scan number: %s\n Buckets: %s\n  BSSID: %s",
468                              snumber, len(results), bssids)
469                asserts.assert_equal(
470                    len(results), number_bucket,
471                    "Test fail because number_bucket %s" % len(results))
472                asserts.assert_true(bssids >= 1, EMPTY_RESULT)
473                asserts.assert_true(validity, INVALID_RESULT)
474                if snumber % 2 == 1 and check_get_result:
475                    self.log.info("Get Scan result using GetScanResult API")
476                    time.sleep(wait_time / number_bucket)
477                    if self.dut.droid.wifiScannerGetScanResults():
478                        event = self.dut.ed.pop_event(event_name, 1)
479                        self.log.debug("Event onResults: %s", event)
480                        results = event["data"]["Results"]
481                        bssids, validity = self.proces_and_valid_batch_scan_result(
482                            results, scan_rt, event["data"][KEY_RET],
483                            scan_setting)
484                        self.log.info("Got Scan result number: %s BSSID: %s",
485                                      snumber, bssids)
486                        asserts.assert_true(bssids >= 1, EMPTY_RESULT)
487                        asserts.assert_true(validity, INVALID_RESULT)
488                    else:
489                        self.log.error("Error while fetching the scan result")
490        except queue.Empty as error:
491            raise AssertionError("Event did not triggered for batch scan %s" %
492                                 error)
493        finally:
494            self.dut.droid.wifiScannerStopBackgroundScan(idx)
495            self.dut.ed.clear_all_events()
496
497    def start_wifi_scanner_single_scan_expect_failure(self, scan_setting):
498        """Common logic to test wif scanner single scan with invalid settings
499           or environment
500
501         1. Start WifiScanner batch scan for setting parameters.
502         2. Verify that scan is not started.
503
504         Args:
505            scan_setting: The params for the single scan.
506        """
507        try:
508            idx = self.dut.droid.wifiScannerStartScan(scan_setting)
509            event = self.dut.ed.pop_event(
510                "{}{}onFailure".format(EVENT_TAG, idx), SHORT_TIMEOUT)
511        except queue.Empty as error:
512            raise AssertionError("Did not get expected onFailure {}".format(
513                error))
514
515    def start_wifi_scanner_background_scan_expect_failure(self, scan_setting):
516        """Common logic to test wif scanner batch scan with invalid settings
517           or environment
518
519         1. Start WifiScanner batch scan for setting parameters.
520         2. Verify that scan is not started.
521
522         Args:
523          scan_setting: The params for the single scan.
524        """
525        try:
526            idx = self.dut.droid.wifiScannerStartBackgroundScan(scan_setting)
527            event = self.dut.ed.pop_event(
528                "{}{}onFailure".format(EVENT_TAG, idx), SHORT_TIMEOUT)
529        except queue.Empty as error:
530            raise AssertionError("Did not get expected onFailure {}".format(
531                error))
532
533    def check_get_available_channels_with_one_band(self, band):
534        """Common logic to check available channels for a band.
535
536         1. Get available channels for band.
537         2. Verify that channels match with supported channels for band.
538
539         Args:
540            band: wifi band."""
541
542        r = self.dut.droid.wifiScannerGetAvailableChannels(band)
543        self.log.info("Band: %s" % band)
544        self.log.info("Available channels: %s" % r)
545        expected = self.wifi_chs.band_to_freq(band)
546        self.log.info("Expected channels: %s" % expected)
547        asserts.assert_equal(set(r), set(expected), "Band %s failed." % band)
548
549    def connect_to_reference_network(self):
550        """Connect to reference network and make sure that connection happen"""
551        self.dut.droid.wakeLockAcquireBright()
552        self.dut.droid.wakeUpNow()
553        try:
554            self.dut.droid.wifiConnectByConfig(self.reference_networks[0]["2g"])
555            connect_result = self.dut.ed.pop_event(
556                wifi_constants.CONNECT_BY_CONFIG_SUCCESS, SHORT_TIMEOUT)
557            self.log.info(connect_result)
558            return wutils.track_connection(self.dut,
559                self.reference_networks[0]["2g"]["SSID"], 1)
560        except Exception as error:
561            self.log.exception(traceback.format_exc())
562            self.log.error("Connection to network fail because %s", error)
563            return False
564        finally:
565            self.dut.droid.wifiLockRelease()
566            self.dut.droid.goToSleepNow()
567
568    """ Helper Functions End """
569    """ Tests Begin """
570
571    # Test channels
572    """ Test available channels for different bands.
573
574        1. Get available channels for different bands.
575        2. Verify that channels match with supported channels for respective band.
576    """
577    @test_tracker_info(uuid="7cca8142-529f-4951-ab6f-cd03b359b3cc")
578    def test_available_channels_band_1(self):
579        self.check_get_available_channels_with_one_band(1)
580
581    @test_tracker_info(uuid="612afda1-0d74-4d2f-bc37-72ef2b98310a")
582    def test_available_channels_band_2(self):
583        self.check_get_available_channels_with_one_band(2)
584
585    @test_tracker_info(uuid="a9275bb9-afa7-4dd4-b2e0-60296ffd33bb")
586    def test_available_channels_band_3(self):
587        self.check_get_available_channels_with_one_band(3)
588
589    @test_tracker_info(uuid="5413632e-ce72-4ecc-bf9b-33ac9e4bf3fc")
590    def test_available_channels_band_4(self):
591        self.check_get_available_channels_with_one_band(4)
592
593    @test_tracker_info(uuid="a8f40b4f-d79d-4d2f-bed8-3b139a082f6c")
594    def test_available_channels_band_6(self):
595        self.check_get_available_channels_with_one_band(6)
596
597    @test_tracker_info(uuid="84cdfc25-8e64-42c7-b7f9-0a04e45d78b6")
598    def test_available_channels_band_7(self):
599        self.check_get_available_channels_with_one_band(7)
600
601    @test_tracker_info(uuid="95069244-b76c-4834-b3a6-96b0d8da98d8")
602    def test_single_scan_report_each_scan_for_channels_with_enumerated_params(
603            self):
604        """Test WiFi scanner single scan for channels with enumerated settings.
605
606         1. Start WifiScanner single scan for different channels with enumerated
607            scan settings.
608         2. Verify that scan results match with respective scan settings.
609        """
610        scan_settings = self.wifi_generate_scanner_scan_settings(
611            self.run_extended_test, "channels",
612            wutils.WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN)
613        self.log.debug("Scan settings: %s\n%s", len(scan_settings),
614                       scan_settings)
615        self.wifi_scanner_single_scan(scan_settings[0])
616
617    @test_tracker_info(uuid="5595ebe5-6d91-4379-a606-be59967e5ec9")
618    def test_single_scan_report_each_scan_for_band_with_enumerated_params(
619            self):
620        """Test WiFi scanner single scan for bands with enumerated settings.
621
622         1. Start WifiScanner single scan for different bands with enumerated
623            scan settings.
624         2. Verify that scan results match with respective scan settings.
625        """
626        scan_settings = self.wifi_generate_scanner_scan_settings(
627            self.run_extended_test, "band",
628            wutils.WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN)
629        self.log.debug("Scan settings:%s\n%s", len(scan_settings),
630                       scan_settings)
631        self.wifi_scanner_single_scan(scan_settings[0])
632
633    @test_tracker_info(uuid="44989f93-e63b-4c2e-a90a-a483477303bb")
634    def test_batch_scan_report_buffer_full_for_channels_with_enumerated_params(
635            self):
636        """Test WiFi scanner batch scan using channels with enumerated settings
637           to report buffer full scan results.
638
639         1. Start WifiScanner batch scan using different channels with enumerated
640            scan settings to report buffer full scan results.
641         2. Verify that scan results match with respective scan settings.
642        """
643        scan_settings = self.wifi_generate_scanner_scan_settings(
644            self.run_extended_test, "channels",
645            wutils.WifiEnums.REPORT_EVENT_AFTER_BUFFER_FULL)
646        self.log.debug("Scan settings:%s\n%s", len(scan_settings),
647                       scan_settings)
648        self.wifi_scanner_batch_scan(scan_settings[0])
649
650    @test_tracker_info(uuid="63538df6-388a-4c16-964f-e9c19b750e07")
651    def test_batch_scan_report_buffer_full_for_band_with_enumerated_params(
652            self):
653        """Test WiFi scanner batch scan using band with enumerated settings
654           to report buffer full scan results.
655
656         1. Start WifiScanner batch scan using different bands with enumerated
657            scan settings to report buffer full scan results.
658         2. Verify that scan results match with respective scan settings.
659        """
660        scan_settings = self.wifi_generate_scanner_scan_settings(
661            self.run_extended_test, "band",
662            wutils.WifiEnums.REPORT_EVENT_AFTER_BUFFER_FULL)
663        self.log.debug("Scan settings:{}\n{}".format(
664            len(scan_settings), scan_settings))
665        self.wifi_scanner_batch_scan(scan_settings[0])
666
667    @test_tracker_info(uuid="bd4e8c53-16c8-4ed6-b680-55c1ba688ad8")
668    def test_batch_scan_report_each_scan_for_channels_with_enumerated_params(
669            self):
670        """Test WiFi scanner batch scan using channels with enumerated settings
671           to report each scan results.
672
673         1. Start WifiScanner batch scan using different channels with enumerated
674            scan settings to report each scan results.
675         2. Verify that scan results match with respective scan settings.
676        """
677        scan_settings = self.wifi_generate_scanner_scan_settings(
678            self.run_extended_test, "channels",
679            wutils.WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN)
680        self.log.debug("Scan settings:{}\n{}".format(
681            len(scan_settings), scan_settings))
682        self.wifi_scanner_batch_scan(scan_settings[0])
683
684    @test_tracker_info(uuid="d11e8c09-97d0-49c1-bf09-b9ec672c2fa6")
685    def test_batch_scan_report_each_scan_for_band_with_enumerated_params(self):
686        """Test WiFi scanner batch scan using band with enumerated settings
687           to report each scan results.
688
689         1. Start WifiScanner batch scan using different bands with enumerated
690            scan settings to report each scan results.
691         2. Verify that scan results match with respective scan settings.
692        """
693        scan_settings = self.wifi_generate_scanner_scan_settings(
694            self.run_extended_test, "band",
695            wutils.WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN)
696        self.log.debug("Scan settings:{}\n{}".format(
697            len(scan_settings), scan_settings))
698        self.wifi_scanner_batch_scan(scan_settings[0])
699
700    @test_tracker_info(uuid="7f967b0e-82fe-403e-9d74-0dee7f09a21d")
701    def test_single_scan_report_full_scan_for_channels_with_enumerated_params(
702            self):
703        """Test WiFi scanner single scan using channels with enumerated settings
704           to report full scan results.
705
706         1. Start WifiScanner single scan using different channels with enumerated
707            scan settings to report full scan results.
708         2. Verify that scan results match with respective scan settings.
709        """
710        scan_settings = self.wifi_generate_scanner_scan_settings(
711            self.run_extended_test, "channels",
712            wutils.WifiEnums.REPORT_EVENT_FULL_SCAN_RESULT)
713        self.log.debug("Full Scan settings:{}\n{}".format(
714            len(scan_settings), scan_settings))
715        self.wifi_scanner_single_scan_full(scan_settings[0])
716
717    @test_tracker_info(uuid="34d09f60-31bf-4952-8fb3-03fc93ec98fa")
718    def test_single_scan_report_full_scan_for_band_with_enumerated_params(
719            self):
720        """Test WiFi scanner single scan using band with enumerated settings
721           to report full scan results.
722
723         1. Start WifiScanner single scan using different bands with enumerated
724            scan settings to report full scan results.
725         2. Verify that scan results match with respective scan settings.
726        """
727        scan_settings = self.wifi_generate_scanner_scan_settings(
728            self.run_extended_test, "band",
729            wutils.WifiEnums.REPORT_EVENT_FULL_SCAN_RESULT)
730        self.log.debug("Full Scan settings:{}\n{}".format(
731            len(scan_settings), scan_settings))
732        self.wifi_scanner_single_scan_full(scan_settings[0])
733
734    @test_tracker_info(uuid="0ddccf2e-b518-45a7-ae75-96924070b841")
735    def test_batch_scan_report_full_scan_for_channels_with_enumerated_params(
736            self):
737        """Test WiFi scanner batch scan using channels with enumerated settings
738           to report full scan results.
739
740         1. Start WifiScanner batch scan using different channels with enumerated
741            scan settings to report full scan results.
742         2. Verify that scan results match with respective scan settings.
743        """
744        scan_settings = self.wifi_generate_scanner_scan_settings(
745            self.run_extended_test, "channels",
746            wutils.WifiEnums.REPORT_EVENT_FULL_SCAN_RESULT)
747        self.log.debug("Full Scan settings:{}\n{}".format(
748            len(scan_settings), scan_settings))
749        self.wifi_scanner_batch_scan_full(scan_settings[0])
750
751    @test_tracker_info(uuid="0685b667-8470-43a0-923d-dee71428f8ce")
752    def test_batch_scan_report_full_scan_for_band_with_enumerated_params(self):
753        """Test WiFi scanner batch scan using channels with enumerated settings
754           to report full scan results.
755
756         1. Start WifiScanner batch scan using different channels with enumerated
757            scan settings to report full scan results.
758         2. Verify that scan results match with respective scan settings.
759        """
760        scan_settings = self.wifi_generate_scanner_scan_settings(
761            self.run_extended_test, "band",
762            wutils.WifiEnums.REPORT_EVENT_FULL_SCAN_RESULT)
763        self.log.debug("Full Scan settings:{}\n{}".format(
764            len(scan_settings), scan_settings))
765        self.wifi_scanner_batch_scan_full(scan_settings[0])
766
767    @test_tracker_info(uuid="e9a7cfb5-21c4-4c40-8169-8d88b65a1dee")
768    @WifiBaseTest.wifi_test_wrap
769    def test_single_scan_while_pno(self):
770        """Test wifi scanner single scan parallel to PNO connection.
771
772         1. Check device have a saved network.
773         2. Trigger PNO by attenuate the signal to move out of range.
774         3. Start WifiScanner single scan for both band with default scan settings.
775         4. Verify that scanner report single scan results.
776         5. Attenuate the signal to move in range.
777         6. Verify connection occurred through PNO.
778        """
779        self.log.info("Check connection through PNO for reference network")
780        self.attenuators[ATTENUATOR].set_atten(0)
781        asserts.assert_true(self.connect_to_reference_network(), NETWORK_ERROR)
782        time.sleep(10)  #wait for connection to be active
783        asserts.assert_true(
784            wutils.validate_connection(self.dut, self.ping_addr),
785            "Error, No internet connection for current network")
786
787        current_network = self.dut.droid.wifiGetConnectionInfo()
788        self.log.info("Current network: {}".format(current_network))
789        asserts.assert_true('network_id' in current_network, NETWORK_ID_ERROR)
790        asserts.assert_true(current_network['network_id'] >= 0, NETWORK_ERROR)
791        self.log.info("Kicking PNO for reference network")
792        self.attenuators[ATTENUATOR].set_atten(90)
793        time.sleep(10)  #wait for PNO to be kicked
794        self.log.info("Starting single scan while PNO")
795        self.wifi_scanner_single_scan(self.default_scan_setting)
796        self.attenuators[ATTENUATOR].set_atten(0)
797        self.log.info("Check connection through PNO for reference network")
798        time.sleep(60)  #wait for connection through PNO
799        current_network = self.dut.droid.wifiGetConnectionInfo()
800        self.log.info("Current network: {}".format(current_network))
801        asserts.assert_true('network_id' in current_network, NETWORK_ID_ERROR)
802        asserts.assert_true(current_network['network_id'] >= 0, NETWORK_ERROR)
803        time.sleep(10)  #wait for IP to be assigned
804        asserts.assert_true(
805            wutils.validate_connection(self.dut, self.ping_addr),
806            "Error, No internet connection for current network")
807        wutils.wifi_forget_network(self.dut,
808            self.reference_networks[0]["2g"]["SSID"])
809
810    @test_tracker_info(uuid="fc18d947-0b5a-42b4-98f3-dd1f2b52a7af")
811    def test_wifi_connection_and_pno_while_batch_scan(self):
812        """Test configuring a connection and PNO connection parallel to wifi
813           scanner batch scan.
814
815         1. Start WifiScanner batch scan with default batch scan settings.
816         2. Wait for scan result event for a time depend on scan settings.
817         3. Verify reported batch scan results.
818         4. Configure a connection to reference network.
819         5. Verify that connection to reference network occurred.
820         6. Wait for scan result event for a time depend on scan settings.
821         7. Verify reported batch scan results.
822         8. Trigger PNO by attenuate the signal to move out of range.
823         9. Wait for scan result event for a time depend on scan settings.
824         10. Verify reported batch scan results.
825         11. Attenuate the signal to move in range.
826         12. Verify connection occurred through PNO.
827        """
828        self.attenuators[ATTENUATOR].set_atten(0)
829        data = wutils.start_wifi_background_scan(
830            self.dut, self.default_batch_scan_setting)
831        idx = data["Index"]
832        scan_rt = data["ScanElapsedRealtime"]
833        self.log.info(
834            "Wifi background scan started with index: {} rt {}".format(
835                idx, scan_rt))
836        #generating event wait time from scan setting plus leeway
837        scan_time, scan_channels = wutils.get_scan_time_and_channels(
838            self.wifi_chs, self.default_batch_scan_setting, self.stime_channel)
839        #default number buckets
840        number_bucket = 10
841        time_cache = self.default_batch_scan_setting[
842            'periodInMs'] * number_bucket  #default cache
843        #add 2 seconds extra time for switch between the channel for connection scan
844        #multiply cache time by two to account for scheduler changing period
845        wait_time = (time_cache * 2 + scan_time) / 1000 + self.leeway + 2
846        result_flag = 0
847        try:
848            for snumber in range(1, 7):
849                event_name = "{}{}onResults".format(EVENT_TAG, idx)
850                self.log.info("Waiting for event: {}".format(event_name))
851                event = self.dut.ed.pop_event(event_name, wait_time)
852                self.log.debug("Event onResults: {}".format(event))
853                results = event["data"]["Results"]
854                bssids, validity = self.proces_and_valid_batch_scan_result(
855                    results, scan_rt, event["data"][KEY_RET],
856                    self.default_batch_scan_setting)
857                self.log.info(
858                    "Scan number: {}\n Buckets: {}\n BSSID: {}".format(
859                        snumber, len(results), bssids))
860                asserts.assert_true(bssids >= 1,
861                                    "Not able to fetch scan result")
862                if snumber == 1:
863                    self.log.info(
864                        "Try to connect AP while waiting for event: {}".format(
865                            event_name))
866                    asserts.assert_true(self.connect_to_reference_network(),
867                                        NETWORK_ERROR)
868                    time.sleep(10)  #wait for connection to be active
869                    asserts.assert_true(
870                        wutils.validate_connection(self.dut, self.ping_addr),
871                        "Error, No internet connection for current network")
872                elif snumber == 3:
873                    self.log.info("Kicking PNO for reference network")
874                    self.attenuators[ATTENUATOR].set_atten(90)
875                elif snumber == 4:
876                    self.log.info("Bring back device for PNO connection")
877                    current_network = self.dut.droid.wifiGetConnectionInfo()
878                    self.log.info("Current network: {}".format(
879                        current_network))
880                    asserts.assert_true('network_id' in current_network,
881                                        NETWORK_ID_ERROR)
882                    asserts.assert_true(
883                        current_network['network_id'] == -1,
884                        "Device is still connected to network  {}".format(
885                            current_network[wutils.WifiEnums.SSID_KEY]))
886                    self.attenuators[ATTENUATOR].set_atten(0)
887                    time.sleep(
888                        10
889                    )  #wait for connection to take place before waiting for scan result
890                elif snumber == 6:
891                    self.log.info(
892                        "Check connection through PNO for reference network")
893                    current_network = self.dut.droid.wifiGetConnectionInfo()
894                    self.log.info("Current network: {}".format(
895                        current_network))
896                    asserts.assert_true('network_id' in current_network,
897                                        NETWORK_ID_ERROR)
898                    asserts.assert_true(current_network['network_id'] >= 0,
899                                        NETWORK_ERROR)
900                    time.sleep(10)  #wait for connection to be active
901                    asserts.assert_true(
902                        wutils.validate_connection(self.dut, self.ping_addr),
903                        "Error, No internet connection for current network")
904                    wutils.wifi_forget_network(self.dut,
905                        self.reference_networks[0]["2g"]["SSID"])
906        except queue.Empty as error:
907            raise AssertionError(
908                "Event did not triggered for batch scan {}".format(error))
909        finally:
910            self.dut.droid.wifiScannerStopBackgroundScan(idx)
911            self.dut.ed.clear_all_events()
912
913    @test_tracker_info(uuid="7c25ce32-0fae-4a68-a7cb-fdf6d4d03caf")
914    def test_wifi_scanner_single_scan_channel_sanity(self):
915        """Test WiFi scanner single scan for mix channel with default setting
916           parameters.
917
918         1. Start WifiScanner single scan for mix channels with default setting
919            parameters.
920         2. Verify that scan results match with respective scan settings.
921        """
922        scan_setting = {"channels": self.wifi_chs.MIX_CHANNEL_SCAN,
923                        "periodInMs": SCANTIME,
924                        "reportEvents":
925                        wutils.WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN}
926        self.wifi_scanner_single_scan(scan_setting)
927
928    @test_tracker_info(uuid="7c8da0c4-dec7-4d04-abd4-f8ea467a5c6d")
929    @WifiBaseTest.wifi_test_wrap
930    def test_wifi_scanner_dual_radio_low_latency(self):
931        """Test WiFi scanner single scan for mix channel with default setting
932           parameters.
933
934         1. Start WifiScanner single scan for type = SCAN_TYPE_LOW_LATENCY.
935         2. Verify that scan results match with respective scan settings.
936        """
937        if self.dut.model not in self.dbs_supported_models:
938            asserts.skip(
939                ("Device %s does not support dual radio scanning.")
940                % self.dut.model)
941        scan_setting = {"channels": self.wifi_chs.MIX_CHANNEL_SCAN,
942                        "periodInMs": SCANTIME,
943                        "reportEvents":
944                            wutils.WifiEnums.REPORT_EVENT_FULL_SCAN_RESULT,
945                        "type": wutils.WifiEnums.SCAN_TYPE_LOW_LATENCY}
946        self.wifi_scanner_single_scan_full(scan_setting)
947
948    @test_tracker_info(uuid="58b49b01-851b-4e45-b218-9fd27c0be921")
949    @WifiBaseTest.wifi_test_wrap
950    def test_wifi_scanner_dual_radio_low_power(self):
951        """Test WiFi scanner single scan for mix channel with default setting
952           parameters.
953
954         1. Start WifiScanner single scan for type = SCAN_TYPE_LOW_POWER.
955         2. Verify that scan results match with respective scan settings.
956        """
957        if self.dut.model not in self.dbs_supported_models:
958            asserts.skip(
959                ("Device %s does not support dual radio scanning.")
960                % self.dut.model)
961        scan_setting = {"channels": self.wifi_chs.MIX_CHANNEL_SCAN,
962                        "periodInMs": SCANTIME,
963                        "reportEvents":
964                            wutils.WifiEnums.REPORT_EVENT_FULL_SCAN_RESULT,
965                        "type": wutils.WifiEnums.SCAN_TYPE_LOW_POWER}
966        self.wifi_scanner_single_scan_full(scan_setting)
967
968    @test_tracker_info(uuid="3e7288bc-45e4-497c-bf3a-977eec4e896e")
969    @WifiBaseTest.wifi_test_wrap
970    def test_wifi_scanner_dual_radio_high_accuracy(self):
971        """Test WiFi scanner single scan for mix channel with default setting
972           parameters.
973
974         1. Start WifiScanner single scan for type = SCAN_TYPE_HIGH_ACCURACY.
975         2. Verify that scan results match with respective scan settings.
976        """
977        if self.dut.model not in self.dbs_supported_models:
978            asserts.skip(
979                ("Device %s does not support dual radio scanning.")
980                % self.dut.model)
981        scan_setting = {"channels": self.wifi_chs.MIX_CHANNEL_SCAN,
982                        "periodInMs": SCANTIME,
983                        "reportEvents":
984                            wutils.WifiEnums.REPORT_EVENT_FULL_SCAN_RESULT,
985                        "type": wutils.WifiEnums.SCAN_TYPE_HIGH_ACCURACY}
986        self.wifi_scanner_single_scan_full(scan_setting)
987
988    @test_tracker_info(uuid="e9f3aaad-4af3-4c54-9829-65dc1d6d4987")
989    def test_wifi_scanner_batch_scan_channel_sanity(self):
990        """Test WiFi scanner batch scan for mix channel with default setting
991           parameters to report the result on buffer full.
992
993         1. Start WifiScanner batch scan for mix channels with default setting
994            parameters.
995         2. Verify that scan results match with respective scan settings.
996        """
997        scan_setting = {"channels": self.wifi_chs.MIX_CHANNEL_SCAN,
998                        "periodInMs": SCANTIME,
999                        "reportEvents":
1000                        wutils.WifiEnums.REPORT_EVENT_AFTER_BUFFER_FULL}
1001        self.wifi_scanner_batch_scan(scan_setting)
1002
1003    @test_tracker_info(uuid="49ba245a-52e2-4c9b-90ad-a2fbc97e3d9f")
1004    def test_wifi_scanner_batch_scan_period_too_short(self):
1005        """Test WiFi scanner batch scan for band with too short period time.
1006
1007         1. Start WifiScanner batch scan for both band with interval period as 5s.
1008         2. Verify that scan is not started."""
1009        scan_setting = {"band": wutils.WifiEnums.WIFI_BAND_BOTH_WITH_DFS,
1010                        "periodInMs": 5000,
1011                        "reportEvents":
1012                        wutils.WifiEnums.REPORT_EVENT_AFTER_BUFFER_FULL}
1013        self.start_wifi_scanner_background_scan_expect_failure(scan_setting)
1014
1015    @test_tracker_info(uuid="6fe45cd7-4fac-4ddd-a950-b9431e68f735")
1016    def test_wifi_scanner_single_scan_in_isolated(self):
1017        """Test WiFi scanner in isolated environment with default scan settings.
1018
1019         1. Created isolated environment by attenuating the single by 90db
1020         2. Start WifiScanner single scan for mix channels with default setting
1021            parameters.
1022         3. Verify that empty scan results reported.
1023        """
1024        self.attenuators[0].set_atten(90)
1025        self.attenuators[1].set_atten(90)
1026        data = wutils.start_wifi_single_scan(self.dut,
1027                                             self.default_scan_setting)
1028        idx = data["Index"]
1029        scan_rt = data["ScanElapsedRealtime"]
1030        self.log.info("Wifi single shot scan started with index: {}".format(
1031            idx))
1032        results = []
1033        #generating event wait time from scan setting plus leeway
1034        scan_time, scan_channels = wutils.get_scan_time_and_channels(
1035            self.wifi_chs, self.default_scan_setting, self.stime_channel)
1036        wait_time = int(scan_time / 1000) + self.leeway
1037        try:
1038            event_name = "{}{}onResults".format(EVENT_TAG, idx)
1039            self.log.debug("Waiting for event: {} for time {}".format(
1040                event_name, wait_time))
1041            event = self.dut.ed.pop_event(event_name, wait_time)
1042            self.log.debug("Event received: {}".format(event))
1043            results = event["data"]["Results"]
1044            for batch in results:
1045                asserts.assert_false(batch["ScanResults"],
1046                                     "Test fail because report scan "
1047                                     "results reported are not empty")
1048        except queue.Empty as error:
1049            raise AssertionError(
1050                "Event did not triggered for in isolated environment {}".format(
1051                    error))
1052        finally:
1053            self.dut.ed.clear_all_events()
1054            self.attenuators[0].set_atten(0)
1055            self.attenuators[1].set_atten(0)
1056
1057    @test_tracker_info(uuid="46f817b9-97a3-455e-af2c-56f9aea64f7e")
1058    def test_wifi_scanner_with_wifi_off(self):
1059        """Test WiFi scanner single scan when wifi is off.
1060
1061         1. Toggle wifi state to off.
1062         2. Start WifiScanner single scan for both band with default scan settings.
1063         3. Verify that scan is not started.
1064        """
1065        self.log.debug("Make sure wifi is off.")
1066        wutils.wifi_toggle_state(self.dut, False)
1067        self.start_wifi_scanner_single_scan_expect_failure(
1068            self.default_scan_setting)
1069        self.log.debug("Turning wifi back on.")
1070        wutils.wifi_toggle_state(self.dut, True)
1071
1072    @test_tracker_info(uuid="257ad734-c21f-49f4-b448-3986b70eba3d")
1073    def test_wifi_scanner_with_invalid_numBssidsPerScan(self):
1074        """Test WiFi scanner single scan with invalid number of bssids reported
1075           per scan.
1076
1077         1. Start WifiScanner single scan with invalid number of bssids reported
1078            per scan.
1079         2. Verify that scan results triggered for default supported number of
1080            bssids per scan.
1081        """
1082        scan_setting = {
1083            "band": wutils.WifiEnums.WIFI_BAND_BOTH_WITH_DFS,
1084            "periodInMs": SCANTIME,
1085            "reportEvents": wutils.WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
1086            'numBssidsPerScan': 33
1087        }
1088        self.wifi_scanner_single_scan(scan_setting)
1089
1090    """ Tests End """
1091