mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-16 09:55:26 -07:00
Use lint/junit output for compile test. (#22395)
* Refactor sanity classes for use in all tests. * Use lint/junit output for compile test. * Add missing options for compile test. * Fix early bailout on requirements install.
This commit is contained in:
parent
a8910e78ca
commit
3ab344e8bd
6 changed files with 489 additions and 321 deletions
|
@ -2,7 +2,6 @@
|
|||
|
||||
from __future__ import absolute_import, print_function
|
||||
|
||||
import datetime
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
|
@ -41,6 +40,15 @@ from lib.executor import (
|
|||
SanityConfig,
|
||||
)
|
||||
|
||||
from lib.test import (
|
||||
TestSuccess,
|
||||
TestFailure,
|
||||
TestSkipped,
|
||||
TestMessage,
|
||||
)
|
||||
|
||||
COMMAND = 'sanity'
|
||||
|
||||
PEP8_SKIP_PATH = 'test/sanity/pep8/skip.txt'
|
||||
PEP8_LEGACY_PATH = 'test/sanity/pep8/legacy-files.txt'
|
||||
|
||||
|
@ -317,7 +325,7 @@ def command_sanity_pep8(args, targets):
|
|||
status = ex.status
|
||||
|
||||
if stderr:
|
||||
raise SubprocessError(cmd=cmd, status=status, stderr=stderr)
|
||||
raise SubprocessError(cmd=cmd, status=status, stderr=stderr, stdout=stdout)
|
||||
|
||||
if args.explain:
|
||||
return SanitySkipped(test)
|
||||
|
@ -444,7 +452,7 @@ def command_sanity_yamllint(args, targets):
|
|||
status = ex.status
|
||||
|
||||
if stderr:
|
||||
raise SubprocessError(cmd=cmd, status=status, stderr=stderr)
|
||||
raise SubprocessError(cmd=cmd, status=status, stderr=stderr, stdout=stdout)
|
||||
|
||||
if args.explain:
|
||||
return SanitySkipped(test)
|
||||
|
@ -542,143 +550,27 @@ def sanity_get_tests():
|
|||
return SANITY_TESTS
|
||||
|
||||
|
||||
class SanityResult(object):
|
||||
"""Base class for sanity test results."""
|
||||
def __init__(self, test, python_version=None):
|
||||
"""
|
||||
:type test: str
|
||||
:type python_version: str
|
||||
"""
|
||||
self.test = test
|
||||
self.python_version = python_version
|
||||
|
||||
try:
|
||||
import junit_xml
|
||||
except ImportError:
|
||||
junit_xml = None
|
||||
|
||||
self.junit = junit_xml
|
||||
|
||||
def write(self, args):
|
||||
"""
|
||||
:type args: SanityConfig
|
||||
"""
|
||||
self.write_console()
|
||||
self.write_bot(args)
|
||||
|
||||
if args.lint:
|
||||
self.write_lint()
|
||||
|
||||
if args.junit:
|
||||
if self.junit:
|
||||
self.write_junit(args)
|
||||
else:
|
||||
display.warning('Skipping junit xml output because the `junit-xml` python package was not found.', unique=True)
|
||||
|
||||
def write_console(self):
|
||||
"""Write results to console."""
|
||||
pass
|
||||
|
||||
def write_lint(self):
|
||||
"""Write lint results to stdout."""
|
||||
pass
|
||||
|
||||
def write_bot(self, args):
|
||||
"""
|
||||
:type args: SanityConfig
|
||||
"""
|
||||
pass
|
||||
|
||||
def write_junit(self, args):
|
||||
"""
|
||||
:type args: SanityConfig
|
||||
"""
|
||||
pass
|
||||
|
||||
def create_path(self, directory, extension):
|
||||
"""
|
||||
:type directory: str
|
||||
:type extension: str
|
||||
:rtype: str
|
||||
"""
|
||||
path = 'test/results/%s/ansible-test-%s' % (directory, self.test)
|
||||
|
||||
if self.python_version:
|
||||
path += '-python-%s' % self.python_version
|
||||
|
||||
path += extension
|
||||
|
||||
return path
|
||||
|
||||
def save_junit(self, args, test_case, properties=None):
|
||||
"""
|
||||
:type args: SanityConfig
|
||||
:type test_case: junit_xml.TestCase
|
||||
:type properties: dict[str, str] | None
|
||||
:rtype: str | None
|
||||
"""
|
||||
path = self.create_path('junit', '.xml')
|
||||
|
||||
test_suites = [
|
||||
self.junit.TestSuite(
|
||||
name='ansible-test',
|
||||
test_cases=[test_case],
|
||||
timestamp=datetime.datetime.utcnow().replace(microsecond=0).isoformat(),
|
||||
properties=properties,
|
||||
),
|
||||
]
|
||||
|
||||
report = self.junit.TestSuite.to_xml_string(test_suites=test_suites, prettyprint=True, encoding='utf-8')
|
||||
|
||||
if args.explain:
|
||||
return
|
||||
|
||||
with open(path, 'wb') as xml:
|
||||
xml.write(report.encode('utf-8', 'strict'))
|
||||
|
||||
|
||||
class SanitySuccess(SanityResult):
|
||||
class SanitySuccess(TestSuccess):
|
||||
"""Sanity test success."""
|
||||
def __init__(self, test, python_version=None):
|
||||
"""
|
||||
:type test: str
|
||||
:type python_version: str
|
||||
"""
|
||||
super(SanitySuccess, self).__init__(test, python_version)
|
||||
|
||||
def write_junit(self, args):
|
||||
"""
|
||||
:type args: SanityConfig
|
||||
"""
|
||||
test_case = self.junit.TestCase(name=self.test)
|
||||
|
||||
self.save_junit(args, test_case)
|
||||
super(SanitySuccess, self).__init__(COMMAND, test, python_version)
|
||||
|
||||
|
||||
class SanitySkipped(SanityResult):
|
||||
class SanitySkipped(TestSkipped):
|
||||
"""Sanity test skipped."""
|
||||
def __init__(self, test, python_version=None):
|
||||
"""
|
||||
:type test: str
|
||||
:type python_version: str
|
||||
"""
|
||||
super(SanitySkipped, self).__init__(test, python_version)
|
||||
|
||||
def write_console(self):
|
||||
"""Write results to console."""
|
||||
display.info('No tests applicable.', verbosity=1)
|
||||
|
||||
def write_junit(self, args):
|
||||
"""
|
||||
:type args: SanityConfig
|
||||
"""
|
||||
test_case = self.junit.TestCase(name=self.test)
|
||||
test_case.add_skipped_info('No tests applicable.')
|
||||
|
||||
self.save_junit(args, test_case)
|
||||
super(SanitySkipped, self).__init__(COMMAND, test, python_version)
|
||||
|
||||
|
||||
class SanityFailure(SanityResult):
|
||||
class SanityFailure(TestFailure):
|
||||
"""Sanity test failure."""
|
||||
def __init__(self, test, python_version=None, messages=None, summary=None):
|
||||
"""
|
||||
|
@ -687,117 +579,10 @@ class SanityFailure(SanityResult):
|
|||
:type messages: list[SanityMessage]
|
||||
:type summary: str
|
||||
"""
|
||||
super(SanityFailure, self).__init__(test, python_version)
|
||||
|
||||
self.messages = messages
|
||||
self.summary = summary
|
||||
|
||||
def write_console(self):
|
||||
"""Write results to console."""
|
||||
if self.summary:
|
||||
display.error(self.summary)
|
||||
else:
|
||||
display.error('Found %d %s issue(s) which need to be resolved:' % (len(self.messages), self.test))
|
||||
|
||||
for message in self.messages:
|
||||
display.error(message)
|
||||
|
||||
def write_lint(self):
|
||||
"""Write lint results to stdout."""
|
||||
if self.summary:
|
||||
command = self.format_command()
|
||||
message = 'The test `%s` failed. See stderr output for details.' % command
|
||||
path = 'test/runner/ansible-test'
|
||||
message = SanityMessage(message, path)
|
||||
print(message)
|
||||
else:
|
||||
for message in self.messages:
|
||||
print(message)
|
||||
|
||||
def write_junit(self, args):
|
||||
"""
|
||||
:type args: SanityConfig
|
||||
"""
|
||||
title = self.format_title()
|
||||
output = self.format_block()
|
||||
|
||||
test_case = self.junit.TestCase(classname='sanity', name=self.test)
|
||||
|
||||
# Include a leading newline to improve readability on Shippable "Tests" tab.
|
||||
# Without this, the first line becomes indented.
|
||||
test_case.add_failure_info(message=title, output='\n%s' % output)
|
||||
|
||||
self.save_junit(args, test_case)
|
||||
|
||||
def write_bot(self, args):
|
||||
"""
|
||||
:type args: SanityConfig
|
||||
"""
|
||||
message = self.format_title()
|
||||
output = self.format_block()
|
||||
|
||||
bot_data = dict(
|
||||
results=[
|
||||
dict(
|
||||
message=message,
|
||||
output=output,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
path = self.create_path('bot', '.json')
|
||||
|
||||
if args.explain:
|
||||
return
|
||||
|
||||
with open(path, 'wb') as bot_fd:
|
||||
json.dump(bot_data, bot_fd, indent=4, sort_keys=True)
|
||||
bot_fd.write('\n')
|
||||
|
||||
def format_command(self):
|
||||
"""
|
||||
:rtype: str
|
||||
"""
|
||||
command = 'ansible-test sanity --test %s' % self.test
|
||||
|
||||
if self.python_version:
|
||||
command += ' --python %s' % self.python_version
|
||||
|
||||
return command
|
||||
|
||||
def format_title(self):
|
||||
"""
|
||||
:rtype: str
|
||||
"""
|
||||
command = self.format_command()
|
||||
|
||||
if self.summary:
|
||||
reason = 'error'
|
||||
else:
|
||||
reason = 'error' if len(self.messages) == 1 else 'errors'
|
||||
|
||||
title = 'The test `%s` failed with the following %s:' % (command, reason)
|
||||
|
||||
return title
|
||||
|
||||
def format_block(self):
|
||||
"""
|
||||
:rtype: str
|
||||
"""
|
||||
if self.summary:
|
||||
block = self.summary
|
||||
else:
|
||||
block = '\n'.join(str(m) for m in self.messages)
|
||||
|
||||
message = block.strip()
|
||||
|
||||
# Hack to remove ANSI color reset code from SubprocessError messages.
|
||||
message = message.replace(display.clear, '')
|
||||
|
||||
return message
|
||||
super(SanityFailure, self).__init__(COMMAND, test, python_version, messages, summary)
|
||||
|
||||
|
||||
class SanityMessage(object):
|
||||
class SanityMessage(TestMessage):
|
||||
"""Single sanity test message for one file."""
|
||||
def __init__(self, message, path, line=0, column=0, level='error', code=None):
|
||||
"""
|
||||
|
@ -808,20 +593,7 @@ class SanityMessage(object):
|
|||
:type level: str
|
||||
:type code: str | None
|
||||
"""
|
||||
self.path = path
|
||||
self.line = line
|
||||
self.column = column
|
||||
self.level = level
|
||||
self.code = code
|
||||
self.message = message
|
||||
|
||||
def __str__(self):
|
||||
if self.code:
|
||||
msg = '%s %s' % (self.code, self.message)
|
||||
else:
|
||||
msg = self.message
|
||||
|
||||
return '%s:%s:%s: %s' % (self.path, self.line, self.column, msg)
|
||||
super(SanityMessage, self).__init__(message, path, line, column, level, code)
|
||||
|
||||
|
||||
class SanityTargets(object):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue