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