Added more tests and exception handling

This commit is contained in:
nepoz 2021-07-08 22:55:23 -05:00
parent 2100a7cfdb
commit f9017c3a38
2 changed files with 96 additions and 39 deletions

View file

@ -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
self.__interface = netifaces.gateways()["default"][netifaces.AF_INET][1] try:
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:
with open("/proc/net/wireless", "r") as f: try:
self.__is_wireless = self.__interface in f.read() with open("/proc/net/wireless", "r") as f:
f.close() self.__is_wireless = self.__interface in f.read()
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()
signal = config_tokens[config_tokens.index("level") + 1]
# handle weird output
try:
signal = config_tokens[config_tokens.index("level") + 1]
except Exception:
signal = None
return signal return signal

View file

@ -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"