6
0
mirror of https://github.com/FirebirdSQL/firebird-qa.git synced 2025-01-22 21:43:06 +01:00

Better handling of captured stdout/stderr on external utility execution failure. Metadata for JIRA ticket ID.

This commit is contained in:
Pavel Císař 2022-01-18 20:47:57 +01:00
parent 63b28f9dd4
commit c3ddfee00b
3 changed files with 43 additions and 73 deletions

View File

@ -37,4 +37,5 @@
"""
from .plugin import db_factory, Database, user_factory, User, isql_act, python_act, Action, \
temp_file, temp_files, role_factory, Role, envar_factory, Envar, ServerKeeper
temp_file, temp_files, role_factory, Role, envar_factory, Envar, ServerKeeper, \
ExecutionError

View File

@ -75,6 +75,10 @@ FIELD_ISSUE = 'ISSUE:'
FIELD_TITLE = 'TITLE:'
FIELD_DECRIPTION = 'DESCRIPTION:'
FIELD_NOTES = 'NOTES:'
FIELD_JIRA = 'JIRA:'
class ExecutionError(Exception):
pass
def format_title(title, patterns):
return _remove_patterns(title, patterns).replace('_', ' ').strip()
@ -385,6 +389,7 @@ def pytest_collection_modifyitems(session, config, items):
for item in items:
item._qa_id_ = item.nodeid
item._qa_issue_ = None
item._qa_jira_ = None
item._qa_title_ = 'UNKNOWN'
item._qa_description_ = ''
item._qa_notes_ = ''
@ -401,6 +406,9 @@ def pytest_collection_modifyitems(session, config, items):
elif uline.startswith(FIELD_ISSUE):
current_field = FIELD_ISSUE
item._qa_issue_ = line[len(FIELD_ISSUE):].strip()
elif uline.startswith(FIELD_JIRA):
current_field = FIELD_JIRA
item._qa_jira_ = line[len(FIELD_JIRA):].strip()
elif uline.startswith(FIELD_TITLE):
current_field = FIELD_TITLE
item._qa_title_ = line[len(FIELD_TITLE):].strip()
@ -1232,7 +1240,8 @@ class Action:
Do not create instances of this class directly! Use **only** fixtures created by
`isql_act` or `python_act`.
"""
def __init__(self, db: Database, script: str, substitutions: List[str], outfile: Path):
def __init__(self, db: Database, script: str, substitutions: List[str], outfile: Path, node: pytest.Item):
self._node: pytest.Item = node
#: Primary test database.
self.db: Database = db
#: Test script
@ -1321,11 +1330,9 @@ class Action:
result: CompletedProcess = run(params, input=self.script,
encoding=io_enc, capture_output=True)
if result.returncode and not bool(self.expected_stderr) and not combine_output:
print(f"-- ISQL script stdout {'-' * 20}")
print(result.stdout)
print(f"-- ISQL script stderr {'-' * 20}")
print(result.stderr)
raise Exception("ISQL script execution failed")
self._node.add_report_section('call', 'ISQL stdout', result.stdout)
self._node.add_report_section('call', 'ISQL stderr', result.stderr)
raise ExecutionError("ISQL script execution failed")
self.return_code: int = result.returncode
self.stdout: str = result.stdout
@ -1372,11 +1379,9 @@ class Action:
'-password', db.password, str(db.dsn)],
encoding=io_enc, capture_output=True)
if result.returncode:
print(f"-- ISQL stdout {'-' * 20}")
print(result.stdout)
print(f"-- ISQL stderr {'-' * 20}")
print(result.stderr)
raise Exception("ISQL execution failed")
self._node.add_report_section('call', 'ISQL stdout', result.stdout)
self._node.add_report_section('call', 'ISQL stderr', result.stderr)
raise ExecutionError("ISQL execution failed")
self.return_code: int = result.returncode
self.stdout: str = result.stdout
self.stderr: str = result.stderr
@ -1434,11 +1439,9 @@ class Action:
params.append(str(self.db.dsn))
result: CompletedProcess = run(params, encoding=io_enc, capture_output=True)
if result.returncode and not bool(self.expected_stderr):
print(f"-- gstat stdout {'-' * 20}")
print(result.stdout)
print(f"-- gstat stderr {'-' * 20}")
print(result.stderr)
raise Exception("gstat execution failed")
self._node.add_report_section('call', 'gstat stdout', result.stdout)
self._node.add_report_section('call', 'gstat stderr', result.stderr)
raise ExecutionError("gstat execution failed")
self.return_code: int = result.returncode
self.stdout: str = result.stdout
self.stderr: str = result.stderr
@ -1495,11 +1498,9 @@ class Action:
result: CompletedProcess = run(params, input=input,
encoding=io_enc, capture_output=True)
if result.returncode and not bool(self.expected_stderr):
print(f"-- gsec stdout {'-' * 20}")
print(result.stdout)
print(f"-- gsec stderr {'-' * 20}")
print(result.stderr)
raise Exception("gsec execution failed")
self._node.add_report_section('call', 'gsec stdout', result.stdout)
self._node.add_report_section('call', 'gsec stderr', result.stderr)
raise ExecutionError("gsec execution failed")
self.return_code: int = result.returncode
self.stdout: str = result.stdout
self.stderr: str = result.stderr
@ -1555,11 +1556,9 @@ class Action:
result: CompletedProcess = run(params, input=input,
encoding=io_enc, capture_output=True)
if result.returncode and not (bool(self.expected_stderr) or combine_output):
print(f"-- gbak stdout {'-' * 20}")
print(result.stdout)
print(f"-- gbak stderr {'-' * 20}")
print(result.stderr)
raise Exception("gbak execution failed")
self._node.add_report_section('call', 'gbak stdout', result.stdout)
self._node.add_report_section('call', 'gbak stderr', result.stderr)
raise ExecutionError("gbak execution failed")
self.return_code: int = result.returncode
self.stdout: str = result.stdout
self.stderr: str = result.stderr
@ -1612,11 +1611,9 @@ class Action:
else:
result: CompletedProcess = run(params, encoding=io_enc, capture_output=True)
if result.returncode and not (bool(self.expected_stderr) or combine_output):
print(f"-- nbackup stdout {'-' * 20}")
print(result.stdout)
print(f"-- nbackup stderr {'-' * 20}")
print(result.stderr)
raise Exception("nbackup execution failed")
self._node.add_report_section('call', 'nbackup stdout', result.stdout)
self._node.add_report_section('call', 'nbackup stderr', result.stderr)
raise ExecutionError("nbackup execution failed")
self.return_code: int = result.returncode
self.stdout: str = result.stdout
self.stderr: str = result.stderr
@ -1668,11 +1665,9 @@ class Action:
result: CompletedProcess = run(params, input=input,
encoding=io_enc, capture_output=True)
if result.returncode and not bool(self.expected_stderr):
print(f"-- gfix stdout {'-' * 20}")
print(result.stdout)
print(f"-- gfix stderr {'-' * 20}")
print(result.stderr)
raise Exception("gfix execution failed")
self._node.add_report_section('call', 'gfix stdout', result.stdout)
self._node.add_report_section('call', 'gfix stderr', result.stderr)
raise ExecutionError("gfix execution failed")
self.return_code: int = result.returncode
self.stdout: str = result.stdout
self.stderr: str = result.stderr
@ -1733,11 +1728,9 @@ class Action:
result: CompletedProcess = run(params, input=input,
encoding=io_enc, capture_output=True)
if result.returncode and not (bool(self.expected_stderr) or combine_output):
print(f"-- isql stdout {'-' * 20}")
print(result.stdout)
print(f"-- isql stderr {'-' * 20}")
print(result.stderr)
raise Exception("isql execution failed")
self._node.add_report_section('call', 'ISQL stdout', result.stdout)
self._node.add_report_section('call', 'ISQL stderr', result.stderr)
raise ExecutionError("ISQL execution failed")
self.return_code: int = result.returncode
self.stdout: str = result.stdout
self.stderr: str = result.stderr
@ -1789,11 +1782,9 @@ class Action:
params.extend(switches)
result: CompletedProcess = run(params, encoding=io_enc, capture_output=True)
if result.returncode and not bool(self.expected_stderr):
print(f"-- fbsvcmgr stdout {'-' * 20}")
print(result.stdout)
print(f"-- fbsvcmgr stderr {'-' * 20}")
print(result.stderr)
raise Exception("fbsvcmgr execution failed")
self._node.add_report_section('call', 'fbsvcmgr stdout', result.stdout)
self._node.add_report_section('call', 'fbsvcmgr stderr', result.stderr)
raise ExecutionError("fbsvcmgr execution failed")
self.return_code: int = result.returncode
self.stdout: str = result.stdout
self.stderr: str = result.stderr
@ -1817,29 +1808,7 @@ class Action:
spec = SpecifierSet(version_spec)
return _vars_['version'] in spec
def get_server_architecture(self) -> str:
with self.db.connect() as con1, self.db.connect() as con2:
sql = f"""
select count(distinct a.mon$server_pid), min(a.mon$remote_protocol),
max(iif(a.mon$remote_protocol is null, 1, 0))
from mon$attachments a
where a.mon$attachment_id in ({con1.info.id}, {con2.info.id}) or upper(a.mon$user) = upper('cache writer')
"""
cur1 = con1.cursor()
cur1.execute(sql)
server_cnt, server_pro, cache_wrtr = cur1.fetchone()
if server_pro is None:
result = 'Embedded'
elif cache_wrtr == 1:
result = 'SS'
elif server_cnt == 2:
result = 'CS'
else:
f1 = con1.info.get_info(DbInfoCode.FETCHES)
cur2 = con2.cursor()
cur2.execute('select 1 from rdb$database').fetchall()
f2 = con1.info.get_info(DbInfoCode.FETCHES)
result = 'SC' if f1 == f2 else 'SS'
return result
return _vars_['server-arch']
def get_dsn(self, filename: Union[str, Path], protocol: str=None) -> str:
return _connect_helper('', self.host, self.port, str(filename),
protocol if protocol else self.protocol)
@ -1988,7 +1957,7 @@ def isql_act(db_fixture_name: str, script: str, *, substitutions: List[str]=None
if _vars_['save-output'] and not f.parent.exists():
f.parent.mkdir(parents=True)
f = f.with_name(f'{f.stem}-{request.function.__name__}.out')
result: Action = Action(db, script, substitutions, f)
result: Action = Action(db, script, substitutions, f, request.node)
return result
return isql_act_fixture
@ -2002,7 +1971,7 @@ def python_act(db_fixture_name: str, *, substitutions: List[str]=None):
if _vars_['save-output'] and not f.parent.exists():
f.parent.mkdir(parents=True)
f = f.with_name(f'{f.stem}-{request.function.__name__}.out')
result: Action = Action(db, '', substitutions, f)
result: Action = Action(db, '', substitutions, f, request.node)
return result
return python_act_fixture

View File

@ -5,7 +5,7 @@ all-files=True
[metadata]
name = firebird-qa
version = 0.10.0
version = 0.10.1
description = pytest plugin for Firebird QA
long_description = file: README.rst
long_description_content_type = text/x-rst; charset=UTF-8