# Copyright (C) 2015 Chintalagiri Shashank
#
# This file is part of Tendril.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Testing Dox Module (:mod:`tendril.dox.testing`)
===============================================
This module provides functions to generate testing documents.
The functions here use the :mod:`tendril.dox.render` module to actually
produce the output files after constructing the appropriate stage.
.. seealso:: :mod:`tendril.testing.analysis`, which does much of
the heavy lifting
.. rubric:: Document Generators
.. autosummary::
render_test_report
render_device_summary
"""
import os
from tendril.testing import analysis
from tendril.utils.db import with_db
from tendril.entityhub import serialnos
from tendril.entityhub import projects
from tendril.gedaif.conffile import ConfigsFile
from tendril.utils import vcs
from tendril.entityhub.db.model import SerialNumber
from tendril.entityhub.db import controller as sno_controller
from render import render_pdf
import docstore
from tendril.utils.config import INSTANCE_ROOT
from tendril.utils import log
logger = log.get_logger(__name__, log.DEFAULT)
default_target = os.path.join(INSTANCE_ROOT, 'scratch', 'testing')
@with_db
[docs]def render_test_report(serialno=None, outfolder=None, session=None):
"""
Renders the latest test results marked against the specified ``serialno``.
Since this function is defined against the database, all arguments should
be keyword arguments.
:param serialno: The serial number of the device.
:type serialno: :class:`str` or :class:`tendril.entityhub.db.SerialNumber`
:param outfolder: The folder in which the output file should be created.
:type outfolder: str
:param session: The database session. If None, the function will make
it's own.
:return: The output file path.
.. rubric:: Template Used
``tendril/dox/templates/testing/test_report_template.tex``
(:download:`Included version
<../../tendril/dox/templates/testing/test_report_template.tex>`)
.. rubric:: Stage Keys Provided
.. list-table::
* - ``sno``
- Serial number of the device.
* - ``testdate``
- The timestamp of the latest test suite.
* - ``devicetype``
- The device type.
* - ``desc``
- The device description.
* - ``svnrevision``
- The VCS revision of the project config file.
* - ``svnrepo``
- The VCS repository containing the project
* - ``graphs``
- A list of graphs, each graph being a list of tuples of
(graphpath, graphtitle)
* - ``instruments``
- A list of instrument ident strings, one for each unique
instrument used in the suites.
* - ``suites``
- A list of instances of
:class:`tendril.testing.testbase.TestSuiteBase` or its subclasses.
Note that the ``suites`` provided to the template are typically
expected to be offline test suites which are reconstructed from the
database.
.. seealso:: :func:`tendril.testing.analysis.get_test_suite_objects`
"""
if serialno is None:
raise ValueError("serialno cannot be None")
if not isinstance(serialno, SerialNumber):
serialno = sno_controller.get_serialno_object(sno=serialno,
session=session)
if outfolder is None:
outfolder = os.path.join(INSTANCE_ROOT, 'scratch', 'testing')
template = os.path.join('testing', 'test_report_template.tex')
outpath = os.path.join(outfolder,
'TEST-REPORT-' + serialno.sno + '.pdf')
devicetype = serialnos.get_serialno_efield(sno=serialno.sno,
session=session)
projectfolder = projects.cards[devicetype]
gcf = ConfigsFile(projectfolder)
suites = analysis.get_test_suite_objects(serialno=serialno.sno,
session=session)
graphs = []
instruments = {}
for suite in suites:
for test in suite._tests:
graphs.extend(test.graphs)
graphs.extend(test.histograms)
if test._inststr is not None and \
test._inststr not in instruments.keys():
instruments[test._inststr] = len(instruments.keys()) + 1
stage = {'suites': [x.render_dox() for x in suites],
'sno': serialno.sno,
'testdate': max([x.ts for x in suites]).format(),
'devicetype': devicetype,
'desc': gcf.description(devicetype),
'svnrevision': vcs.get_path_revision(projectfolder),
'svnrepo': vcs.get_path_repository(projectfolder),
'graphs': graphs,
'instruments': instruments
}
return render_pdf(stage, template, outpath)
[docs]def gen_local_test_results(serialno, devicetype, suites, outfolder=None):
if serialno is None:
raise ValueError("serialno cannot be None")
if devicetype is None:
raise ValueError("devicetype cannot be None")
if suites is None:
raise ValueError("suites cannot be None")
if outfolder is None:
outfolder = os.path.join(INSTANCE_ROOT, 'scratch', 'testing')
outpath = os.path.join(outfolder, serialno + '.yaml')
# TODO Try with test data using suite.render or suite.render_dox
# fileOut = file(outpath, 'w')
# import yaml
# yaml.dump(suites, fileOut)
return outpath
[docs]def render_test_report_standalone(serialno, devicetype, suites, outfolder=None):
if serialno is None:
raise TypeError("serialno cannot be None")
if devicetype is None:
raise TypeError("devicetype cannot be None")
if suites is None:
raise TypeError("suites cannot be None")
if outfolder is None:
outfolder = os.path.join(INSTANCE_ROOT, 'scratch', 'testing')
template = os.path.join('testing', 'test_report_template.tex')
outpath = os.path.join(outfolder,
'TEST-REPORT-' + serialno + '.pdf')
projectfolder = projects.cards[devicetype]
gcf = ConfigsFile(projectfolder)
graphs = []
instruments = {}
for suite in suites:
for test in suite._tests:
graphs.extend(test.graphs)
graphs.extend(test.histograms)
if test._inststr is not None and \
test._inststr not in instruments.keys():
instruments[test._inststr] = len(instruments.keys()) + 1
stage = {'suites': [x.render_dox() for x in suites],
'sno': serialno,
'testdate': max([x.ts for x in suites]).format(),
'devicetype': devicetype,
'desc': gcf.description(devicetype),
'svnrevision': vcs.get_path_revision(projectfolder),
'svnrepo': vcs.get_path_repository(projectfolder),
'graphs': graphs,
'instruments': instruments
}
return render_pdf(stage, template, outpath)
[docs]def render_device_summary(devicetype, include_failed=False, outfolder=None):
"""
Renders a summary of all of the latest test results marked against the
serial numbers of the specified ``devicetype``.
:param devicetype: The type of device for which a summary is desired.
:type devicetype: str
:param outfolder: The folder in which the output file should be created.
:type outfolder: str
:param include_failed: Whether failed test results should be included in
the graphs and the statistical analysis. Default False.
:type include_failed: bool
:return: The output file path.
.. rubric:: Template Used
``tendril/dox/templates/testing/test_device_summary_template.tex``
(:download:`Included version
<../../tendril/dox/templates/testing/test_device_summary_template.tex>`)
.. rubric:: Stage Keys Provided
.. list-table::
* - ``devicetype``
- The device type.
* - ``desc``
- The device description.
* - ``svnrevision``
- The VCS revision of the project config file.
* - ``svnrepo``
- The VCS repository containing the project
* - ``graphs``
- A list of graphs, each graph being a list of tuples of
(graphpath, graphtitle)
* - ``collector``
- An instance of :class:`tendril.testing.analysis.ResultCollector`,
containing the collated test results.
.. seealso:: :func:`tendril.testing.analysis.get_device_test_summary`
"""
if outfolder is None:
outfolder = os.path.join(INSTANCE_ROOT, 'scratch', 'testing')
template = os.path.join('testing', 'test_device_summary_template.tex')
outpath = os.path.join(outfolder,
'TEST-DEVICE-SUMMARY-' + devicetype + '.pdf')
projectfolder = projects.cards[devicetype]
gcf = ConfigsFile(projectfolder)
summary = analysis.get_device_test_summary(devicetype=devicetype,
include_failed=include_failed)
graphs = summary.graphs
stage = {'devicetype': devicetype,
'desc': gcf.description(devicetype),
'svnrevision': vcs.get_path_revision(projectfolder),
'svnrepo': vcs.get_path_repository(projectfolder),
'graphs': graphs,
'collector': summary
}
return render_pdf(stage, template, outpath)
[docs]def get_all_test_reports(limit=None):
return docstore.get_docs_list_for_sno_doctype(serialno=None,
doctype='TEST-RESULT',
limit=limit)
[docs]def get_latest_test_report(serialno=None):
return docstore.get_docs_list_for_sno_doctype(serialno=serialno,
doctype='TEST-RESULT',
limit=1)