import unittest from unittest.mock import patch, mock_open from app.network_utils import parse_iwlist, connect_network, disconnect_network, cleanup_network from config import ClientInterface class TestNetworkUtils(unittest.TestCase): def test_parse_iwlist(self): iwlist_text = """wlan0 Scan completed : Cell 01 - Address: 94:37:F7:ED:E5:F5 Channel:5 Frequency:2.432 GHz (Channel 5) Quality=70/70 Signal level=-38 dBm Encryption key:on ESSID:"Home" Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 18 Mb/s 24 Mb/s; 36 Mb/s; 54 Mb/s Bit Rates:6 Mb/s; 9 Mb/s; 12 Mb/s; 48 Mb/s Mode:Master Extra:tsf=0000000000000000 Extra: Last beacon: 80ms ago IE: Unknown: 0004486F6D65 IE: Unknown: 010882840B162430486C IE: Unknown: 030105 IE: Unknown: 050400010000 IE: Unknown: 23020E00 IE: Unknown: 2A0104 IE: Unknown: 32040C121860 IE: IEEE 802.11i/WPA2 Version 1 Group Cipher : CCMP Pairwise Ciphers (1) : CCMP Authentication Suites (1) : PSK IE: Unknown: 0B0507005C0000 IE: Unknown: 2D1AEE191BFFFF000000000000000000000000000000000000000000 IE: Unknown: 3D1605081500000000000000000000000000000000000000 IE: Unknown: 4A0E14000A002C01C800140005001900 IE: Unknown: 7F080500080000000040 IE: Unknown: DD0F00E0FC400000000000FD0480000000 IE: Unknown: DD350050F204104A000110104400010210470010D96C7EFC2F8938F1EFBD6E5148BFA812103C0001031049000A00372A00012005020780 IE: Unknown: DD090010180207008C0000 IE: Unknown: DD180050F2020101840003A4000027A4000042435E0062322F00 Cell 02 - Address: 20:B0:01:9C:02:F9 Channel:2 Frequency:2.417 GHz (Channel 2) Quality=56/70 Signal level=-54 dBm Encryption key:on ESSID:"HOME2" Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 18 Mb/s 24 Mb/s; 36 Mb/s; 54 Mb/s Bit Rates:6 Mb/s; 9 Mb/s; 12 Mb/s; 48 Mb/s Mode:Master Extra:tsf=0000000000000000 Extra: Last beacon: 80ms ago IE: Unknown: 0005484F4D4532 IE: Unknown: 010882848B962430486C IE: Unknown: 030102 IE: Unknown: 050400010000 IE: Unknown: 2A0104 IE: Unknown: 32040C121860 IE: IEEE 802.11i/WPA2 Version 1 Group Cipher : CCMP Pairwise Ciphers (1) : CCMP Authentication Suites (1) : PSK IE: Unknown: 0B050100330000 IE: Unknown: 46053000000000 IE: Unknown: 2D1A2D0017FFFFFF0000000000000000000000000000000000000000 IE: Unknown: 3D1602080400000000000000000000000000000000000000 IE: Unknown: 4A0E14000A002C01C800140005001900 IE: Unknown: 7F080500080000400040 IE: Unknown: DD1D0050F204104A0001101044000102103C0001031049000600372A000120 IE: Unknown: DD1E00904C0400BF0C1258820FEAFF0000EAFF0000C0050002000000C3020002 IE: Unknown: DD090010180201101C0000 IE: Unknown: DD180050F2020101000003A4000027A4000042435E0062322F00 Cell 03 - Address: 1C:BF:CE:8A:B4:41 Channel:7 Frequency:2.442 GHz (Channel 7) Quality=70/70 Signal level=-10 dBm Encryption key:on ESSID:"rpi" Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 6 Mb/s 9 Mb/s; 12 Mb/s; 18 Mb/s Bit Rates:24 Mb/s; 36 Mb/s; 48 Mb/s; 54 Mb/s Mode:Master Extra:tsf=0000000000000000 Extra: Last beacon: 80ms ago IE: Unknown: 0003727069 IE: Unknown: 010882848B960C121824 IE: Unknown: 030107 IE: Unknown: 050400010000 IE: Unknown: 2A0104 IE: Unknown: 32043048606C IE: IEEE 802.11i/WPA2 Version 1 Group Cipher : CCMP Pairwise Ciphers (1) : CCMP Authentication Suites (1) : PSK Cell 04 - Address: 96:37:F7:ED:E5:F9 Channel:5 Frequency:2.432 GHz (Channel 5) Quality=67/70 Signal level=-43 dBm Encryption key:on ESSID:"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00" Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 18 Mb/s 24 Mb/s; 36 Mb/s; 54 Mb/s Bit Rates:6 Mb/s; 9 Mb/s; 12 Mb/s; 48 Mb/s Mode:Master Extra:tsf=0000000000000000 Extra: Last beacon: 80ms ago IE: Unknown: 0018000000000000000000000000000000000000000000000000 IE: Unknown: 010882840B162430486C IE: Unknown: 030105 IE: Unknown: 050400010000 IE: Unknown: 2D1AEE191BFFFF000000000000000000000000000000000000000000 IE: Unknown: 3D1605081500000000000000000000000000000000000000 IE: Unknown: 4A0E14000A002C01C800140005001900 IE: Unknown: 7F080500080000000040 IE: Unknown: DD090010180200000C0000 IE: Unknown: DD180050F2020101840003A4000027A4000042435E0062322F00 """ expected_results = [ {'Connected': '', 'SSID': 'Home', 'Signal': '70/70', 'WPA': 'WPA2'}, {'Connected': '', 'SSID': 'HOME2', 'Signal': '56/70', 'WPA': 'WPA2'}, {'Connected': '', 'SSID': 'rpi', 'Signal': '70/70', 'WPA': 'WPA2'} ] results = parse_iwlist(iwlist_text, "") # We can't guarantee the order of the results, so we'll sort them by SSID results.sort(key=lambda x: x['SSID']) expected_results.sort(key=lambda x: x['SSID']) self.assertEqual(results, expected_results) class TestNetworkConnection(unittest.TestCase): @patch('app.network_utils.run_subprocess_interface') @patch('app.network_utils.run_subprocess') @patch('builtins.open', new_callable=mock_open) def test_connect_network_wpa2_success(self, mock_file, mock_run_subprocess, mock_run_subprocess_interface): mock_run_subprocess.return_value = "Success" mock_run_subprocess_interface.return_value = "Success" result = connect_network("TestSSID", "WPA2", "TestPassword") self.assertTrue(result) mock_file.assert_any_call('/etc/network/interfaces', 'r') mock_file.assert_any_call('/etc/network/interfaces', 'w') mock_file.assert_any_call('/etc/wpa_supplicant/wpa_supplicant.conf', 'wt') mock_run_subprocess_interface.assert_any_call(f'sudo /usr/sbin/ifdown {{}}') mock_run_subprocess.assert_any_call('sudo /usr/bin/systemctl stop wpa_supplicant') mock_run_subprocess.assert_any_call('sudo /usr/bin/systemctl start wpa_supplicant') mock_run_subprocess_interface.assert_any_call(f'sudo /usr/sbin/ifup {{}}') @patch('app.network_utils.run_subprocess') @patch('builtins.open', new_callable=mock_open) def test_connect_network_wpa2_failure(self, mock_file, mock_run_subprocess): mock_run_subprocess.return_value = None result = connect_network("TestSSID", "WPA2", "TestPassword") self.assertFalse(result) @patch('app.network_utils.run_subprocess_interface') @patch('app.network_utils.run_subprocess') @patch('builtins.open', new_callable=mock_open) def test_disconnect_network_success(self, mock_file, mock_run_subprocess, mock_run_subprocess_interface): mock_run_subprocess.return_value = "Success" mock_run_subprocess_interface.return_value = "Success" result = disconnect_network() self.assertTrue(result) mock_file.assert_any_call('/etc/wpa_supplicant/wpa_supplicant.conf', 'wt') mock_run_subprocess_interface.assert_any_call(f'sudo /usr/sbin/ifdown {{}}') mock_run_subprocess.assert_any_call('sudo /usr/bin/systemctl stop wpa_supplicant') mock_run_subprocess.assert_any_call('sudo /usr/bin/systemctl start wpa_supplicant') mock_run_subprocess_interface.assert_any_call(f'sudo /usr/sbin/ifup {{}}') @patch('app.network_utils.run_subprocess') @patch('builtins.open', new_callable=mock_open) def test_disconnect_network_failure(self, mock_file, mock_run_subprocess): mock_run_subprocess.return_value = None result = disconnect_network() self.assertFalse(result) @patch('app.network_utils.run_subprocess_interface') @patch('app.network_utils.run_subprocess') @patch('builtins.open', new_callable=mock_open) def test_cleanup_network_success(self, mock_file, mock_run_subprocess, mock_run_subprocess_interface): mock_run_subprocess.return_value = "Success" mock_run_subprocess_interface.return_value = "Success" result = cleanup_network() self.assertTrue(result) mock_file.assert_any_call('/etc/wpa_supplicant/wpa_supplicant.conf', 'wt') mock_run_subprocess_interface.assert_any_call(f'sudo /usr/sbin/ifdown {{}}') mock_run_subprocess.assert_any_call('sudo /usr/bin/systemctl stop wpa_supplicant') mock_run_subprocess.assert_any_call('sudo /usr/bin/systemctl start wpa_supplicant') mock_run_subprocess_interface.assert_any_call(f'sudo /usr/sbin/ifup {{}}') @patch('app.network_utils.run_subprocess') @patch('builtins.open', new_callable=mock_open) def test_cleanup_network_failure(self, mock_file, mock_run_subprocess): mock_run_subprocess.return_value = None result = cleanup_network() self.assertFalse(result) if __name__ == '__main__': unittest.main()