• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3#   Copyright 2019 - The Android Open Source Project
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16import logging
17import unittest
18
19import mock
20import os
21
22from acts.controllers import iperf_server
23from acts.controllers.iperf_server import IPerfServer
24from acts.controllers.iperf_server import IPerfServerOverAdb
25from acts.controllers.iperf_server import IPerfServerOverSsh
26
27# The position in the call tuple that represents the args array.
28ARGS = 0
29
30# The position in the call tuple that represents the kwargs dict.
31KWARGS = 1
32
33MOCK_LOGFILE_PATH = '/path/to/foo'
34
35
36class IPerfServerModuleTest(unittest.TestCase):
37    """Tests the acts.controllers.iperf_server module."""
38    def test_create_creates_local_iperf_server_with_int(self):
39        self.assertIsInstance(
40            iperf_server.create([12345])[0], IPerfServer,
41            'create() failed to create IPerfServer for integer input.')
42
43    def test_create_creates_local_iperf_server_with_str(self):
44        self.assertIsInstance(
45            iperf_server.create(['12345'])[0], IPerfServer,
46            'create() failed to create IPerfServer for integer input.')
47
48    def test_create_cannot_create_local_iperf_server_with_bad_str(self):
49        with self.assertRaises(ValueError):
50            iperf_server.create(['12345BAD_STRING'])
51
52    @mock.patch('acts.controllers.iperf_server.utils')
53    def test_create_creates_server_over_ssh_with_ssh_config_and_port(self, _):
54        self.assertIsInstance(
55            iperf_server.create([{
56                'ssh_config': {
57                    'user': '',
58                    'host': ''
59                },
60                'port': ''
61            }])[0], IPerfServerOverSsh,
62            'create() failed to create IPerfServerOverSsh for a valid config.')
63
64    def test_create_creates_server_over_adb_with_proper_config(self):
65        self.assertIsInstance(
66            iperf_server.create([{
67                'AndroidDevice': '53R147',
68                'port': 0
69            }])[0], IPerfServerOverAdb,
70            'create() failed to create IPerfServerOverAdb for a valid config.')
71
72    def test_create_raises_value_error_on_bad_config_dict(self):
73        with self.assertRaises(ValueError):
74            iperf_server.create([{
75                'AndroidDevice': '53R147',
76                'ssh_config': {}
77            }])
78
79    def test_get_port_from_ss_output_returns_correct_port_ipv4(self):
80        ss_output = ('tcp LISTEN  0 5 127.0.0.1:<PORT>  *:*'
81                     ' users:(("cmd",pid=<PID>,fd=3))')
82        self.assertEqual(
83            iperf_server._get_port_from_ss_output(ss_output, '<PID>'),
84            '<PORT>')
85
86    def test_get_port_from_ss_output_returns_correct_port_ipv6(self):
87        ss_output = ('tcp LISTEN  0 5 ff:ff:ff:ff:ff:ff:<PORT>  *:*'
88                     ' users:(("cmd",pid=<PID>,fd=3))')
89        self.assertEqual(
90            iperf_server._get_port_from_ss_output(ss_output, '<PID>'),
91            '<PORT>')
92
93
94class IPerfServerBaseTest(unittest.TestCase):
95    """Tests acts.controllers.iperf_server.IPerfServerBase."""
96    @mock.patch('os.makedirs')
97    def test_get_full_file_path_creates_parent_directory(self, mock_makedirs):
98        # Will never actually be created/used.
99        logging.log_path = '/tmp/unit_test_garbage'
100
101        server = IPerfServer('port')
102
103        full_file_path = server._get_full_file_path()
104
105        self.assertTrue(mock_makedirs.called,
106                        'Did not attempt to create a directory.')
107        self.assertEqual(
108            os.path.dirname(full_file_path), mock_makedirs.call_args[ARGS][0],
109            'The parent directory of the full file path was not created.')
110
111
112class IPerfServerTest(unittest.TestCase):
113    """Tests acts.controllers.iperf_server.IPerfServer."""
114
115    PID = 123456
116
117    def setUp(self):
118        iperf_server._get_port_from_ss_output = lambda *_: IPerfServerTest.PID
119
120    @mock.patch('builtins.open')
121    @mock.patch('acts.controllers.iperf_server.subprocess')
122    @mock.patch('acts.controllers.iperf_server.job')
123    def test_start_makes_started_true(self, mock_job, __, ___):
124        """Tests calling start() without calling stop() makes started True."""
125        server = IPerfServer('port')
126        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
127        server.start()
128
129        self.assertTrue(server.started)
130
131    @mock.patch('builtins.open')
132    @mock.patch('acts.controllers.iperf_server.subprocess')
133    @mock.patch('acts.controllers.iperf_server.job')
134    def test_start_stop_makes_started_false(self, _, __, ___):
135        """Tests calling start() without calling stop() makes started True."""
136        server = IPerfServer('port')
137        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
138
139        server.start()
140        server.stop()
141
142        self.assertFalse(server.started)
143
144    @mock.patch('builtins.open')
145    @mock.patch('acts.controllers.iperf_server.subprocess')
146    @mock.patch('acts.controllers.iperf_server.job')
147    def test_start_sets_current_log_file(self, _, __, ___):
148        server = IPerfServer('port')
149        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
150
151        server.start()
152
153        self.assertEqual(
154            server._current_log_file, MOCK_LOGFILE_PATH,
155            'The _current_log_file was not received from _get_full_file_path.')
156
157    @mock.patch('builtins.open')
158    @mock.patch('acts.controllers.iperf_server.subprocess')
159    def test_stop_returns_current_log_file(self, _, __):
160        server = IPerfServer('port')
161        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
162        server._current_log_file = MOCK_LOGFILE_PATH
163        server._iperf_process = mock.Mock()
164
165        log_file = server.stop()
166
167        self.assertEqual(log_file, MOCK_LOGFILE_PATH,
168                         'The _current_log_file was not returned by stop().')
169
170    @mock.patch('builtins.open')
171    @mock.patch('acts.controllers.iperf_server.subprocess')
172    @mock.patch('acts.controllers.iperf_server.job')
173    def test_start_does_not_run_two_concurrent_processes(
174            self, start_proc, _, __):
175        server = IPerfServer('port')
176        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
177        server._iperf_process = mock.Mock()
178
179        server.start()
180
181        self.assertFalse(
182            start_proc.called,
183            'start() should not begin a second process if another is running.')
184
185    @mock.patch('acts.utils.stop_standing_subprocess')
186    def test_stop_exits_early_if_no_process_has_started(self, stop_proc):
187        server = IPerfServer('port')
188        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
189        server._iperf_process = None
190
191        server.stop()
192
193        self.assertFalse(
194            stop_proc.called,
195            'stop() should not kill a process if no process is running.')
196
197
198class IPerfServerOverSshTest(unittest.TestCase):
199    """Tests acts.controllers.iperf_server.IPerfServerOverSsh."""
200
201    INIT_ARGS = [{'host': 'TEST_HOST', 'user': 'test'}, 'PORT']
202
203    @mock.patch('acts.controllers.iperf_server.connection')
204    def test_start_makes_started_true(self, _):
205        """Tests calling start() without calling stop() makes started True."""
206        server = IPerfServerOverSsh(*self.INIT_ARGS)
207        server._ssh_session = mock.Mock()
208        server._cleanup_iperf_port = mock.Mock()
209        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
210
211        server.start()
212
213        self.assertTrue(server.started)
214
215    @mock.patch('builtins.open')
216    @mock.patch('acts.controllers.iperf_server.connection')
217    def test_start_stop_makes_started_false(self, _, __):
218        """Tests calling start() without calling stop() makes started True."""
219        server = IPerfServerOverSsh(*self.INIT_ARGS)
220        server._ssh_session = mock.Mock()
221        server._cleanup_iperf_port = mock.Mock()
222        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
223
224        server.start()
225        server.stop()
226
227        self.assertFalse(server.started)
228
229    @mock.patch('builtins.open')
230    @mock.patch('acts.controllers.iperf_server.connection')
231    def test_stop_returns_expected_log_file(self, _, __):
232        server = IPerfServerOverSsh(*self.INIT_ARGS)
233        server._ssh_session = mock.Mock()
234        server._cleanup_iperf_port = mock.Mock()
235        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
236        server._iperf_pid = mock.Mock()
237
238        log_file = server.stop()
239
240        self.assertEqual(log_file, MOCK_LOGFILE_PATH,
241                         'The expected log file was not returned by stop().')
242
243    @mock.patch('acts.controllers.iperf_server.connection')
244    def test_start_does_not_run_two_concurrent_processes(self, _):
245        server = IPerfServerOverSsh(*self.INIT_ARGS)
246        server._ssh_session = mock.Mock()
247        server._cleanup_iperf_port = mock.Mock()
248        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
249        server._iperf_pid = mock.Mock()
250
251        server.start()
252
253        self.assertFalse(
254            server._ssh_session.run_async.called,
255            'start() should not begin a second process if another is running.')
256
257    @mock.patch('acts.utils.stop_standing_subprocess')
258    @mock.patch('acts.controllers.iperf_server.connection')
259    def test_stop_exits_early_if_no_process_has_started(self, _, __):
260        server = IPerfServerOverSsh(*self.INIT_ARGS)
261        server._ssh_session = mock.Mock()
262        server._cleanup_iperf_port = mock.Mock()
263        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
264        server._iperf_pid = None
265
266        server.stop()
267
268        self.assertFalse(
269            server._ssh_session.run_async.called,
270            'stop() should not kill a process if no process is running.')
271
272
273class IPerfServerOverAdbTest(unittest.TestCase):
274    """Tests acts.controllers.iperf_server.IPerfServerOverSsh."""
275
276    ANDROID_DEVICE_PROP = ('acts.controllers.iperf_server.'
277                           'IPerfServerOverAdb._android_device')
278
279    @mock.patch(ANDROID_DEVICE_PROP)
280    def test_start_makes_started_true(self, mock_ad):
281        """Tests calling start() without calling stop() makes started True."""
282        server = IPerfServerOverAdb('53R147', 'PORT')
283        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
284        mock_ad.adb.shell.return_value = '<PID>'
285
286        server.start()
287
288        self.assertTrue(server.started)
289
290    @mock.patch('acts.libs.proc.job.run')
291    @mock.patch('builtins.open')
292    @mock.patch(ANDROID_DEVICE_PROP)
293    def test_start_stop_makes_started_false(self, mock_ad, _, __):
294        """Tests calling start() without calling stop() makes started True."""
295        server = IPerfServerOverAdb('53R147', 'PORT')
296        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
297        mock_ad.adb.shell.side_effect = ['<PID>', '', '', '']
298
299        server.start()
300        server.stop()
301
302        self.assertFalse(server.started)
303
304    @mock.patch('acts.libs.proc.job.run')
305    @mock.patch('builtins.open')
306    @mock.patch(ANDROID_DEVICE_PROP)
307    def test_stop_returns_expected_log_file(self, mock_ad, _, __):
308        server = IPerfServerOverAdb('53R147', 'PORT')
309        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
310        server._iperf_process = mock.Mock()
311        server._iperf_process_adb_pid = '<PID>'
312        mock_ad.adb.shell.side_effect = ['', '', '']
313
314        log_file = server.stop()
315
316        self.assertEqual(log_file, MOCK_LOGFILE_PATH,
317                         'The expected log file was not returned by stop().')
318
319    @mock.patch(ANDROID_DEVICE_PROP)
320    def test_start_does_not_run_two_concurrent_processes(self, android_device):
321        server = IPerfServerOverAdb('53R147', 'PORT')
322        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
323        server._iperf_process = mock.Mock()
324
325        server.start()
326
327        self.assertFalse(
328            android_device.adb.shell_nb.called,
329            'start() should not begin a second process if another is running.')
330
331    @mock.patch('acts.libs.proc.job.run')
332    @mock.patch('builtins.open')
333    @mock.patch(ANDROID_DEVICE_PROP)
334    def test_stop_exits_early_if_no_process_has_started(
335            self, android_device, _, __):
336        server = IPerfServerOverAdb('53R147', 'PORT')
337        server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
338        server._iperf_pid = None
339
340        server.stop()
341
342        self.assertFalse(
343            android_device.adb.shell_nb.called,
344            'stop() should not kill a process if no process is running.')
345
346
347if __name__ == '__main__':
348    unittest.main()
349