xref: /qemu/tests/qemu-iotests/297 (revision 85cfec53d0b43182a14f8b5c3aa685955a852f1c)
159aec869SMax Reitz#!/usr/bin/env python3
29dd003a9SVladimir Sementsov-Ogievskiy# group: meta
319b7868eSKevin Wolf#
419b7868eSKevin Wolf# Copyright (C) 2020 Red Hat, Inc.
519b7868eSKevin Wolf#
619b7868eSKevin Wolf# This program is free software; you can redistribute it and/or modify
719b7868eSKevin Wolf# it under the terms of the GNU General Public License as published by
819b7868eSKevin Wolf# the Free Software Foundation; either version 2 of the License, or
919b7868eSKevin Wolf# (at your option) any later version.
1019b7868eSKevin Wolf#
1119b7868eSKevin Wolf# This program is distributed in the hope that it will be useful,
1219b7868eSKevin Wolf# but WITHOUT ANY WARRANTY; without even the implied warranty of
1319b7868eSKevin Wolf# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1419b7868eSKevin Wolf# GNU General Public License for more details.
1519b7868eSKevin Wolf#
1619b7868eSKevin Wolf# You should have received a copy of the GNU General Public License
1719b7868eSKevin Wolf# along with this program.  If not, see <http://www.gnu.org/licenses/>.
1819b7868eSKevin Wolf
1959aec869SMax Reitzimport os
2059aec869SMax Reitzimport re
2159aec869SMax Reitzimport subprocess
2259aec869SMax Reitzimport sys
232d804f55SJohn Snowfrom typing import List, Mapping, Optional
2419b7868eSKevin Wolf
2559aec869SMax Reitzimport iotests
2619b7868eSKevin Wolf
2719b7868eSKevin Wolf
2859aec869SMax Reitz# TODO: Empty this list!
2959aec869SMax ReitzSKIP_FILES = (
3059aec869SMax Reitz    '030', '040', '041', '044', '045', '055', '056', '057', '065', '093',
31636aa64dSMax Reitz    '096', '118', '124', '132', '136', '139', '147', '148', '149',
3226db7b23SHanna Reitz    '151', '152', '155', '163', '165', '194', '196', '202',
3359aec869SMax Reitz    '203', '205', '206', '207', '208', '210', '211', '212', '213', '216',
34f08ef043SVladimir Sementsov-Ogievskiy    '218', '219', '224', '228', '234', '235', '236', '237', '238',
3559aec869SMax Reitz    '240', '242', '245', '246', '248', '255', '256', '257', '258', '260',
3659aec869SMax Reitz    '262', '264', '266', '274', '277', '280', '281', '295', '296', '298',
3759c9466dSMax Reitz    '299', '302', '303', '304', '307',
3859aec869SMax Reitz    'nbd-fault-injector.py', 'qcow2.py', 'qcow2_format.py', 'qed.py'
3959aec869SMax Reitz)
4019b7868eSKevin Wolf
4119b7868eSKevin Wolf
4259aec869SMax Reitzdef is_python_file(filename):
4359aec869SMax Reitz    if not os.path.isfile(filename):
4459aec869SMax Reitz        return False
4519b7868eSKevin Wolf
4659aec869SMax Reitz    if filename.endswith('.py'):
4759aec869SMax Reitz        return True
4859aec869SMax Reitz
4981dcb9caSHanna Reitz    with open(filename, encoding='utf-8') as f:
5059aec869SMax Reitz        try:
5159aec869SMax Reitz            first_line = f.readline()
5259aec869SMax Reitz            return re.match('^#!.*python', first_line) is not None
5359aec869SMax Reitz        except UnicodeDecodeError:  # Ignore binary files
5459aec869SMax Reitz            return False
5559aec869SMax Reitz
5659aec869SMax Reitz
573c1d5012SJohn Snowdef get_test_files() -> List[str]:
58098d983eSHanna Reitz    named_tests = [f'tests/{entry}' for entry in os.listdir('tests')]
59098d983eSHanna Reitz    check_tests = set(os.listdir('.') + named_tests) - set(SKIP_FILES)
603c1d5012SJohn Snow    return list(filter(is_python_file, check_tests))
613c1d5012SJohn Snow
623c1d5012SJohn Snow
63a4bde736SJohn Snowdef run_linter(
64a4bde736SJohn Snow        tool: str,
65a4bde736SJohn Snow        args: List[str],
662d804f55SJohn Snow        env: Optional[Mapping[str, str]] = None,
67a4bde736SJohn Snow        suppress_output: bool = False,
682d804f55SJohn Snow) -> None:
69a4bde736SJohn Snow    """
70a4bde736SJohn Snow    Run a python-based linting tool.
7159aec869SMax Reitz
72752f425dSJohn Snow    :param suppress_output: If True, suppress all stdout/stderr output.
73752f425dSJohn Snow    :raise CalledProcessError: If the linter process exits with failure.
74a4bde736SJohn Snow    """
75752f425dSJohn Snow    subprocess.run(
76a4bde736SJohn Snow        ('python3', '-m', tool, *args),
7759aec869SMax Reitz        env=env,
78752f425dSJohn Snow        check=True,
79a4bde736SJohn Snow        stdout=subprocess.PIPE if suppress_output else None,
80a4bde736SJohn Snow        stderr=subprocess.STDOUT if suppress_output else None,
81a4bde736SJohn Snow        universal_newlines=True,
82a4bde736SJohn Snow    )
8359aec869SMax Reitz
8459aec869SMax Reitz
85*85cfec53SJohn Snowdef check_linter(linter: str) -> bool:
867a90bcc2SJohn Snow    try:
877a90bcc2SJohn Snow        run_linter(linter, ['--version'], suppress_output=True)
887a90bcc2SJohn Snow    except subprocess.CalledProcessError:
89*85cfec53SJohn Snow        iotests.case_notrun(f"'{linter}' not found")
90*85cfec53SJohn Snow        return False
91*85cfec53SJohn Snow    return True
9259aec869SMax Reitz
93*85cfec53SJohn Snow
94*85cfec53SJohn Snowdef test_pylint(files: List[str]) -> None:
95*85cfec53SJohn Snow    print('=== pylint ===')
96*85cfec53SJohn Snow    sys.stdout.flush()
97*85cfec53SJohn Snow
98*85cfec53SJohn Snow    if not check_linter('pylint'):
99*85cfec53SJohn Snow        return
100*85cfec53SJohn Snow
101*85cfec53SJohn Snow    run_linter('pylint', files)
102*85cfec53SJohn Snow
103*85cfec53SJohn Snow
104*85cfec53SJohn Snowdef test_mypy(files: List[str]) -> None:
105*85cfec53SJohn Snow    print('=== mypy ===')
106*85cfec53SJohn Snow    sys.stdout.flush()
107*85cfec53SJohn Snow
108*85cfec53SJohn Snow    if not check_linter('mypy'):
109*85cfec53SJohn Snow        return
110*85cfec53SJohn Snow
111*85cfec53SJohn Snow    env = os.environ.copy()
112*85cfec53SJohn Snow    env['MYPYPATH'] = env['PYTHONPATH']
113*85cfec53SJohn Snow
114*85cfec53SJohn Snow    run_linter('mypy', files, env=env, suppress_output=True)
115*85cfec53SJohn Snow
116*85cfec53SJohn Snow
117*85cfec53SJohn Snowdef main() -> None:
1182d804f55SJohn Snow    files = get_test_files()
1192d804f55SJohn Snow
1202d804f55SJohn Snow    iotests.logger.debug('Files to be checked:')
1212d804f55SJohn Snow    iotests.logger.debug(', '.join(sorted(files)))
1222d804f55SJohn Snow
123*85cfec53SJohn Snow    for test in (test_pylint, test_mypy):
124752f425dSJohn Snow        try:
125*85cfec53SJohn Snow            test(files)
126752f425dSJohn Snow        except subprocess.CalledProcessError as exc:
127*85cfec53SJohn Snow            # Linter failure will be caught by diffing the IO.
128752f425dSJohn Snow            if exc.output:
129752f425dSJohn Snow                print(exc.output)
130447aebdaSJohn Snow
131447aebdaSJohn Snow
132447aebdaSJohn Snowiotests.script_main(main)
133