Skip to content

Commit aa50766

Browse files
sroetByron
authored andcommitted
Add a way to force status codes inside AutoInterrupt._terminate, and let tests use it
1 parent 893ddab commit aa50766

File tree

2 files changed

+22
-11
lines changed

2 files changed

+22
-11
lines changed

Diff for: git/cmd.py

+12-7
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,10 @@ class AutoInterrupt(object):
409409

410410
__slots__ = ("proc", "args", "status")
411411

412+
# If this is non-zero it will override any status code during
413+
# _terminate, used to prevent race conditions in testing
414+
_status_code_if_terminate: int = 0
415+
412416
def __init__(self, proc: Union[None, subprocess.Popen], args: Any) -> None:
413417
self.proc = proc
414418
self.args = args
@@ -427,11 +431,10 @@ def _terminate(self) -> None:
427431
proc.stdout.close()
428432
if proc.stderr:
429433
proc.stderr.close()
430-
431434
# did the process finish already so we have a return code ?
432435
try:
433436
if proc.poll() is not None:
434-
self.status = proc.poll()
437+
self.status = self._status_code_if_terminate or proc.poll()
435438
return None
436439
except OSError as ex:
437440
log.info("Ignored error after process had died: %r", ex)
@@ -443,7 +446,9 @@ def _terminate(self) -> None:
443446
# try to kill it
444447
try:
445448
proc.terminate()
446-
self.status = proc.wait() # ensure process goes away
449+
status = proc.wait() # ensure process goes away
450+
451+
self.status = self._status_code_if_terminate or status
447452
except OSError as ex:
448453
log.info("Ignored error after process had died: %r", ex)
449454
except AttributeError:
@@ -849,7 +854,7 @@ def execute(self,
849854

850855
if is_win:
851856
cmd_not_found_exception = OSError
852-
if kill_after_timeout:
857+
if kill_after_timeout is not None:
853858
raise GitCommandError(redacted_command, '"kill_after_timeout" feature is not supported on Windows.')
854859
else:
855860
cmd_not_found_exception = FileNotFoundError # NOQA # exists, flake8 unknown @UndefinedVariable
@@ -916,7 +921,7 @@ def _kill_process(pid: int) -> None:
916921
return
917922
# end
918923

919-
if kill_after_timeout:
924+
if kill_after_timeout is not None:
920925
kill_check = threading.Event()
921926
watchdog = threading.Timer(kill_after_timeout, _kill_process, args=(proc.pid,))
922927

@@ -927,10 +932,10 @@ def _kill_process(pid: int) -> None:
927932
newline = "\n" if universal_newlines else b"\n"
928933
try:
929934
if output_stream is None:
930-
if kill_after_timeout:
935+
if kill_after_timeout is not None:
931936
watchdog.start()
932937
stdout_value, stderr_value = proc.communicate()
933-
if kill_after_timeout:
938+
if kill_after_timeout is not None:
934939
watchdog.cancel()
935940
if kill_check.is_set():
936941
stderr_value = ('Timeout: the command "%s" did not complete in %d '

Diff for: test/test_remote.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -658,10 +658,16 @@ def test_push_error(self, repo):
658658
class TestTimeouts(TestBase):
659659
@with_rw_repo('HEAD', bare=False)
660660
def test_timeout_funcs(self, repo):
661-
for function in ["pull"]: # can't get fetch and push to reliably timeout
661+
# Force error code to prevent a race condition if the python thread is
662+
# slow
663+
default = Git.AutoInterrupt._status_code_if_terminate
664+
Git.AutoInterrupt._status_code_if_terminate = -15
665+
for function in ["pull", "fetch"]: # can't get push to timeout
662666
f = getattr(repo.remotes.origin, function)
663667
assert f is not None # Make sure these functions exist
664-
_ = f() # Make sure the function runs
668+
_ = f() # Make sure the function runs
665669
with pytest.raises(GitCommandError,
666-
match="kill_after_timeout=0.001 s"):
667-
f(kill_after_timeout=0.001)
670+
match="kill_after_timeout=0 s"):
671+
f(kill_after_timeout=0)
672+
673+
Git.AutoInterrupt._status_code_if_terminate = default

0 commit comments

Comments
 (0)