| # Copyright 2015 The ChromiumOS Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """This module tests the cros debug command.""" |
| |
| from chromite.cli import command_unittest |
| from chromite.cli.cros import cros_debug |
| from chromite.lib import cros_build_lib |
| from chromite.lib import cros_test_lib |
| from chromite.lib import remote_access |
| |
| |
| pytestmark = cros_test_lib.pytestmark_inside_only |
| |
| |
| class MockDebugCommand(command_unittest.MockCommand): |
| """Mock out the debug command.""" |
| |
| TARGET = "chromite.cli.cros.cros_debug.DebugCommand" |
| TARGET_CLASS = cros_debug.DebugCommand |
| COMMAND = "debug" |
| ATTRS = ("_ListProcesses", "_DebugNewProcess", "_DebugRunningProcess") |
| |
| def _ListProcesses(self, _inst, *_args, **_kwargs) -> None: |
| """Mock out _ListProcesses.""" |
| |
| def _DebugNewProcess(self, _inst, *_args, **_kwargs) -> None: |
| """Mock out _DebugNewProcess.""" |
| |
| def _DebugRunningProcess(self, _inst, *_args, **_kwargs) -> None: |
| """Mock out _DebugRunningProcess.""" |
| |
| |
| class DebugRunThroughTest(cros_test_lib.MockTempDirTestCase): |
| """Test the flow of DebugCommand.run with the debug methods mocked out.""" |
| |
| DEVICE = remote_access.TEST_IP |
| EXE = "/path/to/exe" |
| PID = "1" |
| |
| def SetupCommandMock(self, cmd_args) -> None: |
| """Set up command mock.""" |
| self.cmd_mock = MockDebugCommand( |
| cmd_args, base_args=["--cache-dir", str(self.tempdir)] |
| ) |
| self.StartPatcher(self.cmd_mock) |
| |
| def setUp(self) -> None: |
| """Patches objects.""" |
| self.cmd_mock = None |
| self.device_mock = self.PatchObject( |
| remote_access, "ChromiumOSDevice" |
| ).return_value |
| |
| def testMissingExeAndPid(self) -> None: |
| """Test that command fails when --exe and --pid are not provided.""" |
| self.SetupCommandMock([self.DEVICE]) |
| self.assertRaises( |
| SystemExit, |
| self.cmd_mock.inst.ProcessOptions, |
| self.cmd_mock.parser, |
| self.cmd_mock.inst.options, |
| ) |
| |
| def testListDisallowedWithPid(self) -> None: |
| """Test that --list is disallowed when --pid is used.""" |
| self.SetupCommandMock([self.DEVICE, "--list", "--pid", self.PID]) |
| self.assertRaises( |
| SystemExit, |
| self.cmd_mock.inst.ProcessOptions, |
| self.cmd_mock.parser, |
| self.cmd_mock.inst.options, |
| ) |
| |
| def testExeDisallowedWithPid(self) -> None: |
| """Test that --exe is disallowed when --pid is used.""" |
| self.SetupCommandMock( |
| [self.DEVICE, "--exe", self.EXE, "--pid", self.PID] |
| ) |
| self.assertRaises( |
| SystemExit, |
| self.cmd_mock.inst.ProcessOptions, |
| self.cmd_mock.parser, |
| self.cmd_mock.inst.options, |
| ) |
| |
| def testExeMustBeFullPath(self) -> None: |
| """Test that --exe only takes full path as a valid argument.""" |
| self.SetupCommandMock([self.DEVICE, "--exe", "bash"]) |
| self.assertRaises( |
| SystemExit, |
| self.cmd_mock.inst.ProcessOptions, |
| self.cmd_mock.parser, |
| self.cmd_mock.inst.options, |
| ) |
| |
| def testDebugProcessWithPid(self) -> None: |
| """Test that methods are called correctly when pid is provided.""" |
| self.SetupCommandMock([self.DEVICE, "--pid", self.PID]) |
| self.cmd_mock.inst.Run() |
| self.assertFalse(self.cmd_mock.patched["_ListProcesses"].called) |
| self.assertFalse(self.cmd_mock.patched["_DebugNewProcess"].called) |
| self.assertTrue(self.cmd_mock.patched["_DebugRunningProcess"].called) |
| |
| def testListProcesses(self) -> None: |
| """Test that methods are called correctly for listing processes.""" |
| self.SetupCommandMock([self.DEVICE, "--exe", self.EXE, "--list"]) |
| self.cmd_mock.inst.Run() |
| self.assertTrue(self.cmd_mock.patched["_ListProcesses"].called) |
| self.assertFalse(self.cmd_mock.patched["_DebugNewProcess"].called) |
| self.assertFalse(self.cmd_mock.patched["_DebugRunningProcess"].called) |
| |
| def testNoRunningProcess(self) -> None: |
| """Test command starts a new process to debug if no process running.""" |
| self.SetupCommandMock([self.DEVICE, "--exe", self.EXE]) |
| self.PatchObject(self.device_mock, "GetRunningPids", return_value=[]) |
| self.cmd_mock.inst.Run() |
| self.assertTrue(self.cmd_mock.patched["_ListProcesses"].called) |
| self.assertTrue(self.cmd_mock.patched["_DebugNewProcess"].called) |
| self.assertFalse(self.cmd_mock.patched["_DebugRunningProcess"].called) |
| |
| def testDebugNewProcess(self) -> None: |
| """Test that user can select zero to start a new process to debug.""" |
| self.SetupCommandMock([self.DEVICE, "--exe", self.EXE]) |
| self.PatchObject(self.device_mock, "GetRunningPids", return_value=["1"]) |
| mock_prompt = self.PatchObject( |
| cros_build_lib, "GetChoice", return_value=0 |
| ) |
| self.cmd_mock.inst.Run() |
| self.assertTrue(mock_prompt.called) |
| self.assertTrue(self.cmd_mock.patched["_ListProcesses"].called) |
| self.assertTrue(self.cmd_mock.patched["_DebugNewProcess"].called) |
| self.assertFalse(self.cmd_mock.patched["_DebugRunningProcess"].called) |
| |
| def testDebugRunningProcess(self) -> None: |
| """Test that user can select none-zero to debug a running process.""" |
| self.SetupCommandMock([self.DEVICE, "--exe", self.EXE]) |
| self.PatchObject(self.device_mock, "GetRunningPids", return_value=["1"]) |
| mock_prompt = self.PatchObject( |
| cros_build_lib, "GetChoice", return_value=1 |
| ) |
| self.cmd_mock.inst.Run() |
| self.assertTrue(mock_prompt.called) |
| self.assertTrue(self.cmd_mock.patched["_ListProcesses"].called) |
| self.assertFalse(self.cmd_mock.patched["_DebugNewProcess"].called) |
| self.assertTrue(self.cmd_mock.patched["_DebugRunningProcess"].called) |