Skip to content

Commit

Permalink
[ADD] tests_summary
Browse files Browse the repository at this point in the history
  • Loading branch information
paradoxxxzero committed Nov 20, 2024
1 parent 57d7ef2 commit bb321e1
Show file tree
Hide file tree
Showing 11 changed files with 754 additions and 0 deletions.
1 change: 1 addition & 0 deletions setup/tests_summary/odoo/addons/tests_summary
6 changes: 6 additions & 0 deletions setup/tests_summary/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import setuptools

setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)
94 changes: 94 additions & 0 deletions tests_summary/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
============
Test Summary
============

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:126364c9ac7a093bc9b07176ff3b3cf0026146b57743ec5486d79788f96cd1e7
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github
:target: https://github.com/OCA/server-tools/tree/14.0/tests_summary
:alt: OCA/server-tools
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/server-tools-14-0/server-tools-14-0-tests_summary
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/server-tools&target_branch=14.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

Add this module to your ``server_wide_modules`` list in your odoo.conf
file to enable the tests summary feature.

At the end of the tests, a summary will be displayed in the logs for
quick review of the test failures grouped by module.

The summary will look like this:

|Tests Summary Tests Summary|

.. |Tests Summary Tests Summary| image:: https://raw.githubusercontent.com/OCA/server-tools/14.0/tests_summary/static/description/tests_summary.png

**Table of contents**

.. contents::
:local:

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-tools/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/server-tools/issues/new?body=module:%20tests_summary%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Akretion

Contributors
------------

- Florian Mounier [email protected]

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

.. |maintainer-paradoxxxzero| image:: https://github.com/paradoxxxzero.png?size=40px
:target: https://github.com/paradoxxxzero
:alt: paradoxxxzero

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-paradoxxxzero|

This module is part of the `OCA/server-tools <https://github.com/OCA/server-tools/tree/14.0/tests_summary>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
165 changes: 165 additions & 0 deletions tests_summary/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# Copyright 2024 Akretion (http://www.akretion.com).
# @author Florian Mounier <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from unittest.mock import patch
from collections import defaultdict
import logging
import re
import os

from odoo.tools import config
from odoo.service.server import preload_registries
from odoo.modules.registry import Registry


class Colorize:
colors = ("black", "red", "green", "yellow", "blue", "magenta", "cyan", "white")

def __init__(self, logger):
self.active = os.name == "posix" and all(
isinstance(handler, logging.StreamHandler)
and hasattr(handler.stream, "fileno")
and os.isatty(handler.stream.fileno())
for handler in logger.handlers
)

def bold(self, text):
if not self.active:
return text
return f"\033[1m{text}\033[0m"

Check warning on line 30 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L29-L30

Added lines #L29 - L30 were not covered by tests

def color(self, text, color, bold=False):
if not self.active:
return text
return (

Check warning on line 35 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L34-L35

Added lines #L34 - L35 were not covered by tests
f"\033[{30 + self.colors.index(color)}{';1' if bold else ''}m{text}\033[0m"
)

def __getattr__(self, attr):
if attr in self.colors:
return lambda text, bold=False: self.color(text, attr, bold)
return super().__getattr__(attr)

Check warning on line 42 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L42

Added line #L42 was not covered by tests


def maybe_pluralize(n, singular, plural=None):
return f"{n} {singular if n == 1 else (plural or singular + 's')}"

Check warning on line 46 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L46

Added line #L46 was not covered by tests


module_re = re.compile(r"odoo\.addons\.(\w+)")


def get_module(test):
if hasattr(test, "test_module"):
return test.test_module

Check warning on line 54 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L54

Added line #L54 was not covered by tests
for key in ("description", "test_description", "test_id"):
if hasattr(test, key):
match = module_re.search(getattr(test, key))

Check warning on line 57 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L57

Added line #L57 was not covered by tests
if match:
return match.group(1)
return "unknown (%s)" % repr(test)

Check warning on line 60 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L59-L60

Added lines #L59 - L60 were not covered by tests


def get_test_name(test):
if hasattr(test, "_testMethodName"):
name = ""

Check warning on line 65 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L65

Added line #L65 was not covered by tests
if hasattr(test, "test_class"):
name += test.test_class + "."
name += test._testMethodName
return name

Check warning on line 69 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L67-L69

Added lines #L67 - L69 were not covered by tests
for key in ("description", "test_description", "test_id"):
if getattr(test, key, False):
return getattr(test, key)
return "unknown (%s)" % repr(test)

Check warning on line 73 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L72-L73

Added lines #L72 - L73 were not covered by tests


def preload_registries_and_display_test_results(dbnames):
_logger = logging.getLogger(__name__)
rc = preload_registries(dbnames)
c = Colorize(_logger)
types = {

Check warning on line 80 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L77-L80

Added lines #L77 - L80 were not covered by tests
"errors": "error",
"failures": "failure",
"skipped": "skip",
"expectedFailures": "expected failure",
"unexpectedSuccesses": "unexpected success",
}
colors = {

Check warning on line 87 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L87

Added line #L87 was not covered by tests
"errors": "red",
"failures": "red",
"skipped": "yellow",
"expectedFailures": "green",
"unexpectedSuccesses": "cyan",
}
for db in dbnames:
report = Registry.registries[db]._assertion_report

Check warning on line 95 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L95

Added line #L95 was not covered by tests

modules_infos = defaultdict(list)

Check warning on line 97 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L97

Added line #L97 was not covered by tests
for type_ in types:
for test_info in getattr(report, type_):
test, info = (

Check warning on line 100 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L100

Added line #L100 was not covered by tests
test_info
if isinstance(test_info, tuple) and len(test_info) == 2
else (test_info, "Success")
)
modules_infos[get_module(test)].append(

Check warning on line 105 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L105

Added line #L105 was not covered by tests
{"type": type_, "info": info, "test": test}
)

message = "\n\n" + c.bold(f"Database {db}: ") + f"{report.testsRun} tests run"

Check warning on line 109 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L109

Added line #L109 was not covered by tests
for type_, type_name in types.items():
if getattr(report, type_):
message += ", " + c.color(

Check warning on line 112 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L112

Added line #L112 was not covered by tests
maybe_pluralize(len(getattr(report, type_)), type_name),
colors[type_],
True,
)

if len(modules_infos):
message += f" in {len(modules_infos)} modules."

Check warning on line 119 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L119

Added line #L119 was not covered by tests

message += "\n\n"

Check warning on line 121 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L121

Added line #L121 was not covered by tests

for module, infos in modules_infos.items():
message += c.black("+" + "-" * (len(module) + 2) + "+", True) + "\n"
message += c.black("| ", True) + c.bold(module) + c.black(" |", True) + "\n"
message += c.black("+" + "-" * (len(module) + 2) + "+", True) + "\n"

Check warning on line 126 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L124-L126

Added lines #L124 - L126 were not covered by tests
for type_, type_name in types.items():
type_infos = [info for info in infos if info["type"] == type_]
if type_infos:
message += (

Check warning on line 130 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L130

Added line #L130 was not covered by tests
c.color(
maybe_pluralize(len(type_infos), type_name) + ":",
colors[type_],
True,
)
+ "\n"
)
for info in type_infos:
message += (

Check warning on line 139 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L139

Added line #L139 was not covered by tests
c.black(
" - "
+ (
(info["test"].__module__.split(".")[-1] + ":")
if getattr(info["test"], "__module__", False)
else ""
),
True,
)
+ c.bold(get_test_name(info["test"]) + ":")
+ "\n"
)
message += info["info"].rstrip("\n") + "\n\n"

Check warning on line 152 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L152

Added line #L152 was not covered by tests

getattr(_logger, "error" if report.errors or report.failures else "info")(

Check warning on line 154 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L154

Added line #L154 was not covered by tests
message
)

return rc

Check warning on line 158 in tests_summary/__init__.py

View check run for this annotation

Codecov / codecov/patch

tests_summary/__init__.py#L158

Added line #L158 was not covered by tests


if config["test_enable"]:
patch(
"odoo.service.server.preload_registries",
preload_registries_and_display_test_results,
).start()
17 changes: 17 additions & 0 deletions tests_summary/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2024 Akretion (http://www.akretion.com).
# @author Florian Mounier <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
"name": "Test Summary",
"version": "14.0.1.0.0",
"author": "Akretion,Odoo Community Association (OCA)",
"summary": "Odoo patch to display a summary of failed tests at the end "
"of odoo startup",
"website": "https://github.com/OCA/server-tools",
"maintainers": ["paradoxxxzero"],
"license": "AGPL-3",
"category": "Generic Modules",
"depends": [],
"data": [],
}
1 change: 1 addition & 0 deletions tests_summary/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Florian Mounier <[email protected]>
9 changes: 9 additions & 0 deletions tests_summary/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Add this module to your `server_wide_modules` list in your odoo.conf file to enable the
tests summary feature.

At the end of the tests, a summary will be displayed in the logs for quick review of the
test failures grouped by module.

The summary will look like this:

![Tests Summary Tests Summary](../static/description/tests_summary.png)
Loading

0 comments on commit bb321e1

Please sign in to comment.