From 1232c4d96092be16c76a9baac35a8c4bb4868683 Mon Sep 17 00:00:00 2001 From: nepoz Date: Mon, 5 Jul 2021 07:55:47 -0500 Subject: [PATCH 01/11] Initial commit -- give basic message about interface being used --- bumblebee_status/modules/contrib/network.py | 48 +++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 bumblebee_status/modules/contrib/network.py diff --git a/bumblebee_status/modules/contrib/network.py b/bumblebee_status/modules/contrib/network.py new file mode 100644 index 0000000..37115e1 --- /dev/null +++ b/bumblebee_status/modules/contrib/network.py @@ -0,0 +1,48 @@ +""" +A module to show currently active network connection (ethernet or wifi) +and connection strength. +""" + +import subprocess +import os + +import core.module +import core.widget + + +class Module(core.module.Module): + def __init__(self, config, theme): + super().__init__(config, theme, core.widget.Widget(self.network)) + self._is_wireless = True + self._interface = None + self._message = None + + def network(self, widgets): + # start subprocess to get networked data + std_out = os.popen("ip route get 8.8.8.8") + route_str = " ".join(std_out.read().split()) + route_tokens = route_str.split(" ") + + try: + self._interface = route_tokens[route_tokens.index("dev") + 1] + ":" + except ValueError: + self._interface = None + + with open("/proc/net/wireless", "r") as f: + if self._interface: + self._is_wireless = self._interface in f.read() + + # setup message to send to bar + if self._interface is None: + self._message = "Not connected to a network" + elif self._is_wireless: + self._message = "Connected to WiFi" + else: + # self._message = "Connected to Ethernet" + self._message = self._message + + + return self._message + + + From f141b95d8f7dd53e86b1e9aff3ce9b12a0178be8 Mon Sep 17 00:00:00 2001 From: nepoz Date: Mon, 5 Jul 2021 10:29:37 -0500 Subject: [PATCH 02/11] Basic functionaly for dealingn with signal strength --- bumblebee_status/modules/contrib/network.py | 49 ++++++++++++++++----- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/bumblebee_status/modules/contrib/network.py b/bumblebee_status/modules/contrib/network.py index 37115e1..c40d0d8 100644 --- a/bumblebee_status/modules/contrib/network.py +++ b/bumblebee_status/modules/contrib/network.py @@ -3,8 +3,9 @@ A module to show currently active network connection (ethernet or wifi) and connection strength. """ -import subprocess -import os + +import util.cli +import util.format import core.module import core.widget @@ -18,31 +19,55 @@ class Module(core.module.Module): self._message = None def network(self, widgets): - # start subprocess to get networked data - std_out = os.popen("ip route get 8.8.8.8") - route_str = " ".join(std_out.read().split()) + # run ip route command, tokenize output + cmd = "ip route get 8.8.8.8" + std_out = util.cli.execute(cmd) + route_str = " ".join(std_out.split()) route_tokens = route_str.split(" ") + # Attempt to extract a valid network interface device try: - self._interface = route_tokens[route_tokens.index("dev") + 1] + ":" + self._interface = route_tokens[route_tokens.index("dev") + 1] except ValueError: self._interface = None - with open("/proc/net/wireless", "r") as f: - if self._interface: + # Check to see if the interface (if it exists) is wireless + if self._interface: + with open("/proc/net/wireless", "r") as f: self._is_wireless = self._interface in f.read() + f.close() - # setup message to send to bar + # setup message to send to the user if self._interface is None: self._message = "Not connected to a network" elif self._is_wireless: - self._message = "Connected to WiFi" + cmd = "iwgetid" + iw_dat = util.cli.execute(cmd) + has_ssid = "ESSID" in iw_dat + ssid = iw_dat[iw_dat.index(":") + 2: -2] if has_ssid else "Unknown" + + # Get connection strength + cmd = "iwconfig {}".format(self._interface) + config_dat = " ".join(util.cli.execute(cmd).split()) + config_tokens = config_dat.replace("=", " ").split() + strength = config_tokens[config_tokens.index("level") + 1] + strength = util.format.asint(strength, minimum=-110, maximum=-30) + + self._message = self.__generate_wireless_message(ssid, strength) else: - # self._message = "Connected to Ethernet" self._message = self._message - return self._message + def __generate_wireless_message(self, ssid, strength): + computed_strength = 100 * (strength + 110) / 70.0 + if computed_strength < 25: + return ssid + " poor" + if computed_strength < 50: + return ssid + " fair" + if computed_strength < 75: + return ssid + " good" + + return ssid + " excellent" From 4987c7d3e2fa1152224c3d7d540f56dbfdf315dc Mon Sep 17 00:00:00 2001 From: nepoz Date: Mon, 5 Jul 2021 11:26:46 -0500 Subject: [PATCH 03/11] added stateful behavior --- bumblebee_status/modules/contrib/network.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/bumblebee_status/modules/contrib/network.py b/bumblebee_status/modules/contrib/network.py index c40d0d8..30601b5 100644 --- a/bumblebee_status/modules/contrib/network.py +++ b/bumblebee_status/modules/contrib/network.py @@ -17,6 +17,7 @@ class Module(core.module.Module): self._is_wireless = True self._interface = None self._message = None + self.__signal = -110 def network(self, widgets): # run ip route command, tokenize output @@ -51,19 +52,27 @@ class Module(core.module.Module): config_dat = " ".join(util.cli.execute(cmd).split()) config_tokens = config_dat.replace("=", " ").split() strength = config_tokens[config_tokens.index("level") + 1] - strength = util.format.asint(strength, minimum=-110, maximum=-30) + self.__signal = util.format.asint(strength, minimum=-110, maximum=-30) - self._message = self.__generate_wireless_message(ssid, strength) + self._message = self.__generate_wireless_message(ssid, self.__signal) else: self._message = self._message return self._message + def state(self, widget): + if self.__signal < -65: + return "warning" + if self.__signal < -80: + return "critical" + return None + + def __generate_wireless_message(self, ssid, strength): - computed_strength = 100 * (strength + 110) / 70.0 - if computed_strength < 25: - return ssid + " poor" + computed_strength = 100 * ((strength + 100) / 70.0) + if computed_strength < 30: + return ssid + " poor" if computed_strength < 50: return ssid + " fair" if computed_strength < 75: From 448ab6de836b0eedcc7250c0aa97104f3df0c696 Mon Sep 17 00:00:00 2001 From: nepoz Date: Mon, 5 Jul 2021 12:34:42 -0500 Subject: [PATCH 04/11] Functional display for wireless connection --- bumblebee_status/modules/contrib/network.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bumblebee_status/modules/contrib/network.py b/bumblebee_status/modules/contrib/network.py index 30601b5..f91073e 100644 --- a/bumblebee_status/modules/contrib/network.py +++ b/bumblebee_status/modules/contrib/network.py @@ -9,9 +9,11 @@ import util.format import core.module import core.widget +import core.input class Module(core.module.Module): + @core.decorators.every(seconds=10) def __init__(self, config, theme): super().__init__(config, theme, core.widget.Widget(self.network)) self._is_wireless = True @@ -19,6 +21,9 @@ class Module(core.module.Module): self._message = None self.__signal = -110 + # Set up event handler for left mouse click + core.input.register(self, button=core.input.LEFT_MOUSE, cmd="nm-connection-editor") + def network(self, widgets): # run ip route command, tokenize output cmd = "ip route get 8.8.8.8" @@ -71,12 +76,7 @@ class Module(core.module.Module): def __generate_wireless_message(self, ssid, strength): computed_strength = 100 * ((strength + 100) / 70.0) - if computed_strength < 30: - return ssid + " poor" - if computed_strength < 50: - return ssid + " fair" - if computed_strength < 75: - return ssid + " good" + return " {} {}%".format(ssid, int(computed_strength)) + - return ssid + " excellent" From c7df1926dce8fdf3fb0427d79e802955a60694d6 Mon Sep 17 00:00:00 2001 From: nepoz Date: Mon, 5 Jul 2021 13:09:17 -0500 Subject: [PATCH 05/11] Formatting fixes, fixed state management and added some icons --- bumblebee_status/modules/contrib/network.py | 36 +++++++++++---------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/bumblebee_status/modules/contrib/network.py b/bumblebee_status/modules/contrib/network.py index f91073e..924c7f4 100644 --- a/bumblebee_status/modules/contrib/network.py +++ b/bumblebee_status/modules/contrib/network.py @@ -16,9 +16,9 @@ class Module(core.module.Module): @core.decorators.every(seconds=10) def __init__(self, config, theme): super().__init__(config, theme, core.widget.Widget(self.network)) - self._is_wireless = True - self._interface = None - self._message = None + self.__is_wireless = True + self.__interface = None + self.__message = None self.__signal = -110 # Set up event handler for left mouse click @@ -33,48 +33,50 @@ class Module(core.module.Module): # Attempt to extract a valid network interface device try: - self._interface = route_tokens[route_tokens.index("dev") + 1] + self.__interface = route_tokens[route_tokens.index("dev") + 1] except ValueError: - self._interface = None + self.__interface = None # Check to see if the interface (if it exists) is wireless - if self._interface: + if self.__interface: 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() # setup message to send to the user - if self._interface is None: - self._message = "Not connected to a network" - elif self._is_wireless: + if self.__interface is None: + self.__message = " No connection" + elif self.__is_wireless: cmd = "iwgetid" iw_dat = util.cli.execute(cmd) has_ssid = "ESSID" in iw_dat ssid = iw_dat[iw_dat.index(":") + 2: -2] if has_ssid else "Unknown" # Get connection strength - cmd = "iwconfig {}".format(self._interface) + cmd = "iwconfig {}".format(self.__interface) config_dat = " ".join(util.cli.execute(cmd).split()) config_tokens = config_dat.replace("=", " ").split() strength = config_tokens[config_tokens.index("level") + 1] self.__signal = util.format.asint(strength, minimum=-110, maximum=-30) - self._message = self.__generate_wireless_message(ssid, self.__signal) + self.__message = self.__generate_wireles_message(ssid, self.__signal) else: - self._message = self._message + self.__signal = -30 + self.__message = " Ethernet" - return self._message + return self.__message def state(self, widget): - if self.__signal < -65: - return "warning" if self.__signal < -80: return "critical" + if self.__signal < -65: + return "warning" + return None - def __generate_wireless_message(self, ssid, strength): + def __generate_wireles_message(self, ssid, strength): computed_strength = 100 * ((strength + 100) / 70.0) return " {} {}%".format(ssid, int(computed_strength)) From 911230c65998ac8969eba88507c09b8de463373e Mon Sep 17 00:00:00 2001 From: nepoz Date: Mon, 5 Jul 2021 13:54:28 -0500 Subject: [PATCH 06/11] first complete implementation of the network module --- bumblebee_status/modules/contrib/network.py | 34 ++++++++++++--------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/bumblebee_status/modules/contrib/network.py b/bumblebee_status/modules/contrib/network.py index 924c7f4..0c366d6 100644 --- a/bumblebee_status/modules/contrib/network.py +++ b/bumblebee_status/modules/contrib/network.py @@ -1,6 +1,8 @@ """ -A module to show currently active network connection (ethernet or wifi) -and connection strength. +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 """ @@ -16,14 +18,17 @@ class Module(core.module.Module): @core.decorators.every(seconds=10) def __init__(self, config, theme): super().__init__(config, theme, core.widget.Widget(self.network)) - self.__is_wireless = True + self.__is_wireless = False self.__interface = None self.__message = None self.__signal = -110 # Set up event handler for left mouse click - core.input.register(self, button=core.input.LEFT_MOUSE, cmd="nm-connection-editor") + core.input.register( + self, button=core.input.LEFT_MOUSE, cmd="nm-connection-editor" + ) + # Get network information to display to the user def network(self, widgets): # run ip route command, tokenize output cmd = "ip route get 8.8.8.8" @@ -33,7 +38,7 @@ class Module(core.module.Module): # Attempt to extract a valid network interface device try: - self.__interface = route_tokens[route_tokens.index("dev") + 1] + self.__interface = route_tokens[route_tokens.index("dev") + 1] except ValueError: self.__interface = None @@ -47,10 +52,13 @@ class Module(core.module.Module): if self.__interface is None: self.__message = " No connection" elif self.__is_wireless: - cmd = "iwgetid" - iw_dat = util.cli.execute(cmd) + iw_dat = util.cli.execute("iwgetid") has_ssid = "ESSID" in iw_dat - ssid = iw_dat[iw_dat.index(":") + 2: -2] if has_ssid else "Unknown" + ssid = ( + iw_dat[iw_dat.index(":") + 1 :].replace('"', "").strip() + if has_ssid + else "Unknown" + ) # Get connection strength cmd = "iwconfig {}".format(self.__interface) @@ -61,12 +69,13 @@ class Module(core.module.Module): self.__message = self.__generate_wireles_message(ssid, self.__signal) else: + # Set signal to -30 as ethernet shouldn't have signal issues self.__signal = -30 - self.__message = " Ethernet" + self.__message = " Ethernet" return self.__message - + # The signal is measured in decibels/milliwatt, hence the weird numbers def state(self, widget): if self.__signal < -80: return "critical" @@ -75,10 +84,7 @@ class Module(core.module.Module): return None - + # manually done for better granularity / ease of parsing strength data def __generate_wireles_message(self, ssid, strength): computed_strength = 100 * ((strength + 100) / 70.0) return " {} {}%".format(ssid, int(computed_strength)) - - - From 3f524ab371a1780619914c12fbb7d87836a57f92 Mon Sep 17 00:00:00 2001 From: nepoz Date: Thu, 8 Jul 2021 09:04:40 -0500 Subject: [PATCH 07/11] Refactoring, making use of netifaces --- bumblebee_status/modules/contrib/network.py | 82 +++++++++++---------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/bumblebee_status/modules/contrib/network.py b/bumblebee_status/modules/contrib/network.py index 0c366d6..d90a21b 100644 --- a/bumblebee_status/modules/contrib/network.py +++ b/bumblebee_status/modules/contrib/network.py @@ -13,78 +13,84 @@ import core.module import core.widget import core.input +import netifaces +import socket + class Module(core.module.Module): @core.decorators.every(seconds=10) def __init__(self, config, theme): super().__init__(config, theme, core.widget.Widget(self.network)) self.__is_wireless = False + self.__is_connected = False self.__interface = None self.__message = None self.__signal = -110 - # Set up event handler for left mouse click - core.input.register( - self, button=core.input.LEFT_MOUSE, cmd="nm-connection-editor" - ) - # Get network information to display to the user def network(self, widgets): - # run ip route command, tokenize output - cmd = "ip route get 8.8.8.8" - std_out = util.cli.execute(cmd) - route_str = " ".join(std_out.split()) - route_tokens = route_str.split(" ") + # Determine whether there is an internet connection + try: + socket.create_connection(("1.1.1.1", 53)) + self.__is_connected = True + except OSError: + self.__is_connected = False # Attempt to extract a valid network interface device - try: - self.__interface = route_tokens[route_tokens.index("dev") + 1] - except ValueError: - self.__interface = None + self.__interface = netifaces.gateways()["default"][netifaces.AF_INET][1] - # Check to see if the interface (if it exists) is wireless - if self.__interface: + # Check to see if the interface (if connected to the internet) is wireless + if self.__is_connected: with open("/proc/net/wireless", "r") as f: self.__is_wireless = self.__interface in f.read() - f.close() + f.close() # setup message to send to the user - if self.__interface is None: - self.__message = " No connection" - elif self.__is_wireless: + if not self.__is_connected: + self.__message = "No connection" + elif not self.__is_wireless: + # Assuming that if user is connected via non-wireless means that it will be ethernet + self.__signal = -30 + self.__message = "Ethernet" + else: + # We have a wireless connection iw_dat = util.cli.execute("iwgetid") has_ssid = "ESSID" in iw_dat + signal = self.__compute_signal(self.__interface) + self.__signal = util.format.asint(signal, minimum=-110, maximum=-30) + ssid = ( iw_dat[iw_dat.index(":") + 1 :].replace('"', "").strip() if has_ssid else "Unknown" ) - - # Get connection strength - cmd = "iwconfig {}".format(self.__interface) - config_dat = " ".join(util.cli.execute(cmd).split()) - config_tokens = config_dat.replace("=", " ").split() - strength = config_tokens[config_tokens.index("level") + 1] - self.__signal = util.format.asint(strength, minimum=-110, maximum=-30) - self.__message = self.__generate_wireles_message(ssid, self.__signal) - else: - # Set signal to -30 as ethernet shouldn't have signal issues - self.__signal = -30 - self.__message = " Ethernet" return self.__message - # The signal is measured in decibels/milliwatt, hence the weird numbers + # State determined by signal strength def state(self, widget): - if self.__signal < -80: + if self.__compute_strength(self.__signal) < 50: return "critical" - if self.__signal < -65: + if self.__compute_strength(self.__signal) < 75: return "warning" return None # manually done for better granularity / ease of parsing strength data - def __generate_wireles_message(self, ssid, strength): - computed_strength = 100 * ((strength + 100) / 70.0) - return " {} {}%".format(ssid, int(computed_strength)) + def __generate_wireles_message(self, ssid, signal): + computed_strength = self.__compute_strength(signal) + return "{} {}%".format(ssid, int(computed_strength)) + + def __compute_strength(self, signal): + return 100 * ((signal + 100) / 70.0) + + # get signal strength in decibels/milliwat + def __compute_signal(self, interface): + # Get connection strength + cmd = "iwconfig {}".format(interface) + config_dat = " ".join(util.cli.execute(cmd).split()) + config_tokens = config_dat.replace("=", " ").split() + signal = config_tokens[config_tokens.index("level") + 1] + + return signal From 2100a7cfdbb5b768136c5c5c01a087f8541229db Mon Sep 17 00:00:00 2001 From: nepoz Date: Thu, 8 Jul 2021 12:10:46 -0500 Subject: [PATCH 08/11] Set up initial testing framework for network module --- bumblebee_status/modules/contrib/network.py | 2 +- tests/modules/contrib/test_network.py | 65 +++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 tests/modules/contrib/test_network.py diff --git a/bumblebee_status/modules/contrib/network.py b/bumblebee_status/modules/contrib/network.py index d90a21b..26c7889 100644 --- a/bumblebee_status/modules/contrib/network.py +++ b/bumblebee_status/modules/contrib/network.py @@ -33,7 +33,7 @@ class Module(core.module.Module): try: socket.create_connection(("1.1.1.1", 53)) self.__is_connected = True - except OSError: + except: self.__is_connected = False # Attempt to extract a valid network interface device diff --git a/tests/modules/contrib/test_network.py b/tests/modules/contrib/test_network.py new file mode 100644 index 0000000..e171d69 --- /dev/null +++ b/tests/modules/contrib/test_network.py @@ -0,0 +1,65 @@ +import pytest +from unittest import TestCase, mock + +import core.config +import core.widget +import modules.contrib.network + +def build_module(): + config = core.config.Config([]) + return modules.contrib.network.Module(config=config, theme=None) + +def wireless_default(): + return { + "default": { + 1: ('10.0.1.12', 'wlan0') + } + } + +def wired_default(): + return { + 'default': { + 18: ('10.0.1.12', 'eth0') + } + } + +def exec_side_effect(*args, **kwargs): + if args[0] == "iwgetid": + return "ESSID: bumblefoo" + elif "iwconfig" in args[0]: + return "level=-30" + + return "default" + + +class TestNetworkUnit(TestCase): + def test_load_module(self): + __import__("modules.contrib.network") + + @pytest.mark.allow_hosts(['127.0.0.1']) + def test_no_internet(self): + module = build_module() + assert module.widgets()[0].full_text() == "No connection" + + @mock.patch('util.cli.execute') + @mock.patch('netifaces.gateways') + @mock.patch('netifaces.AF_INET', 1) + def test_wireless_connection(self, gateways_mock, execute_mock): + fake_ssid = "bumblefoo" + gateways_mock.return_value = wireless_default() + execute_mock.side_effect = exec_side_effect + + module = build_module() + + assert fake_ssid in module.widgets()[0].full_text() + + @mock.patch('util.cli.execute') + @mock.patch('netifaces.gateways') + @mock.patch('netifaces.AF_INET', 18) + def test_wired_connection(self, gateways_mock, execute_mock): + gateways_mock.return_value = wired_default() + execute_mock.side_effect = exec_side_effect + + module = build_module() + + assert module.widgets()[0].full_text() == "Ethernet" From f9017c3a38e94d8ab67cc15d71e12bf0a63ca3e0 Mon Sep 17 00:00:00 2001 From: nepoz Date: Thu, 8 Jul 2021 22:55:23 -0500 Subject: [PATCH 09/11] Added more tests and exception handling --- bumblebee_status/modules/contrib/network.py | 43 ++++++---- tests/modules/contrib/test_network.py | 92 +++++++++++++++------ 2 files changed, 96 insertions(+), 39 deletions(-) diff --git a/bumblebee_status/modules/contrib/network.py b/bumblebee_status/modules/contrib/network.py index 26c7889..6c35ee4 100644 --- a/bumblebee_status/modules/contrib/network.py +++ b/bumblebee_status/modules/contrib/network.py @@ -1,8 +1,6 @@ """ 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): - @core.decorators.every(seconds=10) + @core.decorators.every(seconds=5) def __init__(self, config, theme): super().__init__(config, theme, core.widget.Widget(self.network)) self.__is_wireless = False @@ -33,20 +31,26 @@ class Module(core.module.Module): try: socket.create_connection(("1.1.1.1", 53)) self.__is_connected = True - except: + except Exception: self.__is_connected = False # 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 - if self.__is_connected: - with open("/proc/net/wireless", "r") as f: - self.__is_wireless = self.__interface in f.read() - f.close() + if self.__is_connected and self.__interface: + try: + with open("/proc/net/wireless", "r") as f: + self.__is_wireless = self.__interface in f.read() + f.close() + except Exception: + self.__is_wireless = False # 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" elif not self.__is_wireless: # 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") has_ssid = "ESSID" in iw_dat 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 = ( 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 def __generate_wireles_message(self, ssid, 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): - return 100 * ((signal + 100) / 70.0) + return int(100 * ((signal + 100) / 70.0)) if signal else None # get signal strength in decibels/milliwat def __compute_signal(self, interface): @@ -91,6 +101,11 @@ class Module(core.module.Module): cmd = "iwconfig {}".format(interface) config_dat = " ".join(util.cli.execute(cmd).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 diff --git a/tests/modules/contrib/test_network.py b/tests/modules/contrib/test_network.py index e171d69..9b270bf 100644 --- a/tests/modules/contrib/test_network.py +++ b/tests/modules/contrib/test_network.py @@ -1,65 +1,107 @@ -import pytest from unittest import TestCase, mock +import pytest import core.config import core.widget import modules.contrib.network +import socket + +pytest.importorskip("netifaces") + + def build_module(): config = core.config.Config([]) return modules.contrib.network.Module(config=config, theme=None) + def wireless_default(): - return { - "default": { - 1: ('10.0.1.12', 'wlan0') - } - } + return {"default": {1: ("10.0.1.12", "wlan3")}} + def wired_default(): - return { - 'default': { - 18: ('10.0.1.12', 'eth0') - } - } + return {"default": {18: ("10.0.1.12", "eth3")}} -def exec_side_effect(*args, **kwargs): + +def exec_side_effect_valid(*args, **kwargs): if args[0] == "iwgetid": return "ESSID: bumblefoo" - elif "iwconfig" in args[0]: + if "iwconfig" in args[0]: 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): def test_load_module(self): __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): module = build_module() assert module.widgets()[0].full_text() == "No connection" - @mock.patch('util.cli.execute') - @mock.patch('netifaces.gateways') - @mock.patch('netifaces.AF_INET', 1) - def test_wireless_connection(self, gateways_mock, execute_mock): + @mock.patch("util.cli.execute") + @mock.patch("netifaces.gateways") + @mock.patch("socket.create_connection") + @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" gateways_mock.return_value = wireless_default() - execute_mock.side_effect = exec_side_effect + execute_mock.side_effect = exec_side_effect_valid module = build_module() assert fake_ssid in module.widgets()[0].full_text() - @mock.patch('util.cli.execute') - @mock.patch('netifaces.gateways') - @mock.patch('netifaces.AF_INET', 18) - def test_wired_connection(self, gateways_mock, execute_mock): + @mock.patch("netifaces.gateways") + @mock.patch("socket.create_connection") + @mock.patch("netifaces.AF_INET", 18) + @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() - execute_mock.side_effect = exec_side_effect + socket_mock.return_value = mock.MagicMock() module = build_module() 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" From 48501fa53478075ed0d6ce5d66ddb3499264bb86 Mon Sep 17 00:00:00 2001 From: nepoz Date: Thu, 8 Jul 2021 23:00:57 -0500 Subject: [PATCH 10/11] Updated docstring --- bumblebee_status/modules/contrib/network.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bumblebee_status/modules/contrib/network.py b/bumblebee_status/modules/contrib/network.py index 6c35ee4..b8d16a4 100644 --- a/bumblebee_status/modules/contrib/network.py +++ b/bumblebee_status/modules/contrib/network.py @@ -1,5 +1,9 @@ """ -A module to show currently active network connection (ethernet or wifi) and connection strength if the connection is wireless. +A module to show the currently active network connection (ethernet or wifi) and connection strength if the connection is wireless. + +Requires the Python netifaces package and iw installed on Linux. + +A simpler take on nic and network_traffic. No extra config necessary! """ From 5d80a5a1a0470b72a79608d1952eb126f7d37ab4 Mon Sep 17 00:00:00 2001 From: nepoz Date: Fri, 9 Jul 2021 00:28:00 -0500 Subject: [PATCH 11/11] Slight refactoring to try and break apart networkmethod --- bumblebee_status/modules/contrib/network.py | 35 ++++++++++++++------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/bumblebee_status/modules/contrib/network.py b/bumblebee_status/modules/contrib/network.py index b8d16a4..a91c947 100644 --- a/bumblebee_status/modules/contrib/network.py +++ b/bumblebee_status/modules/contrib/network.py @@ -32,11 +32,7 @@ class Module(core.module.Module): # Get network information to display to the user def network(self, widgets): # Determine whether there is an internet connection - try: - socket.create_connection(("1.1.1.1", 53)) - self.__is_connected = True - except Exception: - self.__is_connected = False + self.__is_connected = self.__attempt_connection() # Attempt to extract a valid network interface device try: @@ -46,12 +42,7 @@ class Module(core.module.Module): # Check to see if the interface (if connected to the internet) is wireless if self.__is_connected and self.__interface: - try: - with open("/proc/net/wireless", "r") as f: - self.__is_wireless = self.__interface in f.read() - f.close() - except Exception: - self.__is_wireless = False + self.__is_wireless = self.__interface_is_wireless(self.__interface) # setup message to send to the user if not self.__is_connected or not self.__interface: @@ -113,3 +104,25 @@ class Module(core.module.Module): signal = None return signal + + def __attempt_connection(self): + can_connect = False + try: + socket.create_connection(("1.1.1.1", 53)) + can_connect = True + except Exception: + can_connect = False + + return can_connect + + def __interface_is_wireless(self, interface): + is_wireless = False + try: + with open("/proc/net/wireless", "r") as f: + is_wireless = interface in f.read() + f.close() + except Exception: + is_wireless = False + + return is_wireless +