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 queue
18import time
19
20from acts import asserts
21from acts import base_test
22from acts import signals
23from acts.test_decorators import test_tracker_info
24from acts.test_utils.wifi import wifi_test_utils as wutils
25from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest
26
27WifiChannelUS = wutils.WifiChannelUS
28WifiEnums = wutils.WifiEnums
29
30SCAN_EVENT_TAG = "WifiScannerScan"
31
32
33class WifiScanResultEvents():
34    """This class stores the setting of a scan, parameters generated
35    from starting the scan, and events reported later from the scan
36    for validation.
37
38    Attributes:
39        scan_setting: Setting used to perform the scan.
40        scan_channels: Channels used for scanning.
41        events: A list to store the scan result events.
42    """
43
44    def __init__(self, scan_setting, scan_channels):
45        self.scan_setting = scan_setting
46        self.scan_channels = scan_channels
47        self.results_events = []
48
49    def add_results_event(self, event):
50        self.results_events.append(event)
51
52    def check_interval(self, scan_result, scan_result_next):
53        """Verifies that the time gap between two consecutive results is within
54        expected range.
55
56        Right now it is hard coded to be 20 percent of the interval specified
57        by scan settings. This threshold can be imported from the configuration
58        file in the future if necessary later.
59
60        Note the scan result timestamps are in microseconds, but "periodInMs"
61        in scan settings is in milliseconds.
62
63        Args:
64            scan_result: A dictionary representing a scan result for a BSSID.
65            scan_result_next: A dictionary representing a scan result for a
66                BSSID, whose scan happened after scan_result.
67        """
68        actual_interval = scan_result_next["timestamp"] - scan_result[
69            "timestamp"]
70        expected_interval = self.scan_setting['periodInMs'] * 1000
71        delta = abs(actual_interval - expected_interval)
72        margin = expected_interval * 0.25  # 25% of the expected_interval
73        asserts.assert_true(
74            delta < margin, "The difference in time between scan %s and "
75            "%s is %dms, which is out of the expected range %sms" % (
76                scan_result, scan_result_next, delta / 1000,
77                self.scan_setting['periodInMs']))
78
79    def verify_one_scan_result(self, scan_result):
80        """Verifies the scan result of a single BSSID.
81
82        1. Verifies the frequency of the network is within the range requested
83        in the scan.
84
85        Args:
86            scan_result: A dictionary representing the scan result of a single
87                BSSID.
88        """
89        freq = scan_result["frequency"]
90        asserts.assert_true(
91            freq in self.scan_channels,
92            "Frequency %d of result entry %s is out of the expected range %s."
93            % (freq, scan_result, self.scan_channels))
94        # TODO(angli): add RSSI check.
95
96    def verify_one_scan_result_group(self, batch):
97        """Verifies a group of scan results obtained during one scan.
98
99        1. Verifies the number of BSSIDs in the batch is less than the
100        threshold set by scan settings.
101        2. Verifies each scan result for individual BSSID.
102
103        Args:
104            batch: A list of dictionaries, each dictionary represents a scan
105                result.
106        """
107        scan_results = batch["ScanResults"]
108        actual_num_of_results = len(scan_results)
109        expected_num_of_results = self.scan_setting['numBssidsPerScan']
110        asserts.assert_true(actual_num_of_results <= expected_num_of_results,
111                            "Expected no more than %d BSSIDs, got %d." %
112                            (expected_num_of_results, actual_num_of_results))
113        for scan_result in scan_results:
114            self.verify_one_scan_result(scan_result)
115
116    def have_enough_events(self):
117        """Check if there are enough events to properly validate the scan"""
118        return len(self.results_events) >= 2
119
120    def check_scan_results(self):
121        """Validate the reported scan results against the scan settings.
122        Assert if any error detected in the results.
123
124        1. For each scan setting there should be no less than 2 events received.
125        2. For batch scan, the number of buffered results in each event should
126           be exactly what the scan setting specified.
127        3. Each scan result should contain no more BBSIDs than what scan
128           setting specified.
129        4. The frequency reported by each scan result should comply with its
130           scan setting.
131        5. The time gap between two consecutive scan results should be
132           approximately equal to the scan interval specified by the scan
133           setting.
134        A scan result looks like this:
135        {
136          'data':
137           {
138             'Type': 'onResults',
139             'ResultElapsedRealtime': 4280931,
140             'Index': 10,
141             'Results': [
142                         {
143                          'Flags': 0,
144                          'Id': 4,
145                          'ScanResults':[
146                                          {
147                                           'is80211McRTTResponder': False,
148                                           'channelWidth': 0,
149                                           'numUsage': 0,
150                                           'SSID': '"wh_ap1_2g"',
151                                           'timestamp': 4280078660,
152                                           'BSSID': '30:b5:c2:33:f9:05',
153                                           'frequency': 2412,
154                                           'distanceSdCm': 0,
155                                           'distanceCm': 0,
156                                           'centerFreq1': 0,
157                                           'centerFreq0': 0,
158                                           'venueName': '',
159                                           'seen': 0,
160                                           'operatorFriendlyName': '',
161                                           'level': -31,
162                                           'passpointNetwork': False,
163                                           'untrusted': False
164                                          }
165                                        ]
166                         }
167                        ]
168            },
169          'time': 1491744576383,
170          'name': 'WifiScannerScan10onResults'
171        }
172        """
173        num_of_events = len(self.results_events)
174        asserts.assert_true(
175            num_of_events >= 2,
176            "Expected more than one scan result events, got %d." %
177            num_of_events)
178        for event_idx in range(num_of_events):
179            batches = self.results_events[event_idx]["data"]["Results"]
180            actual_num_of_batches = len(batches)
181            if not actual_num_of_batches:
182                raise signals.TestFailure("Scan returned empty Results list %s "
183                                          "% batches")
184            # For batch scan results.
185            report_type = self.scan_setting['reportEvents']
186            if not (report_type & WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN):
187                # Verifies that the number of buffered results matches the
188                # number defined in scan settings.
189                expected_num_of_batches = self.scan_setting['maxScansToCache']
190                asserts.assert_true(
191                    actual_num_of_batches <= expected_num_of_batches,
192                    "Expected to get at most %d batches in event No.%d, got %d."
193                    % (expected_num_of_batches, event_idx,
194                       actual_num_of_batches))
195            # Check the results within each event of batch scan
196            for batch_idx in range(actual_num_of_batches):
197                if not len(batches[batch_idx]["ScanResults"]):
198                    raise signals.TestFailure("Scan event %d returned empty"
199                    " scan results in batch %d" % (event_idx, batch_idx))
200                # Start checking interval from the second batch.
201                if batch_idx >=1:
202                    self.check_interval(
203                        batches[batch_idx - 1]["ScanResults"][0],
204                        batches[batch_idx]["ScanResults"][0])
205            for batch in batches:
206                self.verify_one_scan_result_group(batch)
207
208            # Check the time gap between the first result of an event and
209            # the last result of its previous event
210            # Skip the very first event.
211            if event_idx >= 1:
212                previous_batches = self.results_events[event_idx - 1]["data"][
213                    "Results"]
214                self.check_interval(previous_batches[-1]["ScanResults"][0],
215                                    batches[0]["ScanResults"][0])
216
217
218class WifiScannerMultiScanTest(WifiBaseTest):
219    """This class is the WiFi Scanner Multi-Scan Test suite.
220    It collects a number of test cases, sets up and executes
221    the tests, and validates the scan results.
222
223    Attributes:
224        tests: A collection of tests to excute.
225        leeway: Scan interval drift time (in seconds).
226        stime_channels: Dwell time plus 2ms.
227        dut: Android device(s).
228        wifi_chs: WiFi channels according to the device model.
229        max_bugreports: Max number of bug reports allowed.
230    """
231
232    def __init__(self, controllers):
233        WifiBaseTest.__init__(self, controllers)
234        self.tests = (
235            'test_wifi_two_scans_at_same_interval',
236            'test_wifi_two_scans_at_different_interval',
237            'test_wifi_scans_24GHz_and_both',
238            'test_wifi_scans_5GHz_and_both',
239            'test_wifi_scans_batch_and_24GHz',
240            'test_wifi_scans_batch_and_5GHz',
241            'test_wifi_scans_24GHz_5GHz_full_result',)
242
243    def setup_class(self):
244        # If running in a setup with attenuators, set attenuation on all
245        # channels to zero.
246        if getattr(self, "attenuators", []):
247            for a in self.attenuators:
248                a.set_atten(0)
249        self.leeway = 5  # seconds, for event wait time computation
250        self.stime_channel = 47  #dwell time plus 2ms
251        self.dut = self.android_devices[0]
252        wutils.wifi_test_device_init(self.dut)
253        asserts.assert_true(self.dut.droid.wifiIsScannerSupported(),
254                            "Device %s doesn't support WifiScanner, abort." %
255                            self.dut.model)
256        """ Setup the required dependencies and fetch the user params from
257        config file.
258        """
259        req_params = ["max_bugreports"]
260        opt_param = ["reference_networks"]
261        self.unpack_userparams(
262            req_param_names=req_params, opt_param_names=opt_param)
263
264        if "AccessPoint" in self.user_params:
265            self.legacy_configure_ap_and_start()
266
267        self.wifi_chs = WifiChannelUS(self.dut.model)
268
269    def on_fail(self, test_name, begin_time):
270        if self.max_bugreports > 0:
271            self.dut.take_bug_report(test_name, begin_time)
272            self.max_bugreports -= 1
273        self.dut.cat_adb_log(test_name, begin_time)
274
275    def teardown_class(self):
276        if "AccessPoint" in self.user_params:
277            del self.user_params["reference_networks"]
278            del self.user_params["open_network"]
279
280    """ Helper Functions Begin """
281
282    def start_scan(self, scan_setting):
283        data = wutils.start_wifi_background_scan(self.dut, scan_setting)
284        idx = data["Index"]
285        # Calculate event wait time from scan setting plus leeway
286        scan_time, scan_channels = wutils.get_scan_time_and_channels(
287            self.wifi_chs, scan_setting, self.stime_channel)
288        scan_period = scan_setting['periodInMs']
289        report_type = scan_setting['reportEvents']
290        if report_type & WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN:
291            scan_time += scan_period
292        else:
293            max_scan = scan_setting['maxScansToCache']
294            scan_time += max_scan * scan_period
295        wait_time = scan_time / 1000 + self.leeway
296        return idx, wait_time, scan_channels
297
298    def validate_scan_results(self, scan_results_dict):
299        # Sanity check to make sure the dict is not empty
300        asserts.assert_true(scan_results_dict, "Scan result dict is empty.")
301        for scan_result_obj in scan_results_dict.values():
302            # Validate the results received for each scan setting
303            scan_result_obj.check_scan_results()
304
305    def wait_for_scan_events(self, wait_time_list, scan_results_dict):
306        """Poll for WifiScanner events and record them"""
307
308        # Compute the event wait time
309        event_wait_time = min(wait_time_list)
310
311        # Compute the maximum test time that guarantee that even the scan
312        # which requires the most wait time will receive at least two
313        # results.
314        max_wait_time = max(wait_time_list)
315        max_end_time = time.monotonic() + max_wait_time
316        self.log.debug("Event wait time %s seconds", event_wait_time)
317
318        try:
319            # Wait for scan results on all the caller specified bands
320            event_name = SCAN_EVENT_TAG
321            while True:
322                self.log.debug("Waiting for events '%s' for up to %s seconds",
323                               event_name, event_wait_time)
324                events = self.dut.ed.pop_events(event_name, event_wait_time)
325                for event in events:
326                    self.log.debug("Event received: %s", event)
327                    # Event name is the key to the scan results dictionary
328                    actual_event_name = event["name"]
329                    asserts.assert_true(
330                        actual_event_name in scan_results_dict,
331                        "Expected one of these event names: %s, got '%s'." %
332                        (scan_results_dict.keys(), actual_event_name))
333
334                    # TODO validate full result callbacks also
335                    if event["name"].endswith("onResults"):
336                        # Append the event
337                        scan_results_dict[actual_event_name].add_results_event(
338                            event)
339
340                # If we time out then stop waiting for events.
341                if time.monotonic() >= max_end_time:
342                    break
343                # If enough scan results have been returned to validate the
344                # results then break early.
345                have_enough_events = True
346                for key in scan_results_dict:
347                    if not scan_results_dict[key].have_enough_events():
348                        have_enough_events = False
349                if have_enough_events:
350                    break
351        except queue.Empty:
352            asserts.fail("Event did not trigger for {} in {} seconds".format(
353                event_name, event_wait_time))
354
355    def scan_and_validate_results(self, scan_settings):
356        """Perform WifiScanner scans and check the scan results
357
358        Procedures:
359          * Start scans for each caller specified setting
360          * Wait for at least two results for each scan
361          * Check the results received for each scan
362        """
363        # Awlays get a clean start
364        self.dut.ed.clear_all_events()
365
366        # Start scanning with the caller specified settings and
367        # compute parameters for receiving events
368        idx_list = []
369        wait_time_list = []
370        scan_results_dict = {}
371
372        try:
373            for scan_setting in scan_settings:
374                self.log.debug(
375                    "Scan setting: band %s, interval %s, reportEvents "
376                    "%s, numBssidsPerScan %s", scan_setting["band"],
377                    scan_setting["periodInMs"], scan_setting["reportEvents"],
378                    scan_setting["numBssidsPerScan"])
379                idx, wait_time, scan_chan = self.start_scan(scan_setting)
380                self.log.debug(
381                    "Scan started for band %s: idx %s, wait_time %ss, scan_channels %s",
382                    scan_setting["band"], idx, wait_time, scan_chan)
383                idx_list.append(idx)
384                wait_time_list.append(wait_time)
385
386                report_type = scan_setting['reportEvents']
387                scan_results_events = WifiScanResultEvents(scan_setting,
388                                                           scan_chan)
389                scan_results_dict["{}{}onResults".format(
390                    SCAN_EVENT_TAG, idx)] = scan_results_events
391                if (scan_setting['reportEvents']
392                        & WifiEnums.REPORT_EVENT_FULL_SCAN_RESULT):
393                    scan_results_dict["{}{}onFullResult".format(
394                        SCAN_EVENT_TAG, idx)] = scan_results_events
395
396            self.wait_for_scan_events(wait_time_list, scan_results_dict)
397
398            # Validate the scan results
399            self.validate_scan_results(scan_results_dict)
400
401        finally:
402            # Tear down and clean up
403            for idx in idx_list:
404                self.dut.droid.wifiScannerStopBackgroundScan(idx)
405            self.dut.ed.clear_all_events()
406
407    """ Helper Functions End """
408    """ Tests Begin """
409
410    @test_tracker_info(uuid="d490b146-5fc3-4fc3-9958-78ba0ad63211")
411    @WifiBaseTest.wifi_test_wrap
412    def test_wifi_two_scans_at_same_interval(self):
413        """Perform two WifiScanner background scans, one at 2.4GHz and the other
414        at 5GHz, the same interval and number of BSSIDs per scan.
415
416        Initial Conditions:
417          * Set multiple APs broadcasting 2.4GHz and 5GHz.
418
419        Expected Results:
420          * DUT reports success for starting both scans
421          * Scan results for each callback contains only the results on the
422            frequency scanned
423          * Wait for at least two scan results and confirm that separation
424            between them approximately equals to the expected interval
425          * Number of BSSIDs doesn't exceed
426        """
427        scan_settings = [{"band": WifiEnums.WIFI_BAND_24_GHZ,
428                          "periodInMs": 10000,  # ms
429                          "reportEvents":
430                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
431                          "numBssidsPerScan": 24},
432                         {"band": WifiEnums.WIFI_BAND_5_GHZ,
433                          "periodInMs": 10000,  # ms
434                          "reportEvents":
435                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
436                          "numBssidsPerScan": 24}]
437
438        self.scan_and_validate_results(scan_settings)
439
440    @test_tracker_info(uuid="0ec9a554-f942-41a9-8096-6b0b400f60b0")
441    @WifiBaseTest.wifi_test_wrap
442    def test_wifi_two_scans_at_different_interval(self):
443        """Perform two WifiScanner background scans, one at 2.4GHz and the other
444        at 5GHz, different interval and number of BSSIDs per scan.
445
446        Initial Conditions:
447          * Set multiple APs broadcasting 2.4GHz and 5GHz.
448
449        Expected Results:
450          * DUT reports success for starting both scans
451          * Scan results for each callback contains only the results on the
452            frequency scanned
453          * Wait for at least two scan results and confirm that separation
454            between them approximately equals to the expected interval
455          * Number of BSSIDs doesn't exceed
456        """
457        scan_settings = [{"band": WifiEnums.WIFI_BAND_24_GHZ,
458                          "periodInMs": 10000,  # ms
459                          "reportEvents":
460                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
461                          "numBssidsPerScan": 20},
462                         {"band": WifiEnums.WIFI_BAND_5_GHZ,
463                          "periodInMs": 30000,  # ms
464                          "reportEvents":
465                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
466                          "numBssidsPerScan": 24}]
467
468        self.scan_and_validate_results(scan_settings)
469
470    @test_tracker_info(uuid="0d616591-0d32-4be6-8fd4-e4a5e9ccdce0")
471    @WifiBaseTest.wifi_test_wrap
472    def test_wifi_scans_24GHz_and_both(self):
473        """Perform two WifiScanner background scans, one at 2.4GHz and
474           the other at both 2.4GHz and 5GHz
475
476        Initial Conditions:
477          * Set multiple APs broadcasting 2.4GHz and 5GHz.
478
479        Expected Results:
480          * DUT reports success for starting both scans
481          * Scan results for each callback contains only the results on the
482            frequency scanned
483          * Wait for at least two scan results and confirm that separation
484            between them approximately equals to the expected interval
485          * Number of BSSIDs doesn't exceed
486        """
487        scan_settings = [{"band": WifiEnums.WIFI_BAND_BOTH,
488                          "periodInMs": 10000,  # ms
489                          "reportEvents":
490                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
491                          "numBssidsPerScan": 24},
492                         {"band": WifiEnums.WIFI_BAND_24_GHZ,
493                          "periodInMs": 10000,  # ms
494                          "reportEvents":
495                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
496                          "numBssidsPerScan": 24}]
497
498        self.scan_and_validate_results(scan_settings)
499
500    @test_tracker_info(uuid="ddcf959e-512a-4e86-b3d3-18cebd0b22a0")
501    @WifiBaseTest.wifi_test_wrap
502    def test_wifi_scans_5GHz_and_both(self):
503        """Perform two WifiScanner scans, one at 5GHz and the other at both
504           2.4GHz and 5GHz
505
506        Initial Conditions:
507          * Set multiple APs broadcasting 2.4GHz and 5GHz.
508
509        Expected Results:
510          * DUT reports success for starting both scans
511          * Scan results for each callback contains only the results on the
512            frequency scanned
513          * Wait for at least two scan results and confirm that separation
514            between them approximately equals to the expected interval
515          * Number of BSSIDs doesn't exceed
516        """
517        scan_settings = [{"band": WifiEnums.WIFI_BAND_BOTH,
518                          "periodInMs": 10000,  # ms
519                          "reportEvents":
520                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
521                          "numBssidsPerScan": 24},
522                         {"band": WifiEnums.WIFI_BAND_5_GHZ,
523                          "periodInMs": 10000,  # ms
524                          "reportEvents":
525                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
526                          "numBssidsPerScan": 24}]
527
528        self.scan_and_validate_results(scan_settings)
529
530    @test_tracker_info(uuid="060469f1-fc6b-4255-ab6e-b1d5b54db53d")
531    @WifiBaseTest.wifi_test_wrap
532    def test_wifi_scans_24GHz_5GHz_and_DFS(self):
533        """Perform three WifiScanner scans, one at 5GHz, one at 2.4GHz and the
534        other at just 5GHz DFS channels
535
536        Initial Conditions:
537          * Set multiple APs broadcasting 2.4GHz and 5GHz.
538
539        Expected Results:
540          * DUT reports success for starting both scans
541          * Scan results for each callback contains only the results on the
542            frequency scanned
543          * Wait for at least two scan results and confirm that separation
544            between them approximately equals to the expected interval
545          * Number of BSSIDs doesn't exceed
546        """
547        scan_settings = [
548            {"band": WifiEnums.WIFI_BAND_5_GHZ_DFS_ONLY,
549             "periodInMs": 10000,  # ms
550             "reportEvents": WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
551             "numBssidsPerScan": 24},
552            {"band": WifiEnums.WIFI_BAND_5_GHZ,
553             "periodInMs": 10000,  # ms
554             "reportEvents": WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
555             "numBssidsPerScan": 24},
556            {"band": WifiEnums.WIFI_BAND_24_GHZ,
557             "periodInMs": 30000,  # ms
558             "reportEvents": WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
559             "numBssidsPerScan": 24}
560        ]
561
562        self.scan_and_validate_results(scan_settings)
563
564    @test_tracker_info(uuid="14104e98-27a0-43d5-9525-b36b65ac3957")
565    @WifiBaseTest.wifi_test_wrap
566    def test_wifi_scans_batch_and_24GHz(self):
567        """Perform two WifiScanner background scans, one in batch mode for both
568        bands and the other in periodic mode at 2.4GHz
569
570        Initial Conditions:
571          * Set multiple APs broadcasting 2.4GHz and 5GHz.
572
573        Expected Results:
574          * DUT reports success for starting both scans
575          * Scan results for each callback contains only the results on the
576            frequency scanned
577          * Wait for at least two scan results and confirm that separation
578            between them approximately equals to the expected interval
579          * Number of results in batch mode should match the setting
580          * Number of BSSIDs doesn't exceed
581        """
582        scan_settings = [{"band": WifiEnums.WIFI_BAND_BOTH,
583                          "periodInMs": 10000,  # ms
584                          "reportEvents":
585                          WifiEnums.REPORT_EVENT_AFTER_BUFFER_FULL,
586                          "numBssidsPerScan": 24,
587                          "maxScansToCache": 2},
588                         {"band": WifiEnums.WIFI_BAND_24_GHZ,
589                          "periodInMs": 10000,  # ms
590                          "reportEvents":
591                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
592                          "numBssidsPerScan": 24}]
593
594        self.scan_and_validate_results(scan_settings)
595
596    @test_tracker_info(uuid="cd6064b5-840b-4334-8cd4-8320a6cda52f")
597    @WifiBaseTest.wifi_test_wrap
598    def test_wifi_scans_batch_and_5GHz(self):
599        """Perform two WifiScanner background scans, one in batch mode for both
600        bands and the other in periodic mode at 5GHz
601
602        Initial Conditions:
603          * Set multiple APs broadcasting 2.4GHz and 5GHz.
604
605        Expected Results:
606          * DUT reports success for starting both scans
607          * Scan results for each callback contains only the results on the
608            frequency scanned
609          * Wait for at least two scan results and confirm that separation
610            between them approximately equals to the expected interval
611          * Number of results in batch mode should match the setting
612          * Number of BSSIDs doesn't exceed
613        """
614        scan_settings = [{"band": WifiEnums.WIFI_BAND_BOTH,
615                          "periodInMs": 10000,  # ms
616                          "reportEvents":
617                          WifiEnums.REPORT_EVENT_AFTER_BUFFER_FULL,
618                          "numBssidsPerScan": 24,
619                          "maxScansToCache": 2},
620                         {"band": WifiEnums.WIFI_BAND_5_GHZ,
621                          "periodInMs": 10000,  # ms
622                          "reportEvents":
623                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
624                          "numBssidsPerScan": 24}]
625
626        self.scan_and_validate_results(scan_settings)
627
628    @test_tracker_info(uuid="9f48cb0c-de87-4cd2-9e50-857579d44079")
629    @WifiBaseTest.wifi_test_wrap
630    def test_wifi_scans_24GHz_5GHz_full_result(self):
631        """Perform two WifiScanner background scans, one at 2.4GHz and
632           the other at 5GHz. Report full scan results.
633
634        Initial Conditions:
635          * Set multiple APs broadcasting 2.4GHz and 5GHz.
636
637        Expected Results:
638          * DUT reports success for starting both scans
639          * Scan results for each callback contains only the results on the
640            frequency scanned
641          * Wait for at least two scan results and confirm that separation
642            between them approximately equals to the expected interval
643          * Number of BSSIDs doesn't exceed
644        """
645        scan_settings = [
646            {"band": WifiEnums.WIFI_BAND_24_GHZ,
647             "periodInMs": 10000,  # ms
648             "reportEvents": WifiEnums.REPORT_EVENT_FULL_SCAN_RESULT
649             | WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
650             "numBssidsPerScan": 24},
651            {"band": WifiEnums.WIFI_BAND_5_GHZ,
652             "periodInMs": 10000,  # ms
653             "reportEvents": WifiEnums.REPORT_EVENT_FULL_SCAN_RESULT
654             | WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
655             "numBssidsPerScan": 24}
656        ]
657
658        self.scan_and_validate_results(scan_settings)
659
660    """ Tests End """
661