From 1601a799ba9d6c8c1d3bbfbe8d381ba104eae8be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20M=C3=B6slinger?= <dominik.moeslinger@univie.ac.at> Date: Thu, 22 Jul 2021 15:51:24 +0200 Subject: [PATCH] TST: SQL Schema change !!! Run CCS/Tst/codblocksreusefeature/db_schema.py after merge! (Optional: run db_drop_schema.py before merge, run: add_dummy_data.py after merge) Pre/Post Conditions/Descriptions stored in new SQL Database Addition of Pre/Post Description, General Comment, Step Comment, VRC Step Description Version name added to Json File Name (Only to File name) Progress View: Make .txt Output File --- Tst/progress_view/progress_view.py | 157 +++++++++++++++--- .../testlib/analyse_command_log.py | 18 +- .../testlib/analyse_test_run.py | 130 +++++++-------- Tst/testing_library/testlib/report.py | 12 +- Tst/tst/generator.py | 60 +++++-- Tst/tst/generator_templates/co_footer.py | 11 +- .../generator_templates/co_post_condition.py | 4 +- .../generator_templates/co_pre_condition.py | 4 +- Tst/tst/generator_templates/run_footer.py | 4 +- Tst/tst/generator_templates/run_header.py | 2 +- Tst/tst/tst.py | 13 +- Tst/tst/view.py | 9 +- 12 files changed, 295 insertions(+), 129 deletions(-) diff --git a/Tst/progress_view/progress_view.py b/Tst/progress_view/progress_view.py index dde08e1..2067eaa 100644 --- a/Tst/progress_view/progress_view.py +++ b/Tst/progress_view/progress_view.py @@ -187,6 +187,17 @@ class TestProgressView(Gtk.ApplicationWindow): self.title_box.pack_start(self.test_title, False, True, 0) self.box.pack_start(self.title_box, False, True, 20) + # --------------- tree view --------------- + self.sorted_model = Gtk.TreeModelSort(model=self.progress_tree_store) + self.sorted_model.set_sort_column_id(1, Gtk.SortType.ASCENDING) + self.view = Gtk.TreeView(model=self.sorted_model) + self.view.set_grid_lines(True) + self.view.set_has_tooltip(True) + self.view.set_tooltip_column(10) + + self.scroll_win = Gtk.ScrolledWindow() + self.scroll_win.add(self.view) + # buttons for the tree view (expand all, collapse all) self.make_button_box() self.box.pack_start(self.box_buttons, False, True, 0) @@ -196,21 +207,10 @@ class TestProgressView(Gtk.ApplicationWindow): self.btn_apply_css.connect('clicked', self.on_apply_css) # self.box_buttons.pack_start(self.btn_apply_css, False, False, 0) - # --------------- tree view --------------- - self.sorted_model = Gtk.TreeModelSort(model=self.progress_tree_store) - self.sorted_model.set_sort_column_id(1, Gtk.SortType.ASCENDING) - self.view = Gtk.TreeView(model=self.sorted_model) - self.view.set_grid_lines(True) - self.view.set_has_tooltip(True) - self.view.set_tooltip_column(10) self.make_treeview() self.view.expand_all() - self.scroll_win = Gtk.ScrolledWindow() - #self.scroll_win.set_min_content_height(int(confignator.get_option(section='progress-viewer-window-size', option='minimum-height'))) - #self.scroll_win.set_min_content_width(int(confignator.get_option(section='progress-viewer-window-size', option='minimum-width-step-mode'))) - self.scroll_win.add(self.view) self.box.pack_start(self.scroll_win, True, True, 0) self.connect('destroy', self.on_destroy) @@ -251,15 +251,15 @@ class TestProgressView(Gtk.ApplicationWindow): :param Gio.SimpleAction simple_action: The object which received the signal :param parameter: the parameter to the activation, or None if it has no parameter """ - dialog = Gtk.FileChooserDialog('Please choose a Test Specification', - self, - Gtk.FileChooserAction.OPEN, - (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) + dialog = Gtk.FileChooserDialog(title='Please choose a Test Specification', + parent=self, + action=Gtk.FileChooserAction.OPEN) + dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK) + self.add_filters(dialog) response = dialog.run() if response == Gtk.ResponseType.OK: file_selected = dialog.get_filename() - # ToDo: get the path for all 3 (json, cmd, vrc) and load them self.open_test_files(None, self.get_log_file_paths_from_json_file_name(file_selected)) elif response == Gtk.ResponseType.CANCEL: pass @@ -291,7 +291,7 @@ class TestProgressView(Gtk.ApplicationWindow): self.sort_button = Gtk.Switch() self.sort_button.connect("notify::active", self.on_remake_treeview) - self.sort_button.set_active(False) + self.sort_button.set_active(True) self.box_buttons.pack_end(self.sort_button, False, True, 0) self.sort_label2 = Gtk.Label() @@ -590,21 +590,81 @@ class TestProgressView(Gtk.ApplicationWindow): return def save_as_file_dialog(self): + # If one log file is loaded use it as Log file path, otherwise ask for it in separate dialog + test_name = None + if self.path_cmd: + file_name = self.path_cmd.split('/')[-1] + log_file_path = self.path_cmd[:-len(file_name)] + test_name = file_name.split('_')[0] + elif self.path_vrc: + file_name = self.path_vrc.split('/')[-1] + log_file_path = self.path_vrc[:-len(file_name)] + test_name = file_name.split('_')[0] + else: + log_file_path=None + + if not test_name and self.path_json: + test_name = self.path_json.split('/')[-1].split('.')[0] + dialog = Save_to_File_Dialog(parent=self) response = dialog.run() if response == Gtk.ResponseType.OK: + if not test_name: + test_name = dialog.test_name.get_text() + if not test_name: + dialog.destroy() + self.logger.info('Can not create Output file without test name') + return + folder = dialog.get_current_folder() run_count = dialog.run_id_selection.get_active() - run = None + test_report = dialog.test_report_int.get_text() + sent_run_id = None if run_count: for run_id in self.run_count.keys(): if self.run_count[run_id] == run_count: - run = run_id - analyse_test_run.save_result_to_file('test', log_file_path=folder, run_id=run) - #confignator.save_option('tst-logging', 'output-file-path', folder) + sent_run_id = run_id + if not log_file_path: + if not dialog.log_file_path_check.get_active(): + log_file_path = 'FIND' + if not self.path_json: + if dialog.log_file_path_check.get_active(): + json_file_path = None + else: + json_file_path = 'FIND' + else: + json_file_path = self.path_json + elif response == Gtk.ResponseType.CANCEL: - pass + dialog.destroy() + return + + dialog.destroy() + if log_file_path == 'FIND': + dialog = File_Path_Dialog(parent=self, file='Command or Verification Log File', is_json=False) + response = dialog.run() + if response == Gtk.ResponseType.OK: + log_file_path = dialog.get_current_folder() + elif response == Gtk.ResponseType.CANCEL: + dialog.destroy() + return + dialog.destroy() + + if json_file_path == 'FIND': + dialog = File_Path_Dialog(parent=self, file='the Json File', is_json=True) + response = dialog.run() + if response == Gtk.ResponseType.OK: + json_file_path = dialog.get_filename() + elif response == Gtk.ResponseType.CANCEL: + dialog.destroy() + return + dialog.destroy() + + analyse_test_run.save_result_to_file(test_name=test_name, log_file_path=log_file_path, output_file_path=folder, + json_file_path=json_file_path, run_id=sent_run_id, test_report=test_report, + logger=self.logger) + return def on_destroy(self, *args): @@ -1245,6 +1305,25 @@ class Save_to_File_Dialog(Gtk.FileChooserDialog): self.savedetailes = Gtk.HBox() # Store everything in this box self.savedetailes.set_border_width(15) + # Only shown if a name was not given (Found from Log Files or Json File in main window + name_label = Gtk.Label(label='Test Name: ') + self.test_name = Gtk.Entry() + self.test_name.set_tooltip_text('The name of the Test') + + # Only shown if Log File path was not given (Found from loaded log File in main window) + log_file_path_label = Gtk.Label(label='Use Basic Log File Path: ') + log_file_path_label.set_tooltip_text('Basic File Path: {}'.format(confignator.get_option('tst-logging', 'test_run'))) + self.log_file_path_check = Gtk.CheckButton() + self.log_file_path_check.set_active(True) + + # Only shown if Json File path was not given (Found from loaded json file in main window) + json_file_path_label = Gtk.Label(label='Use Basic Json File Path: ') + json_file_path_label.set_tooltip_text( + 'Basic File Path: {}, Also True if No Json File should be used (Specification Date in Output File will be empty)'.format( + confignator.get_option('tst-paths', 'tst_products'))) + self.json_file_path_check = Gtk.CheckButton() + self.json_file_path_check.set_active(True) + run_id_label = Gtk.Label(label='Select Run ID: ') # Select the Run ID which should be printed to the File @@ -1280,11 +1359,45 @@ class Save_to_File_Dialog(Gtk.FileChooserDialog): self.savedetailes.pack_end(self.test_report_int, False, True, 10) self.savedetailes.pack_end(test_report_label, False, True, 10) + if not self.win.path_vrc and not self.win.path_cmd: + self.savedetailes.pack_end(self.log_file_path_check, False, True, 10) + self.savedetailes.pack_end(log_file_path_label, False, True, 10) + + if not self.win.path_json: + self.savedetailes.pack_end(self.json_file_path_check, False, True, 10) + self.savedetailes.pack_end(json_file_path_label, False, True, 10) + + if not self.win.path_json and not self.win.path_vrc and not self.win.path_cmd: + self.savedetailes.pack_end(self.test_name, False, True, 10) + self.savedetailes.pack_end(name_label, False, True, 10) + + area.pack_start(self.savedetailes, False, True, 0) self.show_all() return +class File_Path_Dialog(Gtk.FileChooserDialog): + def __init__(self, parent=None, file=None, is_json=None): + super(File_Path_Dialog, self).__init__(title='Please choose {}'.format(file), + parent=parent, + action=Gtk.FileChooserAction.OPEN) + + self.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK) + + self.win = parent + if not is_json: + self.set_current_folder(confignator.get_option(section='tst-logging', option='test_run')) + else: + self.set_current_folder(confignator.get_option(section='tst-paths', option='tst_products')) + + if not is_json: + area = self.get_content_area() + #main_box = Gtk.HBox() + label = Gtk.Label(label='It does not matter if Command or Verification Log File is choosen, both are in the same Folder') + #main_box.pack_end(label, False, True, 10) + area.pack_start(label, False, True, 0) + self.show_all() def run(): bus_name = confignator.get_option('dbus_names', 'progress-view') dbus.validate_bus_name(bus_name) diff --git a/Tst/testing_library/testlib/analyse_command_log.py b/Tst/testing_library/testlib/analyse_command_log.py index 521d9e5..d61d4ed 100644 --- a/Tst/testing_library/testlib/analyse_command_log.py +++ b/Tst/testing_library/testlib/analyse_command_log.py @@ -191,6 +191,8 @@ def get_general_run_info(filename, run_id=None): :rtype: list of dict """ general_infos = [] + precon_infos = [] + postcon_infos = [] with open(filename, 'r') as fileobject: for line in fileobject: if report.key_word_found(line, report.cmd_test_start_keyword): @@ -200,7 +202,21 @@ def get_general_run_info(filename, run_id=None): elif general_run_info['run_id'] == run_id: general_infos.append(general_run_info) - return general_infos + elif report.key_word_found(line, report.cmd_precon_keyword): + precon = report.parse_step_from_json_string(line, report.cmd_precon_keyword) + if not run_id: + precon_infos.append(precon) + elif precon['run_id'] == run_id: + precon_infos.append(precon) + + elif report.key_word_found(line, report.cmd_postcon_keyword): + postcon = report.parse_step_from_json_string(line, report.cmd_postcon_keyword) + if not run_id: + postcon_infos.append(postcon) + elif postcon['run_id'] == run_id: + postcon_infos.append(postcon) + + return general_infos, precon_infos, postcon_infos if __name__ == '__main__': example_log_file = '../logs_test_runs/simple_example_command.log' diff --git a/Tst/testing_library/testlib/analyse_test_run.py b/Tst/testing_library/testlib/analyse_test_run.py index 282eee7..a64a7f8 100644 --- a/Tst/testing_library/testlib/analyse_test_run.py +++ b/Tst/testing_library/testlib/analyse_test_run.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 """ -Gives a pretty print overview of the outcome of a test run. For this the log files of the executed Command and Verification scripts are used. +Gives a pretty print overview or an output file of the outcome of a test run. +For this the log files of the executed Command and Verification scripts are used. """ import confignator import csv @@ -12,7 +13,6 @@ import os, os.path import errno import logging - import sys sys.path.append(confignator.get_option('paths', 'ccs')) import ccs_function_lib as cfl @@ -22,7 +22,8 @@ import toolbox from testlib import analyse_verification_log from testlib import analyse_command_log -test_name = 'test' +test_name = 'test' # Name of the test that should be analysed +run_id = '20210722123605' # Run ID that should be analysed or NONE for whole file cmd_log_file_end = '_command.log' vrc_log_file_end = '_verification.log' @@ -31,11 +32,16 @@ basic_output_file_path = confignator.get_option('tst-logging', 'output-file-path basic_json_file_path = confignator.get_option('tst-paths', 'tst_products') output_file_header = ['Item', 'Description', 'Verification', 'TestResult'] -def save_result_to_file(test_name, log_file_path=None, output_file_path=None, json_file_path=None, run_id=None, logger=False): +def save_result_to_file(test_name, log_file_path=None, output_file_path=None, json_file_path=None, run_id=None, test_report=None, logger=False): """ Analyses the command and verification log file and creates a txt output table :param str test_name: the name of the test and of its log files :param str log_file_path: Path to the log files, None if basic one should be used + :param str output_file_path: Path were the output file should be saved + :param str json_file_path: Path to the json file, None if basic one should be used + :param str run_id: Output only for specific Run defined by Run ID, None use whole file + :param str test_report: The Test Report number as a string, end of the output file name + :param str logger: A logger """ # Logger is only used, if function is called from a different file (Progres Viewer), therefore a logger and a file # are already set up, if file is called standalone, messages are printed @@ -45,6 +51,7 @@ def save_result_to_file(test_name, log_file_path=None, output_file_path=None, js console_hdlr = toolbox.create_console_handler(hdlr_lvl=logging.DEBUG) logger.addHandler(hdlr=console_hdlr) + # Get the given file paths or use the basic ones specified in the tst.cfg file if not log_file_path: log_file_path = basic_log_file_path if not output_file_path: @@ -52,14 +59,16 @@ def save_result_to_file(test_name, log_file_path=None, output_file_path=None, js if not json_file_path: json_file_path = basic_json_file_path + '/' + test_name + '.json' - cmd_log_file = log_file_path + test_name + cmd_log_file_end - vrc_log_file = log_file_path + test_name + vrc_log_file_end + cmd_log_file = log_file_path + '/' + test_name + cmd_log_file_end + vrc_log_file = log_file_path + '/' + test_name + vrc_log_file_end + # Get all the steps and verification steps from the respective log files cmd_steps = analyse_command_log.get_steps_and_commands(cmd_log_file) vrc_steps = analyse_verification_log.get_verification_steps(vrc_log_file) cmd_steps_filtered = [] vrc_steps_filtered = [] + # Filter for a specific run if run_id: for step in cmd_steps: @@ -73,34 +82,31 @@ def save_result_to_file(test_name, log_file_path=None, output_file_path=None, js cmd_steps = cmd_steps_filtered vrc_steps = vrc_steps_filtered - # Get the general run information, and the description - general_run_infos = analyse_command_log.get_general_run_info(cmd_log_file, run_id=run_id) - - if run_id and len(general_run_infos) != 1: - if logger: - logger.error('Multiple Runs found with the same given Run ID') - else: - print('Multiple Runs found with the same given Run ID') - return + # Get the general run information/description/precon/postcon and the pre/post that do not belong to a step + # Is already filtered for a specific run if one was given + general_run_infos, precon_info, postcon_info = analyse_command_log.get_general_run_info(cmd_log_file, run_id=run_id) + # Give the output file its name, consits of test name, the specification nbr (version) name_start = '{}-TS-{}-TR-'.format(test_name, cmd_steps[0]['version']) - file_versions = [] - try: + + # Check if output folder exists otherwise make it + if not os.path.isdir(output_file_path): + os.makedirs(output_file_path) + + # If Test Report Integer is not given, check all existing files and use the next higher one + if not test_report: + prev_test_reports = [] for file_name in listdir(output_file_path): if file_name.startswith(name_start): - file_versions.append(int(file_name.split('-')[-1].split('.')[0])) + prev_test_reports.append(int(file_name.split('-')[-1].split('.')[0])) - file_versions.sort() - file_count = file_versions[-1] + 1 if file_versions else 1 - except FileNotFoundError: - if logger: - logger.info('Used Folder: "{}" does not yet exist, is now created'.format(output_file_path)) - else: - print('Used Folder: "{}" does not yet exist, is now created'.format(output_file_path)) - file_count = 1 - os.makedirs(output_file_path) + prev_test_reports.sort() + test_report = prev_test_reports[-1] + 1 if prev_test_reports else 1 + else: + test_report = int(test_report) - output_file_name_path = output_file_path + name_start + f'{file_count:03d}' + '.txt' + # Output file name, with the path + output_file_name_path = output_file_path + '/' + name_start + f'{test_report:03d}' + '.txt' with open(output_file_name_path, 'w', encoding='UTF8', newline='') as file: writer = csv.writer(file, delimiter='|') @@ -110,24 +116,26 @@ def save_result_to_file(test_name, log_file_path=None, output_file_path=None, js # write the general info line, if multiple descriptions/versions are found all are written to the output file version = get_version(cmd_steps, logger) - description = get_description(general_run_infos, logger) - writer.writerow([test_name, description, 'Test Spec. Version: ' + version, 'Test Rep. Version: ' + f'{file_count:03d}']) + description = get_general_run_info_info(general_run_infos, 'descr', logger) + writer.writerow([test_name, description, 'Test Spec. Version: ' + version, 'Test Rep. Version: ' + f'{test_report:03d}']) - # write date line + # write date line, first Date (Specification Date) is the last time the json file was changed or None if no json file was given + # second Date (Execution Date), Is the execution Date of the first step date_format = '%Y-%m-%d' specification_date = datetime.datetime.strftime(datetime.datetime.fromtimestamp(os.stat(json_file_path).st_mtime), date_format) if os.path.isfile(json_file_path) else '' # When was the last time the json file was changed? time_execution = datetime.datetime.strftime(cmd_steps[0]['exec_date'], date_format) writer.writerow(['Date', '', specification_date, time_execution]) - # write Precon line - writer.writerow(['Precon.', 'This has still to be solved', '', '']) # TODO: What should be shown of the Precon + # write Precon line (Precon Descritpion) + precon_descr = get_general_run_info_info(precon_info, 'precon_descr', logger) + writer.writerow(['Precon.', precon_descr, '', '']) - # write the general comment line - general_comment = get_general_comment(general_run_infos, logger) + # write the general comment line, the Test Comment is only shown if it exists + general_comment = get_general_run_info_info(general_run_infos, 'comment', logger) if general_comment: writer.writerow(['Comment', general_comment, '', '']) - # write step line + # write step line with Step Description, VRC Step Description and Result for step in cmd_steps: for vrc_step in vrc_steps: if step['step_id'] == vrc_step['step_id']: @@ -138,30 +146,35 @@ def save_result_to_file(test_name, log_file_path=None, output_file_path=None, js step_number_secondary) == 0 else '{}.{}'.format(step_number_primary, step_number_secondary) step_desc = 'Step ' + str(step_number_shown) - writer.writerow([step_desc, step['descr'], vrc_step['vrc_descr'], test_result]) # TODO: Third coloumn is what? + writer.writerow([step_desc, step['descr'], vrc_step['vrc_descr'], test_result]) if step['comment']: writer.writerow(['Comment', step['comment'], '', '']) - # write Postcon line - writer.writerow(['Postcon.', 'This has still to be solved', '', '']) # TODO: What should be shown of the Postcon + # write Postcon line (Post Con Description) + postcon_descr = get_general_run_info_info(postcon_info, 'postcon_descr', logger) + writer.writerow(['Postcon.', postcon_descr, '', '']) + -def get_description(general_run_infos, logger): +def get_general_run_info_info(general_run_infos, info_keyword, logger): """ - Get a string of the different description that could be found + Get one information from the given general_run_infos (Typically: Description, General Commen, Pre/Post Conditions) :param list of dicts general_run_infos: all the general run information that were found - :return str description: A string that contains all found versions + :param str info_keyword: Which information should be extracted from the general run infos + :return str description: A string that contains all found informations """ + info = '' for count, run_info in enumerate(general_run_infos): if count == 0: - description = run_info['descr'] + info = run_info[info_keyword] else: - description += ' / ' + run_info['descr'] + info += ' / ' + run_info[info_keyword] if logger: - logger.warning('More than one Description was found in the command log File') + logger.warning('More than one {} was found in the command log File'.format(info_keyword)) else: - print('More than one Description was found in the command log File') + print('More than one {} was found in the command log File'.format(info_keyword)) + + return info - return description def get_version(steps, logger): """ @@ -170,6 +183,7 @@ def get_version(steps, logger): :return str version_final: A string that contains all found versions """ version_list = [] + version_final = '' for step in steps: if step['version'] not in version_list: version_list.append(step['version']) @@ -184,24 +198,6 @@ def get_version(steps, logger): print('More than one Version was found in the command log File') return version_final -def get_general_comment(general_run_infos, logger): - """ - Get a string of the different general comment that could be found - :param list of dicts general_run_infos: all the general run information that were found - :return str general_comment: A string that contains all found gerneral comments - """ - for count, run_info in enumerate(general_run_infos): - if count == 0: - general_comment = run_info['comment'] - else: - general_comment += ' / ' + run_info['comment'] - if logger: - logger.warning('More than one General Comment was found in the command log File') - else: - print('More than one General Comment was found in the command log File') - - return general_comment - def show_basic_results(test_name, log_file_path=None): """ Analyses the command and verification log file and prints a basic overview of the results @@ -238,5 +234,5 @@ def show_basic_results(test_name, log_file_path=None): return if __name__ == '__main__': - save_result_to_file(test_name, run_id='20210721092439') - #show_basic_results(test_name) + #save_result_to_file(test_name, run_id=run_id) + show_basic_results(test_name) diff --git a/Tst/testing_library/testlib/report.py b/Tst/testing_library/testlib/report.py index aff1119..ac6920e 100644 --- a/Tst/testing_library/testlib/report.py +++ b/Tst/testing_library/testlib/report.py @@ -292,7 +292,7 @@ def print_event_data_tuple(tm_packets): logger.debug('Event {}: {} -> {}'.format(event_id, src, dest)) -def write_precondition_outcome(result, step_id, precon_descr): +def write_precondition_outcome(result, run_id, precon_descr): """ Logs the outcome of the establish_preconditions function in a test script. :param result: bool @@ -300,15 +300,15 @@ def write_precondition_outcome(result, step_id, precon_descr): """ logger.info('{} {}'.format(cmd_precon_keyword, make_json_string(result=result, - precon_desc=precon_descr, - step_id=step_id))) + precon_descr=precon_descr, + run_id=run_id))) if result is True: logger.info('Preconditions are fulfilled.\n') else: logger.warning('Preconditions are NOT fulfilled.\n') -def write_postcondition_outcome(result, step_id, postcon_descr): +def write_postcondition_outcome(result, run_id, postcon_descr): """ Logs the outcome of the establish_postconditions function in a test script. :param result: bool @@ -316,8 +316,8 @@ def write_postcondition_outcome(result, step_id, postcon_descr): """ logger.info('{} {}'.format(cmd_postcon_keyword, make_json_string(result=result, - postcon_desc=postcon_descr, - step_id=step_id))) + postcon_descr=postcon_descr, + run_id=run_id))) if result is True: logger.info('Postconditions are fulfilled.\n') else: diff --git a/Tst/tst/generator.py b/Tst/tst/generator.py index 94f78c6..f68a538 100644 --- a/Tst/tst/generator.py +++ b/Tst/tst/generator.py @@ -101,6 +101,9 @@ def make_command_script(model, model_spec): with open(co_class_path, 'r') as class_file_obj: class_template_str = class_file_obj.read() class_file_obj.close() + + test_comment_w_indent = model_spec.comment.replace('\n', " ' \\\n".format('\'') + 6 * indent + "'") + class_str = string.Template(class_template_str) cls = class_str.substitute(testSpecClassName=create_class_name(model_spec.name), testSpecFileName=create_file_name(model_spec.name), @@ -109,7 +112,7 @@ def make_command_script(model, model_spec): testSpecVersion=model_spec.version, testPreCondition=model_spec.precon_name, testPostCondition=model_spec.postcon_name, - testComment=model_spec.comment) + testComment=test_comment_w_indent) # add the header string content += '\n\n' + cls @@ -118,9 +121,13 @@ def make_command_script(model, model_spec): pre_cond_template_str = pre_cond_file_obj.read() pre_cond_file_obj.close() + # Be sure that if it is multiline, that all have the right indent + pre_con_code = model_spec.precon_code.replace('\n', '\n' + 2 * indent) + pre_con_descr = model_spec.precon_descr.replace('\n', " ' \\\n" + 6 * indent + "'") + pre_cond_template = string.Template(pre_cond_template_str) - pre_cond_combined = pre_cond_template.substitute(TestPreconEntry=model_spec.precon_code, - TestPreconDescription=model_spec.precon_descr) + pre_cond_combined = pre_cond_template.substitute(TestPreconEntry=pre_con_code, + TestPreconDescription=pre_con_descr) # add the header string content += '\n' + pre_cond_combined @@ -132,11 +139,13 @@ def make_command_script(model, model_spec): step_str = string.Template(step_template_str) command_code = step.command_code command_code_w_indents = command_code.replace('\n', '\n' + 3 * indent) + step_comment_w_indents = step.step_comment.replace('\n', " ' \\\n" + 5 * indent + "'") + step_descr_w_indents = step.description.replace('\n', " ' \\\n" + 5 * indent + "'") if len(command_code_w_indents) == 0: command_code_w_indents = 'pass' step = step_str.substitute(testStepNumber=step.step_number_test_format, - testStepDescription=step.description, - testStepComment=step.step_comment, + testStepDescription=step_descr_w_indents, + testStepComment=step_comment_w_indents, testStepCommandCode=command_code_w_indents, testSpecFileName=create_file_name(model_spec.name), testSpecClassName=create_class_name(model_spec.name)) @@ -148,14 +157,20 @@ def make_command_script(model, model_spec): post_cond_template_str = post_cond_file_obj.read() post_cond_file_obj.close() + # Be sure that if it is multiline, that all have the right indent + post_con_code = model_spec.postcon_code.replace('\n', '\n' + 2 * indent) + post_con_descr = model_spec.postcon_descr.replace('\n', " ' \\\n" + 6 * indent + "'") + post_cond_template = string.Template(post_cond_template_str) - post_cond_combined = post_cond_template.substitute(TestPostconEntry=model_spec.postcon_code, - TestPostconDescr=model_spec.description) + post_cond_combined = post_cond_template.substitute(TestPostconEntry=post_con_code, + TestPostconDescr=post_con_descr) + + #post_cond_combined.replace('\n', '\n' + 3 * indent) # add the header string content += '\n' + post_cond_combined - # add the footer (post condition and other functions) + # add the footer run and other functions) with open(co_footer_path, 'r') as footer_file_obj: footer_template_str = footer_file_obj.read() footer_file_obj.close() @@ -188,13 +203,17 @@ def make_command_run_script(model, model_spec): with open(run_header_path, 'r') as header_file_obj: header_template = header_file_obj.read() header_file_obj.close() + + precon_descr_w_indent = model_spec.precon_descr.replace('\n', '\n{}#{}'.format(indent, 4*indent)) + # add the header string header_template_str = string.Template(header_template) #header_str = header_template_str.substitute(testSpecClassName=create_class_name(model.name), # testSpecFileName=create_file_name(model.name), # testPrecondDesc=model.pre_condition.description) header_str = header_template_str.substitute(testSpecClassName=create_class_name(model_spec.name), - testSpecFileName=create_file_name(model_spec.name)) + testSpecFileName=create_file_name(model_spec.name), + TestPreconDescription=precon_descr_w_indent) content += header_str @@ -203,22 +222,27 @@ def make_command_run_script(model, model_spec): step_template_str = step_file_obj.read() step_file_obj.close() for step in model.steps: + step_descr_w_indent = step.description.replace('\n', '\n{}#{}'.format(indent, 3*indent)) step_str = string.Template(step_template_str) #step = step_str.substitute(testStepNumber=model.steps[step].step_number, # testStepDescription=model.steps[step].description, # testStepComment=model.steps[step].comment) step = step_str.substitute(testStepNumber=step.step_number_test_format, - testStepDescription=step.description) + testStepDescription=step_descr_w_indent) # add the string for a steps content += '\n' + step # add the step definitions - with open(run_footer_path, 'r') as step_file_obj: - step_template_str = step_file_obj.read() - step_file_obj.close() - header_template_str = string.Template(header_template) + with open(run_footer_path, 'r') as footer_file_obj: + footer_template_str = footer_file_obj.read() + footer_file_obj.close() + + postcon_descr_w_indent = model_spec.postcon_descr.replace('\n', '\n{}#{}'.format(indent, 4*indent)) + + footer_template_str = string.Template(footer_template_str) + footer = footer_template_str.substitute(TestPostconDescription=postcon_descr_w_indent) - content += '\n' + header_template_str + content += '\n' + footer # create the new file file_path = create_script_path(name=model_spec.name, auxiliary=run_scrpt_auxiliary) @@ -272,6 +296,8 @@ def make_verification_script(model, model_spec): step_str = string.Template(step_template_str) verification_code = step.verification_code verification_code_w_indents = verification_code.replace('\n', '\n' + 3 * indent) + verification_descr_w_indents = step.step_comment.replace('\n', " ' \\\n" + 6 * indent + "'") + step_descr_w_indents = step.description.replace('\n', " ' \\\n" + 5 * indent + "'") if len(verification_code_w_indents) == 0: verification_code_w_indents = 'pass' #step = step_str.substitute(testStepNumber=model.steps[step].step_number, @@ -279,8 +305,8 @@ def make_verification_script(model, model_spec): # testStepComment=model.steps[step].comment, # testStepVerificationCode=verification_code_w_indents) step = step_str.substitute(testStepNumber=step.step_number_test_format, - testStepDescription=step.description, - testStepVerificationDescription=step.verification_description, + testStepDescription=step_descr_w_indents, + testStepVerificationDescription=verification_descr_w_indents, testStepVerificationCode=verification_code_w_indents) # add the string for a steps content += '\n' + step diff --git a/Tst/tst/generator_templates/co_footer.py b/Tst/tst/generator_templates/co_footer.py index 9bee9f5..32f5cfb 100644 --- a/Tst/tst/generator_templates/co_footer.py +++ b/Tst/tst/generator_templates/co_footer.py @@ -47,13 +47,14 @@ finally: # add the summary of the step to the result array self.step_results.append(res) + + # postcondition of the test + logger.info('Postconditions: {}'.format(self.postcondition)) + self.postcond_ok = self.post_condition(pool_name=pool_name) + else: logger.error('Preconditions could not be established. Test steps were not executed!\n') - # postcondition of the test - logger.info('Postconditions: {}'.format(self.postcondition)) - self.postcond_ok = self.post_condition(pool_name=pool_name) - # save the packet pool self.save_pool_in_file(pool_name=pool_name, save_pool=save_pool) @@ -78,4 +79,4 @@ now = datetime.now() # current date and time if not self.run_id and pool_name: self.run_id = now.strftime("%Y%m%d%H%M%S") - return now.strftime("%Y%m%d%H%M%S%f") \ No newline at end of file + return now.strftime("%Y%m%d%H%M%S%f") diff --git a/Tst/tst/generator_templates/co_post_condition.py b/Tst/tst/generator_templates/co_post_condition.py index 18b0c4d..f2a7037 100644 --- a/Tst/tst/generator_templates/co_post_condition.py +++ b/Tst/tst/generator_templates/co_post_condition.py @@ -44,7 +44,7 @@ :rtype: bool """ testing_logger.cmd_log_handler(__name__) - step_id = self.check_run_and_step_id(pool_name=pool_name) + self.check_run_and_step_id(pool_name=pool_name) postcon_descr = '$TestPostconDescr' success = False logger.info('establishing postconditions started') @@ -52,6 +52,6 @@ $TestPostconEntry logger.info('establishing postconditions finished') - report.write_postcondition_outcome(success, step_id, postcon_descr) + report.write_postcondition_outcome(success, self.run_id, postcon_descr) return success diff --git a/Tst/tst/generator_templates/co_pre_condition.py b/Tst/tst/generator_templates/co_pre_condition.py index 7dbfdd2..c4ca548 100644 --- a/Tst/tst/generator_templates/co_pre_condition.py +++ b/Tst/tst/generator_templates/co_pre_condition.py @@ -8,7 +8,7 @@ True if the preconditions are fulfilled """ testing_logger.cmd_log_handler(__name__) - step_id = self.check_run_and_step_id(pool_name=pool_name) + self.check_run_and_step_id(pool_name=pool_name) precon_descr = '$TestPreconDescription' success = False logger.info('establishing preconditions started') @@ -16,7 +16,7 @@ $TestPreconEntry logger.info('establishing preconditions finished') - report.write_precondition_outcome(success, step_id, precon_descr) + report.write_precondition_outcome(success, self.run_id, precon_descr) return success # INITIALIZE every step -------------------------------------------------------------------------------------------- diff --git a/Tst/tst/generator_templates/run_footer.py b/Tst/tst/generator_templates/run_footer.py index 18e4341..6d48cc0 100644 --- a/Tst/tst/generator_templates/run_footer.py +++ b/Tst/tst/generator_templates/run_footer.py @@ -1,3 +1,3 @@ #! CCS.BREAKPOINT - # Execute the Post Conditions - threading.Thread(target=testinstance.post_condition, kwargs = {'pool_name': pool_name}, daemon = True).start() \ No newline at end of file + # Post-Conditions: $TestPostconDescription + threading.Thread(target=testinstance.post_condition, kwargs = {'pool_name': pool_name}, daemon = True).start() diff --git a/Tst/tst/generator_templates/run_header.py b/Tst/tst/generator_templates/run_header.py index 6f5726b..e10e981 100644 --- a/Tst/tst/generator_templates/run_header.py +++ b/Tst/tst/generator_templates/run_header.py @@ -59,5 +59,5 @@ if False: #! CCS.BREAKPOINT if False: - # Exectute the preconditions + # Pre-Conditions: $TestPreconDescription threading.Thread(target=testinstance.establish_preconditions, kwargs={'pool_name': pool_name}, daemon=True).start() diff --git a/Tst/tst/tst.py b/Tst/tst/tst.py index 4bb532d..1176f93 100755 --- a/Tst/tst/tst.py +++ b/Tst/tst/tst.py @@ -537,6 +537,7 @@ class TstAppWindow(Gtk.ApplicationWindow): self.save_as_file_dialog() def save_as_file_dialog(self): + current_test = self.current_test_instance() current_name = self.current_model().name current_model = self.current_model() dialog = Gtk.FileChooserDialog('Please choose a file', @@ -548,8 +549,16 @@ class TstAppWindow(Gtk.ApplicationWindow): response = dialog.run() if response == Gtk.ResponseType.OK: file_selected = dialog.get_filename() - file_management.save_file(file_path=file_selected, test_spec=current_model, file_extension='json', logger=self.logger) - current_model.filename = file_selected + if '-v_' in file_selected: + test_name = file_selected.split('-v_')[0] + filename = file_selected + else: + test_name = file_selected.split('.json')[0] + filename = '{}-v_{}.json'.format(test_name, current_model.version) + + file_management.save_file(file_path=filename, test_spec=current_model, file_extension='json', logger=self.logger) + current_test.filename = filename.split('/')[-1] + current_model.name = test_name.split('/')[-1] elif response == Gtk.ResponseType.CANCEL: pass dialog.destroy() diff --git a/Tst/tst/view.py b/Tst/tst/view.py index b657b34..1406044 100644 --- a/Tst/tst/view.py +++ b/Tst/tst/view.py @@ -287,6 +287,10 @@ class Board(Gtk.Box): # Set the test comment self.test_meta_data_comment.get_buffer().set_text(self.model.comment) + # Set the Locked STep numeration + self.text_meta_data_test_is_locked.set_active(self.model.primary_counter_locked) + + def collapse_all_steps(self, button): """ Close all expander of the steps """ @@ -1153,7 +1157,7 @@ class StepWidget(Gtk.EventBox): step_in_data_model = self.model.get_sequence(self.sequence).steps[stp_ndx] # use the setter of the data model if isinstance(step_in_data_model, data_model.Step): - step_in_data_model.command_code = self.step_description + step_in_data_model.description = self.step_description else: self.logger('step with the step number {} could not be found'.format(self.step_number)) # update the model @@ -1581,7 +1585,7 @@ class Edit_Pre_Post_Con_Dialog(Gtk.Dialog): self.add_buttons( Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK ) - self.set_default_size(200, 200) + self.set_default_size(400, 400) self.first_entry = selection self.win = parent self.file_path = os.path.join(confignator.get_option('paths', 'tst'), @@ -1718,6 +1722,7 @@ class Edit_Pre_Post_Con_Dialog(Gtk.Dialog): self.con_lbl_box.pack_start(con_lbl, False, False, 0) self.con_scrolled_window = Gtk.ScrolledWindow() + self.con_scrolled_window.set_tooltip_text('Set variable "success" to True/False, to check if {}-Conditon is fulfilled'.format(self.pre_post.upper())) #self.commands_scrolled_window.set_size_request(50, 100) self.con_view = GtkSource.View() self.con_view.set_auto_indent(True) -- GitLab