blob: 75b8a5e37b89730127df3e9ce57f9195ef4af5c1 [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright 2022 The Fuchsia Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import os
import unittest
import mock
from antlion.controllers import iperf_server
from antlion.controllers.iperf_server import (
IPerfServer,
IPerfServerOverAdb,
IPerfServerOverSsh,
)
from antlion.controllers.utils_lib.ssh import settings
# The position in the call tuple that represents the args array.
ARGS = 0
# The position in the call tuple that represents the kwargs dict.
KWARGS = 1
MOCK_LOGFILE_PATH = "/path/to/foo"
class IPerfServerModuleTest(unittest.TestCase):
"""Tests the antlion.controllers.iperf_server module."""
def test_create_creates_local_iperf_server_with_int(self):
self.assertIsInstance(
iperf_server.create([12345])[0],
IPerfServer,
"create() failed to create IPerfServer for integer input.",
)
def test_create_creates_local_iperf_server_with_str(self):
self.assertIsInstance(
iperf_server.create(["12345"])[0],
IPerfServer,
"create() failed to create IPerfServer for integer input.",
)
def test_create_cannot_create_local_iperf_server_with_bad_str(self):
with self.assertRaises(ValueError):
iperf_server.create(["12345BAD_STRING"])
@mock.patch("antlion.controllers.iperf_server.utils")
def test_create_creates_server_over_ssh_with_ssh_config_and_port(self, _):
self.assertIsInstance(
iperf_server.create(
[
{
"ssh_config": {
"user": "",
"host": "",
"identity_file": "/dev/null",
},
"port": "",
}
]
)[0],
IPerfServerOverSsh,
"create() failed to create IPerfServerOverSsh for a valid config.",
)
def test_create_creates_server_over_adb_with_proper_config(self):
self.assertIsInstance(
iperf_server.create([{"AndroidDevice": "53R147", "port": 0}])[0],
IPerfServerOverAdb,
"create() failed to create IPerfServerOverAdb for a valid config.",
)
def test_create_raises_value_error_on_bad_config_dict(self):
with self.assertRaises(ValueError):
iperf_server.create([{"AndroidDevice": "53R147", "ssh_config": {}}])
def test_get_port_from_ss_output_returns_correct_port_ipv4(self):
ss_output = (
"tcp LISTEN 0 5 127.0.0.1:<PORT> *:*" ' users:(("cmd",pid=<PID>,fd=3))'
)
self.assertEqual(
iperf_server._get_port_from_ss_output(ss_output, "<PID>"), "<PORT>"
)
def test_get_port_from_ss_output_returns_correct_port_ipv6(self):
ss_output = (
"tcp LISTEN 0 5 ff:ff:ff:ff:ff:ff:<PORT> *:*"
' users:(("cmd",pid=<PID>,fd=3))'
)
self.assertEqual(
iperf_server._get_port_from_ss_output(ss_output, "<PID>"), "<PORT>"
)
class IPerfServerBaseTest(unittest.TestCase):
"""Tests antlion.controllers.iperf_server.IPerfServerBase."""
@mock.patch("os.makedirs")
def test_get_full_file_path_creates_parent_directory(self, mock_makedirs):
# Will never actually be created/used.
logging.log_path = "/tmp/unit_test_garbage"
server = IPerfServer("port")
full_file_path = server._get_full_file_path()
self.assertTrue(mock_makedirs.called, "Did not attempt to create a directory.")
self.assertEqual(
os.path.dirname(full_file_path),
mock_makedirs.call_args[ARGS][0],
"The parent directory of the full file path was not created.",
)
class IPerfServerTest(unittest.TestCase):
"""Tests antlion.controllers.iperf_server.IPerfServer."""
PID = 123456
def setUp(self):
iperf_server._get_port_from_ss_output = lambda *_: IPerfServerTest.PID
@mock.patch("builtins.open")
@mock.patch("antlion.controllers.iperf_server.subprocess")
@mock.patch("antlion.controllers.iperf_server.job")
def test_start_makes_started_true(self, mock_job, __, ___):
"""Tests calling start() without calling stop() makes started True."""
server = IPerfServer("port")
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server.start()
self.assertTrue(server.started)
@mock.patch("builtins.open")
@mock.patch("antlion.controllers.iperf_server.subprocess")
@mock.patch("antlion.controllers.iperf_server.job")
def test_start_stop_makes_started_false(self, _, __, ___):
"""Tests calling start() without calling stop() makes started True."""
server = IPerfServer("port")
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server.start()
server.stop()
self.assertFalse(server.started)
@mock.patch("builtins.open")
@mock.patch("antlion.controllers.iperf_server.subprocess")
@mock.patch("antlion.controllers.iperf_server.job")
def test_start_sets_current_log_file(self, _, __, ___):
server = IPerfServer("port")
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server.start()
self.assertEqual(
server._current_log_file,
MOCK_LOGFILE_PATH,
"The _current_log_file was not received from _get_full_file_path.",
)
@mock.patch("builtins.open")
@mock.patch("antlion.controllers.iperf_server.subprocess")
def test_stop_returns_current_log_file(self, _, __):
server = IPerfServer("port")
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._current_log_file = MOCK_LOGFILE_PATH
server._iperf_process = mock.Mock()
log_file = server.stop()
self.assertEqual(
log_file,
MOCK_LOGFILE_PATH,
"The _current_log_file was not returned by stop().",
)
@mock.patch("builtins.open")
@mock.patch("antlion.controllers.iperf_server.subprocess")
@mock.patch("antlion.controllers.iperf_server.job")
def test_start_does_not_run_two_concurrent_processes(self, start_proc, _, __):
server = IPerfServer("port")
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_process = mock.Mock()
server.start()
self.assertFalse(
start_proc.called,
"start() should not begin a second process if another is running.",
)
@mock.patch("antlion.utils.stop_standing_subprocess")
def test_stop_exits_early_if_no_process_has_started(self, stop_proc):
server = IPerfServer("port")
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_process = None
server.stop()
self.assertFalse(
stop_proc.called,
"stop() should not kill a process if no process is running.",
)
class IPerfServerOverSshTest(unittest.TestCase):
"""Tests antlion.controllers.iperf_server.IPerfServerOverSsh."""
INIT_ARGS = [
settings.from_config(
{"host": "TEST_HOST", "user": "test", "identity_file": "/dev/null"}
),
"PORT",
]
@mock.patch("antlion.controllers.iperf_server.connection")
def test_start_makes_started_true(self, _):
"""Tests calling start() without calling stop() makes started True."""
server = IPerfServerOverSsh(*self.INIT_ARGS)
server._ssh_session = mock.Mock()
server._cleanup_iperf_port = mock.Mock()
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server.start()
self.assertTrue(server.started)
@mock.patch("builtins.open")
@mock.patch("antlion.controllers.iperf_server.connection")
def test_start_stop_makes_started_false(self, _, __):
"""Tests calling start() without calling stop() makes started True."""
server = IPerfServerOverSsh(*self.INIT_ARGS)
server._ssh_session = mock.Mock()
server._cleanup_iperf_port = mock.Mock()
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server.start()
server.stop()
self.assertFalse(server.started)
@mock.patch("builtins.open")
@mock.patch("antlion.controllers.iperf_server.connection")
def test_stop_returns_expected_log_file(self, _, __):
server = IPerfServerOverSsh(*self.INIT_ARGS)
server._ssh_session = mock.Mock()
server._cleanup_iperf_port = mock.Mock()
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_pid = mock.Mock()
log_file = server.stop()
self.assertEqual(
log_file,
MOCK_LOGFILE_PATH,
"The expected log file was not returned by stop().",
)
@mock.patch("antlion.controllers.iperf_server.connection")
def test_start_does_not_run_two_concurrent_processes(self, _):
server = IPerfServerOverSsh(*self.INIT_ARGS)
server._ssh_session = mock.Mock()
server._cleanup_iperf_port = mock.Mock()
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_pid = mock.Mock()
server.start()
self.assertFalse(
server._ssh_session.run_async.called,
"start() should not begin a second process if another is running.",
)
@mock.patch("antlion.utils.stop_standing_subprocess")
@mock.patch("antlion.controllers.iperf_server.connection")
def test_stop_exits_early_if_no_process_has_started(self, _, __):
server = IPerfServerOverSsh(*self.INIT_ARGS)
server._ssh_session = mock.Mock()
server._cleanup_iperf_port = mock.Mock()
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_pid = None
server.stop()
self.assertFalse(
server._ssh_session.run_async.called,
"stop() should not kill a process if no process is running.",
)
class IPerfServerOverAdbTest(unittest.TestCase):
"""Tests antlion.controllers.iperf_server.IPerfServerOverSsh."""
ANDROID_DEVICE_PROP = (
"antlion.controllers.iperf_server." "IPerfServerOverAdb._android_device"
)
@mock.patch(ANDROID_DEVICE_PROP)
def test_start_makes_started_true(self, mock_ad):
"""Tests calling start() without calling stop() makes started True."""
server = IPerfServerOverAdb("53R147", "PORT")
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
mock_ad.adb.shell.return_value = "<PID>"
server.start()
self.assertTrue(server.started)
@mock.patch("antlion.libs.proc.job.run")
@mock.patch("builtins.open")
@mock.patch(ANDROID_DEVICE_PROP)
def test_start_stop_makes_started_false(self, mock_ad, _, __):
"""Tests calling start() without calling stop() makes started True."""
server = IPerfServerOverAdb("53R147", "PORT")
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
mock_ad.adb.shell.side_effect = ["<PID>", "", "", ""]
server.start()
server.stop()
self.assertFalse(server.started)
@mock.patch("antlion.libs.proc.job.run")
@mock.patch("builtins.open")
@mock.patch(ANDROID_DEVICE_PROP)
def test_stop_returns_expected_log_file(self, mock_ad, _, __):
server = IPerfServerOverAdb("53R147", "PORT")
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_process = mock.Mock()
server._iperf_process_adb_pid = "<PID>"
mock_ad.adb.shell.side_effect = ["", "", ""]
log_file = server.stop()
self.assertEqual(
log_file,
MOCK_LOGFILE_PATH,
"The expected log file was not returned by stop().",
)
@mock.patch(ANDROID_DEVICE_PROP)
def test_start_does_not_run_two_concurrent_processes(self, android_device):
server = IPerfServerOverAdb("53R147", "PORT")
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_process = mock.Mock()
server.start()
self.assertFalse(
android_device.adb.shell_nb.called,
"start() should not begin a second process if another is running.",
)
@mock.patch("antlion.libs.proc.job.run")
@mock.patch("builtins.open")
@mock.patch(ANDROID_DEVICE_PROP)
def test_stop_exits_early_if_no_process_has_started(self, android_device, _, __):
server = IPerfServerOverAdb("53R147", "PORT")
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_pid = None
server.stop()
self.assertFalse(
android_device.adb.shell_nb.called,
"stop() should not kill a process if no process is running.",
)
if __name__ == "__main__":
unittest.main()