aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rwxr-xr-xtests/qemu-iotests/0407
-rwxr-xr-xtests/qemu-iotests/2182
-rwxr-xr-xtests/qemu-iotests/2552
-rwxr-xr-xtests/qemu-iotests/297109
-rwxr-xr-xtests/qemu-iotests/30013
-rw-r--r--tests/qemu-iotests/iotests.py20
-rw-r--r--tests/qemu-iotests/linters.py105
-rw-r--r--tests/qemu-iotests/mypy.ini12
-rw-r--r--tests/qemu-iotests/pylintrc16
-rwxr-xr-xtests/qemu-iotests/tests/mirror-top-perms17
10 files changed, 214 insertions, 89 deletions
diff --git a/tests/qemu-iotests/040 b/tests/qemu-iotests/040
index f3677de..6af5ab9 100755
--- a/tests/qemu-iotests/040
+++ b/tests/qemu-iotests/040
@@ -92,10 +92,9 @@ class TestSingleDrive(ImageCommitTestCase):
self.vm.add_device('virtio-scsi')
self.vm.add_device("scsi-hd,id=scsi0,drive=drive0")
self.vm.launch()
- self.has_quit = False
def tearDown(self):
- self.vm.shutdown(has_quit=self.has_quit)
+ self.vm.shutdown()
os.remove(test_img)
os.remove(mid_img)
os.remove(backing_img)
@@ -127,8 +126,6 @@ class TestSingleDrive(ImageCommitTestCase):
result = self.vm.qmp('quit')
self.assert_qmp(result, 'return', {})
- self.has_quit = True
-
# Same as above, but this time we add the filter after starting the job
@iotests.skip_if_unsupported(['throttle'])
def test_commit_plus_filter_and_quit(self):
@@ -147,8 +144,6 @@ class TestSingleDrive(ImageCommitTestCase):
result = self.vm.qmp('quit')
self.assert_qmp(result, 'return', {})
- self.has_quit = True
-
def test_device_not_found(self):
result = self.vm.qmp('block-commit', device='nonexistent', top='%s' % mid_img)
self.assert_qmp(result, 'error/class', 'DeviceNotFound')
diff --git a/tests/qemu-iotests/218 b/tests/qemu-iotests/218
index 325d824..4922b4d 100755
--- a/tests/qemu-iotests/218
+++ b/tests/qemu-iotests/218
@@ -187,4 +187,4 @@ with iotests.VM() as vm, \
log(vm.qmp('quit'))
with iotests.Timeout(5, 'Timeout waiting for VM to quit'):
- vm.shutdown(has_quit=True)
+ vm.shutdown()
diff --git a/tests/qemu-iotests/255 b/tests/qemu-iotests/255
index c43aa9c..3d6d0e8 100755
--- a/tests/qemu-iotests/255
+++ b/tests/qemu-iotests/255
@@ -123,4 +123,4 @@ with iotests.FilePath('src.qcow2') as src_path, \
vm.qmp_log('block-job-cancel', device='job0')
vm.qmp_log('quit')
- vm.shutdown(has_quit=True)
+ vm.shutdown()
diff --git a/tests/qemu-iotests/297 b/tests/qemu-iotests/297
index 91ec34d..ee78a62 100755
--- a/tests/qemu-iotests/297
+++ b/tests/qemu-iotests/297
@@ -17,89 +17,66 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
-import re
-import shutil
import subprocess
import sys
+from typing import List
import iotests
+import linters
-# TODO: Empty this list!
-SKIP_FILES = (
- '030', '040', '041', '044', '045', '055', '056', '057', '065', '093',
- '096', '118', '124', '132', '136', '139', '147', '148', '149',
- '151', '152', '155', '163', '165', '194', '196', '202',
- '203', '205', '206', '207', '208', '210', '211', '212', '213', '216',
- '218', '219', '224', '228', '234', '235', '236', '237', '238',
- '240', '242', '245', '246', '248', '255', '256', '257', '258', '260',
- '262', '264', '266', '274', '277', '280', '281', '295', '296', '298',
- '299', '302', '303', '304', '307',
- 'nbd-fault-injector.py', 'qcow2.py', 'qcow2_format.py', 'qed.py'
-)
+# Looking for something?
+#
+# List of files to exclude from linting: linters.py
+# mypy configuration: mypy.ini
+# pylint configuration: pylintrc
-def is_python_file(filename):
- if not os.path.isfile(filename):
+def check_linter(linter: str) -> bool:
+ try:
+ linters.run_linter(linter, ['--version'], suppress_output=True)
+ except subprocess.CalledProcessError:
+ iotests.case_notrun(f"'{linter}' not found")
return False
+ return True
- if filename.endswith('.py'):
- return True
- with open(filename, encoding='utf-8') as f:
- try:
- first_line = f.readline()
- return re.match('^#!.*python', first_line) is not None
- except UnicodeDecodeError: # Ignore binary files
- return False
+def test_pylint(files: List[str]) -> None:
+ print('=== pylint ===')
+ sys.stdout.flush()
+ if not check_linter('pylint'):
+ return
-def run_linters():
- named_tests = [f'tests/{entry}' for entry in os.listdir('tests')]
- check_tests = set(os.listdir('.') + named_tests) - set(SKIP_FILES)
- files = [filename for filename in check_tests if is_python_file(filename)]
+ linters.run_linter('pylint', files)
- iotests.logger.debug('Files to be checked:')
- iotests.logger.debug(', '.join(sorted(files)))
- print('=== pylint ===')
+def test_mypy(files: List[str]) -> None:
+ print('=== mypy ===')
sys.stdout.flush()
- # Todo notes are fine, but fixme's or xxx's should probably just be
- # fixed (in tests, at least)
+ if not check_linter('mypy'):
+ return
+
env = os.environ.copy()
- subprocess.run(('pylint-3', '--score=n', '--notes=FIXME,XXX', *files),
- env=env, check=False)
+ env['MYPYPATH'] = env['PYTHONPATH']
- print('=== mypy ===')
- sys.stdout.flush()
+ linters.run_linter('mypy', files, env=env, suppress_output=True)
- env['MYPYPATH'] = env['PYTHONPATH']
- p = subprocess.run(('mypy',
- '--warn-unused-configs',
- '--disallow-subclassing-any',
- '--disallow-any-generics',
- '--disallow-incomplete-defs',
- '--disallow-untyped-decorators',
- '--no-implicit-optional',
- '--warn-redundant-casts',
- '--warn-unused-ignores',
- '--no-implicit-reexport',
- '--namespace-packages',
- '--scripts-are-modules',
- *files),
- env=env,
- check=False,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT,
- universal_newlines=True)
-
- if p.returncode != 0:
- print(p.stdout)
-
-
-for linter in ('pylint-3', 'mypy'):
- if shutil.which(linter) is None:
- iotests.notrun(f'{linter} not found')
-
-iotests.script_main(run_linters)
+
+def main() -> None:
+ files = linters.get_test_files()
+
+ iotests.logger.debug('Files to be checked:')
+ iotests.logger.debug(', '.join(sorted(files)))
+
+ for test in (test_pylint, test_mypy):
+ try:
+ test(files)
+ except subprocess.CalledProcessError as exc:
+ # Linter failure will be caught by diffing the IO.
+ if exc.output:
+ print(exc.output)
+
+
+iotests.script_main(main)
diff --git a/tests/qemu-iotests/300 b/tests/qemu-iotests/300
index 10f9f2a..dbd2838 100755
--- a/tests/qemu-iotests/300
+++ b/tests/qemu-iotests/300
@@ -24,8 +24,6 @@ import random
import re
from typing import Dict, List, Optional
-from qemu.machine import machine
-
import iotests
@@ -461,12 +459,11 @@ class TestBlockBitmapMappingErrors(TestDirtyBitmapMigration):
f"'{self.src_node_name}': Name is longer than 255 bytes",
log)
- # Expect abnormal shutdown of the destination VM because of
- # the failed migration
- try:
- self.vm_b.shutdown()
- except machine.AbnormalShutdown:
- pass
+ # Destination VM will terminate w/ error of its own accord
+ # due to the failed migration.
+ self.vm_b.wait()
+ rc = self.vm_b.exitcode()
+ assert rc is not None and rc > 0
def test_aliased_bitmap_name_too_long(self) -> None:
# Longer than the maximum for bitmap names
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index e5fff6d..e2f9d87 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -30,7 +30,7 @@ import struct
import subprocess
import sys
import time
-from typing import (Any, Callable, Dict, Iterable,
+from typing import (Any, Callable, Dict, Iterable, Iterator,
List, Optional, Sequence, TextIO, Tuple, Type, TypeVar)
import unittest
@@ -114,6 +114,24 @@ luks_default_key_secret_opt = 'key-secret=keysec0'
sample_img_dir = os.environ['SAMPLE_IMG_DIR']
+@contextmanager
+def change_log_level(
+ logger_name: str, level: int = logging.CRITICAL) -> Iterator[None]:
+ """
+ Utility function for temporarily changing the log level of a logger.
+
+ This can be used to silence errors that are expected or uninteresting.
+ """
+ _logger = logging.getLogger(logger_name)
+ current_level = _logger.level
+ _logger.setLevel(level)
+
+ try:
+ yield
+ finally:
+ _logger.setLevel(current_level)
+
+
def unarchive_sample_image(sample, fname):
sample_fname = os.path.join(sample_img_dir, sample + '.bz2')
with bz2.open(sample_fname) as f_in, open(fname, 'wb') as f_out:
diff --git a/tests/qemu-iotests/linters.py b/tests/qemu-iotests/linters.py
new file mode 100644
index 0000000..65c4c4e
--- /dev/null
+++ b/tests/qemu-iotests/linters.py
@@ -0,0 +1,105 @@
+# Copyright (C) 2020 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import re
+import subprocess
+import sys
+from typing import List, Mapping, Optional
+
+
+# TODO: Empty this list!
+SKIP_FILES = (
+ '030', '040', '041', '044', '045', '055', '056', '057', '065', '093',
+ '096', '118', '124', '132', '136', '139', '147', '148', '149',
+ '151', '152', '155', '163', '165', '194', '196', '202',
+ '203', '205', '206', '207', '208', '210', '211', '212', '213', '216',
+ '218', '219', '224', '228', '234', '235', '236', '237', '238',
+ '240', '242', '245', '246', '248', '255', '256', '257', '258', '260',
+ '262', '264', '266', '274', '277', '280', '281', '295', '296', '298',
+ '299', '302', '303', '304', '307',
+ 'nbd-fault-injector.py', 'qcow2.py', 'qcow2_format.py', 'qed.py'
+)
+
+
+def is_python_file(filename):
+ if not os.path.isfile(filename):
+ return False
+
+ if filename.endswith('.py'):
+ return True
+
+ with open(filename, encoding='utf-8') as f:
+ try:
+ first_line = f.readline()
+ return re.match('^#!.*python', first_line) is not None
+ except UnicodeDecodeError: # Ignore binary files
+ return False
+
+
+def get_test_files() -> List[str]:
+ named_tests = [f'tests/{entry}' for entry in os.listdir('tests')]
+ check_tests = set(os.listdir('.') + named_tests) - set(SKIP_FILES)
+ return list(filter(is_python_file, check_tests))
+
+
+def run_linter(
+ tool: str,
+ args: List[str],
+ env: Optional[Mapping[str, str]] = None,
+ suppress_output: bool = False,
+) -> None:
+ """
+ Run a python-based linting tool.
+
+ :param suppress_output: If True, suppress all stdout/stderr output.
+ :raise CalledProcessError: If the linter process exits with failure.
+ """
+ subprocess.run(
+ ('python3', '-m', tool, *args),
+ env=env,
+ check=True,
+ stdout=subprocess.PIPE if suppress_output else None,
+ stderr=subprocess.STDOUT if suppress_output else None,
+ universal_newlines=True,
+ )
+
+
+def main() -> None:
+ """
+ Used by the Python CI system as an entry point to run these linters.
+ """
+ def show_usage() -> None:
+ print(f"Usage: {sys.argv[0]} < --mypy | --pylint >", file=sys.stderr)
+ sys.exit(1)
+
+ if len(sys.argv) != 2:
+ show_usage()
+
+ files = get_test_files()
+
+ if sys.argv[1] == '--pylint':
+ run_linter('pylint', files)
+ elif sys.argv[1] == '--mypy':
+ # mypy bug #9852; disable incremental checking as a workaround.
+ args = ['--no-incremental'] + files
+ run_linter('mypy', args)
+ else:
+ print(f"Unrecognized argument: '{sys.argv[1]}'", file=sys.stderr)
+ show_usage()
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tests/qemu-iotests/mypy.ini b/tests/qemu-iotests/mypy.ini
new file mode 100644
index 0000000..4c0339f
--- /dev/null
+++ b/tests/qemu-iotests/mypy.ini
@@ -0,0 +1,12 @@
+[mypy]
+disallow_any_generics = True
+disallow_incomplete_defs = True
+disallow_subclassing_any = True
+disallow_untyped_decorators = True
+implicit_reexport = False
+namespace_packages = True
+no_implicit_optional = True
+scripts_are_modules = True
+warn_redundant_casts = True
+warn_unused_configs = True
+warn_unused_ignores = True
diff --git a/tests/qemu-iotests/pylintrc b/tests/qemu-iotests/pylintrc
index 8cb4e1d..32ab77b 100644
--- a/tests/qemu-iotests/pylintrc
+++ b/tests/qemu-iotests/pylintrc
@@ -31,6 +31,22 @@ disable=invalid-name,
too-many-statements,
consider-using-f-string,
+
+[REPORTS]
+
+# Activate the evaluation score.
+score=no
+
+
+[MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+# TODO notes are fine, but FIXMEs or XXXs should probably just be
+# fixed (in tests, at least).
+notes=FIXME,
+ XXX,
+
+
[FORMAT]
# Maximum number of characters on a single line.
diff --git a/tests/qemu-iotests/tests/mirror-top-perms b/tests/qemu-iotests/tests/mirror-top-perms
index 3d475aa..0a51a61 100755
--- a/tests/qemu-iotests/tests/mirror-top-perms
+++ b/tests/qemu-iotests/tests/mirror-top-perms
@@ -21,11 +21,12 @@
import os
-from qemu import qmp
+from qemu.aqmp import ConnectError
from qemu.machine import machine
+from qemu.qmp import QMPConnectError
import iotests
-from iotests import qemu_img
+from iotests import change_log_level, qemu_img
image_size = 1 * 1024 * 1024
@@ -99,10 +100,14 @@ class TestMirrorTopPerms(iotests.QMPTestCase):
self.vm_b.add_blockdev(f'file,node-name=drive0,filename={source}')
self.vm_b.add_device('virtio-blk,drive=drive0,share-rw=on')
try:
- self.vm_b.launch()
- print('ERROR: VM B launched successfully, this should not have '
- 'happened')
- except qmp.QMPConnectError:
+ # Silence AQMP errors temporarily.
+ # TODO: Remove this and just allow the errors to be logged when
+ # AQMP fully replaces QMP.
+ with change_log_level('qemu.aqmp'):
+ self.vm_b.launch()
+ print('ERROR: VM B launched successfully, '
+ 'this should not have happened')
+ except (QMPConnectError, ConnectError):
assert 'Is another process using the image' in self.vm_b.get_log()
result = self.vm.qmp('block-job-cancel',