1 # Copyright 2015 The Chromium OS Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 import contextlib 6 import logging 7 import time 8 9 from autotest_lib.client.common_lib import error 10 from autotest_lib.server.cros.network import hostap_config 11 from autotest_lib.server.cros.network import lucid_sleep_test_base 12 from autotest_lib.server.cros.network import wifi_client 13 14 class network_WiFi_ReconnectInDarkResume( 15 lucid_sleep_test_base.LucidSleepTestBase): 16 """Test that known WiFi access points wake up the system.""" 17 18 version = 1 19 20 def run_once(self, 21 disconnect_before_suspend=False, 22 reconnect_to_same_ap=True, 23 num_iterations=1): 24 """Body of the test 25 26 @param disconnect_before_suspend: whether we disconnect the DUT before 27 or after first suspending it. 28 @param reconnect_to_same_ap: if this is true, during suspend, we bring 29 up the same AP that the DUT was last connected to before the first 30 suspend for the DUT to reconnect to. 31 @param num_iterations: number of times to bring the AP down and up 32 during dark resume. In each iteration, we bring the AP down once, and 33 bring it up again once. 34 35 """ 36 client = self.context.client 37 router = self.context.router 38 39 # We configure and connect to two APs (i.e. same AP configured with two 40 # different SSIDs) so that the DUT has two preferred networks. 41 first_ap_ssid = self.configure_and_connect_to_ap( 42 hostap_config.HostapConfig(channel=1)) 43 router.deconfig_aps() 44 second_ap_ssid = self.configure_and_connect_to_ap( 45 hostap_config.HostapConfig(channel=1)) 46 47 if reconnect_to_same_ap: 48 reconnect_ap_ssid = second_ap_ssid 49 else: 50 reconnect_ap_ssid = first_ap_ssid 51 52 # Enable the dark connect feature in shill, and set the scan period. 53 with contextlib.nested( 54 client.wake_on_wifi_features( 55 wifi_client.WAKE_ON_WIFI_DARKCONNECT), 56 client.net_detect_scan_period_seconds( 57 wifi_client.NET_DETECT_SCAN_WAIT_TIME_SECONDS)): 58 logging.info('Set up WoWLAN') 59 60 bring_ap_down_in_suspend = True 61 if disconnect_before_suspend: 62 # If we disconnect before suspend, we do not need to bring the 63 # AP down again on the first suspend. 64 bring_ap_down_in_suspend = False 65 logging.info('Bringing AP %s down.' % router.get_ssid()) 66 router.deconfig_aps() 67 time.sleep(wifi_client.DISCONNECT_WAIT_TIME_SECONDS) 68 69 with self.dr_utils.suspend(): 70 for iter_num in xrange(1, num_iterations+1): 71 logging.info('Iteration %d of %d' % 72 (iter_num, num_iterations)) 73 # Wait for suspend actions to finish. 74 time.sleep(wifi_client.SUSPEND_WAIT_TIME_SECONDS) 75 76 if bring_ap_down_in_suspend: 77 logging.info('Bringing AP %s down.' % router.get_ssid()) 78 router.deconfig_aps() 79 # Wait for the DUT to receive the disconnect, wake in 80 # dark resume, then suspend again. Wait a little more 81 # after that so we don't trigger the next dark resume 82 # too soon and set off the throttling mechanism. 83 time.sleep(wifi_client.DISCONNECT_WAIT_TIME_SECONDS + 84 wifi_client.DARK_RESUME_WAIT_TIME_SECONDS + 85 60) 86 else: 87 # We will bring the AP back up after this, so we 88 # will need to bring the AP down on any subsequent 89 # iterations to test wake on disconnect. 90 bring_ap_down_in_suspend = True 91 92 # Bring the AP back up to wake up the DUT. 93 logging.info('Bringing AP %s up.' % reconnect_ap_ssid) 94 self.context.configure(hostap_config.HostapConfig( 95 ssid=reconnect_ap_ssid, channel=1)) 96 97 # Wait long enough for the NIC on the DUT to perform a net 98 # detect scan, discover the AP with the white-listed SSID, 99 # wake up in dark resume, connect, then suspend again. 100 time.sleep(wifi_client.NET_DETECT_SCAN_WAIT_TIME_SECONDS + 101 wifi_client.DARK_RESUME_WAIT_TIME_SECONDS) 102 103 client.check_connected_on_last_resume() 104 105 num_dark_resumes = self.dr_utils.count_dark_resumes() 106 if disconnect_before_suspend and num_iterations == 1: 107 # Only expect a single wake on SSID dark resume in this case 108 # since no wake on disconnect would have been triggered. 109 expected_num_dark_resumes = 1 110 else: 111 # Expect at least one disconnect dark resume and one SSID dark 112 # resume per iteration. 113 # Note: this is not foolproof; excess wakes on some iteration 114 # can make up for a shortfall in dark resumes in another 115 # iteration. 116 expected_num_dark_resumes = 2 * num_iterations 117 if num_dark_resumes < expected_num_dark_resumes: 118 raise error.TestFail('Client only came up in %d dark resumes ' 119 'during the test (expected: at least %d)' % 120 (num_dark_resumes, 121 expected_num_dark_resumes)) 122