1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
#!/usr/bin/env python3
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
# Copyright (C) 2022 Authors
#
# Released under GNU GPLv2 or later, read the file 'LICENSE.GPLv2+' for
# more information.
#
# Authors:
# Bryce Harrington <bryce@canonical.com>
"""An individual DEP8 test run."""
import json
from functools import lru_cache
class Subtest:
"""An autopkgtest sub-component test run.
A triggered autopkgtest can invoke multiple DEP8 tests, such as running
checks on dependencies, the software's testsuite, and integration tests.
Each of these is considered a "Subtest"
"""
VALUES = {
'PASS': "🟩",
'SKIP': "🟧",
'FAIL': "🟥",
'FLAKY': "🟫",
'BAD': "â›”",
'UNKNOWN': "⚪"
}
def __init__(self, line):
"""Initialize a new Subtext object.
:param str line: The subtest result summary from a test log.
"""
if not line:
raise ValueError("undefined line.")
self._line = line
def __repr__(self) -> str:
"""Return a machine-parsable unique representation of object.
:rtype: str
:returns: Official string representation of the object.
"""
return (f'{self.__class__.__name__}('
f'line={self._line!r})')
def __str__(self) -> str:
"""Return a human-readable summary of the object.
:rtype: str
:returns: Printable summary of the object.
"""
return f"{self.desc:25} {self.status:6} {self.status_icon}"
@lru_cache
def to_dict(self) -> dict:
"""Return a basic dict structure of the Subtest's data."""
return {
'line': self._line,
'desc': self.desc,
'status': self.status,
'status_icon': self.status_icon
}
@property
@lru_cache
def desc(self) -> str:
"""The descriptive text for the given subtest.
:rtype: str
:returns: Descriptive text.
"""
return next(iter(self._line.split()), '')
@property
@lru_cache
def status(self) -> str:
"""The success or failure of the given subtest.
:rtype: str
:returns: Status term in capitalized letters (PASS, FAIL, etc.)
"""
for k in Subtest.VALUES:
if f" {k}" in self._line:
return k
return 'UNKNOWN'
@property
@lru_cache
def status_icon(self) -> str:
"""A unicode symbol corresponding to subtest's status.
:rtype: str
:returns: Single unicode character matching the status.
"""
return Subtest.VALUES[self.status]
if __name__ == "__main__":
print('##############################')
print('## Subtest class smoke test ##')
print('##############################')
print()
print("Valid cases")
print("-----------")
print(Subtest('subtest-a UNKNOWN'))
print(Subtest('subtest-b PASS'))
print(Subtest('subtest-c FAIL'))
print(Subtest('subtest-d FAIL non-zero exit status 123'))
print(Subtest('subtest-e SKIP'))
print(Subtest('subtest-f BAD'))
print(Subtest('librust-clang-sys-dev:clang_10_0 FAIL non-zero exit status 101'))
print(Subtest('librust-clang-sys-dev:static FLAKY non-zero exit status 101'))
print()
print("Invalid cases")
print("-------------")
print(Subtest('invalid subtest: invalid'))
print(Subtest('bAd subtest: bAd'))
print()
print("Object Dump")
print("-----------")
s = Subtest('librust-clang-sys-dev:clang_10_0 FAIL non-zero exit status 101')
print(json.dumps(s.to_dict(), indent=4))
print()
|