iotests: connect stdin to /dev/null when running tests

Currently the tests have their stdin inherited from the test harness,
meaning they are connected to a TTY. The QEMU processes spawned by
certain tests, however, modify TTY settings and if the test exits
abnormally the settings might not be restored.

The python test harness thus has some logic which will capture the
initial TTY settings and restore them once all tests are finished.

This does not, however, take into account the possibility of many
copies of the 'check' program running in parallel. With parallel
execution, a later invokation may save the TTY state that QEMU has
already modified, and thus restore bad state leaving the TTY
non-functional.

None of the I/O tests shnould actually be interactive requiring
user input and so they should not require a TTY at all. To avoid
this while TTY save/restore complexity we can connect the test
stdin to /dev/null instead.

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Acked-by: Hanna Czenczek <hreitz@redhat.com>
Tested-by: Thomas Huth <thuth@redhat.com>
Message-Id: <20230303160727.3977246-6-berrange@redhat.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20230315174331.2959-23-alex.bennee@linaro.org>
This commit is contained in:
Daniel P. Berrangé 2023-03-15 17:43:21 +00:00 committed by Alex Bennée
parent 6e5792a1f6
commit cb845eaa88
1 changed files with 2 additions and 20 deletions

View File

@ -24,12 +24,10 @@ import difflib
import subprocess import subprocess
import contextlib import contextlib
import json import json
import termios
import shutil import shutil
import sys import sys
from multiprocessing import Pool from multiprocessing import Pool
from contextlib import contextmanager from typing import List, Optional, Any, Sequence, Dict, \
from typing import List, Optional, Iterator, Any, Sequence, Dict, \
ContextManager ContextManager
from testenv import TestEnv from testenv import TestEnv
@ -56,22 +54,6 @@ def file_diff(file1: str, file2: str) -> List[str]:
return res return res
# We want to save current tty settings during test run,
# since an aborting qemu call may leave things screwed up.
@contextmanager
def savetty() -> Iterator[None]:
isterm = sys.stdin.isatty()
if isterm:
fd = sys.stdin.fileno()
attr = termios.tcgetattr(fd)
try:
yield
finally:
if isterm:
termios.tcsetattr(fd, termios.TCSADRAIN, attr)
class LastElapsedTime(ContextManager['LastElapsedTime']): class LastElapsedTime(ContextManager['LastElapsedTime']):
""" Cache for elapsed time for tests, to show it during new test run """ Cache for elapsed time for tests, to show it during new test run
@ -169,7 +151,6 @@ class TestRunner(ContextManager['TestRunner']):
self._stack = contextlib.ExitStack() self._stack = contextlib.ExitStack()
self._stack.enter_context(self.env) self._stack.enter_context(self.env)
self._stack.enter_context(self.last_elapsed) self._stack.enter_context(self.last_elapsed)
self._stack.enter_context(savetty())
return self return self
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None: def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
@ -294,6 +275,7 @@ class TestRunner(ContextManager['TestRunner']):
t0 = time.time() t0 = time.time()
with f_bad.open('w', encoding="utf-8") as f: with f_bad.open('w', encoding="utf-8") as f:
with subprocess.Popen(args, cwd=str(f_test.parent), env=env, with subprocess.Popen(args, cwd=str(f_test.parent), env=env,
stdin=subprocess.DEVNULL,
stdout=f, stderr=subprocess.STDOUT) as proc: stdout=f, stderr=subprocess.STDOUT) as proc:
try: try:
proc.wait() proc.wait()