blob: 3ab58e6635976bae21831810a086505fd992497e [file] [log] [blame]
#!/usr/bin/python
"""Tests for connection_manager.py."""
import os
import shutil
import subprocess
import tempfile
import time
import experiment_testutils
import interface
import test_common
from wvtest import wvtest
# pylint: disable=line-too-long
_IP_ADDR_SHOW_TPL = """4: {name}: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
inet {ip}/21 brd 100.100.55.255 scope global {name}
valid_lft forever preferred_lft forever
"""
class FakeInterfaceMixin(object):
"""Replace Interface methods which interact with the system."""
def __init__(self, *args, **kwargs):
super(FakeInterfaceMixin, self).__init__(*args, **kwargs)
self.set_connection_check_result('succeed')
subprocess.ip.register_testonly(self.name)
def set_connection_check_result(self, result):
if result in ['succeed', 'fail', 'restricted']:
subprocess.mock(self.CONNECTION_CHECK, self.name, result)
else:
raise ValueError('Invalid fake connection_check value.')
def current_routes_normal_testonly(self):
result = self.current_routes()
return {k: v for k, v in result.iteritems() if int(v.get('metric', 0)) < 50}
class Bridge(FakeInterfaceMixin, interface.Bridge):
pass
class Wifi(FakeInterfaceMixin, interface.Wifi):
"""Fake Wifi for testing."""
pass
class FrenzyWifi(FakeInterfaceMixin, interface.FrenzyWifi):
pass
@test_common.wvtest
def bridge_test():
"""Test Interface and Bridge."""
tmp_dir = tempfile.mkdtemp()
try:
autoprov_filepath = os.path.join(tmp_dir, 'autoprov')
b = Bridge('br0', '10', acs_autoprovisioning_filepath=autoprov_filepath)
b.set_connection_check_result('succeed')
wvtest.WVFAIL(b.acs())
wvtest.WVFAIL(b.internet())
wvtest.WVFAIL(b.current_routes())
wvtest.WVFAIL(b.current_routes_normal_testonly())
wvtest.WVFAIL(os.path.exists(autoprov_filepath))
b.add_moca_station(0)
wvtest.WVFAIL(os.path.exists(autoprov_filepath))
b.set_subnet('192.168.1.0/24')
b.set_gateway_ip('192.168.1.1')
wvtest.WVFAIL(os.path.exists(autoprov_filepath))
# Everything should fail because the interface is not initialized.
wvtest.WVFAIL(b.acs())
wvtest.WVFAIL(b.internet())
wvtest.WVFAIL(b.current_routes_normal_testonly())
wvtest.WVFAIL(os.path.exists(autoprov_filepath))
b.initialize()
wvtest.WVPASS(b.acs())
wvtest.WVPASS(b.internet())
current_routes = b.current_routes()
wvtest.WVPASSEQ(len(current_routes), 3)
wvtest.WVPASS('default' in current_routes)
wvtest.WVPASS('subnet' in current_routes)
wvtest.WVPASS('multicast' in current_routes)
wvtest.WVPASS(os.path.exists(autoprov_filepath))
b.add_moca_station(1)
wvtest.WVPASS(b.acs())
wvtest.WVPASS(b.internet())
wvtest.WVPASSEQ(len(b.current_routes()), 3)
wvtest.WVPASS(os.path.exists(autoprov_filepath))
b.remove_moca_station(0)
b.remove_moca_station(1)
wvtest.WVFAIL(b.acs())
wvtest.WVFAIL(b.internet())
# We have no links, so should have no routes.
wvtest.WVFAIL(b.current_routes())
wvtest.WVFAIL(os.path.exists(autoprov_filepath))
b.add_moca_station(2)
wvtest.WVPASS(b.acs())
wvtest.WVPASS(b.internet())
wvtest.WVPASSEQ(len(b.current_routes()), 3)
wvtest.WVPASS(os.path.exists(autoprov_filepath))
b.set_connection_check_result('fail')
b.update_routes()
wvtest.WVFAIL(b.acs())
wvtest.WVFAIL(b.internet())
# We have links but the connection check failed, so we should only have a
# low priority route, i.e. metric at least 50.
wvtest.WVPASSEQ(len(b.current_routes()), 3)
wvtest.WVFAIL(b.current_routes_normal_testonly())
wvtest.WVFAIL(os.path.exists(autoprov_filepath))
b.set_connection_check_result('restricted')
b.update_routes()
wvtest.WVPASS(b.acs())
wvtest.WVFAIL(b.internet())
wvtest.WVPASSEQ(len(b.current_routes()), 3)
wvtest.WVPASS(os.path.exists(autoprov_filepath))
wvtest.WVFAIL(b.get_ip_address())
subprocess.call(['ip', 'addr', 'add', '192.168.1.100', 'dev', b.name])
wvtest.WVPASSEQ(b.get_ip_address(), '192.168.1.100')
# Get a new gateway/subnet (e.g. due to joining a new network).
# Not on the subnet; adding IP should fail.
b.set_gateway_ip('192.168.2.1')
wvtest.WVFAIL('default' in b.current_routes())
wvtest.WVPASS('subnet' in b.current_routes())
# Without a default route, the connection check should fail.
wvtest.WVFAIL(b.acs())
# Now we get the subnet and should add updated subnet and gateway routes.
b.set_subnet('192.168.2.0/24')
wvtest.WVPASSEQ(b.current_routes()['default']['via'], '192.168.2.1')
wvtest.WVPASSLE(int(b.current_routes()['default']['metric']), 50)
wvtest.WVPASSEQ(b.current_routes()['subnet']['route'], '192.168.2.0/24')
wvtest.WVPASSLE(int(b.current_routes()['subnet']['metric']), 50)
wvtest.WVPASS(b.acs())
# If we have no subnet, make sure that both subnet and default routes are
# removed.
b.set_subnet(None)
wvtest.WVFAIL('subnet' in b.current_routes())
wvtest.WVFAIL('default' in b.current_routes())
# Now repeat the new-network test, but with a faulty connection. Make sure
# the metrics are set appropriately.
b.set_connection_check_result('fail')
b.set_subnet('192.168.3.0/24')
b.set_gateway_ip('192.168.3.1')
wvtest.WVPASSGE(int(b.current_routes()['default']['metric']), 50)
wvtest.WVPASSGE(int(b.current_routes()['subnet']['metric']), 50)
# Now test deleting only the gateway IP.
b.set_gateway_ip(None)
wvtest.WVPASS('subnet' in b.current_routes())
wvtest.WVFAIL('default' in b.current_routes())
finally:
shutil.rmtree(tmp_dir)
def generic_wifi_test(w, wpa_path):
# Not currently connected.
subprocess.wifi.WPA_PATH = wpa_path
wvtest.WVFAIL(w.wpa_supplicant)
# wpa_supplicant connects.
ssid = 'my=ssid'
psk = 'passphrase'
subprocess.mock('wifi', 'remote_ap', ssid=ssid, psk=psk, band='5',
bssid='00:00:00:00:00:00', connection_check_result='succeed')
subprocess.check_call(['wifi', 'setclient', '--ssid', ssid, '--band', '5'],
env={'WIFI_CLIENT_PSK': psk})
wvtest.WVPASS(w.wpa_supplicant)
w.set_gateway_ip('192.168.1.1')
# wpa_supplicant disconnects.
subprocess.mock('wifi', 'disconnected_event', '5')
wvtest.WVFAIL(w.wpa_supplicant)
# The wpa_supplicant process disconnects and terminates.
subprocess.check_call(['wifi', 'stopclient', '--band', '5'])
wvtest.WVFAIL(w.wpa_supplicant)
@test_common.wvtest
def wifi_test():
"""Test Wifi."""
w = Wifi('wcli0', '21')
w.initialize()
try:
wpa_path = tempfile.mkdtemp()
conman_path = tempfile.mkdtemp()
subprocess.set_conman_paths(conman_path, None)
subprocess.mock('wifi', 'interfaces',
subprocess.wifi.MockInterface(phynum='0', bands=['5'],
driver='cfg80211'))
generic_wifi_test(w, wpa_path)
finally:
shutil.rmtree(wpa_path)
shutil.rmtree(conman_path)
@test_common.wvtest
def frenzy_wifi_test():
"""Test FrenzyWifi."""
w = FrenzyWifi('wlan0', '20')
w.initialize()
try:
wpa_path = tempfile.mkdtemp()
conman_path = tempfile.mkdtemp()
subprocess.set_conman_paths(conman_path, None)
subprocess.mock('wifi', 'interfaces',
subprocess.wifi.MockInterface(phynum='0', bands=['5'],
driver='frenzy'))
generic_wifi_test(w, wpa_path)
finally:
shutil.rmtree(wpa_path)
shutil.rmtree(conman_path)
@test_common.wvtest
def simulate_wireless_test():
"""Test the WifiSimulateWireless experiment."""
unused_raii = experiment_testutils.MakeExperimentDirs()
tmp_dir = tempfile.mkdtemp()
interface.CWMP_PATH = tempfile.mkdtemp()
interface.MAX_ACS_FAILURE_S = 1
contact = os.path.join(interface.CWMP_PATH, 'acscontact')
connected = os.path.join(interface.CWMP_PATH, 'acsconnected')
try:
autoprov_filepath = os.path.join(tmp_dir, 'autoprov')
b = Bridge('br0', '10', acs_autoprovisioning_filepath=autoprov_filepath)
b.add_moca_station(0)
b.set_gateway_ip('192.168.1.1')
b.set_subnet('192.168.1.0/24')
b.set_connection_check_result('succeed')
b.initialize()
# Initially, the connection check passes.
wvtest.WVPASS(b.internet())
# Enable the experiment.
experiment_testutils.enable('WifiSimulateWireless')
# Calling update_routes overwrites the connection status cache, which we
# need in order to see the effects we are looking for immediately
# (ConnectionManager calls this every few seconds).
b.update_routes()
wvtest.WVFAIL(b.internet())
# Create an ACS connection attempt.
open(contact, 'w')
b.update_routes()
wvtest.WVFAIL(b.internet())
# Record success.
open(connected, 'w')
b.update_routes()
wvtest.WVFAIL(b.internet())
# Disable the experiment and the connection check should pass again.
experiment_testutils.disable('WifiSimulateWireless')
b.update_routes()
wvtest.WVPASS(b.internet())
# Reenable the experiment and the connection check should fail again.
experiment_testutils.enable('WifiSimulateWireless')
b.update_routes()
wvtest.WVFAIL(b.internet())
# Wait until we've failed for long enough for the experiment to "expire",
# then log another attempt without success. Make sure the connection check
# passes.
time.sleep(interface.MAX_ACS_FAILURE_S)
open(contact, 'w')
b.update_routes()
wvtest.WVPASS(b.internet())
finally:
shutil.rmtree(tmp_dir)
shutil.rmtree(interface.CWMP_PATH)
if __name__ == '__main__':
wvtest.wvtest_main()