Re-factor _stop_dhcp and add tests
[wifi-radar.git] / test / unit / connections.py
blobebdcb2e39f17b041c52b8bb9dc50c685f8609c49
1 # test.connections - tests for connection manager
3 # Part of WiFi Radar: A utility for managing WiFi profiles on GNU/Linux.
5 # Copyright (C) 2014 Sean Robinson <seankrobinson@gmail.com>
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; version 2 of the License.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License in LICENSE.GPL for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 from signal import SIGTERM
23 from subprocess import CalledProcessError
24 import unittest
26 import mock
28 import wifiradar.connections
29 from wifiradar.config import ConfigManager
30 from wifiradar.misc import DeviceError
33 class TestConnectionManager(unittest.TestCase):
34 def setUp(self):
35 self.conn_manager = wifiradar.connections.ConnectionManager(mock.Mock())
36 self.mock_config = mock.Mock()
37 self.conn_manager.config = self.mock_config
39 def test_set_config(self):
40 """ Test set_config method. """
41 self.assertRaises(TypeError, self.conn_manager.set_config, None)
42 self.assertEqual(None, self.conn_manager.set_config(ConfigManager({})))
44 @mock.patch('wifiradar.misc.shellcmd')
45 def test__run_script(self, mock_shellcmd):
46 """ Test _run_script method. """
47 script_name = 'con_script'
48 device = 'wlan0'
49 ip = '192.168.1.1'
50 essid = 'WinterPalace'
51 bssid = '01:02:03:04:05:06'
52 profile = {
53 'con_script': 'mysterious_bash_command',
54 'essid': essid,
55 'bssid': bssid,
56 'use_wpa': False,
57 'key': '',
58 'security': ''}
59 self.conn_manager.get_current_ip = mock.Mock(return_value=ip)
60 self.conn_manager.get_current_essid = mock.Mock(return_value=essid)
61 self.conn_manager.get_current_bssid = mock.Mock(return_value=bssid)
63 self.assertEqual(None,
64 self.conn_manager._run_script(script_name, profile, device))
66 custom_env = {
67 "WIFIRADAR_IP": ip,
68 "WIFIRADAR_ESSID": essid,
69 "WIFIRADAR_BSSID": bssid,
70 "WIFIRADAR_PROFILE": '{}:{}'.format(essid, bssid),
71 "WIFIRADAR_ENCMODE": 'none',
72 "WIFIRADAR_SECMODE": '',
73 "WIFIRADAR_IF": device}
74 mock_shellcmd.assert_called_with(['mysterious_bash_command'],
75 custom_env)
77 @mock.patch('wifiradar.misc.shellcmd')
78 def test__prepare_nic(self, mock_shellcmd):
79 """ Test _prepare_nic method. """
80 self.mock_config.get_opt.return_value = 'mock_iwconfig'
81 self.mock_config.get_opt_as_bool.return_value = True
82 essid = 'WinterPalace'
83 bssid = '01:02:03:04:05:06'
84 profile = {
85 'essid': essid,
86 'bssid': bssid,
87 'key': '',
88 'mode': 'managed',
89 'channel': 11}
90 device = 'wlan0'
91 self.assertEqual(None,
92 self.conn_manager._prepare_nic(profile, device))
93 mock_shellcmd.assert_called_with(['mock_iwconfig', device,
94 'essid', "'{}'".format(essid), 'key', 'off',
95 'mode', 'managed', 'channel', 11, 'ap', bssid, 'commit'])
97 # Test failure.
98 self.mock_config.get_opt.return_value = 'mock_iwconfig'
99 self.mock_config.get_opt_as_bool.return_value = True
100 mock_shellcmd.side_effect = CalledProcessError(250, 'mock_iwconfig')
101 self.assertRaises(DeviceError,
102 self.conn_manager._prepare_nic, profile, device)
104 @mock.patch('__builtin__.open', )
105 @mock.patch('os.kill')
106 @mock.patch('os.access')
107 @mock.patch('wifiradar.misc.shellcmd')
108 def test__stop_dhcp(self, mock_shellcmd, mock_access, mock_kill, mock_open):
109 """ Test _stop_dhcp method. """
110 dhcp_cmd = 'dhcpcd'
111 kill_args = '-k -d'
112 kill_args_list = ['-k', '-d']
113 self.mock_config.get_opt.side_effect = ['mock_pidfile', kill_args,
114 dhcp_cmd, kill_args]
115 mock_access.return_value = True
116 device = 'wlan0'
118 self.assertEqual(None, self.conn_manager._stop_dhcp(device))
119 call_list = [dhcp_cmd]
120 call_list.extend(kill_args_list)
121 call_list.append(device)
122 mock_shellcmd.assert_called_with(call_list)
124 self.mock_config.get_opt.side_effect = ['mock_pidfile', '',
125 dhcp_cmd, '', 'mock_pidfile']
126 PID = 42
127 mock_open.return_value.readline.return_value = PID
128 self.assertEqual(None, self.conn_manager._stop_dhcp(device))
129 mock_kill.assert_called_with(PID, SIGTERM)
131 @mock.patch('wifiradar.connections.Popen')
132 def test_if_change(self, mock_popen):
133 """ Test if_change method. """
134 self.mock_config.get_opt.return_value = 'mock_ifconfig'
135 self.mock_config.get_network_device.return_value = 'wlan0'
137 # Test normal operation.
138 self.assertEqual(None, self.conn_manager.if_change('up'))
139 self.assertEqual(None, self.conn_manager.if_change('down'))
140 self.assertEqual(None, self.conn_manager.if_change('UP'))
141 self.assertEqual(None, self.conn_manager.if_change('DOWN'))
143 # Test unknown state.
144 self.assertRaises(ValueError, self.conn_manager.if_change, 'sideways')
146 # Test failed state change with found ifconfig.
147 mock_popen_instance = mock.MagicMock()
148 mock_popen_instance.stdout.__iter__.return_value = [
149 'wlan0: ERROR while getting interface flags: No such device']
150 mock_popen.return_value = mock_popen_instance
151 self.assertRaises(DeviceError, self.conn_manager.if_change, 'up')
153 # Test OSError.
154 mock_popen.side_effect = OSError(2, 'No such file or directory')
155 self.assertRaises(OSError, self.conn_manager.if_change, 'up')
157 @mock.patch('wifiradar.connections.Popen')
158 def test_get_current_ip(self, mock_popen):
159 """ Test get_current_ip method. """
160 self.mock_config.get_opt.return_value = 'mock_ifconfig'
161 self.mock_config.get_network_device.return_value = 'wlan0'
163 # Test connected and with an IP address.
164 mock_popen_instance = mock.Mock()
165 mock_popen_instance.stdout.read.return_value = \
166 'wlan0: flags=4098<BROADCAST,MULTICAST> mtu 1500\n' + \
167 'inet addr:192.168.1.1 netmask 255.255.255.0 broadcast 192.168.1.255\n' + \
168 'ether 00:00:00:00:00:00 txqueuelen 1000 (Ethernet)\n' + \
169 'RX packets 246 bytes 259631 (253.5 KiB)\n' + \
170 'RX errors 0 dropped 1 overruns 0 frame 0\n' + \
171 'TX packets 123 bytes 140216 (136.9 KiB)\n' + \
172 'TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0\n'
173 mock_popen.return_value = mock_popen_instance
174 self.assertEqual('192.168.1.1', self.conn_manager.get_current_ip())
176 # Test not connected and without an IP address.
177 mock_popen_instance.stdout.read.return_value = \
178 'wlan0: flags=4098<BROADCAST,MULTICAST> mtu 1500\n' + \
179 'ether 00:00:00:00:00:00 txqueuelen 1000 (Ethernet)\n' + \
180 'RX packets 246 bytes 259631 (253.5 KiB)\n' + \
181 'RX errors 0 dropped 1 overruns 0 frame 0\n' + \
182 'TX packets 123 bytes 140216 (136.9 KiB)\n' + \
183 'TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0\n'
184 mock_popen.return_value = mock_popen_instance
185 self.assertEqual(None, self.conn_manager.get_current_ip())
187 @mock.patch('wifiradar.connections.Popen')
188 def test_get_current_essid(self, mock_popen):
189 """ Test get_current_essid method. """
190 self.mock_config.get_opt.return_value = 'mock_iwconfig'
191 self.mock_config.get_network_device.return_value = 'wlan0'
193 # Test associated interface.
194 mock_popen_instance = mock.Mock()
195 mock_popen_instance.stdout.read.return_value = \
196 'wlan0 IEEE 802.11abgn ESSID:"WinterPalace"\n' + \
197 ' Mode:Managed Frequency:5.26 GHz Access Point: 00:00:00:00:00:00\n' + \
198 ' Tx-Power=15 dBm\n' + \
199 ' Retry long limit:7 RTS thr:off Fragment thr:off\n' + \
200 ' Power Management:off\n'
201 mock_popen.return_value = mock_popen_instance
202 self.assertEqual('WinterPalace', self.conn_manager.get_current_essid())
204 # Test not associated interface.
205 mock_popen_instance = mock.Mock()
206 mock_popen_instance.stdout.read.return_value = \
207 'wlan0 IEEE 802.11abgn ESSID:off/any\n' + \
208 ' Mode:Managed Frequency:5.26 GHz Access Point: Not-Associated\n' + \
209 ' Tx-Power=15 dBm\n' + \
210 ' Retry long limit:7 RTS thr:off Fragment thr:off\n' + \
211 ' Power Management:off\n'
212 mock_popen.return_value = mock_popen_instance
213 self.assertEqual(None, self.conn_manager.get_current_essid())
215 @mock.patch('wifiradar.connections.Popen')
216 def test_get_current_bssid(self, mock_popen):
217 """ Test get_current_bssid method. """
218 self.mock_config.get_opt.return_value = 'mock_iwconfig'
219 self.mock_config.get_network_device.return_value = 'wlan0'
221 # Test associated interface.
222 mock_popen_instance = mock.Mock()
223 mock_popen_instance.stdout.read.return_value = \
224 'wlan0 IEEE 802.11abgn ESSID:"WinterPalace"\n' + \
225 ' Mode:Managed Frequency:5.26 GHz Access Point: 00:00:00:00:00:00\n' + \
226 ' Tx-Power=15 dBm\n' + \
227 ' Retry long limit:7 RTS thr:off Fragment thr:off\n' + \
228 ' Power Management:off\n'
230 mock_popen.return_value = mock_popen_instance
231 self.assertEqual('00:00:00:00:00:00', self.conn_manager.get_current_bssid())
233 # Test not associated interface.
234 mock_popen_instance = mock.Mock()
235 mock_popen_instance.stdout.read.return_value = \
236 'wlan0 IEEE 802.11abgn ESSID:off/any\n' + \
237 ' Mode:Managed Frequency:5.26 GHz Access Point: Not-Associated\n' + \
238 ' Tx-Power=15 dBm\n' + \
239 ' Retry long limit:7 RTS thr:off Fragment thr:off\n' + \
240 ' Power Management:off\n'
241 mock_popen.return_value = mock_popen_instance
242 self.assertEqual(None, self.conn_manager.get_current_bssid())