blob: 4dc55be4d819a66ed93b0e3cb652037c0ae4a8d1 [file] [log] [blame]
# Copyright 2017 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
import time
from autotest_lib.client.common_lib import error
from autotest_lib.server.cros.network import hostap_config
from autotest_lib.server.cros.network import wifi_cell_test_base
class network_WiFi_Reset(wifi_cell_test_base.WiFiCellTestBase):
"""Test that the WiFi interface can be reset successfully, and that WiFi
comes back up properly. Supports only Marvell (mwifiex) Wifi drivers.
"""
version = 1
_MWIFIEX_RESET_PATH = "/sys/kernel/debug/mwifiex/%s/reset"
_NUM_RESETS = 15
@property
def mwifiex_reset_path(self):
"""Get path to the Wifi interface's reset file."""
return self._MWIFIEX_RESET_PATH % self.context.client.wifi_if
def poll_for_condition(self, condition, timeout=20, interval=0.5):
"""Helper for polling for some condition.
@param condition: a condition function for checking the state we're
polling; should return True for success, False for
failure
@param timeout: max number of seconds to poll for
@param interval: polling interval, in seconds
@returns: False if timed out waiting for condition; True otherwise
"""
start_time = time.time()
while time.time() - start_time < timeout:
if condition():
return True
time.sleep(interval)
return False
def mwifiex_reset_exists(self):
"""Check if the mwifiex reset file is present (i.e., a mwifiex
interface is present).
"""
return self.context.client.host.run('test -e "%s"' %
self.mwifiex_reset_path, ignore_status=True).exit_status == 0
def mwifiex_reset(self, client):
"""Perform mwifiex reset, and wait for the interface to come back up.
@returns: True if interface comes back up successfully; False for
errors (e.g., timeout)
"""
ssid = self.context.router.get_ssid()
# Adapter will asynchronously reset.
self.context.client.host.run('echo 1 > ' + self.mwifiex_reset_path)
# Wait for disconnect. We aren't guaranteed to receive a disconnect
# event, but shill will at least notice the adapter went away.
self.context.client.wait_for_service_states(ssid, ['idle'],
timeout_seconds=20)
# Now wait for the reset interface file to come back.
if not self.poll_for_condition(self.mwifiex_reset_exists):
logging.error("Failed, waiting for interface to reappear")
return False
return True
def run_once(self):
"""Body of the test."""
if not self.mwifiex_reset_exists():
self._supports_reset = False
raise error.TestNAError('DUT does not support device reset')
else:
self._supports_reset = True
client = self.context.client
ap_config = hostap_config.HostapConfig(channel=1)
ssid = self.configure_and_connect_to_ap(ap_config)
self.context.assert_ping_from_dut()
router = self.context.router
ssid = router.get_ssid()
logging.info("Running %d resets", self._NUM_RESETS)
for i in range(self._NUM_RESETS):
if not self.mwifiex_reset(client):
raise error.TestFail('Failed to reset device %s' %
client.wifi_if)
client.wait_for_connection(ssid)
self.context.assert_ping_from_dut()
def cleanup(self):
"""Performs cleanup at exit. May reboot the DUT, to keep the system
functioning for the next test.
"""
if self._supports_reset and not self.mwifiex_reset_exists():
logging.info("Test exited, but interface is missing; rebooting")
self.context.client.reboot(timeout=60)