Coverage for /media/ldata/code/tendril/tendril/testing/analysis.py : 0%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
|
""" This file is part of tendril See the COPYING, README, and INSTALL files for more information """
import os import re import numpy
from tendril.utils.db import with_db from tendril.entityhub import serialnos from tendril.entityhub import projects from tendril.entityhub.db import controller as sno_controller from tendril.boms.electronics import import_pcb from tendril.dox.render import make_histogram from tendril.utils.fsutils import TEMPDIR from tendril.utils.fsutils import get_tempname
from db import controller from testbase import TestSuiteBase from tests import get_test_object from testrunner import get_electronics_test_suites
from matplotlib import pyplot
from tendril.utils import log logger = log.get_logger(__name__, log.INFO)
rex_class = re.compile(ur'^<class \'(?P<cl>[a-zA-Z0-9.]+)\'>$')
def sort_by_order(desc, order): rval = [] for d in order: for od, on in desc: if d == od: rval.append((od, on)) desc.remove((od, on)) break rval.extend(desc) return rval
@with_db def get_test_suite_objects(serialno=None, order_by='FILE_ORDER', session=None): # This reconstructs the test objects from the database. Using SQLAlchemy # as the ORM that it is, and letting it handle the object creation would # be infinitely better. It isn't done here since the models are separate # from the actual test objects, which in turn have other dependencies. # Integrating the models with the classes should be considered in the # future when there is time. # suite_names = controller.get_test_suite_names(serialno=serialno, # session=session) suite_descs = controller.get_test_suite_descs(serialno=serialno, session=session) devicetype = serialnos.get_serialno_efield(sno=serialno, session=session) projectfolder = projects.cards[devicetype] bomobj = import_pcb(cardfolder=projectfolder) # Perhaps this bomobject should not be recreated on the fly. bomobj.configure_motifs(devicetype)
if order_by == 'FILE_ORDER':
logger.info("Creating dummy test suites for file ordering") dummy_suites = get_electronics_test_suites(None, devicetype, projectfolder, offline=True) ldummy_suites = [] for suite in dummy_suites: suite.dummy = True ldummy_suites.append(suite)
file_order = [(x.desc, [(y.desc, y.passfailonly) for y in x.tests]) for x in ldummy_suites] suite_order = [x[0] for x in file_order] test_order = {x[0]: x[1] for x in file_order}
elif order_by == 'DONT_CARE': suite_order = [] test_order = {}
else: raise ValueError('Unknown order_by heuristic : ' + order_by)
suites = [] suite_descs = sort_by_order(suite_descs, suite_order)
# for suite_name in suite_names: for desc, name in suite_descs: suite_db_obj = controller.get_latest_test_suite( serialno=serialno, suite_class=name, descr=desc, session=session ) if suite_db_obj.suite_class == \ "<class 'tendril.testing.testbase.TestSuiteBase'>": suite_obj = TestSuiteBase() else: raise ValueError("Unrecognized suite_class : " + suite_db_obj.suite_class)
suite_obj.desc = suite_db_obj.desc suite_obj.title = suite_db_obj.title suite_obj.ts = suite_db_obj.created_at suite_obj.serialno = serialno if order_by == 'FILE_ORDER': test_display_params = {x[0]: x[1] for x in test_order[suite_obj.desc]}
for test_db_obj in suite_db_obj.tests: class_name = rex_class.match(test_db_obj.test_class).group('cl')
test_obj = get_test_object(class_name, offline=True) test_obj.desc = test_db_obj.desc test_obj.title = test_db_obj.title test_obj.ts = test_db_obj.created_at test_obj.use_bom(bomobj) test_obj.load_result_from_obj(test_db_obj.result) if order_by == 'FILE_ORDER': test_obj.passfailonly = test_display_params[test_obj.desc] suite_obj.add_test(test_obj) # Crosscheck test passed?
# Crosscheck suite passed?
suites.append(suite_obj)
return suites
class ResultGraphCollector(object): def __init__(self, dummy_graph, parent): self._parent = parent a, b, self._dummy_graph_params, self._dummy_graph_title = dummy_graph self._collected = []
def add_graph(self, graph): self._collected.append(graph)
def _make_graph(self, color='black', lw=2, marker=None, xscale='linear', yscale='linear', xlabel='', ylabel=''): outpath = os.path.join(TEMPDIR, 'GRAPH_GROUP_' + get_tempname() + '.png' ) for graph in self._collected: pyplot.plot(graph[0], graph[1], color=color, lw=lw, marker=marker) pyplot.xscale(xscale) pyplot.yscale(yscale) pyplot.grid(True, which='major', color='0.3', linestyle='-') pyplot.grid(True, which='minor', color='0.3') pyplot.xlabel(xlabel, fontsize=20) pyplot.ylabel(ylabel, fontsize=20) pyplot.tick_params(axis='both', which='major', labelsize=16) pyplot.tick_params(axis='both', which='minor', labelsize=8) pyplot.tight_layout() pyplot.savefig(outpath) pyplot.close() return outpath
def _make_graphs(self): outpath = self._make_graph(**self._dummy_graph_params) return outpath, self._dummy_graph_title
@property def graphs(self): return [self._make_graphs()]
class ResultLineCollector(object): def __init__(self, dummy_line, parent): self._parent = parent self._dummy_line = dummy_line self._parser = dummy_line.measured self._collected = []
def add_line(self, line): if self._parser is not None: self._collected.append(self._parser(line.measured)) else: self._collected.append(line.measured)
def get_range(self): if self._dummy_line.expected is None: return None center, op, merror = self._dummy_line.expected.split(' ') center = self._parser(center) merror = self._parser(merror) return float(center - merror), float(center + merror)
@property def graphs(self): if self._parser is not None: # rng = self.get_range() rng = None path = os.path.join(TEMPDIR, 'hist_' + get_tempname() + '.png') hist = make_histogram(path, [float(x) for x in self._collected], xlabel=self.desc, x_range=rng) return [(hist, self._parent.desc)] return []
@property def desc(self): return self._dummy_line.desc
@property def expected(self): return self._dummy_line.expected
@property def measured(self): if self._parser is not None: return ( sum(self._collected) / len(self._collected) ).quantized_repr else: return 'VARIOUS'
@property def maxp(self): if self._parser is not None: return max(self._collected).quantized_repr return None
@property def minp(self): if self._parser is not None: return min(self._collected).quantized_repr return None
@property def spread(self): if self._parser is not None: spread = self.maxp - self.minp return spread.integral_repr else: return None
@property def std_dev(self): if self._parser is not None: return self._parser( numpy.std([float(x) for x in self._collected]) ).integral_repr return None
class ResultTestCollector(object): def __init__(self, dummy_test, include_failed=False): self._line_collectors = [] self._graph_collectors = [] self._dummy_test = dummy_test self._total_count = 0 self._passed_count = 0 self._include_failed = include_failed for line in dummy_test.lines: self._line_collectors.append(ResultLineCollector(line, self)) for graph in dummy_test.graphs_data: self._graph_collectors.append(ResultGraphCollector(graph, self))
@property def classname(self): return str(self._dummy_test.__class__)
@property def desc(self): return self._dummy_test.desc
@property def title(self): return self._dummy_test.title
def add_test(self, test): if str(test.__class__) != str(self._dummy_test.__class__): raise TypeError( "Test Class does not match : " + str(test.__class__) + ", expected " + str(self._dummy_test.__class__) ) self._total_count += 1 if test.passed is True: self._passed_count += 1 if self._include_failed is True or test.passed is True: for idx, line in enumerate(test.lines): self._line_collectors[idx].add_line(line) for idx, graph in enumerate(test.graphs_data): self._graph_collectors[idx].add_graph(graph)
@property def graphs(self): rval = [] for collectors in self._graph_collectors: rval.extend(collectors.graphs) for collectors in self._line_collectors: rval.extend(collectors.graphs) return rval
@property def lines(self): return self._line_collectors
@property def total_count(self): return self._total_count
@property def passed_count(self): return self._passed_count
class ResultSuiteCollector(object): def __init__(self, dummy_suite, include_failed=False): self._test_collectors = [] self._dummy_suite = dummy_suite self._total_count = 0 self._passed_count = 0 for test in dummy_suite.tests: self._test_collectors.append( ResultTestCollector(test, include_failed=include_failed) )
def get_collector(self, name, desc): rval = [] for collector in self._test_collectors: if collector.classname == name: rval.append(collector) if len(rval) == 1: return rval[0] else: for collector in rval: if collector.desc == desc: return collector raise ValueError("Can't find collector : " + name + " " + desc)
def add_suite(self, suite): if str(suite.__class__) != str(self._dummy_suite.__class__): raise TypeError( "Suite Class does not match : " + str(suite.__class__) + ", expected " + str(self._dummy_suite.__class__) ) self._total_count += 1 if suite.passed is True: self._passed_count += 1 for idx, test in enumerate(suite.tests): collector = self.get_collector(str(test.__class__), test.desc) collector.add_test(test)
@property def graphs(self): rval = [] for collectors in self._test_collectors: rval.extend(collectors.graphs) return rval
@property def classname(self): return str(self._dummy_suite.__class__)
@property def desc(self): return self._dummy_suite.desc
@property def title(self): return self._dummy_suite.title
@property def tests(self): return self._test_collectors
@property def total_count(self): return self._total_count
@property def passed_count(self): return self._passed_count
class ResultCollector(object): def __init__(self, dummy_suites, include_failed=False): self._suite_collectors = [] for suite in dummy_suites: self._suite_collectors.append( ResultSuiteCollector(suite, include_failed=include_failed) )
def add_suites_set(self, suites): for idx, suite in enumerate(suites): self._suite_collectors[idx].add_suite(suite)
@property def graphs(self): rval = [] for collectors in self._suite_collectors: rval.extend(collectors.graphs) return rval
@property def suites(self): return self._suite_collectors
@with_db def get_device_test_summary(devicetype=None, include_failed=False, session=None): projectfolder = projects.cards[devicetype] bomobj = import_pcb(cardfolder=projectfolder) bomobj.configure_motifs(devicetype)
logger.info("Creating dummy test suites") dummy_suites = get_electronics_test_suites(None, devicetype, projectfolder, offline=True) for suite in dummy_suites: suite.dummy = True
collector = ResultCollector(dummy_suites, include_failed=include_failed)
snos = sno_controller.get_serialnos_by_efield(efield=devicetype, session=session)
for sno in snos: suites = get_test_suite_objects(serialno=sno.sno, session=session) if len(suites) > 0: collector.add_suites_set(suites)
return collector |