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 39 def test_create_creates_local_iperf_server_with_int(self): 40 self.assertIsInstance( 41 iperf_server.create([12345])[0], 42 IPerfServer, 43 'create() failed to create IPerfServer for integer input.' 44 ) 45 46 def test_create_creates_local_iperf_server_with_str(self): 47 self.assertIsInstance( 48 iperf_server.create(['12345'])[0], 49 IPerfServer, 50 'create() failed to create IPerfServer for integer input.' 51 ) 52 53 def test_create_cannot_create_local_iperf_server_with_bad_str(self): 54 with self.assertRaises(ValueError): 55 iperf_server.create(['12345BAD_STRING']) 56 57 @mock.patch('acts.controllers.iperf_server.utils') 58 def test_create_creates_server_over_ssh_with_ssh_config_and_port(self, _): 59 self.assertIsInstance( 60 iperf_server.create([{'ssh_config': {'user': '', 'host': ''}, 61 'port': ''}])[0], 62 IPerfServerOverSsh, 63 'create() failed to create IPerfServerOverSsh for a valid config.' 64 ) 65 66 def test_create_creates_server_over_adb_with_proper_config(self): 67 self.assertIsInstance( 68 iperf_server.create([{'AndroidDevice': '53R147', 'port': 0}])[0], 69 IPerfServerOverAdb, 70 'create() failed to create IPerfServerOverAdb for a valid config.' 71 ) 72 73 def test_create_raises_value_error_on_bad_config_dict(self): 74 with self.assertRaises(ValueError): 75 iperf_server.create([{'AndroidDevice': '53R147', 'ssh_config': {}}]) 76 77 def test_get_port_from_ss_output_returns_correct_port_ipv4(self): 78 ss_output = ('tcp LISTEN 0 5 127.0.0.1:<PORT> *:*' 79 ' users:(("cmd",pid=<PID>,fd=3))') 80 self.assertEqual( 81 iperf_server._get_port_from_ss_output(ss_output, '<PID>'), '<PORT>') 82 83 def test_get_port_from_ss_output_returns_correct_port_ipv6(self): 84 ss_output = ('tcp LISTEN 0 5 ff:ff:ff:ff:ff:ff:<PORT> *:*' 85 ' users:(("cmd",pid=<PID>,fd=3))') 86 self.assertEqual( 87 iperf_server._get_port_from_ss_output(ss_output, '<PID>'), '<PORT>') 88 89 90class IPerfServerBaseTest(unittest.TestCase): 91 """Tests acts.controllers.iperf_server.IPerfServerBase.""" 92 93 @mock.patch('os.makedirs') 94 def test_get_full_file_path_creates_parent_directory(self, mock_makedirs): 95 # Will never actually be created/used. 96 logging.log_path = '/tmp/unit_test_garbage' 97 98 server = IPerfServer('port') 99 100 full_file_path = server._get_full_file_path() 101 102 self.assertTrue( 103 mock_makedirs.called, 104 'Did not attempt to create a directory.' 105 ) 106 self.assertEqual( 107 os.path.dirname(full_file_path), 108 mock_makedirs.call_args[ARGS][0], 109 'The parent directory of the full file path was not created.' 110 ) 111 112 113class IPerfServerTest(unittest.TestCase): 114 """Tests acts.controllers.iperf_server.IPerfServer.""" 115 116 PID = 123456 117 118 def setUp(self): 119 iperf_server._get_port_from_ss_output = lambda *_: IPerfServerTest.PID 120 121 @mock.patch('builtins.open') 122 @mock.patch('acts.controllers.iperf_server.subprocess') 123 @mock.patch('acts.controllers.iperf_server.job') 124 def test_start_makes_started_true(self, mock_job, __, ___): 125 """Tests calling start() without calling stop() makes started True.""" 126 server = IPerfServer('port') 127 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 128 server.start() 129 130 self.assertTrue(server.started) 131 132 @mock.patch('builtins.open') 133 @mock.patch('acts.controllers.iperf_server.subprocess') 134 @mock.patch('acts.controllers.iperf_server.job') 135 def test_start_stop_makes_started_false(self, _, __, ___): 136 """Tests calling start() without calling stop() makes started True.""" 137 server = IPerfServer('port') 138 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 139 140 server.start() 141 server.stop() 142 143 self.assertFalse(server.started) 144 145 @mock.patch('builtins.open') 146 @mock.patch('acts.controllers.iperf_server.subprocess') 147 @mock.patch('acts.controllers.iperf_server.job') 148 def test_start_sets_current_log_file(self, _, __, ___): 149 server = IPerfServer('port') 150 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 151 152 server.start() 153 154 self.assertEqual( 155 server._current_log_file, 156 MOCK_LOGFILE_PATH, 157 'The _current_log_file was not received from _get_full_file_path.' 158 ) 159 160 @mock.patch('builtins.open') 161 @mock.patch('acts.controllers.iperf_server.subprocess') 162 def test_stop_returns_current_log_file(self, _, __): 163 server = IPerfServer('port') 164 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 165 server._current_log_file = MOCK_LOGFILE_PATH 166 server._iperf_process = mock.Mock() 167 168 log_file = server.stop() 169 170 self.assertEqual( 171 log_file, 172 MOCK_LOGFILE_PATH, 173 'The _current_log_file was not returned by stop().' 174 ) 175 176 @mock.patch('builtins.open') 177 @mock.patch('acts.controllers.iperf_server.subprocess') 178 @mock.patch('acts.controllers.iperf_server.job') 179 def test_start_does_not_run_two_concurrent_processes(self, start_proc, _, __): 180 server = IPerfServer('port') 181 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 182 server._iperf_process = mock.Mock() 183 184 server.start() 185 186 self.assertFalse( 187 start_proc.called, 188 'start() should not begin a second process if another is running.' 189 ) 190 191 @mock.patch('acts.utils.stop_standing_subprocess') 192 def test_stop_exits_early_if_no_process_has_started(self, stop_proc): 193 server = IPerfServer('port') 194 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 195 server._iperf_process = None 196 197 server.stop() 198 199 self.assertFalse( 200 stop_proc.called, 201 'stop() should not kill a process if no process is running.' 202 ) 203 204 205class IPerfServerOverSshTest(unittest.TestCase): 206 """Tests acts.controllers.iperf_server.IPerfServerOverSsh.""" 207 208 INIT_ARGS = [{'host': 'TEST_HOST', 'user': 'test'}, 'PORT'] 209 210 @mock.patch('acts.controllers.iperf_server.connection') 211 def test_start_makes_started_true(self, _): 212 """Tests calling start() without calling stop() makes started True.""" 213 server = IPerfServerOverSsh(*self.INIT_ARGS) 214 server._ssh_session = mock.Mock() 215 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 216 217 server.start() 218 219 self.assertTrue(server.started) 220 221 @mock.patch('builtins.open') 222 @mock.patch('acts.controllers.iperf_server.connection') 223 def test_start_stop_makes_started_false(self, _, __): 224 """Tests calling start() without calling stop() makes started True.""" 225 server = IPerfServerOverSsh(*self.INIT_ARGS) 226 server._ssh_session = mock.Mock() 227 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 228 229 server.start() 230 server.stop() 231 232 self.assertFalse(server.started) 233 234 @mock.patch('builtins.open') 235 @mock.patch('acts.controllers.iperf_server.connection') 236 def test_stop_returns_expected_log_file(self, _, __): 237 server = IPerfServerOverSsh(*self.INIT_ARGS) 238 server._ssh_session = mock.Mock() 239 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 240 server._iperf_pid = mock.Mock() 241 242 log_file = server.stop() 243 244 self.assertEqual( 245 log_file, 246 MOCK_LOGFILE_PATH, 247 'The expected log file was not returned by stop().' 248 ) 249 250 @mock.patch('acts.controllers.iperf_server.connection') 251 def test_start_does_not_run_two_concurrent_processes(self, _): 252 server = IPerfServerOverSsh(*self.INIT_ARGS) 253 server._ssh_session = mock.Mock() 254 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 255 server._iperf_pid = mock.Mock() 256 257 server.start() 258 259 self.assertFalse( 260 server._ssh_session.run_async.called, 261 'start() should not begin a second process if another is running.' 262 ) 263 264 @mock.patch('acts.utils.stop_standing_subprocess') 265 @mock.patch('acts.controllers.iperf_server.connection') 266 def test_stop_exits_early_if_no_process_has_started(self, _, __): 267 server = IPerfServerOverSsh(*self.INIT_ARGS) 268 server._ssh_session = mock.Mock() 269 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 270 server._iperf_pid = None 271 272 server.stop() 273 274 self.assertFalse( 275 server._ssh_session.run_async.called, 276 'stop() should not kill a process if no process is running.' 277 ) 278 279 280class IPerfServerOverAdbTest(unittest.TestCase): 281 """Tests acts.controllers.iperf_server.IPerfServerOverSsh.""" 282 283 ANDROID_DEVICE_PROP = ('acts.controllers.iperf_server.' 284 'IPerfServerOverAdb._android_device') 285 286 @mock.patch(ANDROID_DEVICE_PROP) 287 def test_start_makes_started_true(self, mock_ad): 288 """Tests calling start() without calling stop() makes started True.""" 289 server = IPerfServerOverAdb('53R147', 'PORT') 290 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 291 mock_ad.adb.shell.return_value = '<PID>' 292 293 server.start() 294 295 self.assertTrue(server.started) 296 297 @mock.patch('acts.libs.proc.job.run') 298 @mock.patch('builtins.open') 299 @mock.patch(ANDROID_DEVICE_PROP) 300 def test_start_stop_makes_started_false(self, mock_ad, _, __): 301 """Tests calling start() without calling stop() makes started True.""" 302 server = IPerfServerOverAdb('53R147', 'PORT') 303 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 304 mock_ad.adb.shell.side_effect = ['<PID>', '', '', ''] 305 306 server.start() 307 server.stop() 308 309 self.assertFalse(server.started) 310 311 @mock.patch('acts.libs.proc.job.run') 312 @mock.patch('builtins.open') 313 @mock.patch(ANDROID_DEVICE_PROP) 314 def test_stop_returns_expected_log_file(self, mock_ad, _, __): 315 server = IPerfServerOverAdb('53R147', 'PORT') 316 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 317 server._iperf_process = mock.Mock() 318 server._iperf_process_adb_pid = '<PID>' 319 mock_ad.adb.shell.side_effect = ['', '', ''] 320 321 log_file = server.stop() 322 323 self.assertEqual( 324 log_file, 325 MOCK_LOGFILE_PATH, 326 'The expected log file was not returned by stop().' 327 ) 328 329 @mock.patch(ANDROID_DEVICE_PROP) 330 def test_start_does_not_run_two_concurrent_processes(self, android_device): 331 server = IPerfServerOverAdb('53R147', 'PORT') 332 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 333 server._iperf_process = mock.Mock() 334 335 server.start() 336 337 self.assertFalse( 338 android_device.adb.shell_nb.called, 339 'start() should not begin a second process if another is running.' 340 ) 341 342 @mock.patch('acts.libs.proc.job.run') 343 @mock.patch('builtins.open') 344 @mock.patch(ANDROID_DEVICE_PROP) 345 def test_stop_exits_early_if_no_process_has_started(self, android_device, _, 346 __): 347 server = IPerfServerOverAdb('53R147', 'PORT') 348 server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH 349 server._iperf_pid = None 350 351 server.stop() 352 353 self.assertFalse( 354 android_device.adb.shell_nb.called, 355 'stop() should not kill a process if no process is running.' 356 ) 357 358 359if __name__ == '__main__': 360 unittest.main() 361