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
235    def setup_class(self):
236        # If running in a setup with attenuators, set attenuation on all
237        # channels to zero.
238        if getattr(self, "attenuators", []):
239            for a in self.attenuators:
240                a.set_atten(0)
241        self.leeway = 5  # seconds, for event wait time computation
242        self.stime_channel = 47  #dwell time plus 2ms
243        self.dut = self.android_devices[0]
244        wutils.wifi_test_device_init(self.dut)
245        asserts.assert_true(self.dut.droid.wifiIsScannerSupported(),
246                            "Device %s doesn't support WifiScanner, abort." %
247                            self.dut.model)
248        """ Setup the required dependencies and fetch the user params from
249        config file.
250        """
251        req_params = ("bssid_2g", "bssid_5g", "bssid_dfs", "max_bugreports")
252        opt_param = ["reference_networks"]
253        self.unpack_userparams(
254            req_param_names=req_params, opt_param_names=opt_param)
255
256        if "AccessPoint" in self.user_params:
257            self.legacy_configure_ap_and_start()
258
259        self.wifi_chs = WifiChannelUS(self.dut.model)
260
261    def on_fail(self, test_name, begin_time):
262        if self.max_bugreports > 0:
263            self.dut.take_bug_report(test_name, begin_time)
264            self.max_bugreports -= 1
265        self.dut.cat_adb_log(test_name, begin_time)
266
267    def teardown_class(self):
268        if "AccessPoint" in self.user_params:
269            del self.user_params["reference_networks"]
270            del self.user_params["open_network"]
271
272    """ Helper Functions Begin """
273
274    def start_scan(self, scan_setting):
275        data = wutils.start_wifi_background_scan(self.dut, scan_setting)
276        idx = data["Index"]
277        # Calculate event wait time from scan setting plus leeway
278        scan_time, scan_channels = wutils.get_scan_time_and_channels(
279            self.wifi_chs, scan_setting, self.stime_channel)
280        scan_period = scan_setting['periodInMs']
281        report_type = scan_setting['reportEvents']
282        if report_type & WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN:
283            scan_time += scan_period
284        else:
285            max_scan = scan_setting['maxScansToCache']
286            scan_time += max_scan * scan_period
287        wait_time = scan_time / 1000 + self.leeway
288        return idx, wait_time, scan_channels
289
290    def validate_scan_results(self, scan_results_dict):
291        # Sanity check to make sure the dict is not empty
292        asserts.assert_true(scan_results_dict, "Scan result dict is empty.")
293        for scan_result_obj in scan_results_dict.values():
294            # Validate the results received for each scan setting
295            scan_result_obj.check_scan_results()
296
297    def wait_for_scan_events(self, wait_time_list, scan_results_dict):
298        """Poll for WifiScanner events and record them"""
299
300        # Compute the event wait time
301        event_wait_time = min(wait_time_list)
302
303        # Compute the maximum test time that guarantee that even the scan
304        # which requires the most wait time will receive at least two
305        # results.
306        max_wait_time = max(wait_time_list)
307        max_end_time = time.monotonic() + max_wait_time
308        self.log.debug("Event wait time %s seconds", event_wait_time)
309
310        try:
311            # Wait for scan results on all the caller specified bands
312            event_name = SCAN_EVENT_TAG
313            while True:
314                self.log.debug("Waiting for events '%s' for up to %s seconds",
315                               event_name, event_wait_time)
316                events = self.dut.ed.pop_events(event_name, event_wait_time)
317                for event in events:
318                    self.log.debug("Event received: %s", event)
319                    # Event name is the key to the scan results dictionary
320                    actual_event_name = event["name"]
321                    asserts.assert_true(
322                        actual_event_name in scan_results_dict,
323                        "Expected one of these event names: %s, got '%s'." %
324                        (scan_results_dict.keys(), actual_event_name))
325
326                    # TODO validate full result callbacks also
327                    if event["name"].endswith("onResults"):
328                        # Append the event
329                        scan_results_dict[actual_event_name].add_results_event(
330                            event)
331
332                # If we time out then stop waiting for events.
333                if time.monotonic() >= max_end_time:
334                    break
335                # If enough scan results have been returned to validate the
336                # results then break early.
337                have_enough_events = True
338                for key in scan_results_dict:
339                    if not scan_results_dict[key].have_enough_events():
340                        have_enough_events = False
341                if have_enough_events:
342                    break
343        except queue.Empty:
344            asserts.fail("Event did not trigger for {} in {} seconds".format(
345                event_name, event_wait_time))
346
347    def scan_and_validate_results(self, scan_settings):
348        """Perform WifiScanner scans and check the scan results
349
350        Procedures:
351          * Start scans for each caller specified setting
352          * Wait for at least two results for each scan
353          * Check the results received for each scan
354        """
355        # Awlays get a clean start
356        self.dut.ed.clear_all_events()
357
358        # Start scanning with the caller specified settings and
359        # compute parameters for receiving events
360        idx_list = []
361        wait_time_list = []
362        scan_results_dict = {}
363
364        try:
365            for scan_setting in scan_settings:
366                self.log.debug(
367                    "Scan setting: band %s, interval %s, reportEvents "
368                    "%s, numBssidsPerScan %s", scan_setting["band"],
369                    scan_setting["periodInMs"], scan_setting["reportEvents"],
370                    scan_setting["numBssidsPerScan"])
371                idx, wait_time, scan_chan = self.start_scan(scan_setting)
372                self.log.debug(
373                    "Scan started for band %s: idx %s, wait_time %ss, scan_channels %s",
374                    scan_setting["band"], idx, wait_time, scan_chan)
375                idx_list.append(idx)
376                wait_time_list.append(wait_time)
377
378                report_type = scan_setting['reportEvents']
379                scan_results_events = WifiScanResultEvents(scan_setting,
380                                                           scan_chan)
381                scan_results_dict["{}{}onResults".format(
382                    SCAN_EVENT_TAG, idx)] = scan_results_events
383                if (scan_setting['reportEvents']
384                        & WifiEnums.REPORT_EVENT_FULL_SCAN_RESULT):
385                    scan_results_dict["{}{}onFullResult".format(
386                        SCAN_EVENT_TAG, idx)] = scan_results_events
387
388            self.wait_for_scan_events(wait_time_list, scan_results_dict)
389
390            # Validate the scan results
391            self.validate_scan_results(scan_results_dict)
392
393        finally:
394            # Tear down and clean up
395            for idx in idx_list:
396                self.dut.droid.wifiScannerStopBackgroundScan(idx)
397            self.dut.ed.clear_all_events()
398
399    """ Helper Functions End """
400    """ Tests Begin """
401
402    @test_tracker_info(uuid="d490b146-5fc3-4fc3-9958-78ba0ad63211")
403    def test_wifi_two_scans_at_same_interval(self):
404        """Perform two WifiScanner background scans, one at 2.4GHz and the other
405        at 5GHz, the same interval and number of BSSIDs per scan.
406
407        Initial Conditions:
408          * Set multiple APs broadcasting 2.4GHz and 5GHz.
409
410        Expected Results:
411          * DUT reports success for starting both scans
412          * Scan results for each callback contains only the results on the
413            frequency scanned
414          * Wait for at least two scan results and confirm that separation
415            between them approximately equals to the expected interval
416          * Number of BSSIDs doesn't exceed
417        """
418        scan_settings = [{"band": WifiEnums.WIFI_BAND_24_GHZ,
419                          "periodInMs": 10000,  # ms
420                          "reportEvents":
421                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
422                          "numBssidsPerScan": 24},
423                         {"band": WifiEnums.WIFI_BAND_5_GHZ,
424                          "periodInMs": 10000,  # ms
425                          "reportEvents":
426                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
427                          "numBssidsPerScan": 24}]
428
429        self.scan_and_validate_results(scan_settings)
430
431    @test_tracker_info(uuid="0ec9a554-f942-41a9-8096-6b0b400f60b0")
432    def test_wifi_two_scans_at_different_interval(self):
433        """Perform two WifiScanner background scans, one at 2.4GHz and the other
434        at 5GHz, different interval and number of BSSIDs per scan.
435
436        Initial Conditions:
437          * Set multiple APs broadcasting 2.4GHz and 5GHz.
438
439        Expected Results:
440          * DUT reports success for starting both scans
441          * Scan results for each callback contains only the results on the
442            frequency scanned
443          * Wait for at least two scan results and confirm that separation
444            between them approximately equals to the expected interval
445          * Number of BSSIDs doesn't exceed
446        """
447        scan_settings = [{"band": WifiEnums.WIFI_BAND_24_GHZ,
448                          "periodInMs": 10000,  # ms
449                          "reportEvents":
450                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
451                          "numBssidsPerScan": 20},
452                         {"band": WifiEnums.WIFI_BAND_5_GHZ,
453                          "periodInMs": 30000,  # ms
454                          "reportEvents":
455                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
456                          "numBssidsPerScan": 24}]
457
458        self.scan_and_validate_results(scan_settings)
459
460    @test_tracker_info(uuid="0d616591-0d32-4be6-8fd4-e4a5e9ccdce0")
461    def test_wifi_scans_24GHz_and_both(self):
462        """Perform two WifiScanner background scans, one at 2.4GHz and
463           the other at both 2.4GHz and 5GHz
464
465        Initial Conditions:
466          * Set multiple APs broadcasting 2.4GHz and 5GHz.
467
468        Expected Results:
469          * DUT reports success for starting both scans
470          * Scan results for each callback contains only the results on the
471            frequency scanned
472          * Wait for at least two scan results and confirm that separation
473            between them approximately equals to the expected interval
474          * Number of BSSIDs doesn't exceed
475        """
476        scan_settings = [{"band": WifiEnums.WIFI_BAND_BOTH,
477                          "periodInMs": 10000,  # ms
478                          "reportEvents":
479                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
480                          "numBssidsPerScan": 24},
481                         {"band": WifiEnums.WIFI_BAND_24_GHZ,
482                          "periodInMs": 10000,  # ms
483                          "reportEvents":
484                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
485                          "numBssidsPerScan": 24}]
486
487        self.scan_and_validate_results(scan_settings)
488
489    @test_tracker_info(uuid="ddcf959e-512a-4e86-b3d3-18cebd0b22a0")
490    def test_wifi_scans_5GHz_and_both(self):
491        """Perform two WifiScanner scans, one at 5GHz and the other at both
492           2.4GHz and 5GHz
493
494        Initial Conditions:
495          * Set multiple APs broadcasting 2.4GHz and 5GHz.
496
497        Expected Results:
498          * DUT reports success for starting both scans
499          * Scan results for each callback contains only the results on the
500            frequency scanned
501          * Wait for at least two scan results and confirm that separation
502            between them approximately equals to the expected interval
503          * Number of BSSIDs doesn't exceed
504        """
505        scan_settings = [{"band": WifiEnums.WIFI_BAND_BOTH,
506                          "periodInMs": 10000,  # ms
507                          "reportEvents":
508                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
509                          "numBssidsPerScan": 24},
510                         {"band": WifiEnums.WIFI_BAND_5_GHZ,
511                          "periodInMs": 10000,  # ms
512                          "reportEvents":
513                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
514                          "numBssidsPerScan": 24}]
515
516        self.scan_and_validate_results(scan_settings)
517
518    @test_tracker_info(uuid="060469f1-fc6b-4255-ab6e-b1d5b54db53d")
519    def test_wifi_scans_24GHz_5GHz_and_DFS(self):
520        """Perform three WifiScanner scans, one at 5GHz, one at 2.4GHz and the
521        other at just 5GHz DFS channels
522
523        Initial Conditions:
524          * Set multiple APs broadcasting 2.4GHz and 5GHz.
525
526        Expected Results:
527          * DUT reports success for starting both scans
528          * Scan results for each callback contains only the results on the
529            frequency scanned
530          * Wait for at least two scan results and confirm that separation
531            between them approximately equals to the expected interval
532          * Number of BSSIDs doesn't exceed
533        """
534        scan_settings = [
535            {"band": WifiEnums.WIFI_BAND_5_GHZ_DFS_ONLY,
536             "periodInMs": 10000,  # ms
537             "reportEvents": WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
538             "numBssidsPerScan": 24},
539            {"band": WifiEnums.WIFI_BAND_5_GHZ,
540             "periodInMs": 10000,  # ms
541             "reportEvents": WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
542             "numBssidsPerScan": 24},
543            {"band": WifiEnums.WIFI_BAND_24_GHZ,
544             "periodInMs": 30000,  # ms
545             "reportEvents": WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
546             "numBssidsPerScan": 24}
547        ]
548
549        self.scan_and_validate_results(scan_settings)
550
551    @test_tracker_info(uuid="14104e98-27a0-43d5-9525-b36b65ac3957")
552    def test_wifi_scans_batch_and_24GHz(self):
553        """Perform two WifiScanner background scans, one in batch mode for both
554        bands and the other in periodic mode at 2.4GHz
555
556        Initial Conditions:
557          * Set multiple APs broadcasting 2.4GHz and 5GHz.
558
559        Expected Results:
560          * DUT reports success for starting both scans
561          * Scan results for each callback contains only the results on the
562            frequency scanned
563          * Wait for at least two scan results and confirm that separation
564            between them approximately equals to the expected interval
565          * Number of results in batch mode should match the setting
566          * Number of BSSIDs doesn't exceed
567        """
568        scan_settings = [{"band": WifiEnums.WIFI_BAND_BOTH,
569                          "periodInMs": 10000,  # ms
570                          "reportEvents":
571                          WifiEnums.REPORT_EVENT_AFTER_BUFFER_FULL,
572                          "numBssidsPerScan": 24,
573                          "maxScansToCache": 2},
574                         {"band": WifiEnums.WIFI_BAND_24_GHZ,
575                          "periodInMs": 10000,  # ms
576                          "reportEvents":
577                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
578                          "numBssidsPerScan": 24}]
579
580        self.scan_and_validate_results(scan_settings)
581
582    @test_tracker_info(uuid="cd6064b5-840b-4334-8cd4-8320a6cda52f")
583    def test_wifi_scans_batch_and_5GHz(self):
584        """Perform two WifiScanner background scans, one in batch mode for both
585        bands and the other in periodic mode at 5GHz
586
587        Initial Conditions:
588          * Set multiple APs broadcasting 2.4GHz and 5GHz.
589
590        Expected Results:
591          * DUT reports success for starting both scans
592          * Scan results for each callback contains only the results on the
593            frequency scanned
594          * Wait for at least two scan results and confirm that separation
595            between them approximately equals to the expected interval
596          * Number of results in batch mode should match the setting
597          * Number of BSSIDs doesn't exceed
598        """
599        scan_settings = [{"band": WifiEnums.WIFI_BAND_BOTH,
600                          "periodInMs": 10000,  # ms
601                          "reportEvents":
602                          WifiEnums.REPORT_EVENT_AFTER_BUFFER_FULL,
603                          "numBssidsPerScan": 24,
604                          "maxScansToCache": 2},
605                         {"band": WifiEnums.WIFI_BAND_5_GHZ,
606                          "periodInMs": 10000,  # ms
607                          "reportEvents":
608                          WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
609                          "numBssidsPerScan": 24}]
610
611        self.scan_and_validate_results(scan_settings)
612
613    @test_tracker_info(uuid="9f48cb0c-de87-4cd2-9e50-857579d44079")
614    def test_wifi_scans_24GHz_5GHz_full_result(self):
615        """Perform two WifiScanner background scans, one at 2.4GHz and
616           the other at 5GHz. Report full scan results.
617
618        Initial Conditions:
619          * Set multiple APs broadcasting 2.4GHz and 5GHz.
620
621        Expected Results:
622          * DUT reports success for starting both scans
623          * Scan results for each callback contains only the results on the
624            frequency scanned
625          * Wait for at least two scan results and confirm that separation
626            between them approximately equals to the expected interval
627          * Number of BSSIDs doesn't exceed
628        """
629        scan_settings = [
630            {"band": WifiEnums.WIFI_BAND_24_GHZ,
631             "periodInMs": 10000,  # ms
632             "reportEvents": WifiEnums.REPORT_EVENT_FULL_SCAN_RESULT
633             | WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
634             "numBssidsPerScan": 24},
635            {"band": WifiEnums.WIFI_BAND_5_GHZ,
636             "periodInMs": 10000,  # ms
637             "reportEvents": WifiEnums.REPORT_EVENT_FULL_SCAN_RESULT
638             | WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN,
639             "numBssidsPerScan": 24}
640        ]
641
642        self.scan_and_validate_results(scan_settings)
643
644    """ Tests End """
645