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 17 import json 18 import os 19 import itertools 20 21 from queue import Empty 22 from acts import asserts 23 from acts.base_test import BaseTestClass 24 from acts.utils import load_config 25 from acts.test_utils.wifi.wifi_test_utils import start_wifi_track_bssid 26 from acts.test_utils.wifi.wifi_test_utils import start_wifi_background_scan 27 from acts.test_utils.wifi.wifi_test_utils import wifi_test_device_init 28 from acts.test_utils.wifi.wifi_test_utils import WifiChannelUS 29 from acts.test_utils.wifi.wifi_test_utils import WifiEnums 30 from acts.test_utils.wifi.wifi_test_utils import get_scan_time_and_channels 31 32 33 BSSID_EVENT_WAIT = 30 34 35 BSSID_EVENT_TAG = "WifiScannerBssid" 36 SCAN_EVENT_TAG = "WifiScannerScan" 37 SCANTIME = 10000 #framework support only 10s as minimum scan interval 38 39 class WifiScannerBssidError(Exception): 40 pass 41 42 class WifiScannerBssidTest(BaseTestClass): 43 44 def __init__(self, controllers): 45 BaseTestClass.__init__(self, controllers) 46 # A list of all test cases to be executed in this class. 47 self.tests = ("test_wifi_track_bssid_sanity", 48 "test_wifi_track_bssid_found", 49 "test_wifi_track_bssid_lost", 50 "test_wifi_track_bssid_for_2g_while_scanning_5g_channels", 51 "test_wifi_track_bssid_for_5g_while_scanning_2g_channels",) 52 self.default_scan_setting = { 53 "band": WifiEnums.WIFI_BAND_BOTH_WITH_DFS, 54 "periodInMs": SCANTIME, 55 "reportEvents": WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN, 56 'numBssidsPerScan': 32 57 } 58 self.leeway = 5 59 self.stime_channel = 47 #dwell time plus 2ms 60 61 def setup_class(self): 62 self.dut = self.android_devices[0] 63 wifi_test_device_init(self.dut) 64 asserts.assert_true(self.dut.droid.wifiIsScannerSupported(), 65 "Device %s doesn't support WifiScanner, abort." % self.dut.model) 66 """It will setup the required dependencies and fetch the user params from 67 config file""" 68 self.attenuators[0].set_atten(0) 69 self.attenuators[1].set_atten(0) 70 req_params = ("bssid_2g", "bssid_5g", "bssid_dfs", "attenuator_id", 71 "max_bugreports") 72 self.wifi_chs = WifiChannelUS(self.dut.model) 73 self.unpack_userparams(req_params) 74 75 def teardown_class(self): 76 BaseTestClass.teardown_test(self) 77 self.log.debug("Shut down all wifi scanner activities.") 78 self.dut.droid.wifiScannerShutdown() 79 80 def on_fail(self, test_name, begin_time): 81 if self.max_bugreports > 0: 82 self.dut.take_bug_report(test_name, begin_time) 83 self.max_bugreports -= 1 84 85 """ Helper Functions Begin """ 86 def fetch_scan_result(self, scan_idx, scan_setting): 87 """Fetch the scan result for provider listener index. 88 89 This function calculate the time required for scanning based on scan setting 90 and wait for scan result event, on triggering of event process the scan result. 91 92 Args: 93 scan_idx: Index of the scan listener. 94 scan_setting: Setting used for starting the scan. 95 96 Returns: 97 scan_results: if scan result available. 98 """ 99 #generating event wait time from scan setting plus leeway 100 self.log.debug(scan_setting) 101 scan_time, scan_channels = get_scan_time_and_channels(self.wifi_chs, 102 scan_setting, 103 self.stime_channel) 104 scan_time += scan_setting['periodInMs'] #add scan period delay for next cycle 105 if scan_setting["reportEvents"] == WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN: 106 waittime = int(scan_time/1000) + self.leeway 107 else: 108 time_cache = scan_setting['periodInMs'] * 10 #default cache 109 waittime = int((time_cache + scan_time )/1000) + self.leeway 110 event_name = "{}{}onResults".format(SCAN_EVENT_TAG, scan_idx) 111 self.log.info("Waiting for the scan result event {}".format(event_name)) 112 event = self.dut.ed.pop_event(event_name, waittime) 113 results = event["data"]["Results"] 114 if len(results) > 0 and "ScanResults" in results[0]: 115 return results[0]["ScanResults"] 116 117 def start_scan_and_validate_environment(self, scan_setting, bssid_settings): 118 """Validate environment for test using current scan result for provided 119 settings. 120 121 This function start the scan for given setting and verify that interested 122 Bssids are in scan result or not. 123 124 Args: 125 scan_setting: Setting used for starting the scan. 126 bssid_settings: list of bssid settings. 127 128 Returns: 129 True, if bssid not found in scan result. 130 """ 131 try: 132 data = start_wifi_background_scan(self.dut, scan_setting) 133 self.scan_idx = data["Index"] 134 results = self.fetch_scan_result(self.scan_idx, scan_setting) 135 self.log.debug("scan result {}".format(results)) 136 asserts.assert_true(results, "Device is not able to fetch the scan results") 137 for result in results: 138 for bssid_setting in bssid_settings: 139 if bssid_setting[WifiEnums.BSSID_KEY] == result[WifiEnums.BSSID_KEY]: 140 self.log.error("Bssid {} already exist in current scan results". 141 format(result[WifiEnums.BSSID_KEY])) 142 return False 143 except Empty as error: 144 self.dut.droid.wifiScannerStopBackgroundScan(self.scan_idx) 145 raise AssertionError("OnResult event did not triggered for scanner\n{}". 146 format(error)) 147 return True 148 149 def check_bssid_in_found_result(self, bssid_settings, found_results): 150 """look for any tracked bssid in reported result of found bssids. 151 152 Args: 153 bssid_settings:Setting used for tracking bssids. 154 found_results: Result reported in found event. 155 156 Returns: 157 True if bssid is present in result. 158 """ 159 for bssid_setting in bssid_settings: 160 for found_result in found_results: 161 if found_result[WifiEnums.BSSID_KEY] == bssid_setting[WifiEnums. 162 BSSID_KEY]: 163 return True 164 return False 165 166 def track_bssid_with_vaild_scan_for_found(self, track_setting): 167 """Common logic for tracking a bssid for Found event. 168 169 1. Starts Wifi Scanner bssid tracking for interested bssids in track_setting. 170 2. Start Wifi Scanner scan with default scan settings. 171 3. Validate the environment to check AP is not in range. 172 4. Attenuate the signal to make AP in range. 173 5. Verified that onFound event is triggered for interested bssids in 174 track setting. 175 176 Args: 177 track_setting: Setting for bssid tracking. 178 179 Returns: 180 True if found event occur for interested BSSID. 181 """ 182 self.attenuators[self.attenuator_id].set_atten(90) 183 data = start_wifi_track_bssid(self.dut, track_setting) 184 idx = data["Index"] 185 valid_env = self.start_scan_and_validate_environment( 186 self.default_scan_setting, track_setting["bssidInfos"]) 187 try: 188 asserts.assert_true(valid_env, 189 "Test environment is not valid, AP is in range") 190 self.attenuators[self.attenuator_id].set_atten(0) 191 event_name = "{}{}onFound".format(BSSID_EVENT_TAG, idx) 192 self.log.info("Waiting for the BSSID event {}".format(event_name)) 193 event = self.dut.ed.pop_event(event_name, BSSID_EVENT_WAIT) 194 self.log.debug(event) 195 found = self.check_bssid_in_found_result(track_setting["bssidInfos"], 196 event["data"]["Results"]) 197 asserts.assert_true(found, 198 "Test fail because Bssid is not found in event results") 199 except Empty as error: 200 self.log.error("{}".format(error)) 201 # log scan result for debugging 202 results = self.fetch_scan_result(self.scan_idx, 203 self.default_scan_setting) 204 self.log.debug("scan result {}".format(results)) 205 raise AssertionError("Event {} did not triggered for {}\n{}". 206 format(event_name, track_setting["bssidInfos"], 207 error)) 208 finally: 209 self.dut.droid.wifiScannerStopBackgroundScan(self.scan_idx) 210 self.dut.droid.wifiScannerStopTrackingBssids(idx) 211 212 def track_bssid_with_vaild_scan_for_lost(self, track_setting): 213 """Common logic for tracking a bssid for Lost event. 214 215 1. Start Wifi Scanner scan with default scan settings. 216 2. Validate the environment to check AP is not in range. 217 3. Starts Wifi Scanner bssid tracking for interested bssids in track_setting. 218 4. Attenuate the signal to make Bssids in range. 219 5. Verified that onFound event is triggered for interested bssids in 220 track setting. 221 6. Attenuate the signal to make Bssids out of range. 222 7. Verified that onLost event is triggered. 223 224 Args: 225 track_setting: Setting for bssid tracking. 226 scan_setting: Setting used for starting the scan. 227 228 Returns: 229 True if Lost event occur for interested BSSID. 230 """ 231 self.attenuators[self.attenuator_id].set_atten(90) 232 valid_env = self.start_scan_and_validate_environment( 233 self.default_scan_setting, track_setting["bssidInfos"]) 234 idx = None 235 found = False 236 try: 237 asserts.assert_true(valid_env, 238 "Test environment is not valid, AP is in range") 239 data = start_wifi_track_bssid(self.dut, track_setting) 240 idx = data["Index"] 241 self.attenuators[self.attenuator_id].set_atten(0) 242 #onFound event should be occurre before tracking for onLost event 243 event_name = "{}{}onFound".format(BSSID_EVENT_TAG, idx) 244 self.log.info("Waiting for the BSSID event {}".format(event_name)) 245 event = self.dut.ed.pop_event(event_name, BSSID_EVENT_WAIT) 246 self.log.debug(event) 247 found = self.check_bssid_in_found_result(track_setting["bssidInfos"], 248 event["data"]["Results"]) 249 asserts.assert_true(found, 250 "Test fail because Bssid is not found in event results") 251 if found: 252 self.attenuators[self.attenuator_id].set_atten(90) 253 # log scan result for debugging 254 for i in range(1, track_setting["apLostThreshold"]): 255 results = self.fetch_scan_result(self.scan_idx, 256 self.default_scan_setting) 257 self.log.debug("scan result {} {}".format(i, results)) 258 event_name = "{}{}onLost".format(BSSID_EVENT_TAG, idx) 259 self.log.info("Waiting for the BSSID event {}".format(event_name)) 260 event = self.dut.ed.pop_event(event_name, BSSID_EVENT_WAIT) 261 self.log.debug(event) 262 except Empty as error: 263 raise AssertionError("Event {} did not triggered for {}\n{}". 264 format(event_name, track_setting["bssidInfos"], error)) 265 finally: 266 self.dut.droid.wifiScannerStopBackgroundScan(self.scan_idx) 267 if idx: 268 self.dut.droid.wifiScannerStopTrackingBssids(idx) 269 270 def wifi_generate_track_bssid_settings(self, isLost): 271 """Generates all the combinations of different track setting parameters. 272 273 Returns: 274 A list of dictionaries each representing a set of track settings. 275 """ 276 bssids = [[self.bssid_2g], [self.bssid_5g], 277 [self.bssid_2g, self.bssid_5g]] 278 if self.dut.model != "hammerhead": 279 bssids.append([self.bssid_dfs]) 280 if isLost: 281 apthreshold = (3,5) 282 else: 283 apthreshold = (1,) 284 # Create track setting strings based on the combinations 285 setting_combinations = list(itertools.product(bssids, apthreshold)) 286 # Create scan setting strings based on the combinations 287 track_settings = [] 288 for combo in setting_combinations: 289 s = {} 290 s["bssidInfos"] = combo[0] 291 s["apLostThreshold"] = combo[1] 292 track_settings.append(s) 293 return track_settings 294 295 def track_setting_to_string(self, track_setting): 296 """Convert track setting to string for Bssids in that""" 297 string = "" 298 for bssid_setting in track_setting: 299 string += bssid_setting[WifiEnums.BSSID_KEY] 300 string += "_" 301 return string 302 303 def combineBssids(self, *track_settings): 304 """Combine bssids in the track_settings to one list""" 305 bssids = [] 306 for track_setting in track_settings: 307 bssids.extend(track_setting["bssidInfos"]) 308 return bssids 309 310 """ Helper Functions End """ 311 312 """ Tests Begin """ 313 def test_wifi_track_bssid_found(self): 314 """Test bssid track for event found with a list of different settings. 315 316 1. Starts Wifi Scanner bssid tracking for interested bssids in track_setting. 317 2. Start Wifi Scanner scan with default scan settings. 318 3. Validate the environment to check AP is not in range. 319 4. Attenuate the signal to make AP in range. 320 5. Verified that onFound event is triggered for interested bssids in 321 track setting. 322 """ 323 track_settings = self.wifi_generate_track_bssid_settings(False) 324 name_func = (lambda track_setting : 325 "test_wifi_track_found_bssidInfos_{}apLostThreshold_{}". 326 format(self.track_setting_to_string(track_setting["bssidInfos"]), 327 track_setting["apLostThreshold"])) 328 failed = self.run_generated_testcases( self.track_bssid_with_vaild_scan_for_found, 329 track_settings, name_func = name_func) 330 asserts.assert_true(not failed, 331 "Track bssid found failed with these bssids: {}". 332 format(failed)) 333 334 def test_wifi_track_bssid_lost(self): 335 """Test bssid track for event lost with a list of different settings. 336 337 1. Start Wifi Scanner scan with default scan settings. 338 2. Validate the environment to check AP is not in range. 339 3. Starts Wifi Scanner bssid tracking for interested bssids in track_setting. 340 4. Attenuate the signal to make Bssids in range. 341 5. Verified that onFound event is triggered for interested bssids in 342 track setting. 343 6. Attenuate the signal to make Bssids out of range. 344 7. Verified that onLost event is triggered. 345 """ 346 track_settings = self.wifi_generate_track_bssid_settings(True) 347 name_func = (lambda track_setting : 348 "test_wifi_track_lost_bssidInfos_{}apLostThreshold_{}". 349 format(self.track_setting_to_string(track_setting["bssidInfos"]), 350 track_setting["apLostThreshold"])) 351 failed = self.run_generated_testcases( self.track_bssid_with_vaild_scan_for_lost, 352 track_settings, name_func = name_func) 353 asserts.assert_true(not failed, 354 "Track bssid lost failed with these bssids: {}".format(failed)) 355 356 def test_wifi_track_bssid_sanity(self): 357 """Test bssid track for event found and lost with default settings. 358 359 1. Start WifiScanner scan for default scan settings. 360 2. Start Bssid track for "bssid_2g" AP. 361 3. Attenuate the signal to move in AP range. 362 4. Verify that onFound event occur. 363 5. Attenuate the signal to move out of range 364 6. Verify that onLost event occur. 365 """ 366 track_setting = {"bssidInfos":[self.bssid_2g], "apLostThreshold":3} 367 self.track_bssid_with_vaild_scan_for_lost(track_setting) 368 369 def test_wifi_track_bssid_for_2g_while_scanning_5g_channels(self): 370 """Test bssid track for 2g bssids while scanning 5g channels. 371 372 1. Starts Wifi Scanner bssid tracking for 2g bssids in track_setting. 373 2. Start Wifi Scanner scan for 5G Band only. 374 3. Validate the environment to check AP is not in range. 375 4. Attenuate the signal to make AP in range. 376 5. Verified that onFound event isn't triggered for 2g bssids. 377 """ 378 self.attenuators[self.attenuator_id].set_atten(90) 379 scan_setting = { "band": WifiEnums.WIFI_BAND_5_GHZ, 380 "periodInMs": SCANTIME, 381 "reportEvents": WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN, 382 "numBssidsPerScan": 32} 383 track_setting = {"bssidInfos":[self.bssid_2g], "apLostThreshold":3} 384 valid_env = self.start_scan_and_validate_environment(scan_setting, 385 track_setting["bssidInfos"]) 386 idx = None 387 try: 388 asserts.assert_true(valid_env, 389 "Test environment is not valid, AP is in range") 390 data = start_wifi_track_bssid(self.dut, track_setting) 391 idx = data["Index"] 392 self.attenuators[self.attenuator_id].set_atten(0) 393 event_name = "{}{}onFound".format(BSSID_EVENT_TAG, idx) 394 self.log.info("Waiting for the BSSID event {}".format(event_name)) 395 #waiting for 2x time to make sure 396 event = self.dut.ed.pop_event(event_name, BSSID_EVENT_WAIT * 2) 397 self.log.debug(event) 398 found = self.check_bssid_in_found_result(track_setting["bssidInfos"], 399 event["data"]["Results"]) 400 asserts.assert_true(not found, 401 "Test fail because Bssid onFound event is triggered") 402 except Empty as error: 403 self.log.info("As excepted event didn't occurred with different scan setting") 404 finally: 405 self.dut.droid.wifiScannerStopBackgroundScan(self.scan_idx) 406 if idx: 407 self.dut.droid.wifiScannerStopTrackingBssids(idx) 408 409 def test_wifi_track_bssid_for_5g_while_scanning_2g_channels(self): 410 """Test bssid track for 5g bssids while scanning 2g channels. 411 412 1. Starts Wifi Scanner bssid tracking for 5g bssids in track_setting. 413 2. Start Wifi Scanner scan for 2G Band only. 414 3. Validate the environment to check AP is not in range. 415 4. Attenuate the signal to make AP in range. 416 5. Verified that onFound event isn't triggered for 5g bssids. 417 """ 418 self.attenuators[self.attenuator_id].set_atten(90) 419 scan_setting = { "band": WifiEnums.WIFI_BAND_24_GHZ, 420 "periodInMs": SCANTIME, 421 "reportEvents": WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN, 422 "numBssidsPerScan": 32} 423 track_setting = {"bssidInfos":[self.bssid_5g], "apLostThreshold":3} 424 data = start_wifi_track_bssid(self.dut, track_setting) 425 idx = data["Index"] 426 valid_env = self.start_scan_and_validate_environment(scan_setting, 427 track_setting["bssidInfos"]) 428 try: 429 asserts.assert_true(valid_env, 430 "Test environment is not valid, AP is in range") 431 self.attenuators[self.attenuator_id].set_atten(0) 432 event_name = "{}{}onFound".format(BSSID_EVENT_TAG, idx) 433 self.log.info("Waiting for the BSSID event {}".format(event_name)) 434 #waiting for 2x time to make sure 435 event = self.dut.ed.pop_event(event_name, BSSID_EVENT_WAIT * 2) 436 self.log.debug(event) 437 found = self.check_bssid_in_found_result(track_setting["bssidInfos"], 438 event["data"]["Results"]) 439 asserts.assert_true(not found, 440 "Test fail because Bssid onFound event is triggered") 441 except Empty as error: 442 self.log.info("As excepted event didn't occurred with different scan setting") 443 finally: 444 self.dut.droid.wifiScannerStopBackgroundScan(self.scan_idx) 445 if idx: 446 self.dut.droid.wifiScannerStopTrackingBssids(idx) 447 448 def test_wifi_tracking_bssid_multi_listeners_found(self): 449 """Test bssid tracking for multiple listeners 450 1. Start BSSID tracking for 5g bssids 451 2. Start BSSID tracking for 2g bssids 452 3. Start WifiScanner scan on both bands. 453 4. Valid the environment and check the APs are not in range. 454 5. Attenuate the signal to make the APs in range. 455 6. Verify onFound event triggered on both APs. 456 """ 457 # Attenuate the signal to make APs invisible. 458 self.attenuators[self.attenuator_id].set_atten(90) 459 scan_setting = { "band": WifiEnums.WIFI_BAND_BOTH_WITH_DFS, 460 "periodInMs": SCANTIME, 461 "reportEvents": WifiEnums.REPORT_EVENT_AFTER_EACH_SCAN, 462 "numBssidsPerScan": 32} 463 track_setting_5g = {"bssidInfos":[self.bssid_5g], "apLostThreshold":3} 464 data_5g = start_wifi_track_bssid(self.dut, track_setting_5g) 465 idx_5g = data_5g["Index"] 466 467 track_setting_2g = {"bssidInfos":[self.bssid_2g], "apLostThreshold":3} 468 data_2g = start_wifi_track_bssid(self.dut, track_setting_2g) 469 idx_2g = data_2g["Index"] 470 471 valid_env = self.start_scan_and_validate_environment( 472 scan_setting, self.combineBssids(track_setting_5g, track_setting_2g)) 473 try: 474 asserts.assert_true(valid_env, 475 "Test environment is not valid, AP is in range") 476 self.attenuators[self.attenuator_id].set_atten(0) 477 event_name = "{}{}{}{}onFound".format(BSSID_EVENT_TAG, idx_5g, BSSID_EVENT_TAG, idx_2g) 478 self.log.info("Waiting for the BSSID event {}".format(event_name)) 479 #waiting for 2x time to make sure 480 event = self.dut.ed.pop_event(event_name, BSSID_EVENT_WAIT * 2) 481 self.log.debug(event) 482 found = self.check_bssid_in_found_result( 483 self.combineBssids(track_setting_5g, track_setting_2g), 484 event["data"]["Results"]) 485 asserts.assert_true(found, 486 "Test failed because Bssid onFound event is not triggered") 487 finally: 488 self.dut.droid.wifiScannerStopBackgroundScan(self.scan_idx) 489 if idx_5g: 490 self.dut.droid.wifiScannerStopTrackingBssids(idx_5g) 491 if idx_2g: 492 self.dut.droid.wifiScannerStopTrackingBssids(idx_2g); 493 494 """ Tests End """ 495