Commit c69ae313 authored by Ian Norton's avatar Ian Norton 🌏
Browse files

31.1.4 timings in the matrix

* Sort by class name in matrix view
* Show 5 slowest suites in matrix view
* Sync dark and classic themes

Also:
Add `-s` shortcut for `--summary-matrix`
Add `-m` shortcut for `--report-matrix`
Added a test data generator
parent 69383199
Loading
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
    - python -m pytest -v . --junitxml=junit2html-job-${CI_JOB_NAME}.xml
    - python -m junit2htmlreport junit2html-job-${CI_JOB_NAME}.xml
    - python -m junit2htmlreport --merge junit2html-merged-example.xml tests/junit-unicode.xml tests/junit-unicode2.xml tests/junit-cute2.xml
    - python -m junit2htmlreport -m tests/large-matrix.html tests/test_large_random1.xml tests/test_large_random2.xml tests/test_large_random3.xml tests/test_large_random4.xml tests/test_large_random5.xml tests/test_large_random6.xml tests/test_large_random7.xml
    - python -m junit2htmlreport junit2html-merged-example.xml
    - python -m build -w
    - python -m junit2htmlreport --summary-matrix - < junit2html-job-${CI_JOB_NAME}.xml
+25 −1
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@ class ReportMatrix(ReportContainer):
        self.casenames = {}
        self.result_stats = {}
        self.case_results = {}
        self.class_timings = {}
        self.class_anchors = {}

    def add_case_result(self, case: "Case"):
        if case.testclass is None or case.testclass.name is None:
@@ -88,6 +90,9 @@ class ReportMatrix(ReportContainer):
            for testclass in suite.classes:
                if testclass not in self.classes:
                    self.classes[testclass] = {}
                    self.class_timings[testclass] = 0
                    self.class_anchors[testclass] = f"cls_{len(self.class_anchors)}"
                self.class_timings[testclass] += suite.classes[testclass].duration
                if testclass not in self.casenames:
                    self.casenames[testclass] = list()
                self.classes[testclass][filename] = suite.classes[testclass]
@@ -148,10 +153,27 @@ class ReportMatrix(ReportContainer):
            return self.short_outcome(CaseResult.UNTESTED), CaseResult.UNTESTED.title()
        return " ", ""

    def class_time_breakdown(self) -> "Dict[str, float]":
        """Sort the matrix by duration of each class (largest first)"""
        total_time = sum(self.class_timings.values())
        pct = {}
        total = 0
        breaks = 0
        for classname, classtime in sorted(self.class_timings.items(), key=lambda x: x[1], reverse=True):
            frac = classtime / total_time
            total += classtime
            breaks += 1
            if classname not in pct:
                pct[classname] = 0
            pct[classname] += frac

        return pct


class HTMLMatrix:
    def __init__(self, matrix: "ReportMatrix"):
        self.matrix = matrix
        self.show_time_usage = True
        self.title: str = "JUnit Matrix"

    def __str__(self) -> str:
@@ -161,7 +183,9 @@ class HTMLMatrix:
            autoescape=select_autoescape(["html"])
        )
        template = env.get_template("matrix.html")
        return template.render(matrix=self.matrix, title=self.title)
        return template.render(matrix=self.matrix,
                               show_time_usage=self.show_time_usage,
                               title=self.title)


class HtmlReportMatrix(ReportMatrix):
+15 −1
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ Parse a junit report file into a family of objects
"""
from __future__ import unicode_literals

import xml.dom
from typing import TYPE_CHECKING

import os
@@ -110,6 +111,10 @@ class Class(AnchorBase):
        super(Class, self).__init__()
        self.cases = list()

    @property
    def duration(self) -> float:
        return sum((x.duration for x in self.cases))


class Property(AnchorBase, ToJunitXmlBase):
    """
@@ -258,7 +263,7 @@ class Suite(AnchorBase, ToJunitXmlBase):
    name: "Optional[str]" = None
    properties: "List[Property]"
    classes: "OrderedDict[str, Class]"
    duration: float = 0
    _duration: float = 0
    package: "Optional[str]" = None
    errors: "List[Dict[str, Optional[Union[str,Any]]]]"
    stdout: "Optional[Union[str,Any]]" = None
@@ -270,6 +275,15 @@ class Suite(AnchorBase, ToJunitXmlBase):
        self.properties = []
        self.errors = []

    @property
    def duration(self) -> float:
        total = sum((x.duration for x in self.classes.values()))
        return max(total, self._duration)

    @duration.setter
    def duration(self, value: float) -> None:
        self._duration = value

    def tojunit(self):
        """
        Return an element for this whole suite and all it's cases
+6 −2
Original line number Diff line number Diff line
@@ -120,8 +120,9 @@ class ReportContainer(JunitLoaderBase):

class HTMLReport:

    def __init__(self, show_toc: bool=True):
    def __init__(self, show_toc: bool=True, show_time_usage: bool=True):
        self.show_toc = show_toc
        self.show_time_usage = show_time_usage
        self.title: str = ""
        self.report: "Optional[Junit]" = None

@@ -139,5 +140,8 @@ class HTMLReport:
        loader = self.report.loader_factory.get_loader()
        env = Environment(loader=loader, autoescape=select_autoescape(["html"]))
        template = env.get_template("report.html")
        return template.render(report=self, title=self.title, show_toc=self.show_toc)
        return template.render(report=self,
                               title=self.title,
                               show_toc=self.show_toc,
                               show_time_usage=self.show_time_usage)
+2 −2
Original line number Diff line number Diff line
@@ -17,11 +17,11 @@ installed_themes = sorted(list(loader_factory.styles))

PARSER = ArgumentParser(prog="junit2html")

PARSER.add_argument("--summary-matrix", dest="text_matrix", action="store_true",
PARSER.add_argument("--summary-matrix", "-s", dest="text_matrix", action="store_true",
                    default=False,
                    help="Render multiple result files to the console")

PARSER.add_argument("--report-matrix", dest="html_matrix", type=str,
PARSER.add_argument("--report-matrix", "-m", dest="html_matrix", type=str,
                    metavar="REPORT",
                    help="Generate an HTML report matrix")

Loading