Added more tests and exception handling
This commit is contained in:
parent
2100a7cfdb
commit
f9017c3a38
2 changed files with 96 additions and 39 deletions
|
@ -1,8 +1,6 @@
|
||||||
"""
|
"""
|
||||||
A module to show currently active network connection (ethernet or wifi) and connection strength if the connection is wireless.
|
A module to show currently active network connection (ethernet or wifi) and connection strength if the connection is wireless.
|
||||||
|
|
||||||
Dependencies: nm-connection-editor if users would like a graphical
|
|
||||||
network manager when left-clicking the module
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +16,7 @@ import socket
|
||||||
|
|
||||||
|
|
||||||
class Module(core.module.Module):
|
class Module(core.module.Module):
|
||||||
@core.decorators.every(seconds=10)
|
@core.decorators.every(seconds=5)
|
||||||
def __init__(self, config, theme):
|
def __init__(self, config, theme):
|
||||||
super().__init__(config, theme, core.widget.Widget(self.network))
|
super().__init__(config, theme, core.widget.Widget(self.network))
|
||||||
self.__is_wireless = False
|
self.__is_wireless = False
|
||||||
|
@ -33,20 +31,26 @@ class Module(core.module.Module):
|
||||||
try:
|
try:
|
||||||
socket.create_connection(("1.1.1.1", 53))
|
socket.create_connection(("1.1.1.1", 53))
|
||||||
self.__is_connected = True
|
self.__is_connected = True
|
||||||
except:
|
except Exception:
|
||||||
self.__is_connected = False
|
self.__is_connected = False
|
||||||
|
|
||||||
# Attempt to extract a valid network interface device
|
# Attempt to extract a valid network interface device
|
||||||
|
try:
|
||||||
self.__interface = netifaces.gateways()["default"][netifaces.AF_INET][1]
|
self.__interface = netifaces.gateways()["default"][netifaces.AF_INET][1]
|
||||||
|
except Exception:
|
||||||
|
self.__interface = None
|
||||||
|
|
||||||
# Check to see if the interface (if connected to the internet) is wireless
|
# Check to see if the interface (if connected to the internet) is wireless
|
||||||
if self.__is_connected:
|
if self.__is_connected and self.__interface:
|
||||||
|
try:
|
||||||
with open("/proc/net/wireless", "r") as f:
|
with open("/proc/net/wireless", "r") as f:
|
||||||
self.__is_wireless = self.__interface in f.read()
|
self.__is_wireless = self.__interface in f.read()
|
||||||
f.close()
|
f.close()
|
||||||
|
except Exception:
|
||||||
|
self.__is_wireless = False
|
||||||
|
|
||||||
# setup message to send to the user
|
# setup message to send to the user
|
||||||
if not self.__is_connected:
|
if not self.__is_connected or not self.__interface:
|
||||||
self.__message = "No connection"
|
self.__message = "No connection"
|
||||||
elif not self.__is_wireless:
|
elif not self.__is_wireless:
|
||||||
# Assuming that if user is connected via non-wireless means that it will be ethernet
|
# Assuming that if user is connected via non-wireless means that it will be ethernet
|
||||||
|
@ -57,7 +61,11 @@ class Module(core.module.Module):
|
||||||
iw_dat = util.cli.execute("iwgetid")
|
iw_dat = util.cli.execute("iwgetid")
|
||||||
has_ssid = "ESSID" in iw_dat
|
has_ssid = "ESSID" in iw_dat
|
||||||
signal = self.__compute_signal(self.__interface)
|
signal = self.__compute_signal(self.__interface)
|
||||||
self.__signal = util.format.asint(signal, minimum=-110, maximum=-30)
|
|
||||||
|
# If signal is None, that means that we can't compute the default interface's signal strength
|
||||||
|
self.__signal = (
|
||||||
|
util.format.asint(signal, minimum=-110, maximum=-30) if signal else None
|
||||||
|
)
|
||||||
|
|
||||||
ssid = (
|
ssid = (
|
||||||
iw_dat[iw_dat.index(":") + 1 :].replace('"', "").strip()
|
iw_dat[iw_dat.index(":") + 1 :].replace('"', "").strip()
|
||||||
|
@ -80,10 +88,12 @@ class Module(core.module.Module):
|
||||||
# manually done for better granularity / ease of parsing strength data
|
# manually done for better granularity / ease of parsing strength data
|
||||||
def __generate_wireles_message(self, ssid, signal):
|
def __generate_wireles_message(self, ssid, signal):
|
||||||
computed_strength = self.__compute_strength(signal)
|
computed_strength = self.__compute_strength(signal)
|
||||||
return "{} {}%".format(ssid, int(computed_strength))
|
strength_str = str(computed_strength) if computed_strength else "?"
|
||||||
|
|
||||||
|
return "{} {}%".format(ssid, strength_str)
|
||||||
|
|
||||||
def __compute_strength(self, signal):
|
def __compute_strength(self, signal):
|
||||||
return 100 * ((signal + 100) / 70.0)
|
return int(100 * ((signal + 100) / 70.0)) if signal else None
|
||||||
|
|
||||||
# get signal strength in decibels/milliwat
|
# get signal strength in decibels/milliwat
|
||||||
def __compute_signal(self, interface):
|
def __compute_signal(self, interface):
|
||||||
|
@ -91,6 +101,11 @@ class Module(core.module.Module):
|
||||||
cmd = "iwconfig {}".format(interface)
|
cmd = "iwconfig {}".format(interface)
|
||||||
config_dat = " ".join(util.cli.execute(cmd).split())
|
config_dat = " ".join(util.cli.execute(cmd).split())
|
||||||
config_tokens = config_dat.replace("=", " ").split()
|
config_tokens = config_dat.replace("=", " ").split()
|
||||||
|
|
||||||
|
# handle weird output
|
||||||
|
try:
|
||||||
signal = config_tokens[config_tokens.index("level") + 1]
|
signal = config_tokens[config_tokens.index("level") + 1]
|
||||||
|
except Exception:
|
||||||
|
signal = None
|
||||||
|
|
||||||
return signal
|
return signal
|
||||||
|
|
|
@ -1,65 +1,107 @@
|
||||||
import pytest
|
|
||||||
from unittest import TestCase, mock
|
from unittest import TestCase, mock
|
||||||
|
import pytest
|
||||||
|
|
||||||
import core.config
|
import core.config
|
||||||
import core.widget
|
import core.widget
|
||||||
import modules.contrib.network
|
import modules.contrib.network
|
||||||
|
|
||||||
|
import socket
|
||||||
|
|
||||||
|
pytest.importorskip("netifaces")
|
||||||
|
|
||||||
|
|
||||||
def build_module():
|
def build_module():
|
||||||
config = core.config.Config([])
|
config = core.config.Config([])
|
||||||
return modules.contrib.network.Module(config=config, theme=None)
|
return modules.contrib.network.Module(config=config, theme=None)
|
||||||
|
|
||||||
|
|
||||||
def wireless_default():
|
def wireless_default():
|
||||||
return {
|
return {"default": {1: ("10.0.1.12", "wlan3")}}
|
||||||
"default": {
|
|
||||||
1: ('10.0.1.12', 'wlan0')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def wired_default():
|
def wired_default():
|
||||||
return {
|
return {"default": {18: ("10.0.1.12", "eth3")}}
|
||||||
'default': {
|
|
||||||
18: ('10.0.1.12', 'eth0')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def exec_side_effect(*args, **kwargs):
|
|
||||||
|
def exec_side_effect_valid(*args, **kwargs):
|
||||||
if args[0] == "iwgetid":
|
if args[0] == "iwgetid":
|
||||||
return "ESSID: bumblefoo"
|
return "ESSID: bumblefoo"
|
||||||
elif "iwconfig" in args[0]:
|
if "iwconfig" in args[0]:
|
||||||
return "level=-30"
|
return "level=-30"
|
||||||
|
return mock.DEFAULT
|
||||||
|
|
||||||
return "default"
|
|
||||||
|
def exec_side_effect_invalid(*args, **kwargs):
|
||||||
|
return "invalid gibberish, can't parse for info"
|
||||||
|
|
||||||
|
|
||||||
class TestNetworkUnit(TestCase):
|
class TestNetworkUnit(TestCase):
|
||||||
def test_load_module(self):
|
def test_load_module(self):
|
||||||
__import__("modules.contrib.network")
|
__import__("modules.contrib.network")
|
||||||
|
|
||||||
@pytest.mark.allow_hosts(['127.0.0.1'])
|
@pytest.mark.allow_hosts(["127.0.0.1"])
|
||||||
def test_no_internet(self):
|
def test_no_internet(self):
|
||||||
module = build_module()
|
module = build_module()
|
||||||
assert module.widgets()[0].full_text() == "No connection"
|
assert module.widgets()[0].full_text() == "No connection"
|
||||||
|
|
||||||
@mock.patch('util.cli.execute')
|
@mock.patch("util.cli.execute")
|
||||||
@mock.patch('netifaces.gateways')
|
@mock.patch("netifaces.gateways")
|
||||||
@mock.patch('netifaces.AF_INET', 1)
|
@mock.patch("socket.create_connection")
|
||||||
def test_wireless_connection(self, gateways_mock, execute_mock):
|
@mock.patch("netifaces.AF_INET", 1)
|
||||||
|
@mock.patch("builtins.open", mock.mock_open(read_data="wlan3"))
|
||||||
|
def test_valid_wireless_connection(self, socket_mock, gateways_mock, execute_mock):
|
||||||
|
socket_mock.return_value = mock.MagicMock()
|
||||||
fake_ssid = "bumblefoo"
|
fake_ssid = "bumblefoo"
|
||||||
gateways_mock.return_value = wireless_default()
|
gateways_mock.return_value = wireless_default()
|
||||||
execute_mock.side_effect = exec_side_effect
|
execute_mock.side_effect = exec_side_effect_valid
|
||||||
|
|
||||||
module = build_module()
|
module = build_module()
|
||||||
|
|
||||||
assert fake_ssid in module.widgets()[0].full_text()
|
assert fake_ssid in module.widgets()[0].full_text()
|
||||||
|
|
||||||
@mock.patch('util.cli.execute')
|
@mock.patch("netifaces.gateways")
|
||||||
@mock.patch('netifaces.gateways')
|
@mock.patch("socket.create_connection")
|
||||||
@mock.patch('netifaces.AF_INET', 18)
|
@mock.patch("netifaces.AF_INET", 18)
|
||||||
def test_wired_connection(self, gateways_mock, execute_mock):
|
@mock.patch("builtins.open", mock.mock_open(read_data="wlan3"))
|
||||||
|
def test_valid_wired_connection(self, socket_mock, gateways_mock):
|
||||||
gateways_mock.return_value = wired_default()
|
gateways_mock.return_value = wired_default()
|
||||||
execute_mock.side_effect = exec_side_effect
|
socket_mock.return_value = mock.MagicMock()
|
||||||
|
|
||||||
module = build_module()
|
module = build_module()
|
||||||
|
|
||||||
assert module.widgets()[0].full_text() == "Ethernet"
|
assert module.widgets()[0].full_text() == "Ethernet"
|
||||||
|
|
||||||
|
@mock.patch("netifaces.gateways")
|
||||||
|
@mock.patch("socket.create_connection")
|
||||||
|
def test_invalid_gateways(self, socket_mock, gateways_mock):
|
||||||
|
socket_mock.return_value = mock.Mock()
|
||||||
|
gateways_mock.return_value = {"xyz": "abc"}
|
||||||
|
|
||||||
|
module = build_module()
|
||||||
|
assert module.widgets()[0].full_text() == "No connection"
|
||||||
|
|
||||||
|
@mock.patch("util.cli.execute")
|
||||||
|
@mock.patch("socket.create_connection")
|
||||||
|
@mock.patch("netifaces.gateways")
|
||||||
|
@mock.patch("netifaces.AF_INET", 1)
|
||||||
|
@mock.patch("builtins.open", mock.mock_open(read_data="wlan3"))
|
||||||
|
def test_invalid_execs(self, gateways_mock, socket_mock, execute_mock):
|
||||||
|
execute_mock.side_effect = exec_side_effect_invalid
|
||||||
|
socket_mock.return_value = mock.MagicMock()
|
||||||
|
gateways_mock.return_value = wireless_default()
|
||||||
|
|
||||||
|
module = build_module()
|
||||||
|
|
||||||
|
assert module.widgets()[0].full_text() == "Unknown ?%"
|
||||||
|
|
||||||
|
@mock.patch("builtins.open", **{"return_value.raiseError.side_effect": Exception()})
|
||||||
|
@mock.patch("socket.create_connection")
|
||||||
|
@mock.patch("netifaces.gateways")
|
||||||
|
@mock.patch("netifaces.AF_INET", 18)
|
||||||
|
@mock.patch("builtins.open", mock.mock_open(read_data="wlan3"))
|
||||||
|
def test_no_wireless_file(self, gateways_mock, socket_mock, mock_open):
|
||||||
|
gateways_mock.return_value = wired_default()
|
||||||
|
socket_mock.return_value = mock.MagicMock()
|
||||||
|
module = build_module()
|
||||||
|
|
||||||
|
assert module.widgets()[0].full_text() == "Ethernet"
|
||||||
|
|
Loading…
Reference in a new issue