siso: consolidate collector kill tests for posix and windows.

Bug: b/459690822
Change-Id: If23c54307a76ecba19e856da145e66736a6a6964
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/7244731
Commit-Queue: Alex Ovsienko <ovsienko@google.com>
Reviewed-by: Philipp Wollermann <philwo@google.com>
Reviewed-by: Fumitoshi Ukai <ukai@google.com>
This commit is contained in:
Alex Ovsienko
2025-12-09 22:19:50 -08:00
committed by LUCI CQ
parent ff6558d2ee
commit a6671ce6c7

View File

@@ -87,6 +87,7 @@ ninja --failure_verbose=false -k=0
self.assertTrue(siso._is_subcommand_present('siso_path', 'ninja')) self.assertTrue(siso._is_subcommand_present('siso_path', 'ninja'))
self.assertFalse(siso._is_subcommand_present('siso_path', 'unknown')) self.assertFalse(siso._is_subcommand_present('siso_path', 'unknown'))
def test_apply_metrics_labels(self):
user_system = siso._SYSTEM_DICT.get(sys.platform, sys.platform) user_system = siso._SYSTEM_DICT.get(sys.platform, sys.platform)
test_cases = { test_cases = {
'no_labels': { 'no_labels': {
@@ -684,194 +685,173 @@ ninja --failure_verbose=false -k=0
@mock.patch('sys.platform', new='linux') @mock.patch('sys.platform', new='linux')
@mock.patch('siso.os.kill') @mock.patch('siso.os.kill')
@mock.patch('siso.subprocess.run') @mock.patch('siso.subprocess.run')
def test_kill_collector_process_found_and_killed_posix( def test_kill_collector_posix(self, mock_subprocess_run, mock_os_kill):
self, mock_subprocess_run, mock_os_kill): test_cases = {
mock_subprocess_run.return_value = mock.Mock(stdout=b'123\n', 'found_and_killed': {
stderr=b'', 'run_return': mock.Mock(stdout=b'123\n',
returncode=0)
self.assertTrue(siso._kill_collector())
mock_subprocess_run.assert_called_once_with(
['lsof', '-t', f'-i:{siso._OTLP_HEALTH_PORT}'], capture_output=True)
mock_os_kill.assert_called_once_with(123, siso.signal.SIGKILL)
@unittest.skipIf(sys.platform == 'win32', 'Not applicable on Windows')
@mock.patch('sys.platform', new='linux')
@mock.patch('siso.os.kill')
@mock.patch('siso.subprocess.run')
def test_kill_collector_process_not_found_posix(self, mock_subprocess_run,
mock_os_kill):
mock_subprocess_run.return_value = mock.Mock(
stdout=b'', stderr=b'lsof: no process found\n', returncode=1)
self.assertFalse(siso._kill_collector())
mock_subprocess_run.assert_called_once_with(
['lsof', '-t', f'-i:{siso._OTLP_HEALTH_PORT}'], capture_output=True)
mock_os_kill.assert_not_called()
@unittest.skipIf(sys.platform == 'win32', 'Not applicable on Windows')
@mock.patch('sys.platform', new='linux')
@mock.patch('siso.os.kill')
@mock.patch('siso.subprocess.run')
def test_kill_collector_kill_fails_posix(self, mock_subprocess_run,
mock_os_kill):
mock_subprocess_run.return_value = mock.Mock(stdout=b'123\n',
stderr=b'',
returncode=0)
mock_os_kill.side_effect = OSError("Operation not permitted")
self.assertFalse(siso._kill_collector())
mock_subprocess_run.assert_called_once_with(
['lsof', '-t', f'-i:{siso._OTLP_HEALTH_PORT}'], capture_output=True)
mock_os_kill.assert_called_once_with(123, siso.signal.SIGKILL)
@unittest.skipIf(sys.platform == 'win32', 'Not applicable on Windows')
@mock.patch('sys.platform', new='linux')
@mock.patch('siso.os.kill')
@mock.patch('siso.subprocess.run')
def test_kill_collector_no_pids_found_posix(self, mock_subprocess_run,
mock_os_kill):
# stdout is empty, so no PIDs.
mock_subprocess_run.return_value = mock.Mock(stdout=b'\n',
stderr=b'',
returncode=0)
self.assertFalse(siso._kill_collector())
mock_subprocess_run.assert_called_once_with(
['lsof', '-t', f'-i:{siso._OTLP_HEALTH_PORT}'], capture_output=True)
# os.kill should not be called.
mock_os_kill.assert_not_called()
@unittest.skipIf(sys.platform == 'win32', 'Not applicable on Windows')
@mock.patch('sys.platform', new='linux')
@mock.patch('siso.os.kill')
@mock.patch('siso.subprocess.run')
def test_kill_collector_multiple_pids_found_posix(self, mock_subprocess_run,
mock_os_kill):
# stdout has two PIDs.
mock_subprocess_run.return_value = mock.Mock(stdout=b'0\n123\n456\n',
stderr=b'',
returncode=0)
self.assertTrue(siso._kill_collector())
mock_subprocess_run.assert_called_once_with(
['lsof', '-t', f'-i:{siso._OTLP_HEALTH_PORT}'], capture_output=True)
# Only the first PID should be killed.
mock_os_kill.assert_called_once_with(123, siso.signal.SIGKILL)
@mock.patch('sys.platform', new='win32')
@mock.patch('siso.subprocess.run')
def test_kill_collector_process_found_and_killed_windows(
self, mock_subprocess_run):
netstat_output = (
f' TCP 127.0.0.1:{siso._OTLP_HEALTH_PORT} [::]:0 LISTENING 1234\r\n'
)
mock_subprocess_run.side_effect = [
mock.Mock(stdout=netstat_output.encode('utf-8'),
stderr=b'', stderr=b'',
returncode=0), returncode=0),
mock.Mock(stdout=b'', stderr=b'', returncode=0) 'kill_side_effect': None,
] 'expected_result': True,
'expected_kill_args': (123, siso.signal.SIGKILL),
self.assertTrue(siso._kill_collector()) },
'process_not_found': {
self.assertEqual(mock_subprocess_run.call_count, 2) 'run_return':
mock_subprocess_run.assert_has_calls([ mock.Mock(stdout=b'',
mock.call(['netstat', '-aon'], capture_output=True), stderr=b'lsof: no process found\n',
mock.call( returncode=1),
['taskkill', '/F', '/T', '/PID', '1234'], 'kill_side_effect':
capture_output=True, None,
) 'expected_result':
]) False,
'expected_kill_args':
@mock.patch('sys.platform', new='win32') None,
@mock.patch('siso.subprocess.run') },
def test_kill_collector_process_not_found_windows(self, 'kill_fails': {
mock_subprocess_run): 'run_return': mock.Mock(stdout=b'123\n',
netstat_output = (
b' TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 868\r\n'
)
mock_subprocess_run.return_value = mock.Mock(stdout=netstat_output,
stderr=b'', stderr=b'',
returncode=0) returncode=0),
'kill_side_effect': OSError("Operation not permitted"),
'expected_result': False,
'expected_kill_args': (123, siso.signal.SIGKILL),
},
'no_pids_found': {
'run_return': mock.Mock(stdout=b'\n', stderr=b'', returncode=0),
'kill_side_effect': None,
'expected_result': False,
'expected_kill_args': None,
},
'multiple_pids_found': {
'run_return':
mock.Mock(stdout=b'0\n123\n456\n', stderr=b'', returncode=0),
'kill_side_effect':
None,
'expected_result':
True,
'expected_kill_args': (123, siso.signal.SIGKILL),
},
}
self.assertFalse(siso._kill_collector()) for name, tc in test_cases.items():
with self.subTest(name):
mock_subprocess_run.reset_mock()
mock_os_kill.reset_mock()
mock_subprocess_run.assert_called_once_with(['netstat', '-aon'], mock_subprocess_run.return_value = tc['run_return']
mock_os_kill.side_effect = tc['kill_side_effect']
result = siso._kill_collector()
self.assertEqual(result, tc['expected_result'])
mock_subprocess_run.assert_called_once_with(
['lsof', '-t', f'-i:{siso._OTLP_HEALTH_PORT}'],
capture_output=True) capture_output=True)
self.assertEqual(mock_subprocess_run.call_count, 1) if tc['expected_kill_args']:
mock_os_kill.assert_called_once_with(
*tc['expected_kill_args'])
else:
mock_os_kill.assert_not_called()
@mock.patch('sys.platform', new='win32') @mock.patch('sys.platform', new='win32')
@mock.patch('siso.subprocess.run') @mock.patch('siso.subprocess.run')
def test_kill_collector_multiple_pids_found_windows(self, def test_kill_collector_windows(self, mock_subprocess_run):
mock_subprocess_run): netstat_output_found = (
netstat_output = ( f' TCP 127.0.0.1:{siso._OTLP_HEALTH_PORT} [::]:0 LISTENING 1234\r\n'
f' TCP 127.0.0.1:{siso._OTLP_HEALTH_PORT} [::]:0 LISTENING 0\r\n' )
netstat_output_multiple = (
f' TCP 127.0.0.1:{siso._OTLP_HEALTH_PORT} [::]:0 LISTENING 0\r\n' f' TCP 127.0.0.1:{siso._OTLP_HEALTH_PORT} [::]:0 LISTENING 0\r\n'
f' TCP 127.0.0.1:{siso._OTLP_HEALTH_PORT} [::]:0 LISTENING 1234\r\n' f' TCP 127.0.0.1:{siso._OTLP_HEALTH_PORT} [::]:0 LISTENING 1234\r\n'
f' TCP 127.0.0.1:{siso._OTLP_HEALTH_PORT} [::]:0 LISTENING 5678\r\n' f' TCP 127.0.0.1:{siso._OTLP_HEALTH_PORT} [::]:0 LISTENING 5678\r\n'
) )
mock_subprocess_run.side_effect = [ netstat_output_not_found = (
mock.Mock(stdout=netstat_output.encode('utf-8'), b' TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 868\r\n'
)
test_cases = {
'found_and_killed': {
'run_side_effect': [
mock.Mock(stdout=netstat_output_found.encode('utf-8'),
stderr=b'', stderr=b'',
returncode=0), returncode=0),
mock.Mock(stdout=b'', stderr=b'', returncode=0) mock.Mock(stdout=b'', stderr=b'', returncode=0),
] ],
'expected_result':
self.assertTrue(siso._kill_collector()) True,
'expected_calls': [
self.assertEqual(mock_subprocess_run.call_count, 2)
mock_subprocess_run.assert_has_calls([
mock.call(['netstat', '-aon'], capture_output=True), mock.call(['netstat', '-aon'], capture_output=True),
# Only the first PID should be killed. mock.call(['taskkill', '/F', '/T', '/PID', '1234'],
mock.call( capture_output=True),
['taskkill', '/F', '/T', '/PID', '1234'], ],
capture_output=True, },
) 'process_not_found': {
]) 'run_side_effect': [
mock.Mock(stdout=netstat_output_not_found,
@mock.patch('sys.platform', new='win32') stderr=b'',
@mock.patch('siso.subprocess.run') returncode=0),
def test_kill_collector_netstat_fails_windows(self, mock_subprocess_run): ],
mock_subprocess_run.return_value = mock.Mock(stdout=b'', 'expected_result':
False,
'expected_calls': [
mock.call(['netstat', '-aon'], capture_output=True),
],
},
'multiple_pids_found': {
'run_side_effect': [
mock.Mock(stdout=netstat_output_multiple.encode('utf-8'),
stderr=b'',
returncode=0),
mock.Mock(stdout=b'', stderr=b'', returncode=0),
],
'expected_result':
True,
'expected_calls': [
mock.call(['netstat', '-aon'], capture_output=True),
mock.call(['taskkill', '/F', '/T', '/PID', '1234'],
capture_output=True),
],
},
'netstat_fails': {
'run_side_effect': [
mock.Mock(stdout=b'',
stderr=b'netstat error\n', stderr=b'netstat error\n',
returncode=1) returncode=1),
],
self.assertFalse(siso._kill_collector()) 'expected_result':
False,
mock_subprocess_run.assert_called_once_with(['netstat', '-aon'], 'expected_calls': [
capture_output=True) mock.call(['netstat', '-aon'], capture_output=True),
],
@mock.patch('sys.platform', new='win32') },
@mock.patch('siso.subprocess.run') 'taskkill_fails': {
def test_kill_collector_taskkill_fails_windows(self, mock_subprocess_run): 'run_side_effect': [
netstat_output = ( mock.Mock(stdout=netstat_output_found.encode('utf-8'),
f' TCP 127.0.0.1:{siso._OTLP_HEALTH_PORT} [::]:0 LISTENING 1234\r\n'
)
mock_subprocess_run.side_effect = [
mock.Mock(stdout=netstat_output.encode('utf-8'),
stderr=b'', stderr=b'',
returncode=0), returncode=0),
mock.Mock(stdout=b'', mock.Mock(stdout=b'',
stderr=b'ERROR: Cannot terminate process.', stderr=b'ERROR: Cannot terminate process.',
returncode=1) returncode=1),
] ],
'expected_result':
self.assertFalse(siso._kill_collector()) False,
'expected_calls': [
self.assertEqual(mock_subprocess_run.call_count, 2)
mock_subprocess_run.assert_has_calls([
mock.call(['netstat', '-aon'], capture_output=True), mock.call(['netstat', '-aon'], capture_output=True),
mock.call( mock.call(['taskkill', '/F', '/T', '/PID', '1234'],
['taskkill', '/F', '/T', '/PID', '1234'], capture_output=True),
capture_output=True, ],
) },
]) }
for name, tc in test_cases.items():
with self.subTest(name):
mock_subprocess_run.reset_mock()
mock_subprocess_run.side_effect = tc['run_side_effect']
result = siso._kill_collector()
self.assertEqual(result, tc['expected_result'])
mock_subprocess_run.assert_has_calls(tc['expected_calls'])
self.assertEqual(mock_subprocess_run.call_count,
len(tc['expected_calls']))
def _start_collector_mocks(self): def _start_collector_mocks(self):
patchers = { patchers = {