def __init__(self, test_context: TestContext): AbstractRichOutput.__init__(self) HTMLTemplateMixin.__init__(self) assert test_context.start_datetime is not None, \ "The test context has to have been started before attempting to construct a test report from it" assert test_context.end_datetime is not None, \ "The test context has to have been ended before attempting to construct a test report from it" assert len(test_context.results) > 0, \ "The test context has to have at least on test (!= 0) to construct a test report from it" # constructed attributes self.context = test_context # derived attributes from context self.config = self.context.config self.platform = str(self.context.platform) self.version = self.context.version self.results = self.context.results self.name = self.context.name self.folder_name = self.context.folder_name self.folder_path = self.context.folder_path self.start = self.context.start_datetime.strftime(self.DATETIME_FORMAT) self.end = self.context.end_datetime.strftime(self.DATETIME_FORMAT) self.duration = int( (self.context.end_datetime - self.context.start_datetime).seconds / 60) self.tests = self.context.tests self.hardware_version = self.context.hardware_version self.firmware_version = self.context.firmware_version self.sensor_version = self.context.sensor_version # derived attributes from config self.repository_url = self.config.get_repository_url() self.documentation_url = self.config.get_documentation_url() self.sensor = "{} x {} pixels".format(self.config.get_sensor_height(), self.config.get_sensor_width()) self.test_descriptions = { name: test.description for name, test in self.tests.items() } # calculated attributes self.test_count = len(self.results) self.successful_results = { test_name: result for test_name, result in self.results.items() if result.passing } self.successful_count = len(self.successful_results) self.error_count = self.test_count - self.successful_count self.success_ratio = round(self.successful_count / self.test_count, 2) self.result_dicts = { name: result.to_dict() for name, result in self.results.items() }
def recompile(config): """ This command recompiles all the static HTML files of the test reports. All test reports are actually static HTML files, which are created from a template after the corresponding test run finishes. This presents an issue if any web interface related changes are made to the config or if the html templates are updated with a new release version. In such a case the test report html pages would not reflect the changes. In this case, the "recompile" command can be used to recreate the static html files using the current config / template versions. """ # THE PROBLEM # So this is the problem: Test reports are actually static html files. These html templates for each test reports # are rendered once the test run finishes and then they are just html files. In contrary to dynamically creating # the html content whenever the corresponding request is made. And I would like to keep it like this, because the # it is easier to handle in other regards, but this poses the following problem: If certain changes are made to the # server these are not reflected within the rest report html pages. The most pressing problem is if the URL changes # This will break all links on the test report pages. Another issue is when a new version of ufotest introduces # changes to the report template, which wont be reflected in older reports. # THE IDEA # The "recompile" command should fix this by recreating all the test report static html files with the current # version of the report template based on the info in the report.json file ctitle('RECOMPILE TEST REPORT HTML') cparams({'archive folder': config.get_archive_path()}) count = 0 for root, folders, files in os.walk(config.get_archive_path()): for folder in folders: folder_path = os.path.join(root, folder) report_json_path = os.path.join(folder_path, 'report.json') report_html_path = os.path.join(folder_path, 'report.html') if not os.path.exists(report_json_path): continue with open(report_json_path, mode='r+') as file: report_data = json.load(file) with open(report_html_path, mode='w+') as file: # "report_data" is only the dict representation of the test report. This is problematic because we # cannot call the "to_html" method then. But the test report class and all the test result classes # implement the HTMLTemplateMixin class, which enables to render the html template from just this dict # representation using the static method "html_from_dict". This is possible because the dict itself # saves the entire template string in one of its fields. html = HTMLTemplateMixin.html_from_dict(report_data) file.write(html) cprint(f'Recompiled test report {folder}') count += 1 break cresult(f'Recompiled {count} test reports!') sys.exit(0)
def test_rendering_html_from_loaded_json_string(self): """ If an instance which has been exported to a JSON string and loaded into a dict can be rendered as html. This should not be different from just the dict version but just for completeness """ local = HelloWorldParagraph() local_dict = local.to_dict() json_string = json.dumps(local_dict) del local, local_dict loaded_dict = json.loads(json_string) html = HTMLTemplateMixin.html_from_dict(loaded_dict) expected_html = "<p>Hello World</p>" self.assertEqual(expected_html, html)
def to_dict(self) -> dict: return { **HTMLTemplateMixin.to_dict(self), 'platform': self.platform, 'version': self.version, 'sensor': self.sensor, 'name': self.name, 'folder_name': self.folder_name, 'folder_path': self.folder_path, 'start': self.start, 'start_iso': self.context.start_datetime.isoformat(), 'end': self.end, 'end_iso': self.context.end_datetime.isoformat(), 'duration': self.duration, 'test_count': self.test_count, 'successful_count': self.successful_count, 'success_ratio': self.success_ratio, # Added 1.3.0 'hardware_version': self.hardware_version, 'firmware_version': self.firmware_version, 'sensor_version': self.sensor_version, 'test_descriptions': self.test_descriptions, 'result_dicts': self.result_dicts, }
def to_dict(self): return { **HTMLTemplateMixin.to_dict(self), 'passing': self.passing, 'exit_code': self.exit_code, 'html': self.to_html() }
def to_dict(self): return {**HTMLTemplateMixin.to_dict(self), 'text': self.text}
def __init__(self): HTMLTemplateMixin.__init__(self) self.text = 'Hello World'