def run_test(serialno=None, force=False, stale=5): if serialno is None: raise AttributeError("serialno cannot be None") logger.info("Staring Test for Serial No : " + serialno) devicetype = serialnos.get_serialno_efield(sno=serialno) logger.info(serialno + " is device : " + devicetype) try: projectfolder = projects.cards[devicetype] except KeyError: raise AttributeError("Project for " + devicetype + " not found.") incremental = not force suites = run_electronics_test(serialno, devicetype, projectfolder, incremental=incremental, stale=stale) user_input = raw_input("Write to device [y/N] ?: ").strip() if user_input.lower() in ["y", "yes", "ok", "pass"]: write_to_device(serialno, devicetype) user_input = raw_input("Print to Paper [y/N] ?: ").strip() if user_input.lower() in ["y", "yes", "ok", "pass"]: publish_and_print(serialno, devicetype, print_to_paper=True) else: publish_and_print(serialno, devicetype, print_to_paper=False) return suites
def run_test(serialno=None, force=False, stale=5): if serialno is None: raise AttributeError("serialno cannot be None") logger.info("Staring Test for Serial No : " + serialno) devicetype = serialnos.get_serialno_efield(sno=serialno) logger.info(serialno + " is device : " + devicetype) try: projectfolder = projects.cards[devicetype] except KeyError: raise AttributeError("Project for " + devicetype + " not found.") incremental = not force suites = run_electronics_test(serialno, devicetype, projectfolder, incremental=incremental, stale=stale) user_input = raw_input("Write to device [y/N] ?: ").strip() if user_input.lower() in ['y', 'yes', 'ok', 'pass']: write_to_device(serialno, devicetype) user_input = raw_input("Print to Paper [y/N] ?: ").strip() if user_input.lower() in ['y', 'yes', 'ok', 'pass']: publish_and_print(serialno, devicetype, print_to_paper=True) else: publish_and_print(serialno, devicetype, print_to_paper=False) return suites
def _check_efield(self, sno): try: efield = serialnos.get_serialno_efield(sno=sno) except: raise ValidationError(self._message) if isinstance(self.efield, str) and efield != self.efield: raise ValidationError(self._message + " Efield must be '{0}'.".format(self.efield)) elif isinstance(self.efield, list) and efield not in self.efield: raise ValidationError(self._message + "'{0}' Efield not allowed.".format(efield))
def run(serialno=None): """ Write calibration to device. :param serialno: The serial number of the device. """ if serialno is None: raise AttributeError("serialno cannot be None") devicetype = serialnos.get_serialno_efield(sno=serialno) logger.info(serialno + " is device : " + devicetype) testrunner.write_to_device(serialno, devicetype)
def run(serialno=None): """ Write calibration to device. :param serialno: The serial number of the device. """ if serialno is None: raise AttributeError("serialno cannot be None") devicetype = serialnos.get_serialno_efield(sno=serialno) logger.info(serialno + " is device : " + devicetype) testrunner.write_to_device(serialno, devicetype)
def _check_efield(self, sno): try: efield = serialnos.get_serialno_efield(sno=sno) except: raise ValidationError(self._message) if isinstance(self.efield, str) and efield != self.efield: raise ValidationError( self._message + " Efield must be '{0}'.".format(self.efield) ) elif isinstance(self.efield, list) and efield not in self.efield: raise ValidationError( self._message + "'{0}' Efield not allowed.".format(efield) )
def validate_orig_cardname(form, field): cardname = field.data.strip() if form.sno.data and not cardname: raise ValidationError("Specify original Indent.") if form.target_cardname.data and not cardname: raise ValidationError("Specify original Indent.") if not cardname: return if cardname: if cardname not in cards.keys(): raise ValidationError("Ident not recognized.") try: efield = serialnos.get_serialno_efield(sno=form.sno.data.strip()) if cardname != efield: raise ValidationError("S.No. seems to be {0}.".format(efield)) except SerialNoNotFound: pass
def validate_orig_cardname(form, field): cardname = field.data.strip() if form.sno.data and not cardname: raise ValidationError("Specify original Indent.") if form.target_cardname.data and not cardname: raise ValidationError("Specify original Indent.") if not cardname: return if cardname: if cardname not in cards.keys(): raise ValidationError("Ident not recognized.") try: efield = serialnos.get_serialno_efield(sno=form.sno.data.strip()) if cardname != efield: raise ValidationError("S.No. seems to be {0}.".format(efield)) except SerialNoNotFound: pass
def run(serialno, force, stale, devicetype): """ Run tests for device. :param serialno: The serial number of the device. :param force: Re-run all test suites, even if fresh passed results exist. :param stale: Minimum age of test result to consider it stage. :param devicetype: Specify the device type for offline testing. """ if serialno is None: raise AttributeError("serialno cannot be None") if devicetype is None: devicetype = serialnos.get_serialno_efield(sno=serialno) logger.info(serialno + " is device : " + devicetype) testrunner.run_test(serialno, force=force, stale=stale) else: testrunner.run_test_offline(serialno, devicetype)
def get_mac_from_sno(serialno=None, session=None): devicetype = serialnos.get_serialno_efield(sno=serialno) try: projectfolder = projects.cards[devicetype] except KeyError: raise AttributeError("Project for " + devicetype + " not found.") try: gcf = ConfigsFile(projectfolder) logger.debug("Using gEDA configs file from : " + projects.cards[devicetype]) except NoGedaProjectError: raise AttributeError("gEDA project for " + devicetype + " not found.") modname = gcf.mactype funcname = 'get_mac_from_sno' mod = import_(os.path.join(macs_folder, modname)) func = getattr(mod, funcname) return func(serialno=serialno, session=session)
def get_mac_from_sno(serialno=None, session=None): devicetype = serialnos.get_serialno_efield(sno=serialno) try: projectfolder = projects.cards[devicetype] except KeyError: raise AttributeError("Project for " + devicetype + " not found.") try: gcf = ConfigsFile(projectfolder) logger.debug("Using gEDA configs file from : " + projects.cards[devicetype]) except NoGedaProjectError: raise AttributeError("gEDA project for " + devicetype + " not found.") modname = gcf.mactype funcname = 'get_mac_from_sno' mod = import_(os.path.join(macs_folder, modname)) func = getattr(mod, funcname) return func(serialno=serialno, session=session)
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
def gen_production_order(outfolder, prod_sno, sourcedata, snos, sourcing_orders=None, root_orders=None, verbose=True): """ Generates a Production Order for a production order defined in a ``.yaml`` file. .. note:: This function does not register the document in the :mod:`tendril.dox.docstore`. You should use the output file path (returned by this function) to register the document when desired. .. todo:: Update this function to also handle registering once the main scripts are better integrated into the core. .. todo:: Document the format of the .yaml file. :param outfolder: The folder within which the output file should be created. :type outfolder: str :param prod_sno: The serial number of the Production Order to generate. :type prod_sno: str :param sourcedata: The source data loaded from a ``.yaml`` file. :type sourcedata: dict :param snos: A list of serial numbers to produce, along with whatever other information should be included in the order. See the template for details. :type snos: :class:`list` of :class:`dict` :param sourcing_orders: A list of sourcing orders which were made to obtain raw materials for this production order. :type sourcing_orders: :class:`list` of :class:`str` :param root_orders: A list of root orders which is production order is intended to fulfill. :type root_orders: :class:`list` of :class:`str` :return: The path to the output PDF file. .. rubric:: Template Used ``tendril\dox\\templates\production\production-order-template.tex`` (:download:`Included version <../../tendril/dox/templates/production/production-order-template.tex>`) .. rubric:: Stage Keys Provided .. list-table:: * - ``sno`` - The serial number of the production order. * - ``title`` - The title of the production order. * - ``cards`` - A list of different card types to be produced, and quantities of each. * - ``snos`` - A list of cards to produce, with serial numbers and other included information. * - ``sourcing_orders`` - A list of sourcing orders which were made to obtain raw materials for this production order. * - ``root_orders`` - A list of root orders which is production order is intended to fulfill. """ cards = [] if 'cards' in sourcedata.keys(): cards = [{ 'qty': sourcedata['cards'][k], 'desc': ConfigsFile(projects.cards[k]).description(k), 'ident': k } for k in sorted(sourcedata['cards'].keys())] deltas = {} if 'deltas' in sourcedata.keys(): for delta in sourcedata['deltas']: desc = delta['orig-cardname'] + ' -> ' + delta['target-cardname'] if desc in deltas.keys(): deltas[desc] += 1 else: deltas[desc] = 1 lroot_orders = [] for root_order in root_orders: if root_order is not None: try: root_order_desc = serialnos.get_serialno_efield(root_order) except AttributeError: root_order_desc = None else: root_order_desc = None lroot_orders.append({'no': root_order, 'desc': root_order_desc}) stage = { 'title': sourcedata['title'], 'cards': cards, 'deltas': deltas, 'sourcing_orders': sourcing_orders, 'sno': prod_sno, 'snos': snos, 'root_orders': lroot_orders, } outpath = os.path.join(outfolder, str(prod_sno) + '.pdf') template = 'production/production-order-template.tex' render.render_pdf(stage, template, outpath, verbose=verbose) return outpath
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)
def get_test_report(serialno=None, session=None): """ Constructs and returns the stage components for 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 session: The database session. If None, the function will make it's own. :return: The output file path. .. 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 the htmlcontent generated by python-nvd3. * - ``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` .. todo:: Move this function into :mod:`tendril.testing.analysis` and have :func:`tendril.dox.testing.render_test_report` use the same infrastructure. """ 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) 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) instruments = {} for suite in suites: for test in suite._tests: 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), 'instruments': instruments } return stage
from tendril.entityhub.db import controller from tendril.entityhub import serialnos from tendril.utils.config import INSTANCE_ROOT from tendril.dox.labelmaker import manager if __name__ == '__main__': snos = [x.sno for x in controller.get_serialnos_by_efield(efield="QSENS-ACCEL1-1.7G") ] #snos += [x.sno for x in # controller.get_serialnos_by_efield(efield="QASC-T1-RTD-R3") # ] #snos += [x.sno for x in # controller.get_serialnos_by_efield(efield="QASC-LVDT-AD598-R2") # ] #snos += [x.sno for x in # controller.get_serialnos_by_efield(efield="CBL-STRAIN-HBC-A-120E") # ] #snos += [x.sno for x in # controller.get_serialnos_by_efield(efield="CBL-STRAIN-QBC-120E") # ] #snos += [x.sno for x in # controller.get_serialnos_by_efield(efield="CBL-PIEZO") # ] for sno in snos: product = products.get_product_by_core(serialnos.get_serialno_efield(sno=sno)) # noqa if product is not None: products.generate_labels(product, sno) manager.generate_pdfs(INSTANCE_ROOT, force=True)
from tendril.entityhub import serialnos from tendril.utils.config import INSTANCE_ROOT from tendril.dox.labelmaker import manager if __name__ == '__main__': snos = [ x.sno for x in controller.get_serialnos_by_efield(efield="QSENS-ACCEL1-1.7G") ] #snos += [x.sno for x in # controller.get_serialnos_by_efield(efield="QASC-T1-RTD-R3") # ] #snos += [x.sno for x in # controller.get_serialnos_by_efield(efield="QASC-LVDT-AD598-R2") # ] #snos += [x.sno for x in # controller.get_serialnos_by_efield(efield="CBL-STRAIN-HBC-A-120E") # ] #snos += [x.sno for x in # controller.get_serialnos_by_efield(efield="CBL-STRAIN-QBC-120E") # ] #snos += [x.sno for x in # controller.get_serialnos_by_efield(efield="CBL-PIEZO") # ] for sno in snos: product = products.get_product_by_core( serialnos.get_serialno_efield(sno=sno)) # noqa if product is not None: products.generate_labels(product, sno) manager.generate_pdfs(INSTANCE_ROOT, force=True)
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
def gen_production_order(outfolder, prod_sno, sourcedata, snos, sourcing_orders=None, root_orders=None, verbose=True): """ Generates a Production Order for a production order defined in a ``.yaml`` file. .. note:: This function does not register the document in the :mod:`tendril.dox.docstore`. You should use the output file path (returned by this function) to register the document when desired. .. todo:: Update this function to also handle registering once the main scripts are better integrated into the core. .. todo:: Document the format of the .yaml file. :param outfolder: The folder within which the output file should be created. :type outfolder: str :param prod_sno: The serial number of the Production Order to generate. :type prod_sno: str :param sourcedata: The source data loaded from a ``.yaml`` file. :type sourcedata: dict :param snos: A list of serial numbers to produce, along with whatever other information should be included in the order. See the template for details. :type snos: :class:`list` of :class:`dict` :param sourcing_orders: A list of sourcing orders which were made to obtain raw materials for this production order. :type sourcing_orders: :class:`list` of :class:`str` :param root_orders: A list of root orders which is production order is intended to fulfill. :type root_orders: :class:`list` of :class:`str` :return: The path to the output PDF file. .. rubric:: Template Used ``tendril\dox\\templates\production\production-order-template.tex`` (:download:`Included version <../../tendril/dox/templates/production/production-order-template.tex>`) .. rubric:: Stage Keys Provided .. list-table:: * - ``sno`` - The serial number of the production order. * - ``title`` - The title of the production order. * - ``cards`` - A list of different card types to be produced, and quantities of each. * - ``snos`` - A list of cards to produce, with serial numbers and other included information. * - ``sourcing_orders`` - A list of sourcing orders which were made to obtain raw materials for this production order. * - ``root_orders`` - A list of root orders which is production order is intended to fulfill. """ cards = [] if 'cards' in sourcedata.keys(): cards = [{'qty': sourcedata['cards'][k], 'desc': ConfigsFile(projects.cards[k]).description(k), 'ident': k} for k in sorted(sourcedata['cards'].keys())] deltas = {} if 'deltas' in sourcedata.keys(): for delta in sourcedata['deltas']: desc = delta['orig-cardname'] + ' -> ' + delta['target-cardname'] if desc in deltas.keys(): deltas[desc] += 1 else: deltas[desc] = 1 lroot_orders = [] for root_order in root_orders: if root_order is not None: try: root_order_desc = serialnos.get_serialno_efield(root_order) except AttributeError: root_order_desc = None else: root_order_desc = None lroot_orders.append({'no': root_order, 'desc': root_order_desc}) stage = { 'title': sourcedata['title'], 'cards': cards, 'deltas': deltas, 'sourcing_orders': sourcing_orders, 'sno': prod_sno, 'snos': snos, 'root_orders': lroot_orders, } outpath = os.path.join(outfolder, str(prod_sno) + '.pdf') template = 'production/production-order-template.tex' render.render_pdf(stage, template, outpath, verbose=verbose) return outpath
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)
def get_test_report(serialno=None, session=None): """ Constructs and returns the stage components for 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 session: The database session. If None, the function will make it's own. :return: The output file path. .. 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 the htmlcontent generated by python-nvd3. * - ``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` .. todo:: Move this function into :mod:`tendril.testing.analysis` and have :func:`tendril.dox.testing.render_test_report` use the same infrastructure. """ 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) 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) instruments = {} for suite in suites: for test in suite._tests: 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), 'instruments': instruments } return stage