Regression test for sequence editor causing hang

Add simple regression test to ensure that setting sequence.editor will
not cause a hang, and add a timeout to interactive mode tests to ensure
they are terminated with an error should they fail to complete
reasonably quickly (suggesting a hang).

Early release 0.9.0 had an issue where setting sequence.editor would
cause git-upstream to hang, due to git-rebase attempting to launch the
editor specified, while the console was being redirected by python's
subprocess.

At some point a behaviour change meant the config setting
sequence.editor was no longer used by the python subprocess calling
git-rebase. Instead the tool would launch the user specified editor
directly (checking the git config settings for sequence.editor, then
core.editor, and falling back to the environment variable EDITOR if
neither were set), and would instead ensure that when finally calling
git-rebase it would only use the special editor provided by
git-upstream.

However it's still important to check that setting sequence.editor
does not cause any future problems such the code be refactored again.

Change-Id: I303dced0d1a52791d18b39e8e6d342374e3d2eeb
Related-Bug: #1394553
This commit is contained in:
Darragh Bailey 2016-09-19 18:16:22 +01:00
parent d50f0a398a
commit dfa212ffd0
3 changed files with 91 additions and 7 deletions

View File

@ -0,0 +1,54 @@
#
# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P.
#
# 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.
#
---
- desc: |
Test that sequence editor is ignored for non-interactive use.
With a simple repository, test that git-upstream ignores sequence
editor by setting sequence editor to a command that will timeout
(and thereby cause a test failure).
Note in this case we need to use the interactive mode tests to
ensure we use a subprocess call with timeouts to confirm that
the process does not hang.
C---D local/master
/
A---B---E---F upstream/master
tree:
- [A, []]
- [B, [A]]
- [C, [B]]
- [D, [C]]
- [E, [B]]
- [F, [E]]
branches:
head: [master, D]
upstream: [upstream/master, F]
parser-args: [import, upstream/master]
pre-script: |
import os
from git.repo import Repo
repo = Repo(os.path.curdir)
repo.git.config("sequence.editor", "sleep 10; echo")

View File

@ -17,8 +17,10 @@
import os
import subprocess
import threading
import mock
import psutil
from testscenarios import TestWithScenarios
from testtools.content import text_content
from testtools.matchers import Contains
@ -31,7 +33,7 @@ from git_upstream.tests.base import BaseTestCase
from git_upstream.tests.base import get_scenarios
@mock.patch.dict('os.environ', {'GIT_SEQUENCE_EDITOR': 'cat'})
@mock.patch.dict('os.environ', {'GIT_EDITOR': 'cat'})
class TestImportInteractiveCommand(TestWithScenarios, BaseTestCase):
scenarios = get_scenarios(os.path.join(os.path.dirname(__file__),
@ -54,16 +56,43 @@ class TestImportInteractiveCommand(TestWithScenarios, BaseTestCase):
target_branch = self.branches['head'][0]
cmdline = self.parser.get_default('script_cmdline') + self.parser_args
try:
self.output = subprocess.check_output(cmdline,
stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as cpe:
# ensure interactive mode cannot hang tests
def kill(proc_pid):
process = psutil.Process(proc_pid)
for proc in process.children(recursive=True):
try:
proc.kill()
except OSError:
continue
try:
process.kill()
except OSError:
pass
def get_output(proc):
self.output = proc.communicate()[0]
proc = subprocess.Popen(cmdline,
stdin=open(os.devnull, "r"),
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, close_fds=True,
cwd=self.testrepo.path)
proc_thread = threading.Thread(target=get_output, args=[proc])
proc_thread.start()
proc_thread.join(getattr(self, 'timeout', 5))
if proc_thread.is_alive():
kill(proc.pid)
proc_thread.join()
self.addDetail('subprocess-output',
text_content(cpe.output.decode('utf-8')))
raise
text_content(self.output.decode('utf-8')))
raise Exception('Process #%d killed after timeout' % proc.pid)
self.addDetail('subprocess-output',
text_content(self.output.decode('utf-8')))
self.assertThat(proc.returncode, Equals(0))
expected = getattr(self, 'expect_rebased', [])
if expected:
changes = list(Commit.iter_items(

View File

@ -11,3 +11,4 @@ testscenarios>=0.4
testtools>=0.9.32
sphinxcontrib-programoutput
PyYAML>=3.1.0
psutil>=1.1.1,<2.0.0 # BSD