S00-014: Make successful runner process-tree cleanup idempotent
Changes: Record completed termination on the Popen instance after all cleanup steps succeed; avoid repeated signals to the reaped group. Add deterministic repeated-EPERM and failed-descendant-kill retry regressions without suppressing permission errors. Validation: Four focused cleanup tests passed; make check passed 72 tests and plan/snapshot validation. git diff --check passed. Natural prior EPERM did not recur; injected EPERM reproduced the pre-fix failure. No application or parent-task acceptance is claimed. Task: S00-014 Agent: auto-ci-cd-14343249da62 Role: ci-cd Action: claim Status: review Task title: Fix repeated runner cleanup after a submitted parent is reaped
This commit is contained in:
1 parent
49c054aaf9
commit
7a737eeb49
9 files changed
+106
-9
No files matched your search
@@ -6,7 +6,7 @@ import subprocess
|
||||
import sys
|
||||
import unittest
|
||||
import uuid
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from test_tasks import WorkflowTests, ROOT, MODULE
|
||||
|
||||
@@ -319,6 +319,31 @@ else:
|
||||
def test_submit_transition_stops_source_writing_descendant(self):
|
||||
self._check_descendant_cleanup(transition=True)
|
||||
|
||||
@unittest.skipUnless(sys.platform != 'win32', 'POSIX process-group cleanup')
|
||||
def test_completed_cleanup_does_not_signal_reaped_group_again(self):
|
||||
process = Mock(pid=12345, returncode=-15)
|
||||
process.poll.return_value = -15
|
||||
with patch.object(RUN_MODULE.os, 'killpg') as killpg:
|
||||
RUN_MODULE.stop_process_tree(process)
|
||||
self.assertEqual(killpg.call_args_list,
|
||||
[unittest.mock.call(12345, RUN_MODULE.signal.SIGTERM),
|
||||
unittest.mock.call(12345, RUN_MODULE.signal.SIGKILL)])
|
||||
killpg.side_effect = PermissionError('Reaped process group inaccessible')
|
||||
RUN_MODULE.stop_process_tree(process)
|
||||
self.assertEqual(killpg.call_count, 2)
|
||||
|
||||
@unittest.skipUnless(sys.platform != 'win32', 'POSIX process-group cleanup')
|
||||
def test_failed_descendant_kill_is_not_marked_complete(self):
|
||||
process = Mock(pid=12345, returncode=-15)
|
||||
process.poll.return_value = -15
|
||||
with patch.object(RUN_MODULE.os, 'killpg',
|
||||
side_effect=[None, PermissionError('Live descendant inaccessible')]) as killpg:
|
||||
with self.assertRaises(PermissionError):
|
||||
RUN_MODULE.stop_process_tree(process)
|
||||
killpg.side_effect = None
|
||||
RUN_MODULE.stop_process_tree(process)
|
||||
self.assertEqual(killpg.call_count, 4)
|
||||
|
||||
def test_scope_matcher_checks_modified_created_deleted_files(self):
|
||||
self.assertEqual(RUN_MODULE.scope_violations({'a': 'old', 'gone': 'old'}, {'a': 'new', 'created': 'new'}, ['a']), ['created', 'gone'])
|
||||
|
||||
|
||||
Reference in new issue
Block a user