Skip to content

Commit

Permalink
wificontrol: Add test cases for ReconnectWorker and minor fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
merindorium committed Jun 19, 2017
1 parent e8d5dc8 commit 6e030af
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 16 deletions.
6 changes: 6 additions & 0 deletions tests/test_edison_wificontrol.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,12 @@ def test_network_add(self, valid_network):

assert valid_network['ssid'] in [network['ssid'] for network in added_networks]

def test_network_add_with_different_security(self, valid_network):
securities = ['wpapsk', 'wpa2psk', 'wep', 'open', 'wpaeap']
for security in securities:
valid_network['security'] = security
self.manager.add_network(valid_network)

def test_network_remove(self, valid_network):
self.test_network_add(valid_network)
self.manager.remove_network(valid_network)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_wificontrol.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,4 @@ def test_supplicant_functions(self):
assert self.manager.wifi.restart_dns.call_count == 1

self.manager.set_hostap_password(name)
assert self.manager.hotspot.set_hostap_password.is_called_once_with(name)
assert self.manager.hotspot.set_hostap_password.is_called_once_with(name)
48 changes: 44 additions & 4 deletions tests/test_wifimonitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ def host_mode_state():
return '', state, ''


@pytest.fixture
def disconnect_state_on_station_del():
state = {
'DisconnectReason': 0
}
return state


class FakeWifiMonitor(WiFiMonitor):
def __init__(self):
self.bus = mock.MagicMock()
Expand All @@ -64,18 +72,21 @@ def __init__(self):
self.current_state = None
self.current_ssid = None

self.reconnect_worker = mock.MagicMock()
self.disconnect_reason = None

self._initialize()


class TestWiFiMonitor():
class TestWiFiMonitor:
@classmethod
def setup_class(cls):
def setup_method(cls):
cls.monitor = FakeWifiMonitor()
cls.monitor.run()
cls.ssid = 'TEST_SSID'

@classmethod
def teardown_class(cls):
def teardown_method(cls):
cls.monitor.shutdown()

def test_initial_start(self):
Expand Down Expand Up @@ -131,10 +142,39 @@ def test_success_connection_event(self, wpa_client_state, host_mode_state, mocke
def test_revert_connection_event(self, wpa_client_state, scanning_state, mocker):
stub_func = mocker.stub(name='stub_func')

self.monitor.wifi_manager.set_ssid(self.ssid)

self.monitor.register_callback(self.monitor.REVERT_EVENT, stub_func, args=('revert',))

self.monitor._wpa_props_changed(scanning_state)
self.monitor._wpa_props_changed(wpa_client_state)
assert self.monitor.current_state == self.monitor.CLIENT_STATE

self.monitor._wpa_props_changed(scanning_state)
assert self.monitor.current_state == self.monitor.SCAN_STATE

self.monitor._wpa_props_changed(wpa_client_state)
assert self.monitor.current_state == self.monitor.CLIENT_STATE
stub_func.assert_called_with('revert')

def test_reconnection_worker_start(self, disconnect_state_on_station_del, wpa_client_state):
self.monitor.wifi_manager.set_ssid(self.ssid)

self.monitor._wpa_props_changed(wpa_client_state)
assert self.monitor.current_state == self.monitor.CLIENT_STATE

self.monitor._wpa_props_changed(disconnect_state_on_station_del)
assert self.monitor.current_state == self.monitor.OFF_STATE
assert self.monitor.disconnect_reason is None

kwargs = {'args': (self.monitor.current_ssid,)}
_call = mock.call('start_reconnection', **kwargs)
assert _call in self.monitor.reconnect_worker.method_calls

def test_reconnection_worker_stop(self, wpa_client_state, disconnect_state_on_station_del):
self.test_reconnection_worker_start(disconnect_state_on_station_del, wpa_client_state)

self.monitor._wpa_props_changed(wpa_client_state)
assert self.monitor.current_state == self.monitor.CLIENT_STATE

_call = mock.call('stop_reconnection')
assert _call in self.monitor.reconnect_worker.method_calls
77 changes: 77 additions & 0 deletions tests/test_wifireconnect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import pytest
import mock
import threading
from wificontrol.wifireconnect import ReconnectWorker


@pytest.fixture
def valid_network():
network = {
'ssid': 'TEST_SSID'
}
return network


class FakeReconnectWorker(ReconnectWorker):
def __init__(self):
self.manager = mock.MagicMock()
self.interrupt = threading.Event()
self.worker = None


class TestReconnectWorker:
def setup_method(self):
self.reconnect_worker = FakeReconnectWorker()
self.reconnect_worker.TIMEOUT = 0.1

def teardown_method(self):
self.reconnect_worker.stop_reconnection()

def test_reconnection_start_and_stop(self, valid_network):
self.reconnect_worker.start_reconnection(valid_network['ssid'])

self.reconnect_worker.interrupt.wait(0.5)

self.reconnect_worker.manager.scan.assert_called()
self.reconnect_worker.manager.get_scan_results.assert_called()

self.reconnect_worker.stop_reconnection()

assert self.reconnect_worker.interrupt.is_set()
assert self.reconnect_worker.worker is None

def test_reconnection_worker_success_connection(self, valid_network):
def start_connecting(network, callback, *args, **kwargs):
assert network == valid_network
callback(True)

self.reconnect_worker.manager.start_connecting.side_effect = start_connecting

self.reconnect_worker.start_reconnection(valid_network['ssid'])
self.reconnect_worker.interrupt.wait(0.5)

self.reconnect_worker.manager.get_scan_results.return_value = [valid_network]

self.reconnect_worker.interrupt.wait(2)
assert self.reconnect_worker.interrupt.is_set()

self.reconnect_worker.stop_reconnection()
assert self.reconnect_worker.worker is None

def test_second_worker_start(self, valid_network):
self.reconnect_worker.start_reconnection(valid_network['ssid'])
worker = self.reconnect_worker.worker
self.reconnect_worker.start_reconnection(valid_network['ssid'])
assert self.reconnect_worker.worker == worker

def test_worker_restart(self, valid_network):
self.reconnect_worker.start_reconnection(valid_network['ssid'])
self.reconnect_worker.interrupt.wait(1)
self.reconnect_worker.stop_reconnection()

self.reconnect_worker.start_reconnection(valid_network['ssid'])
self.reconnect_worker.interrupt.wait(1)
self.reconnect_worker.stop_reconnection()

assert self.reconnect_worker.interrupt.is_set()
assert self.reconnect_worker.worker is None
36 changes: 26 additions & 10 deletions wificontrol/wifimonitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import dbus.service
import dbus.mainloop.glib
import signal
import logging
from wificontrol import WiFiControl
from reachstatus import StateClient
from daemon_tree import DaemonTreeObj, DaemonTreeError
Expand All @@ -12,6 +13,9 @@
except ImportError:
import gobject as GObject

logging.basicConfig()
logger = logging.getLogger(__name__)

DBUS_PROPERTIES_IFACE = 'org.freedesktop.DBus.Properties'

WPAS_INTERFACE_DBUS_OPATH = "/fi/w1/wpa_supplicant1/Interfaces/1"
Expand Down Expand Up @@ -65,17 +69,10 @@ def __init__(self):
self.reconnect_worker = DaemonTreeObj(WORKER_NAME)
self.disconnect_reason = None

self.register_callback(self.CLIENT_STATE, self._check_current_ssid)
self.register_callback(self.CLIENT_STATE, self._stop_reconnect_worker)

self.register_callback(self.HOST_STATE, self._clear_ssid)
self.register_callback(self.HOST_STATE, self._stop_reconnect_worker)

self.register_callback(self.OFF_STATE, self._check_disconnect_reason)

try:
self._initialize()
except dbus.exceptions.DBusException as error:
logger.error(error)
raise WiFiMonitorError(error)

def _initialize(self):
Expand All @@ -95,8 +92,18 @@ def _initialize(self):
signal_name="PropertiesChanged",
path=HOSTAPD_DBUS_UNIT_OPATH)

self._register_local_callbacks()
self._set_initial_state()

def _register_local_callbacks(self):
self.register_callback(self.CLIENT_STATE, self._check_current_ssid)
self.register_callback(self.CLIENT_STATE, self._stop_reconnect_worker)

self.register_callback(self.HOST_STATE, self._clear_ssid)
self.register_callback(self.HOST_STATE, self._stop_reconnect_worker)

self.register_callback(self.OFF_STATE, self._check_disconnect_reason)

def _set_initial_state(self):
state = self.wifi_manager.get_state()
self._process_new_state(state)
Expand Down Expand Up @@ -129,11 +136,12 @@ def _process_new_state(self, state):
def _check_current_ssid(self):
event = self.REVERT_EVENT

if self._ssid_updated():
if self._ssid_updated:
event = self.SUCCESS_EVENT

self._execute_callbacks(event)

@property
def _ssid_updated(self):
_, status = self.wifi_manager.get_status()

Expand All @@ -152,10 +160,14 @@ def _clear_ssid(self):
self.current_ssid = None

def _check_disconnect_reason(self):
if self.disconnect_reason == 0:
if self._station_went_offline:
self._start_reconnect_worker()
self.disconnect_reason = None

@property
def _station_went_offline(self):
return self.disconnect_reason in (0, 3)

def _start_reconnect_worker(self):
try:
self.reconnect_worker.call('start_reconnection', args=(self.current_ssid,))
Expand All @@ -181,7 +193,10 @@ def _execute_callbacks(self, msg):
callback, args = callback
try:
callback(*args)
except WiFiMonitorError as error:
logger.error(error)
except Exception as error:
logger.error(error)
raise WiFiMonitorError(error)

def run(self):
Expand All @@ -195,6 +210,7 @@ def _deinitialize(self):
try:
self.sysd_manager.Unsubscribe()
except dbus.exceptions.DBusException as error:
logger.error(error)
raise WiFiMonitorError(error)


Expand Down
4 changes: 3 additions & 1 deletion wificontrol/wifireconnect.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def __init__(self):
def start_reconnection(self, ssid):
if self.worker is None:
self.worker = threading.Thread(target=self._reconnect, args=(ssid,))
self.worker.daemon = True
self.worker.start()

def _reconnect(self, ssid):
Expand All @@ -45,7 +46,7 @@ def _reconnect(self, ssid):

def _callback(self, result=None):
if result:
self.stop_reconnection()
self.interrupt.set()

def stop_reconnection(self):
self.interrupt.set()
Expand All @@ -56,6 +57,7 @@ def stop_reconnection(self):

def main():
def handler(signum, frame):
reconnect_worker.stop_reconnection()
reconnect_svr.cancel()

reconnect_worker = ReconnectWorker()
Expand Down
1 change: 1 addition & 0 deletions wificontrol/wpasupplicant.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ def find_network_path(self, aim_network):
if self.wpa_network_manager.get_network_SSID(network) == \
aim_network['ssid']:
return network
raise RuntimeError("Network with this ssid not found")

def get_current_network_ssid(self):
self.wpa_supplicant_interface.initialize()
Expand Down

0 comments on commit 6e030af

Please sign in to comment.