diff --git a/Ccs/ccs_function_lib.py b/Ccs/ccs_function_lib.py index f65e8cae0e367a5f7d20b3c07902b52f8b387879..a2f4a45f038b18d94078c5dbbe86807649fc0afb 100644 --- a/Ccs/ccs_function_lib.py +++ b/Ccs/ccs_function_lib.py @@ -225,18 +225,21 @@ def start_tst(console=False, *args): directory = confignator.get_option('paths', 'tst') file_path = os.path.join(directory, 'tst/main.py') start_app(console, file_path, directory, *args) + return def start_progress_view(console=False, *args): directory = confignator.get_option('paths', 'tst') file_path = os.path.join(directory, 'progress_view/progress_view.py') start_app(console, file_path, directory, *args) + return def start_log_viewer(console=False, *args): directory = confignator.get_option('paths', 'tst') file_path = os.path.join(directory, 'log_viewer/log_viewer.py') start_app(console, file_path, directory, *args) + return def start_config_editor(console=False, *args): @@ -3413,6 +3416,63 @@ def setup_gw_spw_routing(gw_hp, gnd_hp, tc_hp=None, spw_head=b'\xfe\x02\x00\x00' gw.close() +## +# Save pool +# +# Dump content of data pool _pname_ to file _fname_, either as a concatenated binary sequence or in hexadecimal +# representation and one packet per line. Selective saving (by service type) possible. +# @param fname File name for the dump +# @param pname Name of pool to be saved +# @param mode Type of the saved file. _binary_ or _hex_ +# @param st_filter Packets of that service type will be saved +def savepool(filename, pool_name, mode='binary', st_filter=None): + # get new session for saving process + logger.info('Saving pool content to disk...') + tmlist = list(get_packets_from_pool(pool_name)) + + Tmdump(filename, tmlist, mode=mode, st_filter=st_filter, crccheck=False) + logger.info('Pool {} saved as {} in {} mode'.format(pool_name, filename, mode.upper())) + + return + +def get_packets_from_pool(pool_name, indices=[], st=None, sst=None, apid=None, dbsession=None): + """ + + @param pool_name: + @param indices: + @param st: + @param sst: + @param apid: + @return: + """ + new_session = scoped_session_storage + + rows = new_session.query( + DbTelemetry + ).join( + DbTelemetryPool, + DbTelemetry.pool_id == DbTelemetryPool.iid + ).filter( + DbTelemetryPool.pool_name == pool_name + ) + + if len(indices) != 0: + rows = rows.filter( + DbTelemetry.idx.in_(indices) + ) + + if st is not None: + rows = rows.filter(DbTelemetry.stc == st) + if sst is not None: + rows = rows.filter(DbTelemetry.sst == sst) + if apid is not None: + rows = rows.filter(DbTelemetry.apid == apid) + + ret = [row.raw for row in rows.yield_per(1000)] + new_session.close() + return ret + + class TestReport: def __init__(self, filename, version, idb_version, gui=False, delimiter='|'): diff --git a/Ccs/editor.py b/Ccs/editor.py index deea0fd2817e7de252c7c65c59d21585db93cbc4..6b3af4c828a614bb9d8931f6b95a1a08cca64e8c 100644 --- a/Ccs/editor.py +++ b/Ccs/editor.py @@ -20,6 +20,7 @@ import struct import IPython import confignator import json +import os import dbus import dbus.service @@ -34,6 +35,7 @@ from threading import Thread #cfl = General_Functions() import ccs_function_lib as cfl +pixmap_folder = confignator.get_option('ccs-paths', 'pixmap') # from jupyter_client import find_connection_file @@ -119,19 +121,35 @@ class IPythonTerminal(Vte.Terminal): # else: # term = ["/usr/bin/env", "ipython3", "--gui=gtk3", "-i", ".ipyloadcfg.py", "--config", ".ipycfg.py"] - term = ["/usr/bin/env", "ipython3", "--gui=gtk3", "-i", ".ipyloadcfg.py", "--config", ".ipycfg.py"] + ccs_path = confignator.get_option('paths', 'ccs') + ipyloadcfg_path = os.path.join(ccs_path, '.ipyloadcfg.py') + ipycfg_path = os.path.join(ccs_path, '.ipycfg.py') + + term = ["/usr/bin/env", "ipython3", "--gui=gtk3", "-i", ipyloadcfg_path, "--config", ipycfg_path] def __init__(self, scrollback_lines, *args, **kwds): super(IPythonTerminal, self).__init__(*args, **kwds) # cfile = find_connection_file() - self.set_scrollback_lines(scrollback_lines) - self.spawn_sync(Vte.PtyFlags.DEFAULT, - None, - self.term, - [], - GLib.SpawnFlags.DO_NOT_REAP_CHILD, - None, - None) + #self.set_scrollback_lines(scrollback_lines) + #self.pty = self.pty_new_sync(Vte.PtyFlags.DEFAULT) + #self.spawn_sync(Vte.PtyFlags.DEFAULT, + # None, + # self.term, + # [], + # GLib.SpawnFlags.DO_NOT_REAP_CHILD, + # None, + # None) + self.spawn_async( + Vte.PtyFlags.DEFAULT, # Pty Flags + None, # Working DIR + self.term, # Command/BIN (argv) + None, # Environmental Variables (envv) + GLib.SpawnFlags.DEFAULT, # Spawn Flags + None, None, # Child Setup + -1, # Timeout (-1 for indefinitely) + None, # Cancellable + None, # Callback + None) # User Data def feed_child_compat(self, msg, msglen=None): """ @@ -203,11 +221,13 @@ class CcsEditor(Gtk.Window): size = button.get_icon_size() t, h, w = Gtk.IconSize.lookup(size) # icons are half the size of button (usually) - logo = GdkPixbuf.Pixbuf.new_from_file_at_size('pixmap/UVIE_Logo_48.png', -1, w * 2) + pixmap_path = os.path.join(pixmap_folder, 'UVIE_Logo_48.png') + logo = GdkPixbuf.Pixbuf.new_from_file_at_size(pixmap_path, -1, w * 2) img = Gtk.Image.new_from_pixbuf(logo) box.pack_end(img, False, False, 0) - logo = GdkPixbuf.Pixbuf.new_from_file_at_size('pixmap/IfA_Logo_48.png', -1, w * 2) + pixmap_path = os.path.join(pixmap_folder, 'IfA_Logo_48.png') + logo = GdkPixbuf.Pixbuf.new_from_file_at_size(pixmap_path, -1, w * 2) img = Gtk.Image.new_from_pixbuf(logo) box.pack_end(img, False, False, 0) self.grid.attach(box, 2, 1, 1, 1) @@ -250,7 +270,7 @@ class CcsEditor(Gtk.Window): self.log_file = None # save the shown text from the log file tab # Update the log-file view window every 2 seconds - GObject.timeout_add(2000, self.switch_notebook_page, self.logwin, self.logwintext, self.logbuffer) + GLib.timeout_add(2000, self.switch_notebook_page, self.logwin, self.logwintext, self.logbuffer) self.ipython_view.connect("size-allocate", self.console_autoscroll, self.ipython_view) @@ -296,7 +316,7 @@ class CcsEditor(Gtk.Window): #Change for terminal if int(instance) != int(cfl.communication[application]): - self._to_console("cfl.communication['"+str(application)+"'] = " + str(int(instance))) + self._to_console_via_socket("cfl.communication['"+str(application)+"'] = " + str(int(instance))) #Local change cfl.communication[application] = int(instance) @@ -355,22 +375,22 @@ class CcsEditor(Gtk.Window): if not cfl.communication[self.my_bus_name.split('.')[1]]: cfl.communication[self.my_bus_name.split('.')[1]] = int(self.my_bus_name[-1]) - self._to_console("cfl.communication = " + str(cfl.communication)) + self._to_console_via_socket("cfl.communication = " + str(cfl.communication)) # Connect to the Terminal if another editor exists if Count == 1: - self._to_console( + self._to_console_via_socket( "editor = dbus.SessionBus().get_object('" + str(My_Bus_Name) + "', '/MessageListener')") else: for service in dbus.SessionBus().list_names(): if service.startswith(self.cfg['ccs-dbus_names']['editor']): if service == self.my_bus_name: - self._to_console("editor" + str(Count) + " = dbus.SessionBus().get_object('" + + self._to_console_via_socket("editor" + str(Count) + " = dbus.SessionBus().get_object('" + str(My_Bus_Name) + "', '/MessageListener')") else: editor = cfl.dbus_connection('editor', service[-1]) - editor.Functions('_to_console', "editor" + str(Count) + + editor.Functions('_to_console_via_socket', "editor" + str(Count) + " = dbus.SessionBus().get_object('" + str(My_Bus_Name) + "', '/MessageListener')") @@ -388,40 +408,40 @@ class CcsEditor(Gtk.Window): con = cfl.dbus_connection('poolmanager', service[-1]) if con.Variables('main_instance') == self.main_instance: if service[-1] == str(1): - self._to_console("pmgr = dbus.SessionBus().get_object('" + + self._to_console_via_socket("pmgr = dbus.SessionBus().get_object('" + str(service) + "', '/MessageListener')") else: - self._to_console("pmgr" + str(service[-1]) + " = dbus.SessionBus().get_object('" + + self._to_console_via_socket("pmgr" + str(service[-1]) + " = dbus.SessionBus().get_object('" + str(service) + "', '/MessageListener')") # Connect to all Poolviewers if service.startswith(self.cfg['ccs-dbus_names']['poolviewer']): con = cfl.dbus_connection('poolviewer', service[-1]) if con.Variables('main_instance') == self.main_instance: if service[-1] == str(1): - self._to_console("pv = dbus.SessionBus().get_object('" + + self._to_console_via_socket("pv = dbus.SessionBus().get_object('" + str(service) + "', '/MessageListener')") else: - self._to_console("pv" + str(service[-1]) + " = dbus.SessionBus().get_object('" + + self._to_console_via_socket("pv" + str(service[-1]) + " = dbus.SessionBus().get_object('" + str(service) + "', '/MessageListener')") # Connect to all Plotters if service.startswith(self.cfg['ccs-dbus_names']['plotter']): con = cfl.dbus_connection('plotter', service[-1]) if con.Variables('main_instance') == self.main_instance: if service[-1] == str(1): - self._to_console("paramplot = dbus.SessionBus().get_object('" + + self._to_console_via_socket("paramplot = dbus.SessionBus().get_object('" + str(service) + "', '/MessageListener')") else: - self._to_console("paramplot" + str(service[-1]) + " = dbus.SessionBus().get_object('" + self._to_console_via_socket("paramplot" + str(service[-1]) + " = dbus.SessionBus().get_object('" + str(service) + "', '/MessageListener')") # Connect to all Monitors if service.startswith(self.cfg['ccs-dbus_names']['monitor']): con = cfl.dbus_connection('monitor', service[-1]) if con.Variables('main_instance') == self.main_instance: if service[-1] == str(1): - self._to_console("monitor = dbus.SessionBus().get_object('" + + self._to_console_via_socket("monitor = dbus.SessionBus().get_object('" + str(service) + "', '/MessageListener')") else: - self._to_console("monitor" + str(service[-1]) + " = dbus.SessionBus().get_object('" + + self._to_console_via_socket("monitor" + str(service[-1]) + " = dbus.SessionBus().get_object('" + str(service) + "', '/MessageListener')") # Connect to all remaining editors if service.startswith(self.cfg['ccs-dbus_names']['editor']): @@ -429,10 +449,10 @@ class CcsEditor(Gtk.Window): con = cfl.dbus_connection('editor', service[-1]) if con.Variables('main_instance') == self.main_instance: if service[-1] == str(1): - self._to_console("editor = dbus.SessionBus().get_object('" + + self._to_console_via_socket("editor = dbus.SessionBus().get_object('" + str(service) + "', '/MessageListener')") else: - self._to_console("editor" + str(service[-1]) + + self._to_console_via_socket("editor" + str(service[-1]) + " = dbus.SessionBus().get_object('" + str(service) + "', '/MessageListener')") return @@ -520,7 +540,7 @@ class CcsEditor(Gtk.Window): nr = self.my_bus_name[-1] if nr == str(1): nr = '' - editor.Functions('_to_console', 'del(editor' + str(nr) + ')') + editor.Functions('_to_console_via_socket', 'del(editor' + str(nr) + ')') self.update_all_connections_quit() Gtk.main_quit() @@ -584,7 +604,6 @@ class CcsEditor(Gtk.Window): while self.is_editor_socket_active: self.console_sock, addr = sock_csl.accept() line = self.console_sock.recv(2**16).decode() - #print(line) # if line.startswith('exec:'): # exec(line.strip('exec:')) # elif line.startswith('get:'): @@ -612,8 +631,6 @@ class CcsEditor(Gtk.Window): print(line) if not line.endswith('\n'): line += '\n' - - #print(self.ipython_view. get_has_selection()) # if line.count('\n') > 1: # self.ipython_view.feed_child('%cpaste\n', len('%cpaste\n')) # time.sleep(0.01) @@ -647,19 +664,21 @@ class CcsEditor(Gtk.Window): def create_mark_attributes(self): self.mark_play = GtkSource.MarkAttributes() - icon = GdkPixbuf.Pixbuf.new_from_file('pixmap/media-playback-start-symbolic_uvie.svg') + pixmap_path = os.path.join(pixmap_folder, 'media-playback-start-symbolic_uvie.svg') + icon = GdkPixbuf.Pixbuf.new_from_file(pixmap_path) self.mark_play.set_pixbuf(icon) # self.mark_play.set_icon_name("media-playback-start-symbolic") self.mark_break = GtkSource.MarkAttributes() - icon = GdkPixbuf.Pixbuf.new_from_file('pixmap/process-stop-symbolic_uvie.svg') + pixmap_path = os.path.join(pixmap_folder, 'process-stop-symbolic_uvie.svg') + icon = GdkPixbuf.Pixbuf.new_from_file(pixmap_path) self.mark_break.set_pixbuf(icon) # self.mark_break.set_icon_name("process-stop-symbolic") # self.tag_found = self.textbuffer.create_tag("found", background="yellow", foreground = "black") def create_menus(self): - action_group = Gtk.ActionGroup("action_group") + action_group = Gtk.ActionGroup(name="action_group") self.create_file_menu(action_group) self.create_edit_menu(action_group) self.create_pool_menu(action_group) @@ -678,110 +697,110 @@ class CcsEditor(Gtk.Window): return menubar def create_file_menu(self, action_group): - action = Gtk.Action("FileMenu", "_File", None, None) + action = Gtk.Action(name="FileMenu", label="_File", tooltip=None, stock_id=None) action_group.add_action(action) - action = Gtk.Action("FileNew", "_New", None, Gtk.STOCK_NEW) + action = Gtk.Action(name="FileNew", label="_New", tooltip=None, stock_id=Gtk.STOCK_NEW) action.connect("activate", self._on_menu_file_new) action_group.add_action_with_accel(action, "<control>N") - action = Gtk.Action("FileOpen", "_Open", None, Gtk.STOCK_OPEN) + action = Gtk.Action(name="FileOpen", label="_Open", tooltip=None, stock_id=Gtk.STOCK_OPEN) action.connect("activate", self.on_menu_file_open) action_group.add_action_with_accel(action, "<control>O") - action = Gtk.Action("FileSave", "_Save", None, Gtk.STOCK_SAVE) + action = Gtk.Action(name="FileSave", label="_Save", tooltip=None, stock_id=Gtk.STOCK_SAVE) action.connect("activate", self.on_menu_file_save) action_group.add_action_with_accel(action, "<control>S") - action = Gtk.Action("FileSaveAs", "_Save As", None, Gtk.STOCK_SAVE_AS) + action = Gtk.Action(name="FileSaveAs", label="_Save As", tooltip=None, stock_id=Gtk.STOCK_SAVE_AS) action.connect("activate", self.on_menu_file_saveas) action_group.add_action(action) - action = Gtk.Action("FileQuit", "_Quit", None, Gtk.STOCK_QUIT) + action = Gtk.Action(name="FileQuit", label="_Quit", tooltip=None, stock_id=Gtk.STOCK_QUIT) action.connect("activate", self.on_menu_file_quit) action_group.add_action_with_accel(action, "<control>Q") def create_edit_menu(self, action_group): - action = Gtk.Action("EditMenu", "_Edit", None, None) + action = Gtk.Action(name="EditMenu", label="_Edit", tooltip=None, stock_id=None) action_group.add_action(action) - action = Gtk.Action("EditUndo", "_Undo", None, Gtk.STOCK_UNDO) + action = Gtk.Action(name="EditUndo", label="_Undo", tooltip=None, stock_id=Gtk.STOCK_UNDO) action.connect("activate", self._on_undo) action_group.add_action_with_accel(action, "<control>Z") - action = Gtk.Action("EditRedo", "Red_o", None, Gtk.STOCK_REDO) + action = Gtk.Action(name="EditRedo", label="Red_o", tooltip=None, stock_id=Gtk.STOCK_REDO) action.connect("activate", self._on_redo) action_group.add_action_with_accel(action, "<control>Y") - action = Gtk.Action("EditCut", "Cu_t", None, Gtk.STOCK_CUT) + action = Gtk.Action(name="EditCut", label="Cu_t", tooltip=None, stock_id=Gtk.STOCK_CUT) action.connect("activate", self._on_cut) action_group.add_action_with_accel(action, "<control>X") - action = Gtk.Action("EditCopy", "_Copy", None, Gtk.STOCK_COPY) + action = Gtk.Action(name="EditCopy", label="_Copy", tooltip=None, stock_id=Gtk.STOCK_COPY) action.connect("activate", self._on_copy) action_group.add_action_with_accel(action, "<control>C") - action = Gtk.Action("EditPaste", "_Paste", None, Gtk.STOCK_PASTE) + action = Gtk.Action(name="EditPaste", label="_Paste", tooltip=None, stock_id=Gtk.STOCK_PASTE) action.connect("activate", self._on_paste) action_group.add_action_with_accel(action, "<control>V") - action = Gtk.Action("EditFind", "_Find", None, Gtk.STOCK_FIND) + action = Gtk.Action(name="EditFind", label="_Find", tooltip=None, stock_id=Gtk.STOCK_FIND) action.connect("activate", self.on_search_clicked) action_group.add_action_with_accel(action, "<control>F") def create_pool_menu(self, action_group): - action = Gtk.Action("PoolMenu", "_Pool", None, None) + action = Gtk.Action(name="PoolMenu", label="_Pool", tooltip=None, stock_id=None) action_group.add_action(action) - action = Gtk.Action("SelectConfig", "_Select Configuration", None, None) + action = Gtk.Action(name="SelectConfig", label="_Select Configuration", tooltip=None, stock_id=None) action.connect("activate", self._on_select_pool_config) action_group.add_action(action) - action = Gtk.Action("EditConfig", "_Edit Configuration", None, None) + action = Gtk.Action(name="EditConfig", label="_Edit Configuration", tooltip=None, stock_id=None) action.connect("activate", self._on_edit_pool_config) action_group.add_action(action) - action = Gtk.Action("CreateConfig", "_Create Configuration", None, None) + action = Gtk.Action(name="CreateConfig", label="_Create Configuration", tooltip=None, stock_id=None) action.connect("activate", self._on_create_pool_config) action_group.add_action(action) def create_modules_menu(self, action_group): - action = Gtk.Action("ModulesMenu", "_Modules", None, None) + action = Gtk.Action(name="ModulesMenu", label="_Modules", tooltip=None, stock_id=None) action_group.add_action(action) - action = Gtk.Action("Poolviewer", "_Start Poolviewer", None,None) + action = Gtk.Action(name="Poolviewer", label="_Start Poolviewer", tooltip=None, stock_id=None) action.connect("activate", self._on_start_poolviewer) action_group.add_action(action) - action = Gtk.Action("Poolmanager", "_Start Poolmanager", None,None) + action = Gtk.Action(name="Poolmanager", label="_Start Poolmanager", tooltip=None, stock_id=None) action.connect("activate", self._on_start_poolmanager) action_group.add_action(action) - action = Gtk.Action("Plotter", "_Start Plotter", None,None) + action = Gtk.Action(name="Plotter", label="_Start Plotter", tooltip=None, stock_id=None) action.connect("activate", self._on_start_plotter) action_group.add_action(action) - action = Gtk.Action("Monitor", "_Start Monitor", None,None) + action = Gtk.Action(name="Monitor", label="_Start Monitor", tooltip=None, stock_id=None) action.connect("activate", self._on_start_monitor) action_group.add_action(action) def create_tools_menu(self, action_group): - action = Gtk.Action("ToolsMenu", "_Tools", None, None) + action = Gtk.Action(name="ToolsMenu", label="_Tools", tooltip=None, stock_id=None) action_group.add_action(action) - action = Gtk.Action("ActionButtons", "_Action Buttons Window", None, None) + action = Gtk.Action(name="ActionButtons", label="_Action Buttons Window", tooltip=None, stock_id=None) action.connect("activate", self._on_show_action_window) action_group.add_action(action) - action = Gtk.Action("RestartTerminal", "_Restart Terminal", None, None) + action = Gtk.Action(name="RestartTerminal", label="_Restart Terminal", tooltip=None, stock_id=None) action.connect("activate", self._on_restart_terminal) action_group.add_action(action) def create_help_menu(self, action_group): - action = Gtk.Action("HelpMenu", "_Help", None, None) + action = Gtk.Action(name="HelpMenu", label="_Help", tooltip=None, stock_id=None) action_group.add_action(action) - action = Gtk.Action("AboutDialog", "_About", None, Gtk.STOCK_ABOUT) + action = Gtk.Action(name="AboutDialog", label="_About", tooltip=None, stock_id=Gtk.STOCK_ABOUT) action.connect("activate", self._on_select_about_dialog) #action.connect("activate", cfl.about_dialog(self)) action_group.add_action(action) @@ -1119,7 +1138,9 @@ class CcsEditor(Gtk.Window): button_run_nextline = Gtk.ToolButton() # button_run_nextline.set_icon_name("media-playback-start-symbolic") - pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size('pixmap/media-playback-start-symbolic_uvie.svg', 24, 24) + + pixmap_path = os.path.join(pixmap_folder, 'media-playback-start-symbolic_uvie.svg') + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(pixmap_path, 24, 24) icon = Gtk.Image.new_from_pixbuf(pixbuf) button_run_nextline.set_icon_widget(icon) button_run_nextline.set_tooltip_text('Run Line') @@ -1129,7 +1150,8 @@ class CcsEditor(Gtk.Window): button_run_sameline = Gtk.ToolButton() # button_run_nextline.set_icon_name("media-playback-start-symbolic") - pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size('pixmap/media-playback-start-symbolic-down_uvie.svg', 24, 24) + pixmap_path = os.path.join(pixmap_folder, 'media-playback-start-symbolic-down_uvie.svg') + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(pixmap_path, 24, 24) icon = Gtk.Image.new_from_pixbuf(pixbuf) button_run_sameline.set_icon_widget(icon) button_run_sameline.set_tooltip_text('Run Line (remain in line)') @@ -1138,7 +1160,8 @@ class CcsEditor(Gtk.Window): button_run_all = Gtk.ToolButton() # button_run_all.set_icon_name("media-seek-forward-symbolic") - pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size('pixmap/media-skip-forward-symbolic_uvie.svg', 24, 24) + pixmap_path = os.path.join(pixmap_folder, 'media-skip-forward-symbolic_uvie.svg') + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(pixmap_path, 24, 24) icon = Gtk.Image.new_from_pixbuf(pixbuf) button_run_all.set_icon_widget(icon) button_run_all.set_tooltip_text('Run All') @@ -1147,7 +1170,8 @@ class CcsEditor(Gtk.Window): button_run_all_nobreak = Gtk.ToolButton() # button_run_all.set_icon_name("media-seek-forward-symbolic") - pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size('pixmap/media-seek-forward-symbolic_uvie.svg', 24, 24) + pixmap_path = os.path.join(pixmap_folder, 'media-seek-forward-symbolic_uvie.svg') + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(pixmap_path, 24, 24) icon = Gtk.Image.new_from_pixbuf(pixbuf) button_run_all_nobreak.set_icon_widget(icon) button_run_all_nobreak.set_tooltip_text('Run All (ignore breakmarks)') @@ -1193,7 +1217,8 @@ class CcsEditor(Gtk.Window): try: pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(button_img_path, 36, 36) except: - pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size('pixmap/action.png', 36, 36) + pixmap_path = os.path.join(pixmap_folder, 'action.png') + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(pixmap_path, 36, 36) icon = Gtk.Image.new_from_pixbuf(pixbuf) button_action.set_icon_widget(icon) button_action.set_name('action{}'.format(n + 1)) @@ -1508,9 +1533,11 @@ class CcsEditor(Gtk.Window): """ dump line into console """ line = textbuffer.get_text(start, stop, True) line += str('\n\n') + # self.ipython_view.text_buffer.insert_at_cursor(line, len(line)) # self.ipython_view._processLine() - self._to_console(line) + #self._to_console(line, editor_read=True) + self._to_console_via_socket(line) self._set_play_mark(view, stop) @@ -1531,9 +1558,11 @@ class CcsEditor(Gtk.Window): """ dump line into console """ line = textbuffer.get_text(start, end, True) line += str('\n\n') + # self.ipython_view.text_buffer.insert_at_cursor(line, len(line)) # self.ipython_view._processLine() - self._to_console(line) + #self._to_console(line, editor_read=True) + self._to_console_via_socket(line) self._set_play_mark(view, end) @@ -1553,7 +1582,16 @@ class CcsEditor(Gtk.Window): editor_sock.close() return ack - def _to_console(self, buf): + #TODO: Very interesting behaviour by the editor console if every execution is done by the '_to_console' command, + # at the beginnig everything works fine, run all and run line by line, if a function is executed the same is true, + # but not if the function is first executed by run all and than by run line per line... the console just deletes + # the command befor it is executed, run all is now executed via socket everything works fine, changes would just be + # a visual plus, and the addvatage to use the built in command to communicate with the console, + # #### Additionally: using python 3.8 or newer, _to_console function does not yet work... but _to_conosle_via_socket + # works for every version, therefore it is used as long no solution is found + + + def _to_console(self, buf, execute=True, editor_read=False): ''' This function sends data to the IPython Terminal, Gtk.VteTerminal has a built in function to do this @param buf: String that should be sent @@ -1570,7 +1608,7 @@ class CcsEditor(Gtk.Window): if len(terminal_text) > shown_length: saved_text = terminal_text[8:-2] else: - saved_text = None + saved_text = '' # If code was entered delete it, otherwise the new command would be added at the end while entry_length > shown_length: @@ -1700,7 +1738,7 @@ class CcsEditor(Gtk.Window): try: # self.ipython_view.text_buffer.insert_at_cursor(cmd, len(cmd)) # self.ipython_view._processLine() - self._to_console(cmd) + self._to_console_via_socket(cmd) # exec(open(action,'r').read()) # print(action + ' executed') except FileNotFoundError: @@ -1721,7 +1759,8 @@ class CcsEditor(Gtk.Window): try: pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(action_img, 36, 36) except: - pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size('pixmap/action.png', 36, 36) + pixmap_path = os.path.join(pixmap_folder, 'action.png') + pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(pixmap_path, 36, 36) button.set_icon_widget(Gtk.Image.new_from_pixbuf(pixbuf)) self.show_all() return @@ -1730,10 +1769,10 @@ class CcsEditor(Gtk.Window): cmd = 'get_ipython().reset()\n\n' # self.ipython_view.text_buffer.insert_at_cursor(cmd, len(cmd)) # self.ipython_view._processLine() - self._to_console(cmd) + self._to_console_via_socket(cmd) # self.ipython_view.updateNamespace({'cfg': self.cfg}) # self.ipython_view.updateNamespace(globals()) - self._to_console('import configparser\n' + self._to_console_via_socket('import configparser\n' 'cfg = configparser.ConfigParser()\n' 'cfg.read("{}")'.format(confignator.get_option('config-files', 'ccs').split('/')[-1])) @@ -1792,7 +1831,8 @@ class ActionWindow(Gtk.Window): self.logger = editor.logger grid = Gtk.Grid() buttons = {} - pixbuf_default = GdkPixbuf.Pixbuf.new_from_file_at_size('pixmap/action.png', 36, 36) + pixmap_path = os.path.join(pixmap_folder, 'action.png') + pixbuf_default = GdkPixbuf.Pixbuf.new_from_file_at_size(pixmap_path, 36, 36) for i in range(nbuttons): button = Gtk.ToolButton() diff --git a/Ccs/monitor.py b/Ccs/monitor.py index 3a81b8667ccacfb9723601d3c4220027c0aeef10..b1e5ccf9745786e8aaf7037d91b3858bca8e63c0 100644 --- a/Ccs/monitor.py +++ b/Ccs/monitor.py @@ -556,14 +556,14 @@ class ParameterMonitor(Gtk.Window): for service in dbus.SessionBus().list_names(): if service.startswith(self.cfg['ccs-dbus_names']['editor']): editor = cfl.dbus_connection('editor', service[-1]) - editor.Functions('_to_console', "monitor = dbus.SessionBus().get_object('" + + editor.Functions('_to_console_via_socket', "monitor = dbus.SessionBus().get_object('" + str(My_Bus_Name) + "', '/MessageListener')") else: for service in dbus.SessionBus().list_names(): if service.startswith(self.cfg['ccs-dbus_names']['editor']): editor = cfl.dbus_connection('editor', service[-1]) - editor.Functions('_to_console', "monitor" +str(Count)+ + editor.Functions('_to_console_via_socket', "monitor" +str(Count)+ " = dbus.SessionBus().get_object('" + str(My_Bus_Name)+ "', '/MessageListener')") @@ -578,7 +578,7 @@ class ParameterMonitor(Gtk.Window): nr = self.my_bus_name[-1] if nr == str(1): nr = '' - editor.Functions('_to_console', 'del(monitor'+str(nr)+')') + editor.Functions('_to_console_via_socket', 'del(monitor'+str(nr)+')') self.update_all_connections_quit() Gtk.main_quit() diff --git a/Ccs/plotter.py b/Ccs/plotter.py index fa698dfd75944e69b31006bcb44a775daaf17aa4..87eaa7ee8c4376194e45179f0f6b5452dd658500 100644 --- a/Ccs/plotter.py +++ b/Ccs/plotter.py @@ -1109,7 +1109,7 @@ class PlotViewer(Gtk.Window): nr = self.my_bus_name[-1] if nr == str(1): nr = '' - editor.Functions('_to_console', 'del(paramplot' + str(nr) + ')') + editor.Functions('_to_console_via_socket', 'del(paramplot' + str(nr) + ')') self.update_all_connections_quit() Gtk.main_quit() @@ -1197,14 +1197,14 @@ class PlotViewer(Gtk.Window): for service in dbus.SessionBus().list_names(): if service.startswith(self.cfg['ccs-dbus_names']['editor']): editor = cfl.dbus_connection('editor', service[-1]) - editor.Functions('_to_console', "paramplot = dbus.SessionBus().get_object('" + + editor.Functions('_to_console_via_socket', "paramplot = dbus.SessionBus().get_object('" + str(My_Bus_Name) + "', '/MessageListener')") else: for service in dbus.SessionBus().list_names(): if service.startswith(self.cfg['ccs-dbus_names']['editor']): editor = cfl.dbus_connection('editor', service[-1]) - editor.Functions('_to_console', "paramplot" + str(Count) + + editor.Functions('_to_console_via_socket', "paramplot" + str(Count) + " = dbus.SessionBus().get_object('" + str(My_Bus_Name) + "', '/MessageListener')") diff --git a/Ccs/poolview_sql.py b/Ccs/poolview_sql.py index 07faf94a50386100b02bd121465a6117e9d9f3cd..c5ff8ae83b7238e6da8948ab897cca95c7f74270 100644 --- a/Ccs/poolview_sql.py +++ b/Ccs/poolview_sql.py @@ -323,7 +323,7 @@ class TMPoolView(Gtk.Window): nr = self.my_bus_name[-1] if nr == str(1): nr = '' - editor.Functions('_to_console', 'del(pv'+str(nr)+')') + editor.Functions('_to_console_via_socket', 'del(pv'+str(nr)+')') return def update_all_connections_quit(self): @@ -502,14 +502,14 @@ class TMPoolView(Gtk.Window): for service in dbus.SessionBus().list_names(): if service.startswith(self.cfg['ccs-dbus_names']['editor']): editor = cfl.dbus_connection('editor', service[-1]) - editor.Functions('_to_console', "pv = dbus.SessionBus().get_object('" + str(My_Bus_Name) + editor.Functions('_to_console_via_socket', "pv = dbus.SessionBus().get_object('" + str(My_Bus_Name) + "', '/MessageListener')") else: for service in dbus.SessionBus().list_names(): if service.startswith(self.cfg['ccs-dbus_names']['editor']): editor = cfl.dbus_connection('editor', service[-1]) - editor.Functions('_to_console', "pv" +str(Count)+ " = dbus.SessionBus().get_object('" + + editor.Functions('_to_console_via_socket', "pv" +str(Count)+ " = dbus.SessionBus().get_object('" + str(My_Bus_Name) + "', '/MessageListener')") ##### @@ -684,7 +684,7 @@ class TMPoolView(Gtk.Window): height = self.treeview.get_allocated_height() cell = self.treeview.get_columns()[0].cell_get_size()[-1] + 2 nlines = height // cell - self.adj.set_page_size(nlines) + self.adj.set_page_size(nlines-3) # self._scroll_treeview() self.reselect_rows() @@ -774,9 +774,9 @@ class TMPoolView(Gtk.Window): #offset = 0 if offset < 0 else offset self.shown_lock.acquire() # Thread lock to changes shared variables between threads - # If the offset is still in buffer range get new packages from buffer and reload the buffer in a thread + # If the offset is still in buffer range get new packages from buffer and reload the buffer in a thread, if autoscroll dont use buffer (makes no sense) #if self.shown_loaded and offset in range(self.shown_upper_limit, self.shown_offset+buffer) and not force_import: - if self.shown_loaded and offset in range(self.shown_all_rows[0][0], self.shown_all_rows[position][0]+1) and not force_import and not sort: + if self.shown_loaded and offset in range(self.shown_all_rows[0][0], self.shown_all_rows[position][0]+1) and not force_import and not sort and not self.autoscroll: if self.filter_rules_active and scrolled: for x, row in enumerate(self.shown_all_rows, start=0): if row[0] >= self.shown_offset: @@ -795,7 +795,7 @@ class TMPoolView(Gtk.Window): self.shown_diff += shown_diff # Thread is already loading, load additional ones else: self.shown_diff = shown_diff # New thread knows how much should be loaded - elif self.shown_loaded and self.shown_offset and abs(self.shown_offset-self.offset) < buffer and sort and not force_import: # If sorted and inside buffer + elif self.shown_loaded and self.shown_offset and abs(self.shown_offset-self.offset) < buffer and sort and not force_import and not self.autoscroll: # If sorted and inside buffer shown_diff = offset - self.shown_offset if isinstance(self.shown_diff, int): @@ -1663,7 +1663,7 @@ class TMPoolView(Gtk.Window): for row in model: if row[0] in self.currently_selected: try: - self.selection.select_path(model.get_path(model.get_iter(min(row[0] - self.offset - 1+2)))) + self.selection.select_path(model.get_path(model.get_iter(row[0] - self.offset - 1))) except ValueError: pass except TypeError: diff --git a/Ccs/pus_datapool.py b/Ccs/pus_datapool.py index 65701fb31a13e52562d9250d94ffaa8523274146..c3b31c277393adcf1cc1e2538c1ccd621104a554 100644 --- a/Ccs/pus_datapool.py +++ b/Ccs/pus_datapool.py @@ -110,6 +110,7 @@ class DatapoolManager: lock = threading.Lock() own_gui = None gui_running = False + main_instance = None windowname = ' .Pool Manager' def __init__(self, given_cfg=None, cfilters='default', max_colour_rows=8000): @@ -1861,6 +1862,7 @@ class DatapoolManager: self.quit_func() def quit_func(self): + pv = cfl.dbus_connection('poolviewer') for service in dbus.SessionBus().list_names(): if service.startswith(self.cfg['ccs-dbus_names']['editor']): editor = cfl.dbus_connection(service[0:-1].split('.')[1], service[-1]) @@ -1868,8 +1870,7 @@ class DatapoolManager: nr = self.my_bus_name[-1] if nr == str(1): nr = '' - editor.Functions('_to_console', 'del(pmgr' + str(nr) + ')') - + editor.Functions('_to_console_via_socket', 'del(pmgr' + str(nr) + ')') self.update_all_connections_quit() Gtk.main_quit() @@ -1888,7 +1889,7 @@ class DatapoolManager: if service == self.my_bus_name: # If own allplication do nothing continue conn = cfl.dbus_connection(service.split('.')[1], service[-1]) - if conn.Variables('main_instance') == self.main_instance: # Check if running in same project + if cfl.Variables(conn,'main_instance') == self.main_instance: # Check if running in same project if service.startswith(self.my_bus_name[:-1]): # Check if it is same application type my_con.append(service) else: @@ -1898,10 +1899,10 @@ class DatapoolManager: our_con = our_con + my_con # Add the instances of same application to change the main communication as well for service in our_con: # Change the main communication for all applications+ conn = cfl.dbus_connection(service.split('.')[1], service[-1]) - comm = conn.Functions('get_communication') + comm = cfl.Functions(conn, 'get_communication') # Check if this application is the main applications otherwise do nothing if str(comm[self.my_bus_name.split('.')[1]]) == self.my_bus_name[-1]: - conn.Functions('change_communication', self.my_bus_name.split('.')[1], instance, False) + cfl.Functions(conn, 'change_communication', self.my_bus_name.split('.')[1], instance, False) return def connect_to_all(self, My_Bus_Name, Count): @@ -1939,13 +1940,13 @@ class DatapoolManager: for service in dbus.SessionBus().list_names(): if service.startswith(self.cfg['ccs-dbus_names']['editor']): editor = cfl.dbus_connection('editor', service[-1]) - editor.Functions('_to_console', "pmgr = dbus.SessionBus().get_object('" + + editor.Functions('_to_console_via_socket', "pmgr = dbus.SessionBus().get_object('" + str(My_Bus_Name) + "', '/MessageListener')") else: for service in dbus.SessionBus().list_names(): if service.startswith(self.cfg['ccs-dbus_names']['editor']): editor = cfl.dbus_connection('editor', service[-1]) - editor.Functions('_to_console', "pmgr" + str(Count) + + editor.Functions('_to_console_via_socket', "pmgr" + str(Count) + " = dbus.SessionBus().get_object('" + str(My_Bus_Name) + "', '/MessageListener')") return @@ -1998,10 +1999,10 @@ class LoadInfo(Gtk.Window): class UnsavedBufferDialog(Gtk.MessageDialog): def __init__(self, parent=None, msg=None): - Gtk.MessageDialog.__init__(self, title="Quit Pool Manager?", parent=parent, flags=0, - buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, + Gtk.MessageDialog.__init__(self, title="Quit Pool Manager?", parent=parent, flags=0.,) + self.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_NO, Gtk.ResponseType.NO, - Gtk.STOCK_YES, Gtk.ResponseType.YES,)) + Gtk.STOCK_YES, Gtk.ResponseType.YES,) head, message = self.get_message_area().get_children() if msg == None: head.set_text('Response NO will keep the Pool Manager running in the background and only the GUI is closed') @@ -2085,11 +2086,11 @@ class PUSDatapoolManagerGUI(Gtk.ApplicationWindow): box.pack_start(optionbox, 0, 0, 0) buttonbox = Gtk.HBox() - connect_in = Gtk.Button('Connect') + connect_in = Gtk.Button.new_with_label('Connect') buttonbox.pack_start(connect_in, 1, 1, 0) - disconnect_in = Gtk.Button('Disconnect') + disconnect_in = Gtk.Button.new_with_label('Disconnect') buttonbox.pack_start(disconnect_in, 1, 1, 0) - display_pool = Gtk.Button('Display') + display_pool = Gtk.Button.new_with_label('Display') buttonbox.pack_start(display_pool, 1, 1, 0) # display_pool.tooltip_text('Select TM connection and display it in the Poolviewer') box.pack_start(buttonbox, 0, 0, 0) diff --git a/Tst/config_editor/config_editor.py b/Tst/config_editor/config_editor.py index d561fa8d62154714a9e87f3e7dd615a64409090d..f3160f4445fab56cc7de3648c72757299051834f 100644 --- a/Tst/config_editor/config_editor.py +++ b/Tst/config_editor/config_editor.py @@ -169,6 +169,7 @@ class ConfigurationEditor(Gtk.ApplicationWindow): self.tabs = [] self.merge_cfg = None self.merge_page = None + self.page_widget = None # loads all configuration files listed in file_path & at least the configuration file of the confignator self.load_configuration(file_path=file_path) @@ -306,12 +307,14 @@ class ConfigurationEditor(Gtk.ApplicationWindow): self.logger.debug('created merge page with index {} for: {}'.format(merge_page_idx, self.merge_cfg.files)) def new_page(self, cfg=None, file_path=None): - page_widget = PageWidget(window=self, file_path=file_path, cfg=cfg) + self.page_widget = PageWidget(window=self, file_path=file_path, cfg=cfg) # create page label if file_path is not None: label_text = os.path.basename(file_path) + self.create_new_merge = False else: label_text = 'Merge' + self.create_new_merge = True label_box = Gtk.Box() label_box.set_orientation(Gtk.Orientation.HORIZONTAL) label = Gtk.Label() @@ -322,12 +325,15 @@ class ConfigurationEditor(Gtk.ApplicationWindow): label_box.pack_start(label_btn_close, True, True, 0) label_box.show_all() # append notebook page - page_index = self.notebook.append_page(child=page_widget, tab_label=label_box) + if self.create_new_merge: + page_index = self.notebook.insert_page(child=self.page_widget, tab_label=label_box, position=0) + else: + page_index = self.notebook.append_page(child=self.page_widget, tab_label=label_box) # connect the tab close button - label_btn_close.connect('clicked', self.on_close_notebook_page, page_widget) + label_btn_close.connect('clicked', self.on_close_notebook_page, self.page_widget) self.show_all() self.notebook.set_current_page(page_index) - return page_widget, page_index + return self.page_widget, page_index def on_close_notebook_page(self, button, page_widget): # remove the page from the notebook @@ -355,8 +361,10 @@ class ConfigurationEditor(Gtk.ApplicationWindow): page_idx = self.notebook.get_current_page() page_widget = self.notebook.get_nth_page(page_idx) page_widget.update_option_data(except_section=except_section, except_option=except_option) - if self.show_merge_page: + if self.show_merge_page and not self.create_new_merge: self.set_merge_page() + if self.create_new_merge: + self.create_new_merge = False def on_reload(self, *args): for idx in range(0, self.notebook.get_n_pages()): diff --git a/Tst/connect_apps.py b/Tst/connect_apps.py index 18682e6ccee0517e75e3d0f094b5c029f728d580..5b8b0a3412f747de766163fea8dc938b89a29c53 100644 --- a/Tst/connect_apps.py +++ b/Tst/connect_apps.py @@ -48,6 +48,8 @@ def connect_to_editor(logger=module_logger): except dbus.exceptions.DBusException as dbe: logger.error('Could not connect to the editor application') logger.exception(dbe) + return + return editor def connect_to_tst(logger=module_logger): @@ -77,7 +79,7 @@ def connect_to_progress_viewer(logger=module_logger): actions = interface_actions.List() logger.debug('Available Actions for {}:'.format(bus_name)) for item in actions: - logger.debug('\t{}'.format(item)) + logger.debug('{}'.format(item)) return interface_actions diff --git a/Tst/prep_test_env.py b/Tst/prep_test_env.py index 35d4d893094f8f7682eb131604596f0890580220..f58104086cc451ed60427bfe215a166eb3ea8caa 100755 --- a/Tst/prep_test_env.py +++ b/Tst/prep_test_env.py @@ -38,7 +38,8 @@ def run(pool_name): time.sleep(1) logger.info('2) ------------------- Start the PoolManager -------------------') - cfl.start_pmgr(False, False) + if not cfl.is_open('poolmanager'): + cfl.start_pmgr() pm = connect_apps.connect_to_app('poolmanager', logger=logger) logger.info('4) ------------------- Connect the Poolmanager to OBC & TMpool database-------------------') if pm is not False: @@ -50,7 +51,8 @@ def run(pool_name): if pm is not False: logger.info('3) ------------------- Start the PoolViewer -------------------') - cfl.start_pv(False) + if not cfl.is_open('poolviewer'): + cfl.start_pv() pv = connect_apps.connect_to_app('poolviewer', logger=logger) if pv is not False: diff --git a/Tst/progress_view/progress_view.py b/Tst/progress_view/progress_view.py index 8a2d6a33e4e1ea2b215826e37a8c9915b56ed710..57ca2c62581f3f9f21cde75c9e27028a2dc85619 100644 --- a/Tst/progress_view/progress_view.py +++ b/Tst/progress_view/progress_view.py @@ -679,7 +679,7 @@ class TestProgressView(Gtk.ApplicationWindow): # add the TC's tcs_str = '' for telecommand in item['tcs']: - if tcs_str is not '': + if tcs_str != '': tcs_str += ', ' tcs_str += telecommand.tc_kind() self.build_row_list(row=new_row, diff --git a/Tst/testing_library/testlib/idb.py b/Tst/testing_library/testlib/idb.py index 59438da089c25f89144e77201d0a7261af1fd656..5bfb2aa6c57a8e8cac12b3a47f4fa577de86ac0b 100644 --- a/Tst/testing_library/testlib/idb.py +++ b/Tst/testing_library/testlib/idb.py @@ -4,6 +4,13 @@ Functions to use the instrument database ======================================== """ import logging +import sys + +import confignator +ccs_path = confignator.get_option('paths', 'ccs') +sys.path.append(ccs_path) + +import ccs_function_lib as cfl # create a logger logger = logging.getLogger(__name__) @@ -14,10 +21,9 @@ logger = logging.getLogger(__name__) # @param ccs: instance of the CCScom class # @param sid: sid of housekeepings <str> # @return: sid <int> -def convert_hk_sid(ccs, sid): +def convert_hk_sid(sid): """ Convert the SID of housekeeping reports in both ways: int to str and str to int - - :param ccs: packets.CCScom: instance of the class CCScom + :param sid: int or str: SID of a housekeeping as string or as integer :return: str or int: SID of the housekeeping as string or integer @@ -25,13 +31,15 @@ def convert_hk_sid(ccs, sid): assert isinstance(sid, int) or isinstance(sid, str), logger.error('convert_hk_sid: argument sid has to be a integer or string') result = None if isinstance(sid, str): - query = ccs.dbcon.execute('SELECT txp_from FROM txp WHERE txp_altxt="{}"'.format(sid)) + #query = ccs.dbcon.execute('SELECT txp_from FROM txp WHERE txp_altxt="{}"'.format(sid)) + query = cfl.scoped_session_idb.execute('SELECT txp_from FROM txp WHERE txp_altxt="{}"'.format(sid)) fetch = query.fetchall() if len(fetch) != 0: result = int(fetch[0][0]) if isinstance(sid, int): # ToDo: replace hardcoded DPKT7030 - query = ccs.dbcon.execute('SELECT txp_altxt FROM txp WHERE txp_numbr="DPKT7030" AND txp_from="{}"'.format(sid)) + #query = ccs.dbcon.execute('SELECT txp_altxt FROM txp WHERE txp_numbr="DPKT7030" AND txp_from="{}"'.format(sid)) + query = cfl.scoped_session_idb.execute('SELECT txp_altxt FROM txp WHERE txp_numbr="DPKT7030" AND txp_from="{}"'.format(sid)) fetch = query.fetchall() if len(fetch) != 0: result = str(fetch[0][0]) @@ -71,22 +79,20 @@ class DataPoolParameter: } self.possible_values.append(entry) - def assign_value(self, ccs, value): - self.value = ccs.get_calibrated(pcf_name=self.name, rawval=value) + def assign_value(self, value): + self.value = cfl.get_calibrated(pcf_name=self.name, rawval=value) def log_par(self): logger.info('name = {}; width = {}'.format(self.name, self.width)) -def get_info_of_data_pool_parameter(ccs, name): +def get_info_of_data_pool_parameter(name): """ from testlib import idb x = idb.get_info_of_data_pool_parameter(ccs=ccs, name='sdu2State') Fetching all information from the instrument database about data pool parameter names. Knowing only the name of the parameter, all other information should be collected by database queries. - :param ccs: packets.CCScom - Instance of the class packets.CCScom :param name: str Name of the parameter. :return: idb.data_pool_parameter @@ -96,7 +102,8 @@ def get_info_of_data_pool_parameter(ccs, name): # get information from pcf query = 'SELECT * from pcf where pcf_descr="{}"'.format(name) - dbres = ccs.dbcon.execute(query) + #dbres = ccs.dbcon.execute(query) + dbres = cfl.scoped_session_idb.execute(query) result = dbres.fetchall() if len(result) == 1: @@ -110,7 +117,8 @@ def get_info_of_data_pool_parameter(ccs, name): if txp_number is not None: # get the possible values query = 'SELECT * from txp where txp_numbr="{}"'.format(txp_number) - dbres = ccs.dbcon.execute(query) + #dbres = ccs.dbcon.execute(query) + dbres = cfl.scoped_session_idb.execute(query) values = dbres.fetchall() if len(values) > 0: for val in values: diff --git a/Tst/testing_library/testlib/precond.py b/Tst/testing_library/testlib/precond.py index 6df2ad2290545a3febf32dfedbbd8efa1bc81078..0ffe20a43dd2a10943adaf7660cf69bb6d57c529 100644 --- a/Tst/testing_library/testlib/precond.py +++ b/Tst/testing_library/testlib/precond.py @@ -4,6 +4,13 @@ Preconditions ============= """ import logging +import sys + +import confignator +ccs_path = confignator.get_option('paths', 'ccs') +sys.path.append(ccs_path) + +import ccs_function_lib as cfl from . import report from . import sim @@ -14,11 +21,9 @@ from . import tools logger = logging.getLogger(__name__) -def get_states(ccs, pool_name, silent=False): +def get_states(pool_name, silent=False): """ Returns the states of IASW, SEM and SEM_Operational state machine - :param ccs: packets.CCScom - Instance of the class packets.CCScom :param pool_name: str Name of the pool for TM/TCs in the database :return: str, str, str @@ -33,7 +38,7 @@ def get_states(ccs, pool_name, silent=False): if state_names is not None: # fetch the house keeping report entries - states = tm.get_hk_entry(ccs=ccs, pool_name=pool_name, hk_name=hk_name, name=state_names, silent=silent) + states = tm.get_hk_entry(pool_name=pool_name, hk_name=hk_name, name=state_names, silent=silent) # check if the states could be found if states is not None and 'iaswState' in states[0]: @@ -48,17 +53,16 @@ def get_states(ccs, pool_name, silent=False): return state_iasw, state_sem, state_sem_oper -def iasw_standby(ccs, pool_name, silent=False): +def iasw_standby(pool_name, silent=False): """ precondition: 'Nominal operation in STANDBY mode' - :param ccs: instance of packets.CCScom :param pool_name: <str>: name of the pool :return: <boolean>: True if the precondition are fulfilled """ success = False # get states - iasw, state_sem, state_sem_oper = get_states(ccs=ccs, pool_name=pool_name, silent=silent) + iasw, state_sem, state_sem_oper = get_states(pool_name=pool_name, silent=silent) # if the IASW is a other mode: shut down the SEM (if running) and command IASW into STANDBY if iasw == 'SEM_OFFLINE' or iasw == 'PRE_SCIENCE' or iasw == 'SCIENCE': @@ -66,12 +70,13 @@ def iasw_standby(ccs, pool_name, silent=False): sem_runs = sim.sem_runs() if sem_runs: # command SEM to shut of - switch_off_sem(ccs=ccs, pool_name=pool_name) + switch_off_sem(pool_name=pool_name) # command IASW into Standby - ccs.TcStopSem() + #ccs.TcStopSem() + cfl.Tcsend_DB('DPU_IFSW_STOP_SEM') logger.info('command IASW into STANDBY') # get states again - iasw, state_sem, state_sem_oper = get_states(ccs=ccs, pool_name=pool_name) + iasw, state_sem, state_sem_oper = get_states(pool_name=pool_name) # check if the conditions are fulfilled if iasw == 'STANDBY': @@ -80,12 +85,10 @@ def iasw_standby(ccs, pool_name, silent=False): return success -def sem_safe_mode(ccs, pool_name): +def sem_safe_mode(pool_name): """ Verify that the IASW is in SAFE. If IASW is in a other mode, command it to SAFE. - :param ccs: packets.CCScom - instance of packets.CCScom :param pool_name: str Name of the pool for telemetry and telecommand packets in the database :return: boolean @@ -95,7 +98,7 @@ def sem_safe_mode(ccs, pool_name): crsem = None # check the current states - iasw, state_sem, state_sem_oper = get_states(ccs=ccs, pool_name=pool_name) + iasw, state_sem, state_sem_oper = get_states(pool_name=pool_name) # if SEM is not in mode SAFE, do the steps to bring it into it if state_sem != 'SAFE': @@ -103,46 +106,46 @@ def sem_safe_mode(ccs, pool_name): sem_runs = sim.sem_runs() if not sem_runs: # send TC to switch on the SEM - tc_on = ccs.Tcsend_DB('DPU_IFSW_START_OFFLINE_O', ack='0b1011', pool_name=pool_name) - t_tc_on = tm.time_tc_accepted(ccs=ccs, pool_name=pool_name, tc_identifier=tc_on) + #tc_on = ccs.Tcsend_DB('DPU_IFSW_START_OFFLINE_O', ack='0b1011', pool_name=pool_name) + tc_on = cfl.Tcsend_DB('DPU_IFSW_START_OFFLINE_O', ack='0b1011', pool_name=pool_name) + t_tc_on = tm.time_tc_accepted(pool_name=pool_name, tc_identifier=tc_on) # switch on the SEM simulator crsem = sim.start_sem_w_fits() # wait for the event when the SEM to enter INIT trans_1 = {'SrcSemSt': 'OFF', 'DestSemSt': 'INIT'} - evt_init = tm.await_event(ccs=ccs, pool_name=pool_name, severity=1, event_id='EVT_SEM_TR', entries=trans_1, + evt_init = tm.await_event(pool_name=pool_name, severity=1, event_id='EVT_SEM_TR', entries=trans_1, t_from=t_tc_on, duration=20) # wait for the event when the SEM enters OPER trans_2 = {'SrcSemSt': 'INIT', 'DestSemSt': 'OPER'} - evt_oper = tm.await_event(ccs=ccs, pool_name=pool_name, severity=1, event_id='EVT_SEM_TR', entries=trans_2, + evt_oper = tm.await_event(pool_name=pool_name, severity=1, event_id='EVT_SEM_TR', entries=trans_2, t_from=t_tc_on, duration=20) # check if IASW is in OPER and go into SAFE - state_sem = tm.get_hk_entry(ccs=ccs, pool_name=pool_name, hk_name='IFSW_HK', name='semState', silent=True) + state_sem = tm.get_hk_entry(pool_name=pool_name, hk_name='IFSW_HK', name='semState', silent=True) if tools.entry_is_equal(entry=state_sem, key_value={'semState': 'OPER'}): # send TC(192,10) command to bring SEM into SAFE - tc_safe = ccs.Tcsend_DB('DPU_IFSW_GO_SAFE', ack='0b1011', pool_name=pool_name) - t_tc_save = tm.time_tc_accepted(ccs=ccs, pool_name=pool_name, tc_identifier=tc_safe) + #tc_safe = ccs.Tcsend_DB('DPU_IFSW_GO_SAFE', ack='0b1011', pool_name=pool_name) + tc_safe = cfl.Tcsend_DB('DPU_IFSW_GO_SAFE', ack='0b1011', pool_name=pool_name) + t_tc_save = tm.time_tc_accepted(pool_name=pool_name, tc_identifier=tc_safe) # wait for the event when the SEM to enter SAFE trans_3 = {'SrcSemSt': 'OPER', 'DestSemSt': 'SAFE'} - evt_init = tm.await_event(ccs=ccs, pool_name=pool_name, severity=1, event_id='EVT_SEM_TR', entries=trans_3, + evt_init = tm.await_event(pool_name=pool_name, severity=1, event_id='EVT_SEM_TR', entries=trans_3, t_from=t_tc_save, duration=20) # verify that the SEM is now in SAFE expected = {'semState': 'SAFE'} - state_sem = tm.get_hk_entry(ccs=ccs, pool_name=pool_name, hk_name='IFSW_HK', name='semState', silent=True) + state_sem = tm.get_hk_entry(pool_name=pool_name, hk_name='IFSW_HK', name='semState', silent=True) if tools.entry_is_equal(entry=state_sem, key_value=expected): # log the current states - iasw, state_sem, state_sem_oper = get_states(ccs=ccs, pool_name=pool_name) + iasw, state_sem, state_sem_oper = get_states(pool_name=pool_name) success = True return success -def any_iasw_state(ccs, pool_name): +def any_iasw_state(pool_name): """ Precondition: 'Nominal operation in any IASW mode'. - :param ccs: packets.CCScom - Instance of packets.CCScom :param pool_name: str Name of the pool for TM/TCs in the database :return: bool @@ -151,7 +154,7 @@ def any_iasw_state(ccs, pool_name): success = False # get the current states - iasw, state_sem, state_sem_oper = get_states(ccs=ccs, pool_name=pool_name) + iasw, state_sem, state_sem_oper = get_states(pool_name=pool_name) # check if preconditions are fulfilled if iasw == 'SEM_OFFLINE' or iasw == 'STANDBY' or iasw == 'PRE_SCIENCE' or iasw == 'SCIENCE': @@ -160,14 +163,12 @@ def any_iasw_state(ccs, pool_name): return success -def switch_off_sem(ccs, pool_name): +def switch_off_sem(pool_name): """ Send the TC() to switch off the SEM. Wait for the transition events EVT_SEM_TR: * 'SrcSemSt': 'OPER', 'DestSemSt': 'SHUTDOWN' * 'SrcSemSt': 'SHUTDOWN', 'DestSemSt': 'OFF' - :param ccs: packets.CCScom - Instance of the class packets.CCScom :param pool_name: str Name of the pool for TC/TMs in the database :return: bool @@ -179,35 +180,36 @@ def switch_off_sem(ccs, pool_name): sem_state = None # switch off the SEM - sem_off = ccs.Tcsend_DB('DPU_IFSW_SWCH_OFF_SEM', ack='0b1011', pool_name=pool_name) + #sem_off = ccs.Tcsend_DB('DPU_IFSW_SWCH_OFF_SEM', ack='0b1011', pool_name=pool_name) + sem_off = cfl.Tcsend_DB('DPU_IFSW_SWCH_OFF_SEM', ack='0b1011', pool_name=pool_name) logger.info('Terminating SEM simulator process') sim.stop_sem(None) - tm.check_acknowledgement(ccs=ccs, pool_name=pool_name, tc_identifier=sem_off) + tm.check_acknowledgement(pool_name=pool_name, tc_identifier=sem_off) # check if a TM(1,7) was received for this TC - suc, acknow = tm.await_tc_acknow(ccs=ccs, pool_name=pool_name, tc_identifier=sem_off, tm_st=1, tm_sst=7) + suc, acknow = tm.await_tc_acknow(pool_name=pool_name, tc_identifier=sem_off, tm_st=1, tm_sst=7) if len(acknow) > 0: logger.info('Command was accepted, started, terminated. Received TM(1,7)') - t_sem_off = tm.time_tc_accepted(ccs=ccs, pool_name=pool_name, tc_identifier=sem_off) + t_sem_off = tm.time_tc_accepted(pool_name=pool_name, tc_identifier=sem_off) # get event EVT_SEM_TR with transistion_1 = {'SrcSemSt': 'OPER', 'DestSemSt': 'SHUTDOWN'} - event_shutdown = tm.await_event(ccs=ccs, severity=ccs.EVENT_SEVERITY_NORMAL, event_id='EVT_SEM_TR', + event_shutdown = tm.await_event(severity=ccs.EVENT_SEVERITY_NORMAL, event_id='EVT_SEM_TR', pool_name=pool_name, t_from=t_sem_off, entries=transistion_1) # get event EVT_SEM_TR with transistion_2 = {'SrcSemSt': 'SHUTDOWN', 'DestSemSt': 'OFF'} - event_off = tm.await_event(ccs=ccs, severity=ccs.EVENT_SEVERITY_NORMAL, event_id='EVT_SEM_TR', + event_off = tm.await_event(severity=ccs.EVENT_SEVERITY_NORMAL, event_id='EVT_SEM_TR', pool_name=pool_name, t_from=t_sem_off, entries=transistion_2) if len(event_shutdown) > 0 and len(event_off) > 0: - t_event_1 = ccs.get_cuctime(event_shutdown) - t_event_2 = ccs.get_cuctime(event_off) - time_diff = t_event_2 - ccs.get_cuctime(t_sem_off) + t_event_1 = cfl.get_cuctime(event_shutdown) + t_event_2 = cfl.get_cuctime(event_off) + time_diff = t_event_2 - cfl.get_cuctime(t_sem_off) logger.info('Time difference between TC acknowledgement and event EVT_SEM_TR (OFF): {}s'.format(time_diff)) # verify that the SEM state machine is in state OFF - sem_state_machine = tm.get_hk_entry(ccs=ccs, pool_name=pool_name, hk_name='IFSW_HK', name='semState', + sem_state_machine = tm.get_hk_entry(pool_name=pool_name, hk_name='IFSW_HK', name='semState', t_from=t_event_2) if sem_state_machine is not None and 'semState' in sem_state_machine[0]: if sem_state_machine[0]['semState'] == 'OFF': @@ -221,7 +223,7 @@ def switch_off_sem(ccs, pool_name): return result -def iasw_semoffline_semoper_standby(ccs, pool_name): +def iasw_semoffline_semoper_standby(pool_name): """ Establish the precondition: Nominal operation with * IASW state machine in 'SEM_OFFLINE' @@ -237,9 +239,7 @@ def iasw_semoffline_semoper_standby(ccs, pool_name): Waiting for the SEM events when entering 'INIT' and 'OPER'. Waiting for the SEM Operational event when entering 'STANDBY'. * Check the states again to verify if the preconditions are satisfied. - - :param ccs: instance of packets.CCScom - Instance of packets.CCScom + :param pool_name: str Name of the pool in the database where TC/TMs are stored :return: bool, subprocess.Popen @@ -248,7 +248,7 @@ def iasw_semoffline_semoper_standby(ccs, pool_name): success = False # get the states - state_iasw, state_sem, state_sem_oper = get_states(ccs=ccs, pool_name=pool_name) + state_iasw, state_sem, state_sem_oper = get_states(pool_name=pool_name) # check if the preconditions are already fulfilled if state_iasw == 'SEM_OFFLINE' and state_sem == 'OPER' and state_sem_oper == 'STANDBY': @@ -259,11 +259,12 @@ def iasw_semoffline_semoper_standby(ccs, pool_name): if state_iasw != 'STANDBY': # command IASW into Standby logger.info('Command IASW into STANDBY') - tc_stop = ccs.TcStopSem() - t_tc_stop = tm.time_tc_accepted(ccs=ccs, pool_name=pool_name, tc_identifier=tc_stop) + #tc_stop = ccs.TcStopSem() + tc_stop = cfl.TcStopSem() + t_tc_stop = tm.time_tc_accepted(pool_name=pool_name, tc_identifier=tc_stop) # wait for the event when the IASW enters STANDBY trans = {'DestIaswSt': 'STANDBY'} - evt_stop = tm.await_event(ccs=ccs, pool_name=pool_name, severity=1, event_id='EVT_IASW_TR', + evt_stop = tm.await_event(pool_name=pool_name, severity=1, event_id='EVT_IASW_TR', entries=trans, t_from=t_tc_stop, duration=10) # check if the CrSem process is already running @@ -275,36 +276,37 @@ def iasw_semoffline_semoper_standby(ccs, pool_name): logger.info('CrSem is already running') # check if the state of the SEM is OFF - sem_state = tm.get_hk_entry(ccs=ccs, pool_name=pool_name, hk_name='IFSW_HK', name='semState', silent=True) + sem_state = tm.get_hk_entry(pool_name=pool_name, hk_name='IFSW_HK', name='semState', silent=True) expect = {'semState': 'OFF'} if tools.entry_is_equal(entry=sem_state, key_value=expect): # command IASW into SEM_OFFLINE if it is in STANDBY expected = {'iaswState': 'STANDBY'} - iasw_state = tm.get_hk_entry(ccs=ccs, pool_name=pool_name, hk_name='IFSW_HK', name=expected, silent=True) + iasw_state = tm.get_hk_entry(pool_name=pool_name, hk_name='IFSW_HK', name=expected, silent=True) if tools.entry_is_equal(entry=iasw_state, key_value=expected): logger.info('Command IASW into SEM_OFFLINE') - tc_on = ccs.Tcsend_DB('DPU_IFSW_START_OFFLINE_O', ack='0b1011', pool_name=pool_name) + #tc_on = ccs.Tcsend_DB('DPU_IFSW_START_OFFLINE_O', ack='0b1011', pool_name=pool_name) + tc_on = cfl.Tcsend_DB('DPU_IFSW_START_OFFLINE_O', ack='0b1011', pool_name=pool_name) # check that the command was successful accepted, started, terminated - tm.check_acknowledgement(ccs=ccs, pool_name=pool_name, tc_identifier=tc_on) - t_tc_on = tm.time_tc_accepted(ccs=ccs, pool_name=pool_name, tc_identifier=tc_on) + tm.check_acknowledgement(pool_name=pool_name, tc_identifier=tc_on) + t_tc_on = tm.time_tc_accepted(pool_name=pool_name, tc_identifier=tc_on) # wait for the events of the SEM start up events if t_tc_on is not None: logger.info('Waiting for the events of the SEM to enter INIT -> OPER and for SemOp to enter STANDBY') # wait for the event when the SEM to enter INIT trans_1 = {'SrcSemSt': 'OFF', 'DestSemSt': 'INIT'} - evt_init = tm.await_event(ccs=ccs, pool_name=pool_name, severity=1, event_id='EVT_SEM_TR', + evt_init = tm.await_event(pool_name=pool_name, severity=1, event_id='EVT_SEM_TR', entries=trans_1, t_from=t_tc_on, duration=2) # wait for the event when the SEM enters OPER trans_2 = {'SrcSemSt': 'INIT', 'DestSemSt': 'OPER'} - evt_oper = tm.await_event(ccs=ccs, pool_name=pool_name, severity=1, event_id='EVT_SEM_TR', + evt_oper = tm.await_event(pool_name=pool_name, severity=1, event_id='EVT_SEM_TR', entries=trans_2, t_from=t_tc_on, duration=60) # wait for the event when the SEM operational enters STANDBY trans_3 = {'DestSemOpSt': 'STANDBY'} - evt_stan = tm.await_event(ccs=ccs, pool_name=pool_name, severity=1, event_id='EVT_SEMOP_TR', + evt_stan = tm.await_event(pool_name=pool_name, severity=1, event_id='EVT_SEMOP_TR', entries=trans_3, t_from=t_tc_on, duration=2) # get the states again - state_iasw, state_sem, state_sem_oper = get_states(ccs=ccs, pool_name=pool_name) + state_iasw, state_sem, state_sem_oper = get_states(pool_name=pool_name) # check if preconditions are fulfilled if state_iasw == 'SEM_OFFLINE' and state_sem == 'OPER' and state_sem_oper == 'STANDBY': success = True @@ -312,11 +314,9 @@ def iasw_semoffline_semoper_standby(ccs, pool_name): return success -def sem_oper_go_stabilize(ccs, pool_name, await_event=True): +def sem_oper_go_stabilize(pool_name, await_event=True): """ bring the SEM Operational State Machine into STABILIZE - :param ccs: packets.CCScom - Instance of the class packets.CCScom :param pool_name: str Name of the pool for TC/TM in the database :param await_event: bool @@ -328,16 +328,16 @@ def sem_oper_go_stabilize(ccs, pool_name, await_event=True): success = False logger.info('bring SEM Operational State Machine into STABILIZE') # send TC(192,3) to order the SEM Operational State Machine into STABILIZE - tc = ccs.Tcsend_DB('DPU_IFSW_GO_STAB', ack='0b1011', pool_name=pool_name) - t_tc = tm.time_tc_accepted(ccs=ccs, pool_name=pool_name, tc_identifier=tc) + #tc = ccs.Tcsend_DB('DPU_IFSW_GO_STAB', ack='0b1011', pool_name=pool_name) + tc = cfl.Tcsend_DB('DPU_IFSW_GO_STAB', ack='0b1011', pool_name=pool_name) + t_tc = tm.time_tc_accepted(pool_name=pool_name, tc_identifier=tc) # check if the command was successful by looking for acknowledgement packets - ack = tm.check_acknowledgement(ccs=ccs, pool_name=pool_name, tc_identifier=tc) + ack = tm.check_acknowledgement(pool_name=pool_name, tc_identifier=tc) # verify the transition of the SEM Operational State Machine into STABILIZE if await_event is True: par = {'SrcSemOpSt': 'TR_STABILIZE', 'DestSemOpSt': 'STABILIZE'} - event = tm.await_event(ccs=ccs, - pool_name=pool_name, + event = tm.await_event(pool_name=pool_name, severity=1, event_id='EVT_SEMOP_TR', entries=par, @@ -348,7 +348,7 @@ def sem_oper_go_stabilize(ccs, pool_name, await_event=True): return success -def pre_science_stabilize(ccs, pool_name): +def pre_science_stabilize(pool_name): """ This function sends the command to enter PRE_SCIENCE. The SEM event forwarding is enabled and at the end of this function disabled again. @@ -360,8 +360,6 @@ def pre_science_stabilize(ccs, pool_name): Then the command to go into PRE_SCIENCE is sent. The events of entering PRE_SCIENCE and STABILIZE are awaited. If they are received the function returns True. - :param ccs: packets.CCScom - Instance of the class packets.CCScom :param pool_name: str Name of the data pool for TM/TCs in the database :return: bool @@ -376,18 +374,19 @@ def pre_science_stabilize(ccs, pool_name): # enable SEM event forwarding logger.info('pre_science_stabilize: enable the SEM event forwarding') - tc_for = ccs.Tcsend_DB('DPU_IFSW_UPDT_PAR_BOOL', 4, + #tc_for = ccs.Tcsend_DB('DPU_IFSW_UPDT_PAR_BOOL', 4, + tc_for = cfl.Tcsend_DB('DPU_IFSW_UPDT_PAR_BOOL', 4, 'SEM_SERV5_1_FORWARD', 'TYPE_BOOL', 0, 1, 'SEM_SERV5_2_FORWARD', 'TYPE_BOOL', 0, 1, 'SEM_SERV5_3_FORWARD', 'TYPE_BOOL', 0, 1, 'SEM_SERV5_4_FORWARD', 'TYPE_BOOL', 0, 1, ack='0b1011') - tm.check_acknowledgement(ccs=ccs, pool_name=pool_name, tc_identifier=tc_for) + tm.check_acknowledgement(pool_name=pool_name, tc_identifier=tc_for) if not sim.sem_runs(): # start the CrSem (with fits or with the data simulator) logger.info('pre_science_stabilize: starting CrSem ...') - t_sem_start = ccs.get_last_pckt_time(pool_name=pool_name, string=False) + t_sem_start = cfl.get_last_pckt_time(pool_name=pool_name, string=False) sim.start_sem_w_fits() # wait for the CrSem to boot and load the configuration @@ -395,9 +394,9 @@ def pre_science_stabilize(ccs, pool_name): sem_event_2 = 'EVT_PRG_CFG_LD' logger.info('pre_science_stabilize: waiting for the CrSem to boot and load the configuration (events {} and {})' .format(sem_event_1, sem_event_2)) - event_1 = tm.await_event(ccs=ccs, severity=ccs.EVENT_SEVERITY_NORMAL, event_id=sem_event_1, + event_1 = tm.await_event(severity=ccs.EVENT_SEVERITY_NORMAL, event_id=sem_event_1, pool_name=pool_name, duration=wait, t_from=t_sem_start) - event_2 = tm.await_event(ccs=ccs, severity=ccs.EVENT_SEVERITY_NORMAL, event_id=sem_event_2, + event_2 = tm.await_event(severity=ccs.EVENT_SEVERITY_NORMAL, event_id=sem_event_2, pool_name=pool_name, duration=wait, t_from=t_sem_start) # check if the IASW, SEM and SEM operational are in the correct states to command them into PRE_SCIENCE @@ -407,25 +406,25 @@ def pre_science_stabilize(ccs, pool_name): 'semOperState': 'STOPPED' } logger.info('pre_science_stabilize: current states are') - entries = tm.get_hk_entry(ccs=ccs, pool_name=pool_name, hk_name='IFSW_HK', name=expected_states, silent=True) + entries = tm.get_hk_entry(pool_name=pool_name, hk_name='IFSW_HK', name=expected_states, silent=True) ready = tools.entry_is_equal(entry=entries, key_value=expected_states) # if the CrSem is ready, send the TC to prepare for science if ready: # a) command the IASW into PRE_SCIENCE and the SEM into STABILIZE with TC(193,1) logger.info('pre_science_stabilize: command IASW into PRE_SCIENCE...') - prepare_tc = ccs.Tcsend_DB('DPU_IFSW_PREPARE_SCI', ack='0b1011', pool_name=pool_name) - tm.check_acknowledgement(ccs=ccs, pool_name=pool_name, tc_identifier=prepare_tc) - t_tc_presci = tm.time_tc_accepted(ccs=ccs, pool_name=pool_name, tc_identifier=prepare_tc) + prepare_tc = cfl.Tcsend_DB('DPU_IFSW_PREPARE_SCI', ack='0b1011', pool_name=pool_name) + tm.check_acknowledgement(pool_name=pool_name, tc_identifier=prepare_tc) + t_tc_presci = tm.time_tc_accepted(pool_name=pool_name, tc_identifier=prepare_tc) # b) wait for the event: IASW is in state PRE_SCIENCE req_event_i = 'EVT_IASW_TR' req_state_i = {'DestIaswSt': 'PRE_SCIENCE'} - event_iasw = tm.await_event(ccs=ccs, severity=ccs.EVENT_SEVERITY_NORMAL, event_id=req_event_i, + event_iasw = tm.await_event(severity=ccs.EVENT_SEVERITY_NORMAL, event_id=req_event_i, pool_name=pool_name, duration=wait, t_from=t_tc_presci, entries=req_state_i) # log the event TM packet if len(event_iasw) > 0: - report.print_event_data_tuple(ccs=ccs, tm_packets=event_iasw) + report.print_event_data_tuple(tm_packets=event_iasw) else: logger.warning('pre_science_stabilize: waited for IASW to go into the state PRE_SCIENCE for {}s.' 'No event report was received.'.format(wait)) @@ -433,11 +432,11 @@ def pre_science_stabilize(ccs, pool_name): # c) wait for the event: SEM is in state STABILIZE req_event_s = 'EVT_SEMOP_TR' req_state_s = {'DestSemOpSt': 'STABILIZE'} - event_sem_op = tm.await_event(ccs=ccs, severity=ccs.EVENT_SEVERITY_NORMAL, event_id=req_event_s, + event_sem_op = tm.await_event(severity=ccs.EVENT_SEVERITY_NORMAL, event_id=req_event_s, pool_name=pool_name, duration=wait, t_from=t_tc_presci, entries=req_state_s) # log the event TM packet if len(event_sem_op) > 0: - report.print_event_data_tuple(ccs=ccs, tm_packets=event_sem_op) + report.print_event_data_tuple(tm_packets=event_sem_op) else: logger.warning('pre_science_stabilize: waited for SEM to go into the state STABILIZE for {}s.' 'No event report was received.'.format(wait)) @@ -448,13 +447,14 @@ def pre_science_stabilize(ccs, pool_name): # disable SEM event forwarding logger.info('pre_science_stabilize: disable the SEM event forwarding') - tc_dis = ccs.Tcsend_DB('DPU_IFSW_UPDT_PAR_BOOL', 4, + #tc_dis = ccs.Tcsend_DB('DPU_IFSW_UPDT_PAR_BOOL', 4, + tc_dis=ccs.Tcsend_DB('DPU_IFSW_UPDT_PAR_BOOL', 4, 'SEM_SERV5_1_FORWARD', 'TYPE_BOOL', 0, 0, 'SEM_SERV5_2_FORWARD', 'TYPE_BOOL', 0, 0, 'SEM_SERV5_3_FORWARD', 'TYPE_BOOL', 0, 0, 'SEM_SERV5_4_FORWARD', 'TYPE_BOOL', 0, 0, ack='0b1011') - tm.check_acknowledgement(ccs=ccs, pool_name=pool_name, tc_identifier=tc_for) + tm.check_acknowledgement(pool_name=pool_name, tc_identifier=tc_for) # if both events were received this procedure was successful if len(event_iasw) > 0 and len(event_sem_op) > 0: diff --git a/Tst/testing_library/testlib/report.py b/Tst/testing_library/testlib/report.py index c9e10b5d66e8c7ef957d6a993304ccb948924734..76d079ed9f57deb871a1dd1f2bd10ffe2ecc40b4 100644 --- a/Tst/testing_library/testlib/report.py +++ b/Tst/testing_library/testlib/report.py @@ -7,6 +7,13 @@ import datetime import logging import collections import json +import sys + +import confignator +ccs_path = confignator.get_option('paths', 'ccs') +sys.path.append(ccs_path) + +import ccs_function_lib as cfl # create a logger logger = logging.getLogger(__name__) @@ -80,13 +87,12 @@ def parse_step_from_json_string(line, key_word): logger.error('parse_tc_id_from_json_string: parsing of the TC JSON string failed!') -def command_step_begin(step_param, script_version, ccs, pool_name, step_start_cuc): +def command_step_begin(step_param, script_version, pool_name, step_start_cuc): """ Builds a string and writes it into the logging file. A keyword is set to enable a machine read out of the log file. All information of the step is written in a JSON string. :param step_param: :param script_version: - :param ccs: :param pool_name: :param step_start_cuc: :return: @@ -111,7 +117,7 @@ def command_step_end(step_param, step_end_cuc): logger.info('{} {}\n'.format(cmd_step_keyword_done, encode_to_json_string(step_param['step_no'], step_end_cuc))) -def verification_step_begin(step_param, script_version, ccs, pool_name, step_start_cuc): +def verification_step_begin(step_param, script_version, pool_name, step_start_cuc): logger.info('{} {} {}'.format(vrc_step_keyword, step_param['step_no'], encode_to_json_string(step_number=step_param['step_no'], @@ -152,7 +158,7 @@ class StepSummary: # -------------------------------------------- -def write_log_step_header(step_param, ccs, pool_name, step_start_cuc): +def write_log_step_header(step_param, pool_name, step_start_cuc): logger.info('STEP {} (starting from {})' .format(step_param['step_no'], step_start_cuc)) logger.info(step_param['msg']) @@ -168,11 +174,11 @@ def write_log_step_footer(step_param, step_result): logger.warning('Step {} failed.'.format(step_param['step_no'])) -def write_log_test_header(test, ccs, pool_name): +def write_log_test_header(test, pool_name): logger.info('-------------------------------------------------------------------------------') logger.info('Running test {} version {}\n\t\t\t\t\tpoolname = {}\n\t\t\t\t\tCUC-timestamp of test ' 'start = {}\n\t\t\t\t\tlocal time = {}' - .format(test.id, test.version, pool_name, ccs.get_last_pckt_time(pool_name=pool_name, string=False), + .format(test.id, test.version, pool_name, cfl.get_last_pckt_time(pool_name=pool_name, string=False), datetime.datetime.now().isoformat())) logger.info('Description:\n\t\t\t\t\t {}'.format(test.description)) if test.comment: @@ -209,12 +215,12 @@ def write_log_test_footer(test): return successful_steps -def print_data_tuple(ccs, tm_packets): +def print_data_tuple(tm_packets): if not isinstance(tm_packets, list): tm_packets = [tm_packets] for packet in tm_packets: if isinstance(packet, bytes): - data = ccs.Tmdata(packet)[0] + data = cfl.Tmdata(packet)[0] elif isinstance(packet, tuple): data = packet[1][0] else: @@ -227,12 +233,12 @@ def print_data_tuple(ccs, tm_packets): logger.debug('{} = {}'.format(name, value)) -def print_event_data_tuple(ccs, tm_packets): +def print_event_data_tuple(tm_packets): if not isinstance(tm_packets, list): tm_packets = [tm_packets] for packet in tm_packets: if isinstance(packet, bytes): - data = ccs.Tmdata(packet)[0] + data = cfl.Tmdata(packet)[0] elif isinstance(packet, tuple): data = packet[1][0] else: @@ -255,3 +261,14 @@ def write_precondition_outcome(result): logger.info('Preconditions are fulfilled.\n') else: logger.warning('Preconditions are NOT fulfilled.\n') + +def write_postcondition_outcome(result): + """ + Logs the outcome of the establish_postconditions function in a test script. + :param result: bool + True if all postcondition could be established successfully + """ + if result is True: + logger.info('Postconditions are fulfilled.\n') + else: + logger.warning('Postconditions are NOT fulfilled.\n') diff --git a/Tst/testing_library/testlib/tc.py b/Tst/testing_library/testlib/tc.py index 6f1e194436394f3de93e7ad186737b5c47b94f5e..042074ee69cb865d8c801c1b7b86e78ea474f3a2 100644 --- a/Tst/testing_library/testlib/tc.py +++ b/Tst/testing_library/testlib/tc.py @@ -7,6 +7,13 @@ This module contains functions which have to do with sending telecommands. import logging import time +import sys + +import confignator +ccs_path = confignator.get_option('paths', 'ccs') +sys.path.append(ccs_path) + +import ccs_function_lib as cfl from . import tm @@ -14,11 +21,10 @@ from . import tm logger = logging.getLogger(__name__) -def generate_stream_of_tc_6_5(ccs, pool_name, duration=300): +def generate_stream_of_tc_6_5(pool_name, duration=300): """ Generating a stream of TC(6,5). Aim to to send one TC(6,5) per cycle (one cycle lasts for 0.125ms) - :param ccs: packets.CCScom - Instance of the class CCScom + :param pool_name: str Name of the pool for TM/TCs in the database :param duration: int @@ -51,7 +57,8 @@ def generate_stream_of_tc_6_5(ccs, pool_name, duration=300): # send TC(6,5) and note the current time again current_time = time.time() - tc = ccs.Tcsend_DB('SES CMD_Memory_Dump', + #tc = ccs.Tcsend_DB('SES CMD_Memory_Dump', + tc = cfl.Tcsend_DB('SES CMD_Memory_Dump', PAR_MEMORY_ID_DUMP, PAR_START_ADDRESS_DUMP, PAR_BLOCK_LENGTH_DUMP, @@ -86,13 +93,11 @@ def generate_stream_of_tc_6_5(ccs, pool_name, duration=300): return in_time, sent_tcs -def reset_housekeeping(ccs, pool_name, name): +def reset_housekeeping(pool_name, name): """ Reset a housekeeping. Set its generation frequency back to its default value. Set back its enable-status back to its default value (by default only IFSW_HK is enabled) - :param ccs: packets.CCScom - Instance of the class packets.CCScom :param pool_name: str Name of the pool for TM/TCs in the database :param name: str @@ -153,21 +158,24 @@ def reset_housekeeping(ccs, pool_name, name): # set the generation frequency to back to its default value logger.info('set the generation frequency of {} back to its default value of {} cycles ({}Hz)' .format(name, hk_freq, hk_freq/8)) - tc_freq = ccs.TcSetHkRepFreq(sid=hk_sid, period=hk_freq) - set_freq, ack_freq = tm.await_tc_acknow(ccs=ccs, pool_name=pool_name, tc_identifier=tc_freq, tm_sst=7) + #tc_freq = ccs.TcSetHkRepFreq(sid=hk_sid, period=hk_freq) + tc_freq = cfl.TcSetHkRepFreq(sid=hk_sid, period=hk_freq) + set_freq, ack_freq = tm.await_tc_acknow(pool_name=pool_name, tc_identifier=tc_freq, tm_sst=7) # disable or enable the housekeeping if hk_enabled is True: # send TC(3,5) to enable the housekeeping report logger.info('enable the {} housekeeping report'.format(name)) - tc_enb = ccs.Tcsend_DB('DPU_IFSW_ENB_HK_DR_GEN', hk_sid, ack='0b1011', pool_name=pool_name) - enabled, ack_enb = tm.await_tc_acknow(ccs=ccs, pool_name=pool_name, tc_identifier=tc_enb, tm_sst=7) + #tc_enb = ccs.Tcsend_DB('DPU_IFSW_ENB_HK_DR_GEN', hk_sid, ack='0b1011', pool_name=pool_name) + tc_enb = cfl.Tcsend_DB('DPU_IFSW_ENB_HK_DR_GEN', hk_sid, ack='0b1011', pool_name=pool_name) + enabled, ack_enb = tm.await_tc_acknow(pool_name=pool_name, tc_identifier=tc_enb, tm_sst=7) if hk_enabled is False: # send TC(3,5) to disable the housekeeping report logger.info('disable the {} housekeeping report'.format(name)) - tc_dis = ccs.Tcsend_DB('DPU_IFSW_DIS_HK_DR_GEN', hk_sid, ack='0b1011', pool_name=pool_name) - disabled, ack_dis = tm.await_tc_acknow(ccs=ccs, pool_name=pool_name, tc_identifier=tc_dis, tm_sst=7) + #tc_dis = ccs.Tcsend_DB('DPU_IFSW_DIS_HK_DR_GEN', hk_sid, ack='0b1011', pool_name=pool_name) + tc_dis = cfl.Tcsend_DB('DPU_IFSW_DIS_HK_DR_GEN', hk_sid, ack='0b1011', pool_name=pool_name) + disabled, ack_dis = tm.await_tc_acknow(pool_name=pool_name, tc_identifier=tc_dis, tm_sst=7) # evaluate if the function was successful if set_freq: @@ -181,13 +189,11 @@ def reset_housekeeping(ccs, pool_name, name): return success -def reset_all_housekeepings(ccs, pool_name): +def reset_all_housekeepings(pool_name): """ This function resets all housekeepings. The frequencies are set to their default value. The enabled status is set back to its default value. - :param ccs: packets.CCScom - Instance of the class packets.CCScom :param poolname: str Name of the pool for TM/TCs in the database :return: bool @@ -209,7 +215,7 @@ def reset_all_housekeepings(ccs, pool_name): # reset all housekeepings result = [] for hk_name in housekeepings: - suc = reset_housekeeping(ccs=ccs, pool_name=pool_name, name=hk_name) + suc = reset_housekeeping(pool_name=pool_name, name=hk_name) result.append(suc) if suc: logger.debug('reset_all_housekeepings: reset of {} was successful'.format(hk_name)) @@ -229,26 +235,26 @@ def reset_all_housekeepings(ccs, pool_name): return success -def stop_sem(ccs, pool_name): +def stop_sem(pool_name): """ The TC (193,4) is sent to stop the SEM. Two events are awaited EVT_IASW_TR with DestIaswSt = STANDBY and EVT_SEM_TR with DestSemSt = OFF. - :param ccs: :param pool_name: :return: """ result = False # send TC(193,4) to stop SEM - tc_stop = ccs.Tcsend_DB('DPU_IFSW_STOP_SEM', ack='0b1011', pool_name=pool_name) - t_tc_stop = tm.time_tc_accepted(ccs=ccs, pool_name=pool_name, tc_identifier=tc_stop) + #tc_stop = ccs.Tcsend_DB('DPU_IFSW_STOP_SEM', ack='0b1011', pool_name=pool_name) + tc_stop = cfl.Tcsend_DB('DPU_IFSW_STOP_SEM', ack='0b1011', pool_name=pool_name) + t_tc_stop = tm.time_tc_accepted(pool_name=pool_name, tc_identifier=tc_stop) # sim.stop_sem(sem=None) ??? entry_iasw = {'DestIaswSt': 'STANDBY'} - evt_iasw = tm.await_event(ccs=ccs, pool_name=pool_name, severity=1, event_id='EVT_IASW_TR', entries=entry_iasw, + evt_iasw = tm.await_event(pool_name=pool_name, severity=1, event_id='EVT_IASW_TR', entries=entry_iasw, duration=20, t_from=t_tc_stop - 1) entry_sem = {'DestSemSt': 'OFF'} - evt_sem = tm.await_event(ccs=ccs, pool_name=pool_name, severity=1, event_id='EVT_SEM_TR', entries=entry_sem, + evt_sem = tm.await_event(pool_name=pool_name, severity=1, event_id='EVT_SEM_TR', entries=entry_sem, duration=20, t_from=t_tc_stop - 1) if len(evt_iasw) > 0 and len(evt_sem) > 0: result = True diff --git a/Tst/testing_library/testlib/testing_logger.py b/Tst/testing_library/testlib/testing_logger.py index c29be18121bf4658cba60b4ea65a7193c78c6bbc..f246ef9f5ee5f716c3eccbc14948896da73e9c27 100644 --- a/Tst/testing_library/testlib/testing_logger.py +++ b/Tst/testing_library/testlib/testing_logger.py @@ -6,6 +6,7 @@ import logging import logging.config import os import datetime +import confignator from . import tools @@ -23,9 +24,10 @@ def get_path_for_logs(module_name): :rtype: str """ # ToDo create the filename using the testing_logger.cmd_scrpt_auxiliary variable - cfg = tools.read_config() + #cfg = tools.read_config() # Fetch the path from the project config file - path = cfg.get('LOGGING', 'test_run') + #path = cfg.get('LOGGING', 'test_run') + path = confignator.get_option('tst-logging', 'test_run') # Create the directory for the logging files os.makedirs(path, mode=0o777, exist_ok=True) filename = path + module_name + '.log' diff --git a/Tst/testing_library/testlib/tm.py b/Tst/testing_library/testlib/tm.py index 446be076da11a6ee41872d8540484072f0f7293e..443be5f6a36e6836f575e9961108fe7d71e44063 100644 --- a/Tst/testing_library/testlib/tm.py +++ b/Tst/testing_library/testlib/tm.py @@ -60,9 +60,11 @@ from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker import confignator + ccs_path = confignator.get_option('paths', 'ccs') sys.path.append(ccs_path) +import ccs_function_lib as cfl from database import config_db from database import tm_db @@ -72,7 +74,7 @@ from . import tools # create a logger logger = logging.getLogger(__name__) - +''' def sessionfactory(ccs): """ Creates a sessionmaker @@ -106,12 +108,16 @@ def new_database_session(ccs): session_maker = sessionfactory(ccs=ccs) session = session_maker() return session +''' +scoped_session_idb = cfl.scoped_session_idb # Connection to CCS IDB -def filter_chain(query, pool_name, is_tm=True, st=None, sst=None, apid=None, seq=None, t_from=None, t_to=None, dest_id=None, not_apid=None): + +def filter_chain(query, pool_name, is_tm=True, st=None, sst=None, apid=None, seq=None, t_from=None, t_to=None, + dest_id=None, not_apid=None): """ Add filter to a database query for telemetry/telecommand packets.l - :param query: + :param query: :param pool_name: str :param is_tm: bool If this argument is True the query asks only for telemetry packets (TM). @@ -122,12 +128,12 @@ def filter_chain(query, pool_name, is_tm=True, st=None, sst=None, apid=None, seq Sub-Service type of the packet :param apid: int Application process ID of the packet - :param seq: - :param t_from: - :param t_to: - :param dest_id: - :param not_apid: - :return: + :param seq: + :param t_from: + :param t_to: + :param dest_id: + :param not_apid: + :return: """ if is_tm is True: query = query.filter(tm_db.DbTelemetry.is_tm == 0) # ToDo: why is this entry in the DB zero when it is a TM? @@ -152,7 +158,8 @@ def filter_chain(query, pool_name, is_tm=True, st=None, sst=None, apid=None, seq # ToDo database has the CUC timestamp as string. Here the timestamps are floats. # Does this comparison operations work? t_from_string = str(t_from) + 'U' # the timestamps in the database are saved as string - query = query.filter(tm_db.DbTelemetry.timestamp >= t_from_string) # ToDo check if the change from > to >= breaks something! + query = query.filter( + tm_db.DbTelemetry.timestamp >= t_from_string) # ToDo check if the change from > to >= breaks something! # query = query.filter(tm_db.DbTelemetry.timestamp > t_from) # <- comparison with float if t_to is not None: # ToDo database has the CUC timestamp as string. Here the timestamps are floats. @@ -167,13 +174,10 @@ def filter_chain(query, pool_name, is_tm=True, st=None, sst=None, apid=None, seq return query -def highest_cuc_timestamp(ccs, tm_list): +def highest_cuc_timestamp(tm_list): """ Get the TM packet with the highest CUC timestamp of the packet list - :param (packets.CCScom) ccs: Instance of the class packets.CCScom - :param list tm_list: List of TM packets - :return: The TM packet with the highest CUC timestamp (this is the one with the smallest difference to now). :rtype: PUS packet || None """ @@ -182,7 +186,7 @@ def highest_cuc_timestamp(ccs, tm_list): cuc = 0 for i in range(len(tm_list)): try: - tstamp = ccs.get_cuctime(tm_list[i]) + tstamp = cfl.get_cuctime(tm_list[i]) except Exception as unknown_error: logger.exception(unknown_error) continue @@ -192,11 +196,10 @@ def highest_cuc_timestamp(ccs, tm_list): return highest -def lowest_cuc_timestamp(ccs, pool_name, tm_list): +def lowest_cuc_timestamp(pool_name, tm_list): """ Get the TM packet with the lowest CUC timestamp of the packet list - :param (packets.CCScom) ccs: Instance of the class packets.CCScom :param (str) pool_name: name of the packet pool in the database :param (list) tm_list: List of TM packets @@ -205,10 +208,10 @@ def lowest_cuc_timestamp(ccs, pool_name, tm_list): """ lowest = None if isinstance(tm_list, list) and len(tm_list) > 0: - cuc = ccs.get_last_pckt_time(pool_name=pool_name, string=False) + cuc = cfl.get_last_pckt_time(pool_name=pool_name, string=False) for i in range(len(tm_list)): try: - tstamp = ccs.get_cuctime(tm_list[i]) + tstamp = cfl.get_cuctime(tm_list[i]) except Exception as unknown_error: logger.exception(unknown_error) continue @@ -218,11 +221,10 @@ def lowest_cuc_timestamp(ccs, pool_name, tm_list): return lowest -def time_tc_accepted(ccs, pool_name, tc_identifier): +def time_tc_accepted(pool_name, tc_identifier): """ Get the CUC timestamp of the command acceptance acknowledgement TM packet (or acceptance failure) - :param packets.CCScom ccs: Instance of the class packets.CCScom :param str pool_name: name of the packet pool in the database :param tuple tc_identifier: TC identifier is a tuple which consists out of apid, ssc, CUC-timestamp @@ -231,21 +233,21 @@ def time_tc_accepted(ccs, pool_name, tc_identifier): """ cuc = None # get the acknowledgement packets - suc, acknow = await_tc_acknow(ccs=ccs, pool_name=pool_name, tc_identifier=tc_identifier, tm_st=1) + suc, acknow = await_tc_acknow(pool_name=pool_name, tc_identifier=tc_identifier, tm_st=1) # filter for accepted TM(1,1) or acceptance failure TM(1,2) if len(acknow) > 0: for i in range(len(acknow)): subservicetype = acknow[i][0][11] if subservicetype == 1 or subservicetype == 2: # get the cuc timestamp of the acknowledgement packet - cuc = ccs.get_cuctime(acknow[i]) + cuc = cfl.get_cuctime(acknow[i]) break else: logger.warning('time_tc_accepted: no acknowledgement TM found for TM {}'.format(tc_identifier)) return cuc -def set_time_interval(ccs, pool_name, t_from, t_to, duration): +def set_time_interval(pool_name, t_from, t_to, duration): """ Calculate the time interval for given values t_from, t_to and duration. The time interval is used to for database queries. @@ -255,8 +257,7 @@ def set_time_interval(ccs, pool_name, t_from, t_to, duration): * If t_to and a duration are provided, the value of t_to is stronger. The duration probably was set as a default value in a other function. * If only a duration and no t_to is provided the upper boundary = lower boundary + duration - - :param packets.CCScom ccs: Instance of the class packets.CCScom + :param str pool_name: name of the packet pool in the database :param float t_from: CUC timestamp, lower boundary for the time interval. If t_from is None the current CUC timestamp is retrieved from the database by packets.get_last_pckt_time() :param float t_to: CUC timestamp, upper boundary for the time interval. @@ -274,7 +275,7 @@ def set_time_interval(ccs, pool_name, t_from, t_to, duration): # set the lower interval boundary, if no t_from is given, the current time will be used if t_from is None: # CUC timestamp of the last tm packet is used as "now" - last_packet_time = ccs.get_last_pckt_time(pool_name=pool_name, string=False) + last_packet_time = cfl.get_last_pckt_time(pool_name=pool_name, string=False) if last_packet_time: t_from = last_packet_time else: @@ -307,7 +308,7 @@ def set_query_interval(t_from, t_to): """ Set the frequency for doing database queries. If the time frame gets larger the frequency of the queries gets lower. - + :param float t_from: lower boundary for the CUC timestamp :param float t_to: upget_last_pckt_timeper boundary for the CUC timestampcheck @@ -329,7 +330,7 @@ def set_query_interval(t_from, t_to): return interval -def decode_single_tm_packet(packet, ccs): +def decode_single_tm_packet(packet): """ Decodes a single TM packet. The packet has to be of the type bytes. If the packet is a TC the returned tuple consists out of (header, None) @@ -337,7 +338,6 @@ def decode_single_tm_packet(packet, ccs): For the case that the data field can not be read the tuple (header, None) is returned :param bytes packet: TM packet in byte-string format - :param packets.CCScom ccs: Instance of the class packets.CCScom :return: tuple or None :rtype: the decoded packet || None @@ -345,14 +345,14 @@ def decode_single_tm_packet(packet, ccs): assert isinstance(packet, bytes) result = None - header = ccs.Tmread(packet) + header = cfl.Tmread(packet) if header is not None: # the packet is a TC if header[1] == 1: result = header, None # the packet is a TM elif header[1] == 0: - data = ccs.Tmdata(packet) + data = cfl.Tmdata(packet) if data != (None, None): # data field could be decoded result = header, data else: # data field could not be decoded @@ -363,13 +363,12 @@ def decode_single_tm_packet(packet, ccs): return result -def decode_tm(tm_packets, ccs): +def decode_tm(tm_packets): """ Check if a TM packet or a list of TM packets are still bytes. If so, they are decoded, otherwise just pass the packets. If a failure occurs while unpacking return None :param list tm_packets: <list> of <bytes>: TM packet or a list of TM packets in byte format or as tm_db.DbTelemetry row - :param packets.CCScom ccs: Instance of the class packets.CCScom :return: list decoded TM packets (a TM packet is a tuple (header, data)) :rtype: list @@ -384,15 +383,15 @@ def decode_tm(tm_packets, ccs): for j in range(len(tm_packets)): t_start = time.time() if isinstance(tm_packets[j], bytes): - decoded.append(decode_single_tm_packet(packet=tm_packets[j], ccs=ccs)) + decoded.append(decode_single_tm_packet(packet=tm_packets[j])) elif isinstance(tm_packets[j], tuple): decoded.append(tm_packets[j]) elif isinstance(tm_packets[j], tm_db.DbTelemetry): row = tm_packets[j].raw - decoded.append(decode_single_tm_packet(packet=row, ccs=ccs)) + decoded.append(decode_single_tm_packet(packet=row)) else: logger.debug('decode_tm: data format for the TM packet is not known! Type of the packet is {}' - .format(type(tm_packets[j]))) + .format(type(tm_packets[j]))) t_end = time.time() if len(tm_packets) > 100: time_per_packet = t_end - t_start @@ -400,24 +399,23 @@ def decode_tm(tm_packets, ccs): else: if isinstance(tm_packets, bytes): - decoded.append(decode_single_tm_packet(packet=tm_packets, ccs=ccs)) + decoded.append(decode_single_tm_packet(packet=tm_packets)) elif isinstance(tm_packets, tuple): decoded.append(tm_packets) elif isinstance(tm_packets, tm_db.DbTelemetry): row = tm_packets.raw - decoded.append(decode_single_tm_packet(packet=row, ccs=ccs)) + decoded.append(decode_single_tm_packet(packet=row)) else: - logger.debug('decode_tm: data format for the TM packet is not known! Type of the packet is {}' - .format(type(tm_packets))) + logger.debug('decode_tm: data format for the TM packet is not known! Type of the packet is {}'.format( + type(tm_packets))) return decoded -def get_tm_data_entries(ccs, tm_packet, data_entry_names): +def get_tm_data_entries(tm_packet, data_entry_names): """ For one TM packet the specified entries are extracted and returned. - :param packets.CCScom ccs: Instance of the class packets.CCScom :param PUS-packet tm_packet: TM packet which holds the desired parameter entries :param string-or-list data_entry_names: string or list of strings: this are the names/identifiers of the data entries @@ -427,7 +425,7 @@ def get_tm_data_entries(ccs, tm_packet, data_entry_names): values = {} keys = data_entry_names # if the TM packets are not decoded already, do it now - packet = decode_tm(tm_packets=tm_packet, ccs=ccs) + packet = decode_tm(tm_packets=tm_packet) # extract the required entries from the telemetry packet/packets if len(packet) == 1: @@ -459,20 +457,19 @@ def get_tm_data_entries(ccs, tm_packet, data_entry_names): # For every TM packet of the list the specified entries are extracted and returned. -# @param ccs: instance of the class CCScom # @param event_tms: <list> or single TM packet (expecting a event TM packet) # @param data_entry_names: <string> or <list of strings>: this are the names/identifiers of the data entry # @return: <list> of <dict>: key-value pairs of the data entries (as dict) or a empty array -def get_tm_list_data_entries(ccs, tm_packets, data_entry_names): +def get_tm_list_data_entries(tm_packets, data_entry_names): result = [] # if the TM packets are not decoded already, do it now - event_packets = decode_tm(tm_packets=tm_packets, ccs=ccs) + event_packets = decode_tm(tm_packets=tm_packets) # extract the required entries from the telemetry packet/packets if event_packets is not None: if isinstance(event_packets, list) and len(event_packets) > 0: for j in range(len(event_packets)): - result.append(get_tm_data_entries(tm_packet=event_packets[j], data_entry_names=data_entry_names, ccs=ccs)) + result.append(get_tm_data_entries(tm_packet=event_packets[j], data_entry_names=data_entry_names)) return result @@ -480,10 +477,9 @@ def get_tm_list_data_entries(ccs, tm_packets, data_entry_names): # @param packet: TM packet # @param entry_name: <str> name of the entry (the 3rd value of the tuple) # @param entry_value: value the entry (the 1st value of the tuple) -# @param ccs: instance of the class CCScom # @return: <boolean>: True if entry exists and has the correct value -def has_entry(packet, entry_name, entry_value, ccs): - item = get_tm_data_entries(tm_packet=packet, data_entry_names=entry_name, ccs=ccs) +def has_entry(packet, entry_name, entry_value): + item = get_tm_data_entries(tm_packet=packet, data_entry_names=entry_name) if item is not None: if entry_name in item and item[entry_name] == entry_value: return True @@ -492,14 +488,13 @@ def has_entry(packet, entry_name, entry_value, ccs): # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -def fetch_packets(ccs, pool_name, is_tm=True, st=None, sst=None, apid=None, ssc=None, t_from=None, t_to=None, +def fetch_packets(pool_name, is_tm=True, st=None, sst=None, apid=None, ssc=None, t_from=None, t_to=None, dest_id=None, not_apid=None, decode=True, silent=False): # ToDo: remove the agrument silent, as this functionality is covert by using log level INFO # (DEBUG still logs more information) """ Makes a single database query for packets from the pool for a fixed time interval. By using arguments, specific packets can be retrieved. - :param ccs: instance of packets.CCScom :param pool_name: str The name of the pool in the database :param is_tm: bool @@ -545,7 +540,8 @@ def fetch_packets(ccs, pool_name, is_tm=True, st=None, sst=None, apid=None, ssc= apid = tools.convert_apid_to_int(apid=apid) # make database query - session = new_database_session(ccs=ccs) + # session = new_database_session(ccs=ccs) + session = scoped_session_idb query = session.query(tm_db.DbTelemetry) query = filter_chain(query, pool_name=pool_name, @@ -561,8 +557,8 @@ def fetch_packets(ccs, pool_name, is_tm=True, st=None, sst=None, apid=None, ssc= data = query.all() session.close() logger.debug('fetch_packets: returned {} packets; is_tm:{}, st:{}, sst:{}, apid:{}, ssc:{}, t_from:{}, t_to:{},' - ' dest_id:{}, not_apid:{}, decode:{}' - .format(len(data), is_tm, st, sst, apid, ssc, t_from, t_to, dest_id, not_apid, decode)) + ' dest_id:{}, not_apid:{}, decode:{}' + .format(len(data), is_tm, st, sst, apid, ssc, t_from, t_to, dest_id, not_apid, decode)) # get the raw data out of the query result for i in range(len(data)): @@ -570,17 +566,16 @@ def fetch_packets(ccs, pool_name, is_tm=True, st=None, sst=None, apid=None, ssc= # decode the data if len(data) > 0 and decode is True: - data = decode_tm(tm_packets=data, ccs=ccs) + data = decode_tm(tm_packets=data) return data -def await_tm(ccs, pool_name, st, sst=None, apid=None, ssc=None, t_from=None, t_to=None, dest_id=None, not_apid=None, decode=True, duration=5, check_int=None): +def await_tm(pool_name, st, sst=None, apid=None, ssc=None, t_from=None, t_to=None, dest_id=None, not_apid=None, + decode=True, duration=5, check_int=None): """ Waiting for a specific TM packet, if it is received the packet is returned immediately. The database queries are done in regular intervals. - - :param ccs: instance of packets.CCScom - instance of packets.CCScom + :param pool_name: str name of the pool in the database :param st: int @@ -612,7 +607,7 @@ def await_tm(ccs, pool_name, st, sst=None, apid=None, ssc=None, t_from=None, t_t result = [] # set time interval for the desired packets - t_from, t_to = set_time_interval(ccs=ccs, pool_name=pool_name, t_from=t_from, t_to=t_to, duration=duration) + t_from, t_to = set_time_interval(pool_name=pool_name, t_from=t_from, t_to=t_to, duration=duration) # set the interval of fetching packets from the pool if check_int is None: @@ -622,8 +617,7 @@ def await_tm(ccs, pool_name, st, sst=None, apid=None, ssc=None, t_from=None, t_t condition = True while condition is True: # get packets from the database - packets = fetch_packets(ccs=ccs, - pool_name=pool_name, + packets = fetch_packets(pool_name=pool_name, is_tm=True, st=st, sst=sst, @@ -636,7 +630,7 @@ def await_tm(ccs, pool_name, st, sst=None, apid=None, ssc=None, t_from=None, t_t decode=decode, silent=True) # check condition - if len(packets) > 0 or ccs.get_last_pckt_time(pool_name=pool_name, string=False) > t_to: + if len(packets) > 0 or cfl.get_last_pckt_time(pool_name=pool_name, string=False) > t_to: condition = False result = packets else: @@ -646,7 +640,7 @@ def await_tm(ccs, pool_name, st, sst=None, apid=None, ssc=None, t_from=None, t_t return result -def get_tm(ccs, pool_name, st=None, sst=None, apid=None, ssc=None, duration=5, t_from=None, t_to=None, +def get_tm(pool_name, st=None, sst=None, apid=None, ssc=None, duration=5, t_from=None, t_to=None, check_interval=0.2, decode=True): # ToDo: remove the argument check_interval """ @@ -654,8 +648,6 @@ def get_tm(ccs, pool_name, st=None, sst=None, apid=None, ssc=None, duration=5, t parameters. Time intervals: ]t_from, t_from+duration[ or ]now, now+duration[. "now" means the CUC timestamp of the last tm packet. - :param ccs: packets.CCScom - Instance of the class packets.CCScom :param pool_name: str Name of the pool for TM and TC packets in the database. :param st: int @@ -679,17 +671,16 @@ def get_tm(ccs, pool_name, st=None, sst=None, apid=None, ssc=None, duration=5, t """ # set the time interval - t_from, t_to = set_time_interval(ccs=ccs, pool_name=pool_name, t_from=t_from, t_to=t_to, duration=duration) + t_from, t_to = set_time_interval(pool_name=pool_name, t_from=t_from, t_to=t_to, duration=duration) # for the case that t_to is in future, wait - current_cuc = ccs.get_last_pckt_time(pool_name=pool_name, string=False) + current_cuc = cfl.get_last_pckt_time(pool_name=pool_name, string=False) if t_to > current_cuc: difference = t_to - current_cuc time.sleep(difference) # get packets - tm_packets = fetch_packets(ccs=ccs, - pool_name=pool_name, + tm_packets = fetch_packets(pool_name=pool_name, st=st, sst=sst, apid=apid, @@ -716,12 +707,10 @@ def get_tm(ccs, pool_name, st=None, sst=None, apid=None, ssc=None, duration=5, t # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -def get_hk_tm(ccs, pool_name, hk_name, t_from=None, t_to=None, duration=5): +def get_hk_tm(pool_name, hk_name, t_from=None, t_to=None, duration=5): """ Fetches housekeeping reports TM(3,25) from the database and filter them by the housekeeping name (SID). - :param ccs: packets.CCScom - Instance of the class packets.CCScom :param pool_name: str Name of the pool for TM/TC packets in the database :param hk_name: str @@ -738,24 +727,22 @@ def get_hk_tm(ccs, pool_name, hk_name, t_from=None, t_to=None, duration=5): hk_list = [] # set the time interval for the database query - t_from, t_to = set_time_interval(ccs=ccs, pool_name=pool_name, t_from=t_from, t_to=t_to, duration=duration) + t_from, t_to = set_time_interval(pool_name=pool_name, t_from=t_from, t_to=t_to, duration=duration) # get the TM packets from the database - data = get_tm(ccs=ccs, pool_name=pool_name, st=3, sst=25, t_from=t_from, t_to=t_to, duration=duration) + data = get_tm(pool_name=pool_name, st=3, sst=25, t_from=t_from, t_to=t_to, duration=duration) for packet in data: - if has_entry(packet=packet, entry_name='Sid', entry_value=hk_name, ccs=ccs): + if has_entry(packet=packet, entry_name='Sid', entry_value=hk_name): hk_list.append(packet) return hk_list -def await_hk_tm(ccs, pool_name, sid=None, t_from=None, duration=5): +def await_hk_tm(pool_name, sid=None, t_from=None, duration=5): """ Get the next housekeeping TM packet with a specific SID. If there are more packets of the same kind. The one with the highest CUC timestamp is returned. - :param ccs: packets.CCScom - Instance of the class packets.CCScom :param pool_name: str Name of the TM/TC pool in the database :param sid: int or str @@ -774,15 +761,15 @@ def await_hk_tm(ccs, pool_name, sid=None, t_from=None, duration=5): # if the sid is a integer, get the name string from the instrument database if isinstance(sid, int): - sid = idb.convert_hk_sid(ccs=ccs, sid=sid) + sid = idb.convert_hk_sid(sid=sid) # get the housekeeping TM packets from the pool - tm_list = await_tm(ccs=ccs, pool_name=pool_name, st=3, sst=25, t_from=t_from, duration=duration) + tm_list = await_tm(pool_name=pool_name, st=3, sst=25, t_from=t_from, duration=duration) # filter for the correct housekeeping kind (SID) housekeepings = [] for packet in tm_list: - packet_sid = get_tm_data_entries(ccs=ccs, tm_packet=packet, data_entry_names='Sid') + packet_sid = get_tm_data_entries(tm_packet=packet, data_entry_names='Sid') if 'Sid' in packet_sid: if packet_sid['Sid'] == sid: housekeepings.append(packet) @@ -791,7 +778,7 @@ def await_hk_tm(ccs, pool_name, sid=None, t_from=None, duration=5): if len(housekeepings) > 0: logger.debug('await_hk_tm: found {} packets with SID {}'.format(len(housekeepings), sid)) # ToDo: change to the lowest_cuc_timestamp (the first HK with this SID), because of waiting for the next HK TM?! - youngest = highest_cuc_timestamp(ccs=ccs, tm_list=housekeepings) + youngest = highest_cuc_timestamp(tm_list=housekeepings) header = youngest[0] data = youngest[1] result = header, data @@ -801,16 +788,14 @@ def await_hk_tm(ccs, pool_name, sid=None, t_from=None, duration=5): return result -def get_self_def_hk_tm(ccs, pool_name, sid, format_string, t_from=None, t_to=None): +def get_self_def_hk_tm(pool_name, sid, format_string, t_from=None, t_to=None): """ Fetches TM(3,25) housekeeping packets for self defined housekeeping. In order to unpack the data field a format string is required. The packets from the pool are filtered, after unpacking, by the SID (which are the first two bytes in the data field). - + Parameters ---------- - :param ccs: packets.CCScom - instance of the class CCSCom :param pool_name: str pool name of the TM/TC packets pool :param sid: int @@ -823,11 +808,11 @@ def get_self_def_hk_tm(ccs, pool_name, sid, format_string, t_from=None, t_to=Non CUC timestamp: from this timestamp on the packets are fetched :param t_to: float CUC timestamp: up to this timestamp the packets are fetched from the pool - + Returns ------- :return: list - a list of TM(3,25) packets or []. All packets have matching SIDs. + a list of TM(3,25) packets or []. All packets have matching SIDs. """ assert isinstance(sid, int) assert isinstance(format_string, str) @@ -837,12 +822,12 @@ def get_self_def_hk_tm(ccs, pool_name, sid, format_string, t_from=None, t_to=Non hk_list = [] # get the TM packets from the database - packets = get_tm(ccs=ccs, pool_name=pool_name, st=3, sst=25, t_from=t_from, t_to=t_to, decode=False) + packets = get_tm(pool_name=pool_name, st=3, sst=25, t_from=t_from, t_to=t_to, decode=False) # filter TM packets with the correct Sid for packet in packets: # read the header - header = ccs.Tmread(pckt=packet) + header = cfl.Tmread(pckt=packet) # extract the SID from the Bits-Field (the first 8 bits are the SID) packet_sid = header[-2][0:8].unpack('uint:8')[0] if packet_sid == sid: @@ -861,11 +846,10 @@ def get_self_def_hk_tm(ccs, pool_name, sid, format_string, t_from=None, t_to=Non return hk_list -def get_hk_entry(ccs, pool_name, hk_name, name=None, t_from=None, t_to=None, duration=5, silent=False): +def get_hk_entry(pool_name, hk_name, name=None, t_from=None, t_to=None, duration=5, silent=False): """ Get a specific entry of the youngest housekeeping report from the TM/TC database by name. - :param ccs: :param pool_name: :param hk_name: :param name: @@ -887,16 +871,16 @@ def get_hk_entry(ccs, pool_name, hk_name, name=None, t_from=None, t_to=None, dur name = new_names # get the TM packets from the database - hk_list = get_hk_tm(ccs=ccs, pool_name=pool_name, hk_name=hk_name, t_from=t_from, t_to=t_to, duration=duration) + hk_list = get_hk_tm(pool_name=pool_name, hk_name=hk_name, t_from=t_from, t_to=t_to, duration=duration) if len(hk_list) > 0: # take the youngest housekeeping report - hk_report = highest_cuc_timestamp(ccs=ccs, tm_list=hk_list) + hk_report = highest_cuc_timestamp(tm_list=hk_list) # get the requested housekeeping entry out of the TM packet - entries = get_tm_data_entries(tm_packet=hk_report, data_entry_names=name, ccs=ccs) + entries = get_tm_data_entries(tm_packet=hk_report, data_entry_names=name) # pick out the results if len(entries) > 0: - result = entries, ccs.get_cuctime(hk_report), hk_name + result = entries, cfl.get_cuctime(hk_report), hk_name # log the result if isinstance(entries, dict): keys = entries.keys() @@ -907,16 +891,17 @@ def get_hk_entry(ccs, pool_name, hk_name, name=None, t_from=None, t_to=None, dur logger.debug('get_hk_entry: UNDER CONSTRUCTION: HERE IS SOMETHING TO IMPLEMENT') if len(entries) < 1: logger.debug('No entry with name(s) {} found in the housekeeping {} with ' - 'CUC timestamp {}'.format(name, hk_name, ccs.get_cuctime(hk_report))) + 'CUC timestamp {}'.format(name, hk_name, cfl.get_cuctime(hk_report))) else: - logger.warning('The required {} housekeeping report/entry could not be found in the database.'.format(hk_name)) + logger.warning( + 'The required {} housekeeping report/entry could not be found in the database.'.format(hk_name)) return result -def await_hk_entries(ccs, pool_name, sid=None, name=None): # 2 usages IASW39 +def await_hk_entries(pool_name, sid=None, name=None): # 2 usages IASW39 result = None - hks = await_hk_tm(ccs, pool_name, sid=sid) + hks = await_hk_tm(pool_name, sid=sid) # extract the required entries from the housekeeping if hks is not None: @@ -943,13 +928,11 @@ def await_hk_entries(ccs, pool_name, sid=None, name=None): # 2 usages IASW39 # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -def get_st_and_sst(ccs, pool_name, apid, ssc, is_tm=False, t_from=None): +def get_st_and_sst(pool_name, apid, ssc, is_tm=False, t_from=None): """ Get the ST and SST of a packet by using the APID and SSC of the packet. Does a database query with the APID and SSC for a TM or a TC. For TC the t_from will be ignored, since TC does not have a valid CUC timestamp - :param ccs: packets.CCScom - instance of packets.CCScom :param pool_name: str name of the pool for TC/TMs in the database :param apid: str or int @@ -974,9 +957,9 @@ def get_st_and_sst(ccs, pool_name, apid, ssc, is_tm=False, t_from=None): # make a database query for the packet in order to retrieve the ST and SST for logging if is_tm is False: # for TC the timestamp is no valid CUC timestamp - tc_list = fetch_packets(ccs=ccs, pool_name=pool_name, is_tm=is_tm, apid=apid, ssc=ssc) + tc_list = fetch_packets(pool_name=pool_name, is_tm=is_tm, apid=apid, ssc=ssc) else: - tc_list = fetch_packets(ccs=ccs, pool_name=pool_name, is_tm=is_tm, apid=apid, ssc=ssc, t_from=t_from) + tc_list = fetch_packets(pool_name=pool_name, is_tm=is_tm, apid=apid, ssc=ssc, t_from=t_from) # if the packet was found read the header and extract the ST and SST if len(tc_list) == 1: @@ -985,11 +968,13 @@ def get_st_and_sst(ccs, pool_name, apid, ssc, is_tm=False, t_from=None): tc_st = header[10] tc_sst = header[11] elif len(tc_list) < 1: - logger.warning('get_st_and_sst: TC packet with apid {} and source sequence counter {} could not be found in the ' - 'database'.format(apid, ssc)) + logger.warning( + 'get_st_and_sst: TC packet with apid {} and source sequence counter {} could not be found in the ' + 'database'.format(apid, ssc)) elif len(tc_list) > 1: - logger.error('get_st_and_sst: More than one TC packet with apid {} and source sequence counter {} were found in ' - 'the database'.format(apid, ssc)) + logger.error( + 'get_st_and_sst: More than one TC packet with apid {} and source sequence counter {} were found in ' + 'the database'.format(apid, ssc)) return tc_st, tc_sst @@ -1067,12 +1052,10 @@ def extract_apid_from_packetid(packet_id): return apid -def get_tc_acknow(ccs, pool_name, t_tc_sent, tc_apid, tc_ssc, tm_st=1, tm_sst=None): +def get_tc_acknow(pool_name, t_tc_sent, tc_apid, tc_ssc, tm_st=1, tm_sst=None): """ Check if for the TC acknowledgement packets can be found in the database. This function makes a single database query. - :param ccs: packets.CCScom - instance of the class packets.CCScom :param pool_name: str Name of the TM pool in the database :param t_tc_sent: float @@ -1098,7 +1081,7 @@ def get_tc_acknow(ccs, pool_name, t_tc_sent, tc_apid, tc_ssc, tm_st=1, tm_sst=No tc_apid = tools.convert_apid_to_int(apid=tc_apid) # make database query - packets = fetch_packets(ccs=ccs, pool_name=pool_name, st=tm_st, sst=tm_sst, t_from=t_tc_sent - 1) + packets = fetch_packets(pool_name=pool_name, st=tm_st, sst=tm_sst, t_from=t_tc_sent - 1) # filter for TM packets with the correct APID and source sequence counter (SSC) in the data field ack_tms = [] @@ -1112,7 +1095,7 @@ def get_tc_acknow(ccs, pool_name, t_tc_sent, tc_apid, tc_ssc, tm_st=1, tm_sst=No else: name_apid = 'TcPacketId' name_psc = 'TcPacketSeqCtrl' - para = get_tm_data_entries(ccs=ccs, tm_packet=packets[i], data_entry_names=[name_apid, name_psc]) + para = get_tm_data_entries(tm_packet=packets[i], data_entry_names=[name_apid, name_psc]) if name_apid in para and name_psc in para: # extract the SSC from the PSC ssc = extract_ssc_from_psc(psc=para[name_psc]) @@ -1130,14 +1113,13 @@ def get_tc_acknow(ccs, pool_name, t_tc_sent, tc_apid, tc_ssc, tm_st=1, tm_sst=No # treat with the result from the database query if len(ack_tms) > 0: # get the ST and SST of the TC for logging purposes - tc_st, tc_sst = get_st_and_sst(ccs=ccs, - pool_name=pool_name, + tc_st, tc_sst = get_st_and_sst(pool_name=pool_name, apid=tc_apid, ssc=tc_ssc, is_tm=False, t_from=t_tc_sent) logger.info('Received acknowledgement TM packets for TC({},{}) apid={} ssc={}:' - .format(tc_st, tc_sst, tc_apid, tc_ssc)) + .format(tc_st, tc_sst, tc_apid, tc_ssc)) # check if there was a failure, the result becomes False if a failure occurred for i in range(len(ack_tms)): @@ -1145,33 +1127,31 @@ def get_tc_acknow(ccs, pool_name, t_tc_sent, tc_apid, tc_ssc, tm_st=1, tm_sst=No data = ack_tms[i][1] if result is not False: if head[11] == 1 or head[11] == 3 or head[11] == 7: - logger.info('TM({},{}) @ {}'.format(head[10], head[11], ccs.get_cuctime(head))) + logger.info('TM({},{}) @ {}'.format(head[10], head[11], cfl.get_cuctime(head))) result = True if head[11] == 2 or head[11] == 4 or head[11] == 8: if head[11] == 2: logger.info('TM({},{}) @ {} FAILURE: Acknowledge failure of acceptance check for a command.' - .format(head[10], head[11], ccs.get_cuctime(head))) + .format(head[10], head[11], cfl.get_cuctime(head))) logger.debug('Data of the TM packet: {}'.format(data)) if head[11] == 4: logger.info('TM({},{}) @ {} FAILURE: Acknowledge failure of start check for a command.' - .format(head[10], head[11], ccs.get_cuctime(head))) + .format(head[10], head[11], cfl.get_cuctime(head))) logger.debug('Data of the TM packet: {}'.format(data)) if head[11] == 8: logger.info( 'TM({},{}) @ {} FAILURE: Acknowledge failure of termination check for a command.' - .format(head[10], head[11], ccs.get_cuctime(head))) + .format(head[10], head[11], cfl.get_cuctime(head))) logger.debug('Data of the TM packet: {}'.format(data)) result = False return result, ack_tms -def await_tc_acknow(ccs, pool_name, tc_identifier, duration=10, tm_st=1, tm_sst=None): +def await_tc_acknow(pool_name, tc_identifier, duration=10, tm_st=1, tm_sst=None): """ Waiting to receive the acknowledgement packet of a sent telecommand (TC) for a given duration. As soon as acknowledgement packets were found the function returns. - - :param ccs: packets.CCScom - instance of the class packets.CCScom + :param pool_name: str Name of the pool in the database :param tc_identifier: tuple @@ -1185,7 +1165,7 @@ def await_tc_acknow(ccs, pool_name, tc_identifier, duration=10, tm_st=1, tm_sst= False if one or all of TM(1,2), TM(1,4), TM(1,8) were found list: list of the found acknowledgement packets - + """ # assert isinstance(ccs, packets.CCScom) assert isinstance(pool_name, str) @@ -1205,8 +1185,7 @@ def await_tc_acknow(ccs, pool_name, tc_identifier, duration=10, tm_st=1, tm_sst= finished = False while True: # get the acknowledgement packets for the TC - outcome, ack_list = get_tc_acknow(ccs=ccs, - pool_name=pool_name, + outcome, ack_list = get_tc_acknow(pool_name=pool_name, t_tc_sent=t_tc_sent, tc_apid=tc_apid, tc_ssc=tc_ssc, @@ -1221,8 +1200,7 @@ def await_tc_acknow(ccs, pool_name, tc_identifier, duration=10, tm_st=1, tm_sst= # if not all 3 TM(1,1), TM(1,3), TM(1,7) were received, wait 1s and query a last time if tm_sst is None and len(ack_list) < 3: time.sleep(1) - outcome, ack_list = get_tc_acknow(ccs=ccs, - pool_name=pool_name, + outcome, ack_list = get_tc_acknow(pool_name=pool_name, t_tc_sent=t_tc_sent, tc_apid=tc_apid, tc_ssc=tc_ssc, @@ -1241,25 +1219,22 @@ def await_tc_acknow(ccs, pool_name, tc_identifier, duration=10, tm_st=1, tm_sst= # if no acknowledgement packets were received at all after the loop if result is None: # get the ST and SST of the TC for logging purposes - tc_st, tc_sst = get_st_and_sst(ccs=ccs, - pool_name=pool_name, + tc_st, tc_sst = get_st_and_sst(pool_name=pool_name, apid=tc_apid, ssc=tc_ssc, is_tm=False, t_from=t_tc_sent) logger.warning('No acknowledgement TM packets for TC({},{}) apid={} ssc={}: found in the database' - .format(tc_st, tc_sst, tc_apid, tc_ssc)) + .format(tc_st, tc_sst, tc_apid, tc_ssc)) return result, ack_list -def check_acknowledgement(ccs, pool_name, tc_identifier, duration=10): +def check_acknowledgement(pool_name, tc_identifier, duration=10): """ Check that for a sent TC the acknowledgement packets were received (assuming the acknowledgement was enabled) Will return True when all tree acknowledgement TM packets (1,1), (1,3), (1,7) or (1,1), (1,3) or just (1,1) were received. - :param ccs: packets.CCScom - Instance of the class packets.CCScom :param pool_name: str Name of the telemetry pool :param tc_identifier: tuple or list @@ -1274,13 +1249,13 @@ def check_acknowledgement(ccs, pool_name, tc_identifier, duration=10): outcome = None # check if there is a single or a list of TC for acknowledgements to check if isinstance(tc_identifier, tuple): - outcome, acks = await_tc_acknow(ccs=ccs, pool_name=pool_name, tc_identifier=tc_identifier, duration=duration) + outcome, acks = await_tc_acknow(pool_name=pool_name, tc_identifier=tc_identifier, duration=duration) if isinstance(tc_identifier, list): tc_res = [] # do the check for all commands for telecommand in tc_identifier: - outcome, acks = await_tc_acknow(ccs=ccs, pool_name=pool_name, tc_identifier=telecommand, duration=duration) + outcome, acks = await_tc_acknow(pool_name=pool_name, tc_identifier=telecommand, duration=duration) tc_res.append(outcome) # check if the TC were successful (by acknowledgement TM packets) @@ -1292,22 +1267,22 @@ def check_acknowledgement(ccs, pool_name, tc_identifier, duration=10): break return outcome + # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -def condition_event_id(ccs, tmpackets, event_id, data_entries=None): +def condition_event_id(tmpackets, event_id, data_entries=None): """ # checking the TM packets (list) if the event_id and, if given, the entries matches # @param tmpackets: <list> of TM packets (events) # returns a list of TM packets - :param ccs: :param tmpackets: :param event_id: :param data_entries: :return: """ found_packets = [] - tmpackets = decode_tm(tm_packets=tmpackets, ccs=ccs) + tmpackets = decode_tm(tm_packets=tmpackets) # compare the event identifier and if requested the data entries if len(tmpackets) > 0: @@ -1335,7 +1310,7 @@ def condition_event_id(ccs, tmpackets, event_id, data_entries=None): if isinstance(data_entries[k], dict): keys = data_entries[k].keys() for key in keys: - value = get_tm_data_entries(ccs=ccs, tm_packet=tmpackets[i], data_entry_names=key) + value = get_tm_data_entries(tm_packet=tmpackets[i], data_entry_names=key) if key in value: if value[key] == data_entries[k][key]: matches = True @@ -1344,8 +1319,8 @@ def condition_event_id(ccs, tmpackets, event_id, data_entries=None): break else: logger.error('condition_event_id(): the provided list of TM packet data entries ' - 'should be a dictionary key-value pairs. But unfortunately something ' - 'else was given.') + 'should be a dictionary key-value pairs. But unfortunately something ' + 'else was given.') if matches is True: found_packets.append(tmpackets[i]) else: # no filtering for entries required, identifier match is enough @@ -1353,15 +1328,13 @@ def condition_event_id(ccs, tmpackets, event_id, data_entries=None): return found_packets -def get_events(ccs, pool_name, severity, event_id, t_from=None, t_to=None, duration=None, entries=None): +def get_events(pool_name, severity, event_id, t_from=None, t_to=None, duration=None, entries=None): """ For a given duration all events with suiting severity are collected. Filtering for events with specific entries can be done by providing them in the argument entries. The function makes a single database query. If upper time interval boundary is the future, the function waits before doing the database query. - :param ccs: packets.CCScom - Instance of the class CCScom :param pool_name: str Name of the pool for TM packets in the database :param severity: int @@ -1383,19 +1356,19 @@ def get_events(ccs, pool_name, severity, event_id, t_from=None, t_to=None, durat result = [] # set the time interval - t_from, t_to = set_time_interval(ccs=ccs, pool_name=pool_name, t_from=t_from, t_to=t_to, duration=duration) + t_from, t_to = set_time_interval(pool_name=pool_name, t_from=t_from, t_to=t_to, duration=duration) # for the case that t_to is in future, wait - current_cuc = ccs.get_last_pckt_time(pool_name=pool_name, string=False) + current_cuc = cfl.get_last_pckt_time(pool_name=pool_name, string=False) if t_to > current_cuc: difference = t_to - current_cuc time.sleep(difference) # get packets - tm_packets = fetch_packets(ccs=ccs, pool_name=pool_name, st=5, sst=severity, t_from=t_from, t_to=t_to) + tm_packets = fetch_packets(pool_name=pool_name, st=5, sst=severity, t_from=t_from, t_to=t_to) # check condition (if the event TM packets have been found) - tm_list = condition_event_id(ccs=ccs, tmpackets=tm_packets, event_id=event_id, data_entries=entries) + tm_list = condition_event_id(tmpackets=tm_packets, event_id=event_id, data_entries=entries) if len(tm_list) > 0: result = tm_list @@ -1414,12 +1387,11 @@ def get_events(ccs, pool_name, severity, event_id, t_from=None, t_to=None, durat return result -def await_event(ccs, pool_name, severity, event_id, entries=None, duration=10, t_from=None, check_period=1, decode=True): +def await_event(pool_name, severity, event_id, entries=None, duration=10, t_from=None, check_period=1, decode=True): """ Wait for a event to happen. When it is received the function returns. Database queries are done periodically till the duration is elapsed or the event is received. - :param packets.CCScom ccs: Instance of the class packets.CCScom :param str pool_name: Name of the TM pool in the database :param int severity: The severity of an event is equal with the Sub-Service Type of the TM packet :param str event_id: Event ID @@ -1436,7 +1408,7 @@ def await_event(ccs, pool_name, severity, event_id, entries=None, duration=10, t result = [] # set time interval for the desired packets - t_from, t_to = set_time_interval(ccs=ccs, pool_name=pool_name, t_from=t_from, t_to=None, duration=duration) + t_from, t_to = set_time_interval(pool_name=pool_name, t_from=t_from, t_to=None, duration=duration) # set the interval of fetching packets from the pool if check_period is None: @@ -1449,8 +1421,7 @@ def await_event(ccs, pool_name, severity, event_id, entries=None, duration=10, t condition = True while condition is True: # get packets from the database - packets = fetch_packets(ccs=ccs, - pool_name=pool_name, + packets = fetch_packets(pool_name=pool_name, is_tm=True, st=st, sst=sst, @@ -1460,9 +1431,9 @@ def await_event(ccs, pool_name, severity, event_id, entries=None, duration=10, t silent=True) # check condition (if the event TM packets have been found) - events = condition_event_id(ccs=ccs, tmpackets=packets, event_id=event_id, data_entries=entries) + events = condition_event_id(tmpackets=packets, event_id=event_id, data_entries=entries) - if len(events) > 0 or ccs.get_last_pckt_time(pool_name=pool_name, string=False) > t_to: + if len(events) > 0 or cfl.get_last_pckt_time(pool_name=pool_name, string=False) > t_to: condition = False result = events else: @@ -1484,14 +1455,12 @@ def await_event(ccs, pool_name, severity, event_id, entries=None, duration=10, t return result -def extract_status_data(ccs, tm_packet): +def extract_status_data(tm_packet): """ Extract status data from Service 21 DAT_CCD_Window packets. Science data blocks are ignored Not all parameters are decoded correctly: HK_STAT_DATA_ACQ_TYPE, HK_STAT_DATA_ACQ_SRC, HK_STAT_CCD_TIMING_SCRIP HK_STAT_DATA_ACQ_TIME - :param ccs: packet.CCScom - Instance of the class CCScom :param tm_packet: PUS packet A TM(21,3) :return: dict @@ -1499,7 +1468,7 @@ def extract_status_data(ccs, tm_packet): """ status_data = {} - header = ccs.Tmread(tm_packet) + header = cfl.Tmread(tm_packet) # check if it is a TM(21,3) if header[10] == 21 and header[11] == 3: data_field = header[-2] @@ -1510,7 +1479,7 @@ def extract_status_data(ccs, tm_packet): ('HK_STAT_DATA_ACQ_SRC', 'uint:4', 4), ('HK_STAT_CCD_TIMING_SCRIP', 'uint:8', 8), ('HK_STAT_DATA_ACQ_TIME', 'bits:48', 48), - ('HK_STAT_EXPOSURE_TIME', 'uint:32', 32), + ('HK_STAT_EXPOSURE_TIME', 'uint:32', 32), ('HK_STAT_TOTAL_PACKET_NUM', 'uint:16', 16), ('HK_STAT_CURRENT_PACKET_N', 'uint:16', 16), ('HK_VOLT_FEE_VOD', 'float:32', 32), @@ -1553,14 +1522,12 @@ def extract_status_data(ccs, tm_packet): return status_data -def get_acquisition(ccs, pool_name, tm_21_3): +def get_acquisition(pool_name, tm_21_3): """ Get all packets with the same acquisition ID. Requirement: the packet of the acquisition with the lowest CUC timestamp For every acquisition type of the same ID, it is checked if all packets were found. - :param ccs: packets.CCScom - Instance of the class packets.CCScom :param pool_name: str Name of the pool for TM/TC packets in the database :param tm_21_3: PUS packet @@ -1571,22 +1538,22 @@ def get_acquisition(ccs, pool_name, tm_21_3): result = [] transmission_finished = False - t_first_received = ccs.get_cuctime(tml=tm_21_3) + t_first_received = cfl.get_cuctime(tml=tm_21_3) # get the acquisition ID - current_acq_id = extract_status_data(ccs=ccs, tm_packet=tm_21_3)['HK_STAT_DATA_ACQ_ID'] + current_acq_id = extract_status_data(tm_packet=tm_21_3)['HK_STAT_DATA_ACQ_ID'] # get TM(21,3), not decoded and check if the acquisition ID are the correct ones t_to = t_first_received + 3 logger.info(t_first_received) while not transmission_finished: - data = get_tm(ccs=ccs, pool_name=pool_name, st=21, sst=3, t_from=t_first_received, t_to=t_to, decode=False) + data = get_tm(pool_name=pool_name, st=21, sst=3, t_from=t_first_received, t_to=t_to, decode=False) # filter data for ACQ_ID data_acq_id = [] data_acq_types = [] for pac in data: # check if the packets has the correct acquisition ID - status_data = extract_status_data(ccs=ccs, tm_packet=pac) + status_data = extract_status_data(tm_packet=pac) if status_data['HK_STAT_DATA_ACQ_ID'] == current_acq_id: data_acq_id.append(pac) # add the acquisition type to a list @@ -1600,11 +1567,11 @@ def get_acquisition(ccs, pool_name, tm_21_3): # extract all packets with the current type (acquisition type) curr_type_packets = [] for item in data_acq_id: - status_data = extract_status_data(ccs=ccs, tm_packet=item) + status_data = extract_status_data(tm_packet=item) if status_data['HK_STAT_DATA_ACQ_TYPE'] == type: curr_type_packets.append(item) # check if all packets of this type are here - total_num = extract_status_data(ccs=ccs, tm_packet=curr_type_packets[0])['HK_STAT_TOTAL_PACKET_NUM'] + total_num = extract_status_data(tm_packet=curr_type_packets[0])['HK_STAT_TOTAL_PACKET_NUM'] if len(curr_type_packets) == total_num: found_all_packets.append(True) else: @@ -1631,8 +1598,8 @@ def get_acquisition(ccs, pool_name, tm_21_3): result = data_acq_id else: # set the new t_to and do another query with extended time interval - last = highest_cuc_timestamp(ccs=ccs, tm_list=data) - t_to = ccs.get_cuctime(last) + 3 + last = highest_cuc_timestamp(tm_list=data) + t_to = cfl.get_cuctime(last) + 3 logger.info(t_to) # after 5 min stop the loop, if not finished yet length_of_time = t_to - t_first_received diff --git a/Tst/testing_library/testlib/tools.py b/Tst/testing_library/testlib/tools.py index be20e894dbe768e35ab87f1d3155868c5000f7ee..6477f2d158f7ffb2803f2022d80998dbde30e2a2 100644 --- a/Tst/testing_library/testlib/tools.py +++ b/Tst/testing_library/testlib/tools.py @@ -5,10 +5,18 @@ Tools """ import logging import os +import sys import configparser import math +import confignator from confignator import config +ccs_path = confignator.get_option('paths', 'ccs') +sys.path.append(ccs_path) + +import ccs_function_lib as cfl + + # create a logger logger = logging.getLogger(__name__) @@ -79,9 +87,10 @@ def read_config_file(): # read the path for the logging files from the configuration file egse.cfg. # if the directory does not exist it is created. # @param self Reference to the current instance of CCScom -def get_path_for_testing_logs(ccs): +def get_path_for_testing_logs(): # fetch the path from the project config file - path = ccs.cfg.get('LOGGING', 'test_run') + path = confignator.get_option('tst-logging', 'test_run') + #path = ccs.cfg.get('LOGGING', 'test_run') # create the directory for the logging files if it does not exist os.makedirs(path, mode=0o777, exist_ok=True) return path @@ -215,11 +224,11 @@ def print_apids(): # @param value1: <float> or <tmpacket> # @param value2: <float> or <tmpacket> # @return: <float> -def get_cuc_diff(ccs, value1, value2): +def get_cuc_diff(value1, value2): if not isinstance(value1, float): # if value1 is a TM packet - value1 = ccs.get_cuctime(value1) + value1 = cfl.get_cuctime(value1) if not isinstance(value2, float): # if value2 is a TM packet - value2 = ccs.get_cuctime(value2) + value2 = cfl.get_cuctime(value2) difference = math.fabs(value2-value1) return difference diff --git a/Tst/tst/data_model.py b/Tst/tst/data_model.py index 76c6ea0146568bf070b064a4e79a8381d4c04e67..02d79e34dcb0583f7eda2382e65f6dc1d045d91a 100644 --- a/Tst/tst/data_model.py +++ b/Tst/tst/data_model.py @@ -179,6 +179,8 @@ class Step: self._secondary_counter = value self._step_number = str(self.primary_counter) + '.' + str(self.secondary_counter) + # Do not use if a test file should be generated, Output is always '1.0' and not '1_0' + # A Point is not supported in a function/method name in python, use 'step_number_test_format' function instead @property def step_number(self): return self._step_number @@ -256,6 +258,12 @@ class Step: assert isinstance(value, int) or value is None self._stop_sequence = value + @property + def step_number_test_format(self): + primary = parse_step_number(self._step_number)[0] + secondary = parse_step_number(self._step_number)[1] + return str(primary) + '_' + str(secondary) + def set_attributes_from_json(self, step): """ Loading the step attributes from a parsed JSON file. @@ -876,10 +884,6 @@ class TestSequence: del obj_dict['logger'] return obj_dict -class Precondition: - def __init__(self): - self.description = 'NO PRECONDITIONS' - class TestSpecification: def __init__(self, json_data=None, logger=logger): self.logger = logger @@ -887,6 +891,8 @@ class TestSpecification: self._description = '' self._version = '' self._primary_counter_locked = False + self._precon = '' + self._postcon = '' self.sequences = [] if json_data is not None: @@ -903,15 +909,6 @@ class TestSpecification: return new_testspec - @property - def sequence_steps(self): - steps = [step for steps in [seq.steps for seq in self.sequences] for step in steps] - return steps - - @property - def pre_condition(self): - return Precondition() - @property def primary_counter_locked(self): return self._primary_counter_locked @@ -952,6 +949,24 @@ class TestSpecification: assert isinstance(value, str) self._version = value + @property + def precon(self): + return self._precon + + @precon.setter + def precon(self, value: str): + assert isinstance(value, str) + self._precon = value + + @property + def postcon(self): + return self._postcon + + @postcon.setter + def postcon(self, value: str): + assert isinstance(value, str) + self._postcon = value + def encode_to_json(self, *args): """ Makes out of the TestSequence a JSON object. diff --git a/Tst/tst/generator.py b/Tst/tst/generator.py index 8d4af6e633c1f8c091495b6c740de5c76fe9ac21..0511beb9e4b10d28a0e83459e241623d8b7be70e 100644 --- a/Tst/tst/generator.py +++ b/Tst/tst/generator.py @@ -4,17 +4,19 @@ import data_model cmd_scrpt_auxiliary = '_command.py' vrc_scrpt_auxiliary = '_verification.py' -man_scrpt_auxiliary = '_manually.py' +run_scrpt_auxiliary = '_run.py' co_header_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'generator_templates/co_header.py')) co_class_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'generator_templates/co_class.py')) co_pre_cond_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'generator_templates/co_pre_condition.py')) +co_pre_cond_entry_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'generator_templates/co_pre_condition_entry.py')) co_step_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'generator_templates/co_step.py')) co_post_cond_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'generator_templates/co_post_condition.py')) +co_post_cond_entry_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'generator_templates/co_post_condition_entry.py')) co_footer_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'generator_templates/co_footer.py')) -man_header_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'generator_templates/manually_header.py')) -man_step_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'generator_templates/manually_step.py')) +run_header_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'generator_templates/run_header.py')) +run_step_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'generator_templates/run_step.py')) ver_header_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'generator_templates/ver_header.py')) ver_class_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'generator_templates/ver_class.py')) @@ -53,16 +55,51 @@ def get_product_file_paths(model_name): paths = [] paths.append(create_script_path(name=model_name, auxiliary=cmd_scrpt_auxiliary)) paths.append(create_script_path(name=model_name, auxiliary=vrc_scrpt_auxiliary)) - paths.append(create_script_path(name=model_name, auxiliary=man_scrpt_auxiliary)) + paths.append(create_script_path(name=model_name, auxiliary=run_scrpt_auxiliary)) return paths +def get_precon_sections(): + pre_con_sections = {} # Name of section points to beginning line and ending line + pre_con_number_sections = [] # Save section name and appearence line number here, to get it to pre con sections + with open(co_pre_cond_entry_path, 'r') as pre_con_entry_obj: + for count, line in enumerate(pre_con_entry_obj): + if line.startswith('#####-'): + pre_con_number_sections.append([line[6:-7], count+1]) # Save section name and line number + pre_con_number_sections.append(['Last line', count+1]) # Add the last line count to have an end for last section + pre_con_entry_obj.close() + for i, sections in enumerate(pre_con_number_sections): # Format it niceline in pre con sections + try: + pre_con_sections[sections[0]] = [int(sections[1]), int(pre_con_number_sections[i+1][1])] + except: + # This just catches the last line which was only added to get end for last section + pass + + return pre_con_sections + +def get_postcon_sections(): + post_con_sections = {} # Name of section points to beginning line and ending line + post_con_number_sections = [] # Save section name and appearence line number here, to get it to post con sections + with open(co_post_cond_entry_path, 'r') as post_con_entry_obj: + for count, line in enumerate(post_con_entry_obj): + if line.startswith('#####-'): + post_con_number_sections.append([line[6:-7], count+1]) # Save section name and line number + post_con_number_sections.append(['Last line', count+1]) # Add the last line count to have an end for last section + post_con_entry_obj.close() + for i, sections in enumerate(post_con_number_sections): # Format it niceline in post con sections + try: + post_con_sections[sections[0]] = [int(sections[1]), int(post_con_number_sections[i+1][1])] + except: + # This just catches the last line which was only added to get end for last section + pass + + return post_con_sections def strip_file_extension(name): assert type(name) is str return name.rsplit('.', 1)[0] -def make_command_script(model): +def make_command_script(model, model_spec): """ Uses a TST TestSpecification data model and creates a python script out of it. A command script has following blocks: @@ -73,7 +110,8 @@ def make_command_script(model): * post condition function * footer - :param data_model.TestSequence model: A instance of a TST TestSpecification data model + :param data_model.TestSequence model: A instance of a TST TestSequence data model + :param model_spec: The above instace of TestSequence, TestSpecification data model :return: path were the command script was saved :rtype: str """ @@ -87,7 +125,7 @@ def make_command_script(model): header_template_str = header_file_obj.read() header_file_obj.close() header_str = string.Template(header_template_str) - header = header_str.substitute(testSpecFileName=create_file_name(model.name)) + header = header_str.substitute(testSpecFileName=create_file_name(model_spec.name)) # add the header string content += header @@ -96,46 +134,81 @@ def make_command_script(model): class_template_str = class_file_obj.read() class_file_obj.close() class_str = string.Template(class_template_str) - cls = class_str.substitute(testSpecClassName=create_class_name(model.name), - testSpecFileName=create_file_name(model.name), - testSpecName=model.name, + cls = class_str.substitute(testSpecClassName=create_class_name(model_spec.name), + testSpecFileName=create_file_name(model_spec.name), + testSpecName=model_spec.name, testSpecDescription=model.description, testSpecVersion=model.version) # add the header string content += '\n\n' + cls # add the pre condition function - with open(co_pre_cond_path, 'r') as pre_cond_file_obj: + with open(co_pre_cond_path, 'r') as pre_cond_file_obj, open(co_pre_cond_entry_path, 'r') as pre_cond_entry_file_obj: pre_cond_template_str = pre_cond_file_obj.read() pre_cond_file_obj.close() + + # Get the needed section and read only those lines + all_precon_sections = get_precon_sections() + precon_position = all_precon_sections[model_spec.precon] + pre_cond_entry_array = pre_cond_entry_file_obj.readlines()[precon_position[0]: precon_position[1]] + pre_cond_entry = '' + # Make a string to combine it with the co_pre_conditions file, add tabs for the additonal lines in form of space so the CCS can read it + for count, line in enumerate(pre_cond_entry_array): + if count > 0: + pre_cond_entry += ' '*8 + pre_cond_entry += line + else: + pre_cond_entry += line + pre_cond_entry_file_obj.close() + + pre_cond_template = string.Template(pre_cond_template_str) + pre_cond_combined = pre_cond_template.substitute(testpreconentry=pre_cond_entry) # add the header string - content += '\n' + pre_cond_template_str + content += '\n' + pre_cond_combined # add the step definitions with open(co_step_path, 'r') as step_file_obj: step_template_str = step_file_obj.read() step_file_obj.close() - for step in model.sequence_steps: # steps_dict: + for step in model.steps: step_str = string.Template(step_template_str) command_code = step.command_code command_code_w_indents = command_code.replace('\n', '\n' + 3 * indent) if len(command_code_w_indents) == 0: command_code_w_indents = 'pass' - step = step_str.substitute(testStepNumber=step.step_number, + step = step_str.substitute(testStepNumber=step.step_number_test_format, testStepDescription=step.description, testStepComment=step.comment, testStepCommandCode=command_code_w_indents, - testSpecFileName=create_file_name(model.name), - testSpecClassName=create_class_name(model.name)) + testSpecFileName=create_file_name(model_spec.name), + testSpecClassName=create_class_name(model_spec.name)) # add the string for a steps content += '\n' + step # add the post condition function - with open(co_post_cond_path, 'r') as post_cond_file_obj: + with open(co_post_cond_path, 'r') as post_cond_file_obj, open(co_post_cond_entry_path, 'r') as post_cond_entry_file_obj: post_cond_template_str = post_cond_file_obj.read() post_cond_file_obj.close() + + # Get the needed section and read only those lines + all_postcon_sections = get_postcon_sections() + postcon_position = all_postcon_sections[model_spec.postcon] + post_cond_entry_array = post_cond_entry_file_obj.readlines()[postcon_position[0]: postcon_position[1]] + post_cond_entry = '' + # Make a string to combine it with the co_post_conditions file, add tabs for the additonal lines in form of space so the CCS can read it + for count, line in enumerate(post_cond_entry_array): + if count > 0: + post_cond_entry += ' '*8 + post_cond_entry += line + else: + post_cond_entry += line + post_cond_entry_file_obj.close() + + post_cond_template = string.Template(post_cond_template_str) + post_cond_combined = post_cond_template.substitute(testpostconentry=post_cond_entry) + # add the header string - content += '\n' + post_cond_template_str + content += '\n' + post_cond_combined # add the footer (post condition and other functions) with open(co_footer_path, 'r') as footer_file_obj: @@ -143,14 +216,15 @@ def make_command_script(model): footer_file_obj.close() # build the array of function calls for the steps step_arr = '' - for step in model.sequence_steps: - step_arr += '\n' + 4 * indent + 'self.step_' + str(step.step_number) + ',' + for step in model.steps: + #step_arr += '\n' + 4 * indent + 'self.step_' + str(model.steps[step].step_number) + ',' + step_arr += '\n' + 4 * indent + 'self.step_' + str(step.step_number_test_format) + ',' footer_str = string.Template(footer_template_str) foot = footer_str.substitute(testStepsList=step_arr) content += '\n' + foot # create the new file - file_path = create_script_path(name=model.name, auxiliary=cmd_scrpt_auxiliary) + file_path = create_script_path(name=model_spec.name, auxiliary=cmd_scrpt_auxiliary) with open(file_path, 'w') as command_script: command_script.write(content) command_script.close() @@ -159,37 +233,43 @@ def make_command_script(model): return file_path -def make_command_manually_steps_script(model): +def make_command_run_script(model, model_spec): #assert isinstance(model, data_model.TestSequence) content = '' indent = ' ' # add the header (import statements and so on) - with open(man_header_path, 'r') as header_file_obj: + with open(run_header_path, 'r') as header_file_obj: header_template = header_file_obj.read() header_file_obj.close() # 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.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)) + content += header_str # add the step definitions - with open(man_step_path, 'r') as step_file_obj: + with open(run_step_path, 'r') as step_file_obj: step_template_str = step_file_obj.read() step_file_obj.close() - for step in model.sequence_steps: + for step in model.steps: step_str = string.Template(step_template_str) - step = step_str.substitute(testStepNumber=step.step_number, + #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, testStepComment=step.comment) # add the string for a steps content += '\n' + step # create the new file - file_path = create_script_path(name=model.name, auxiliary=man_scrpt_auxiliary) + file_path = create_script_path(name=model_spec.name, auxiliary=run_scrpt_auxiliary) with open(file_path, 'w') as command_script: command_script.write(content) command_script.close() @@ -198,7 +278,7 @@ def make_command_manually_steps_script(model): return file_path -def make_verification_script(model): +def make_verification_script(model, model_spec): #assert isinstance(model, data_model.TestSequence) content = '' @@ -217,9 +297,9 @@ def make_verification_script(model): class_template_str = class_file_obj.read() class_file_obj.close() class_str = string.Template(class_template_str) - cls = class_str.substitute(testSpecClassName=create_class_name(model.name), - testSpecFileName=create_file_name(model.name), - testSpecName=model.name, + cls = class_str.substitute(testSpecClassName=create_class_name(model_spec.name), + testSpecFileName=create_file_name(model_spec.name), + testSpecName=model_spec.name, testSpecDescription=model.description, testSpecVersion=model.version) # add the header string @@ -236,13 +316,17 @@ def make_verification_script(model): with open(ver_step_path, 'r') as step_file_obj: step_template_str = step_file_obj.read() step_file_obj.close() - for step in model.sequence_steps: + for step in model.steps: step_str = string.Template(step_template_str) verification_code = step.verification_code verification_code_w_indents = verification_code.replace('\n', '\n' + 3 * indent) if len(verification_code_w_indents) == 0: verification_code_w_indents = 'pass' - step = step_str.substitute(testStepNumber=step.step_number, + #step = step_str.substitute(testStepNumber=model.steps[step].step_number, + # testStepDescription=model.steps[step].description, + # testStepComment=model.steps[step].comment, + # testStepVerificationCode=verification_code_w_indents) + step = step_str.substitute(testStepNumber=step.step_number_test_format, testStepDescription=step.description, testStepComment=step.comment, testStepVerificationCode=verification_code_w_indents) @@ -269,7 +353,7 @@ def make_verification_script(model): # content += '\n' + foot # create the new file - file_path = create_script_path(name=model.name, auxiliary=vrc_scrpt_auxiliary) + file_path = create_script_path(name=model_spec.name, auxiliary=vrc_scrpt_auxiliary) with open(file_path, 'w') as command_script: command_script.write(content) command_script.close() @@ -278,17 +362,22 @@ def make_verification_script(model): return file_path -def make_documentation(model): +def make_documentation(model, model_spec): return None def make_all(model): paths = [] - - cs_path = make_command_script(model) - cms_path = make_command_manually_steps_script(model) - vf_path = make_verification_script(model) - dc_path = make_documentation(model) + for sequence in model.sequences: + cs_path = make_command_script(sequence, model) + cms_path = make_command_run_script(sequence, model) + vf_path = make_verification_script(sequence, model) + dc_path = make_documentation(sequence, model) + + #cs_path = make_command_script(model) + #cms_path = make_command_manually_steps_script(model) + #vf_path = make_verification_script(model) + #dc_path = make_documentation(model) if cs_path is not None: paths.append(cs_path) diff --git a/Tst/tst/generator_templates/co_class.py b/Tst/tst/generator_templates/co_class.py index ebb3cf648521419e57c4048769926ccf36f3e6c6..cfbf5c50542c415dea2231a4d1008900a1a4b0d7 100644 --- a/Tst/tst/generator_templates/co_class.py +++ b/Tst/tst/generator_templates/co_class.py @@ -4,12 +4,14 @@ class ${testSpecClassName}: self.name = '${testSpecName}' self.description = '${testSpecDescription}' self.precondition = '' + self.postcondition = '' self.comment = '' self.number_of_steps = None self.successful_steps = 0 self.step_results = [] self.test_passed = None self.precond_ok = False + self.postcond_ok = False self.integrity = True self.exceptions = [] self.do_verification = do_verification diff --git a/Tst/tst/generator_templates/co_footer.py b/Tst/tst/generator_templates/co_footer.py index 35dc84b4ee9be8624b6142756ff89d2adfa8221a..ceecf91b35dd01a792d3f9a6dbaa250b6cf58a61 100644 --- a/Tst/tst/generator_templates/co_footer.py +++ b/Tst/tst/generator_templates/co_footer.py @@ -1,9 +1,7 @@ # EXECUTE ALL STEPS AUTOMATED -------------------------------------------------------------------------------------- - def run(self, ccs, pool_name, save_pool=True, loglevel='DEBUG', make_new_log_file=True): + def run(self, pool_name, save_pool=True, loglevel='DEBUG', make_new_log_file=True): """ Executes the steps of this test. Before running the steps the preconditions are checked. - :param ccs: packets.CCScom - Instance of the class packets.CCScom :param pool_name: str Name of the datapool for TM/TCs in the database :param save_pool: bool @@ -18,11 +16,11 @@ testing_logger.cmd_log_handler(__name__) # log the header of this test - report.write_log_test_header(test=self, ccs=ccs, pool_name=pool_name) + report.write_log_test_header(test=self, pool_name=pool_name) # preconditions of the test logger.info('Preconditions: {}'.format(self.precondition)) - self.precond_ok = self.establish_preconditions(ccs=ccs, pool_name=pool_name) + self.precond_ok = self.establish_preconditions(pool_name=pool_name) # if preconditions are met, execute the steps and note the results if self.precond_ok: @@ -35,7 +33,7 @@ try: # run a single step t_start = time.time() - res = step(ccs=ccs, pool_name=pool_name) + res = step(pool_name=pool_name) t_end = time.time() logger.debug('runtime of step: {}s\n'.format(t_end - t_start)) except Exception as error: @@ -51,8 +49,12 @@ 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(ccs=ccs, pool_name=pool_name, save_pool=save_pool) + self.save_pool_in_file(pool_name=pool_name, save_pool=save_pool) # log the summary of this test self.successful_steps = report.write_log_test_footer(test=self) @@ -64,7 +66,7 @@ return self - def save_pool_in_file(self, ccs, pool_name, save_pool): + def save_pool_in_file(self, pool_name, save_pool): if save_pool is True: - pool_file = tools.get_path_for_testing_logs(ccs=ccs) + self.id + '.tmpool' - ccs.savepool(filename=pool_file, pool_name=pool_name) + pool_file = tools.get_path_for_testing_logs() + self.id + '.tmpool' + cfl.savepool(filename=pool_file, pool_name=pool_name) diff --git a/Tst/tst/generator_templates/co_header.py b/Tst/tst/generator_templates/co_header.py index 3c115f7eb7fa2ec50c214c6a585085dd150c0452..2f220d2c1a00651f84e74709002458bac453b95e 100644 --- a/Tst/tst/generator_templates/co_header.py +++ b/Tst/tst/generator_templates/co_header.py @@ -5,8 +5,13 @@ import os import time import importlib import threading +import confignator +ccs_path = confignator.get_option('paths', 'ccs') +sys.path.append(ccs_path) +sys.path.append(confignator.get_option('tst-paths', 'testing_library')) + +import ccs_function_lib as cfl -sys.path.append(os.path.realpath('test_specs')) from testlib import tools from testlib import report from testlib import tm diff --git a/Tst/tst/generator_templates/co_post_condition.py b/Tst/tst/generator_templates/co_post_condition.py index b089cf2539b573edd409dd484b8372a4469ead2a..907ad733c5f082410eb267e08c30771878ad663b 100644 --- a/Tst/tst/generator_templates/co_post_condition.py +++ b/Tst/tst/generator_templates/co_post_condition.py @@ -1,30 +1,20 @@ # POST-CONDITION --------------------------------------------------------------------------------------------------- - def post_condition(self, ccs, pool_name): + def post_condition(self, pool_name): """ Set the period and enable-status of all housekeepings back to their default value. - :param (packets.CCScom) ccs: Instance of the class packets.CCScom :param (str) pool_name: Name of the datapool for TM/TCs in the database :return: True if all conditions were successfull. :rtype: bool """ - testing_logger.cmd_log_handler(__name__) - result = False + # testing_logger.cmd_log_handler(__name__) + success = False + logger.info('establishing postconditions started') - # reset all housekeepings to their default period and enable status - reset = tc.reset_all_housekeepings(ccs=ccs, pool_name=pool_name) + $testpostconentry - # add further conditions here + logger.info('establishing postconditions finished') + report.write_postcondition_outcome(success) + return success - # evaluation if the all conditions are fulfilled - if reset: - result = True - - # logging of the result - if result is True: - logger.info('+++ POSTCONDITIONS established successful +++') - else: - logger.info('failed to establish the post conditions') - - return result diff --git a/Tst/tst/generator_templates/co_post_condition_entry.py b/Tst/tst/generator_templates/co_post_condition_entry.py new file mode 100644 index 0000000000000000000000000000000000000000..2a8786a88969c3e4073ec412c65ff0f69f59e2dd --- /dev/null +++ b/Tst/tst/generator_templates/co_post_condition_entry.py @@ -0,0 +1,15 @@ +# Explanation: +# In the test always one choosen section is entered into the postconditions, the start and finish functions are always +# the same and given in co_post_condition. py file +# A section can be added if it starts with the format #####-Nameofthepostcon-##### and will than be shown in the TST +# At the end of the file exactly 2 empty lines should exist + +#####-None-##### +logger.info('No post-conditions have been given') +success = True + +#####-Example-##### +print('Hello, I am the whole post-condition') +#reset = tc.reset_all_housekeepings(pool_name=pool_name) +success = True + diff --git a/Tst/tst/generator_templates/co_pre_condition.py b/Tst/tst/generator_templates/co_pre_condition.py index 04bd912a5b44525a8baa4ffb3030f13897b29bd9..5ac35249b3e484057b80bc807229e860783d3a04 100644 --- a/Tst/tst/generator_templates/co_pre_condition.py +++ b/Tst/tst/generator_templates/co_pre_condition.py @@ -1,31 +1,18 @@ # PRECONDITION ----------------------------------------------------------------------------------------------------- - def establish_preconditions(self, ccs, pool_name): + def establish_preconditions(self, pool_name): """ This functions holds the code which prepares the environment for the test. - :param ccs: packets.CCScom - Instance of the class packets.CCScom :param pool_name: str Name of the datapool for TM/TCs in the database :return: bool True if the preconditions are fulfilled """ - testing_logger.cmd_log_handler(__name__) + #testing_logger.cmd_log_handler(__name__) success = False + logger.info('establishing preconditions started') - # log the current states - expected_states = { - 'iaswState': 'STANDBY', - 'semState': None, - 'semOperState': None, - 'sdbState': None - } - logger.info('establish_preconditions: current states are') - tm.get_hk_entry(ccs=ccs, pool_name=pool_name, hk_name='IFSW_HK', name=expected_states) - - precond.iasw_standby(ccs=ccs, pool_name=pool_name, silent=True) - - states = tm.get_hk_entry(ccs=ccs, pool_name=pool_name, hk_name='IFSW_HK', name=expected_states, silent=True) - success = tools.entry_is_equal(entry=states, key_value=expected_states) + $testpreconentry + logger.info('establishing preconditions finished') report.write_precondition_outcome(success) return success diff --git a/Tst/tst/generator_templates/co_pre_condition_entry.py b/Tst/tst/generator_templates/co_pre_condition_entry.py new file mode 100644 index 0000000000000000000000000000000000000000..be68a95833036cfe53656fb7312cc3196aecbd0a --- /dev/null +++ b/Tst/tst/generator_templates/co_pre_condition_entry.py @@ -0,0 +1,15 @@ +# Explanation: +# In the test always one choosen section is entered into the precondition, the start and finish functions are always +# the same and given in co_pre_condition. py file +# A section can be added if it starts with the format #####-Nameoftheprecon-##### and will than be shown in the TST +# At the end of the file exactly 2 empty lines should exist + +#####-None-##### +logger.info('No pre-conditions have been given') +success = False + +#####-Example-##### +print('No pre-conditions have been given') +success = True + + diff --git a/Tst/tst/generator_templates/co_step.py b/Tst/tst/generator_templates/co_step.py index d7bac6ed49f4becd8131eefbb60da235ff43e6fc..14cd6c87254e3ad4ea786c037a85a66960abd1ca 100644 --- a/Tst/tst/generator_templates/co_step.py +++ b/Tst/tst/generator_templates/co_step.py @@ -1,25 +1,29 @@ # STEP ${testStepNumber} -------------------------------------------------------------------------------------------------------- - def step_${testStepNumber}(self, ccs, pool_name): + def step_${testStepNumber}(self, pool_name): testing_logger.cmd_log_handler(__name__) param = { 'step_no': '$testStepNumber', 'msg': '$testStepDescription', 'comment': '$testStepComment' } - step_start_cuc = ccs.get_last_pckt_time(pool_name=pool_name, string=False) - report.command_step_begin(step_param=param, script_version=self.version(), ccs=ccs, pool_name=pool_name, step_start_cuc=step_start_cuc) + step_start_cuc = cfl.get_last_pckt_time(pool_name=pool_name, string=False) + report.command_step_begin(step_param=param, script_version=self.version(), pool_name=pool_name, step_start_cuc=step_start_cuc) summary = report.StepSummary(step_number=param['step_no']) tc_id = None try: + ########---The defined step starts here---######## + $testStepCommandCode + + ########---The defined step ends here---######## except Exception as e: report.command_step_exception(step_param=param) logger.exception('Exception in the try block of the step') summary.result = False summary.had_exception() finally: - step_end_cuc = ccs.get_last_pckt_time(pool_name=pool_name, string=False) + step_end_cuc = cfl.get_last_pckt_time(pool_name=pool_name, string=False) report.command_step_end(step_param=param, step_end_cuc=step_end_cuc) if self.do_verification: @@ -27,7 +31,7 @@ logger.info('Doing verification for step {}'.format(param['step_no'])) try: instance = ${testSpecFileName}_verification.${testSpecClassName}Verification() - success = instance.step_${testStepNumber}(ccs, pool_name, start_cuc=step_start_cuc, tc_id=tc_id) + success = instance.step_${testStepNumber}(pool_name, start_cuc=step_start_cuc, tc_id=tc_id) summary.result = success except: logger.exception('Exception in the Verification for Step {}'.format(param['step_no'])) diff --git a/Tst/tst/generator_templates/manually_header.py b/Tst/tst/generator_templates/run_header.py similarity index 74% rename from Tst/tst/generator_templates/manually_header.py rename to Tst/tst/generator_templates/run_header.py index a99cf4e2c056b6b0d5b46af0d4e55e4bd631cc76..7d6bfdbe2c11fa5efad36179d823582556bb2cd2 100644 --- a/Tst/tst/generator_templates/manually_header.py +++ b/Tst/tst/generator_templates/run_header.py @@ -7,7 +7,10 @@ import sys import importlib import time print('current working directory: {}'.format(os.getcwd())) -sys.path.append(os.path.realpath('test_specs')) +import confignator +ccs_path = confignator.get_option('paths', 'ccs') +sys.path.append(ccs_path) +sys.path.append(confignator.get_option('tst-paths', 'testing_library')) from testlib import tools from testlib import report from testlib import tm @@ -27,28 +30,32 @@ importlib.reload(${testSpecFileName}_verification) testinstance = ${testSpecFileName}_command.${testSpecClassName}(do_verification=True) verification_instance = ${testSpecFileName}_verification.${testSpecClassName}Verification() -if False: - # run the whole test - threading.Thread(target=testinstance.run, - kwargs={'ccs': ccs, - 'pool_name': pool_name}, - daemon=True).start() +# define the pool name +pool_name = 'new_tmtc_pool' + +#! CCS.BREAKPOINT +# run the whole test +threading.Thread(target=testinstance.run, + kwargs={'pool_name': pool_name}, + daemon=True).start() + if False: # Save the pool to a file threading.Thread(target=testinstance.save_pool_in_file, - kwargs={'ccs': ccs, - 'pool_name': pool_name, + kwargs={'pool_name': pool_name, 'save_pool': True}, daemon=True).start() if False: # do Verification of command log file and saved pool threading.Thread(target=verification_instance.verify, kwargs={'command_log_file':'logs_test_runs/Simple_Example_command_cmd.log', - 'saved_pool_file': 'logs_test_runs/Simple_Example.tmpool', - 'tpv': poolviewer}, + 'saved_pool_file': 'logs_test_runs/Simple_Example.tmpool'}, daemon=True).start() + # ----------------------------------------------------------------------------------------------- +# Run the test step by step + #! CCS.BREAKPOINT -# PRECONDITION: ${testPrecondDesc} -threading.Thread(target=testinstance.establish_preconditions, kwargs={'ccs': ccs, 'pool_name': pool_name}, daemon=True).start() +# Exectute the preconditions +threading.Thread(target=testinstance.establish_preconditions, kwargs={'pool_name': pool_name}, daemon=True).start() diff --git a/Tst/tst/generator_templates/ver_class.py b/Tst/tst/generator_templates/ver_class.py index fce1139ca7ca3172ad5194568f7ea2593e90d85a..145044dd097305f4d10796f7fbbe9d9924534633 100644 --- a/Tst/tst/generator_templates/ver_class.py +++ b/Tst/tst/generator_templates/ver_class.py @@ -20,7 +20,7 @@ class ${testSpecClassName}Verification: def version(): return '${testSpecVersion}' - def verify(self, command_log_file, saved_pool_file, tpv): + def verify(self, command_log_file, saved_pool_file): """ Used to verify a test afterward it was run. The command log file and the saved pool file are needed. :param str command_log_file: log file of the command script :param str saved_pool_file: file where the pool was saved @@ -30,10 +30,15 @@ class ${testSpecClassName}Verification: # ------- load pool from a file ------- # load the tmpool file into the database - tpv.load_pool(filename=saved_pool_file) - pool_name = tpv.active_pool_info.filename + if not cfl.is_open('poolviewer'): + logger.error('Poolviewer has to be running to manually verify steps') + return + pv = cfl.dbus_connection('poolviewer') + cfl.Functions(pv, 'load_pool', filename=saved_pool_file) + pool_name = cfl.Variables(pv, 'active_pool_info')[0] # ------- analyze command log -> get step start CUC timestamps, TCid and step end CUC timestamps ------- + # ToDo steps = analyse_command_log.get_steps(filename=command_log_file) tcs = analyse_command_log.get_sent_tcs(filename=command_log_file) # ------- loop over the verification steps, show progress ------- diff --git a/Tst/tst/generator_templates/ver_header.py b/Tst/tst/generator_templates/ver_header.py index 799507722a123fbe25ec3a37050df029a38406c4..3fa12b7cd9b3bf1ed12103da92d36dbd4e91b179 100644 --- a/Tst/tst/generator_templates/ver_header.py +++ b/Tst/tst/generator_templates/ver_header.py @@ -5,8 +5,16 @@ The verification script import logging import sys import os +import confignator +ccs_path = confignator.get_option('paths', 'ccs') +sys.path.append(ccs_path) +sys.path.append(confignator.get_option('tst-paths', 'testing_library')) -sys.path.append(os.path.realpath('test_specs')) +import ccs_function_lib as cfl + +from testlib import report +from testlib import analyse_command_log +from testlib import testing_logger # create logger logger = logging.getLogger(__name__) diff --git a/Tst/tst/generator_templates/ver_step.py b/Tst/tst/generator_templates/ver_step.py index c85ec4e5121b3b4bcc7002273b3d9e07ee53c52b..4e4e67565593e253446cdcd3a4d5121eeee3e4fc 100644 --- a/Tst/tst/generator_templates/ver_step.py +++ b/Tst/tst/generator_templates/ver_step.py @@ -1,13 +1,13 @@ # STEP $testStepNumber -------------------------------------------------------------------------------------------------------- - def step_$testStepNumber(self, ccs, pool_name, start_cuc=None, tc_id=None): + def step_$testStepNumber(self, pool_name, start_cuc=None, tc_id=None): testing_logger.ver_log_handler(__name__) param = { 'step_no': '$testStepNumber', 'msg': '$testStepDescription', 'comment': '$testStepComment' } - step_start_cuc = ccs.get_last_pckt_time(pool_name=pool_name, string=False) - report.verification_step_begin(step_param=param, script_version=self.version(), ccs=ccs, pool_name=pool_name, step_start_cuc=step_start_cuc) + step_start_cuc = cfl.get_last_pckt_time(pool_name=pool_name, string=False) + report.verification_step_begin(step_param=param, script_version=self.version(), pool_name=pool_name, step_start_cuc=step_start_cuc) # if online: use provided timestamp when the step started, use provided TcId if start_cuc is not None: pass @@ -15,7 +15,7 @@ else: pass - result = False + result = True try: $testStepVerificationCode except Exception as e: @@ -23,6 +23,6 @@ logger.exception('Exception in the try block of the step') result = False finally: - step_end_cuc = ccs.get_last_pckt_time(pool_name=pool_name, string=False) + step_end_cuc = cfl.get_last_pckt_time(pool_name=pool_name, string=False) report.verification_step_end(step_param=param, step_result=result, step_end_cuc=step_end_cuc) return result diff --git a/Tst/tst/tst.py b/Tst/tst/tst.py index a1938c8e6badf28a6f8bd81eedb3f135fe1ab3e0..0eecd364d75016f43524f395ab680c5fa720bbab 100755 --- a/Tst/tst/tst.py +++ b/Tst/tst/tst.py @@ -14,13 +14,36 @@ import tst_logger import generator import confignator import codeblockreuse -# import connect_apps +import connect_apps import sys sys.path.append(confignator.get_option('paths', 'ccs')) import ccs_function_lib as cfl import dbus import toolbox + +# creating lists for type and subtype to get rid of duplicate entries, for TC List +dictionary_of_commands = cfl.get_tc_list() +read_in_list_of_commands = list(dictionary_of_commands.keys()) +list_of_commands = [] +type_list = [] +subtype_list = [] + +for command in read_in_list_of_commands: + command = list(command) + del command[0] + myorder = [2, 3, 0, 1] + command = [command[i] for i in myorder] + command[0] = int(command[0]) + command[1] = int(command[1]) + list_of_commands.append(command) + if command[0] not in type_list: + type_list.append(command[0]) + + +type_list.sort() +subtype_list.sort() + path_icon = os.path.join(os.path.dirname(__file__), 'style/tst.svg') menu_xml = os.path.join(os.path.dirname(__file__), 'app_menu.xml') css_file = os.path.join(os.path.dirname(__file__), 'style/style.css') @@ -266,6 +289,7 @@ class TstAppWindow(Gtk.ApplicationWindow): self.work_desk = Gtk.Paned() self.work_desk.set_wide_handle(True) + # add the notebook for the test specifications self.notebook = Gtk.Notebook() self.work_desk.pack1(self.notebook) @@ -289,6 +313,12 @@ class TstAppWindow(Gtk.ApplicationWindow): self.label_widget_log_view.set_text('LogView') self.feature_area.append_page(child=self.log_view, tab_label=self.label_widget_log_view) + # command list tab + self.tc_table = TCTableClass() + self.label_widget_tc_table = Gtk.Label() + self.label_widget_tc_table.set_text('TC Table') + self.feature_area.append_page(child=self.tc_table, tab_label=self.label_widget_tc_table) + self.box.pack_start(self.work_desk, True, True, 0) # # panes for the step grid an so on @@ -538,6 +568,14 @@ class TstAppWindow(Gtk.ApplicationWindow): # import importlib # importlib.reload(generator) model = self.current_model() + if not model: + logger.info('Test Files can not be generated without Steps') + print('Please add at least one test step') + return + elif not model.name: + logger.info('Test Files can not be generated if Test has no name!') + print('Please give the test a name') + return self.product_paths = generator.make_all(model=model) # triggering the dialog after generation self.on_generate_products_message_dialog(paths=self.product_paths) @@ -548,6 +586,9 @@ class TstAppWindow(Gtk.ApplicationWindow): if editor is None: self.logger.warning('Failed to connect to the CCS-Editor via DBus') self.on_start_ccs_editor(False) + + editor = connect_apps.connect_to_app('editor') + ''' k = 0 while k < 3: # try again to connect to the CCS-Editor @@ -557,7 +598,7 @@ class TstAppWindow(Gtk.ApplicationWindow): if editor is not None: self.logger.info('Successfully connected to the CCS-Editor via DBus.') break - k += 1 + k += 1''' return editor def connect_progress_viewer(self): @@ -628,6 +669,11 @@ class TstAppWindow(Gtk.ApplicationWindow): from testlib import testing_logger paths = {} current_instance = self.current_test_instance() + if not current_instance: + self.logger.info('Progress Viewer started without running Test') + print('Progress Viewer started without running Test') + return '' + current_file_name = os.path.basename(current_instance.filename) path_test_specs = confignator.get_option(section='tst-paths', option='tst_products') path_test_runs = confignator.get_option(section='tst-logging', option='test_run') @@ -687,6 +733,106 @@ class TstAppWindow(Gtk.ApplicationWindow): Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) Gtk.StyleContext.reset_widgets(Gdk.Screen.get_default()) +class TCTableClass(Gtk.Grid): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.set_size_request(500,500) + # self.set_orientation(Gtk.Orientation.VERTICAL) + # self.grid = Gtk.Grid + + self.telecommand_liststore = Gtk.ListStore(int, int, str, str) + for telecommand_ref in list_of_commands: + self.telecommand_liststore.append(list(telecommand_ref)) + self.current_filter_telecommand = None + + # Creating the filter, feeding it with the liststore model + self.telecommand_filter = self.telecommand_liststore.filter_new() + # setting the filter function + self.telecommand_filter.set_visible_func(self.telecommand_filter_func) + + # Create ListStores for the ComboBoxes + self.type_liststore = Gtk.ListStore(int) + for type_ref in type_list: + self.type_liststore.append([type_ref, ]) + # self.current_filter_type = None + + self.type_combo = Gtk.ComboBox.new_with_model(self.type_liststore) + self.type_combo.connect("changed", self.on_type_combo_changed) + renderer_text = Gtk.CellRendererText() + self.type_combo.pack_start(renderer_text, True) + self.type_combo.add_attribute(renderer_text, "text", 0) + self.attach(self.type_combo, 0, 0, 1, 1) + + self.clear_button = Gtk.Button(label="Clear") + self.clear_button.connect("clicked", self.on_clear_button_clicked) + self.attach_next_to( + self.clear_button, self.type_combo, Gtk.PositionType.RIGHT, 1, 1 + ) + + # creating the treeview, making it use the filter a model, adding columns + self.treeview = Gtk.TreeView.new_with_model(Gtk.TreeModelSort(self.telecommand_filter)) + for i, column_title in enumerate( + ["#TYPE", "SUBTYPE", "DESCR", "LONGDESCR"] + ): + renderer = Gtk.CellRendererText() + column = Gtk.TreeViewColumn(column_title, renderer, text=i) + column.set_sort_column_id(i) + self.treeview.append_column(column) + + # Handle selection + self.selected_row = self.treeview.get_selection() + self.selected_row.connect("changed", self.item_selected) + + # setting up layout, treeview in scrollwindow + self.scrollable_treelist = Gtk.ScrolledWindow() + self.scrollable_treelist.set_vexpand(True) + self.scrollable_treelist.set_hexpand(True) + self.attach(self.scrollable_treelist, 0, 1, 8, 10) + + self.scrollable_treelist.add(self.treeview) + + self.command_entry = Gtk.Entry() + self.command_entry.set_placeholder_text("<Command Variables>") + self.attach_next_to(self.command_entry, self.scrollable_treelist, Gtk.PositionType.BOTTOM, 8, 1) + + self.show_all() + + def on_type_combo_changed(self, combo): + combo_iter = combo.get_active_iter() + if combo_iter is not None: + model = combo.get_model() + number = model[combo_iter][0] + # print(number) + self.current_filter_telecommand = int(number) + + self.telecommand_filter.refilter() + + + def on_clear_button_clicked(self, widget): + self.current_filter_telecommand = None + self.telecommand_filter.refilter() + + def item_selected(self, selection): + model, row = selection.get_selected() + if row is not None: + descr = model[row][2] + self.command_entry.set_text(cfl.make_tc_template(descr, comment=False)) + else: + pass + + def telecommand_filter_func(self, model, iter, data): + + placeholder1 = 0 + placeholder2 = 0 + if ( + self.current_filter_telecommand is None + or self.current_filter_telecommand == "None" + ): + return True + else: + return model[iter][0] == self.current_filter_telecommand + class ViewModelAsJson(Gtk.Box): def __init__(self, *args, **kwargs): @@ -742,7 +888,8 @@ class ViewModelAsJson(Gtk.Box): def update(self, model): """ Gets the data of the model and makes a JSON string out of it. Intended to display the model data as plain JSON - :param data_model.TestSequence model: a instance of the TestSpecification class + :param data_model.TestSpecification model: a instance of the TestSpecification class + # param data_model.TestSequence model: a instance of the TestSpecification class """ assert isinstance(model, data_model.TestSpecification) or model is None if model is not None: diff --git a/Tst/tst/view.py b/Tst/tst/view.py index c53491d64c9c024417bab8d16789af058a2e9845..5fb11b60bfc04310d624e971592c31710c3d87da 100644 --- a/Tst/tst/view.py +++ b/Tst/tst/view.py @@ -7,9 +7,17 @@ gi.require_version('GtkSource', '3.0') from gi.repository import Gtk, Gdk, GtkSource # ------------------------------------------- import data_model +import generator import dnd_data_parser import toolbox import cairo +import sys + +import confignator +ccs_path = confignator.get_option('paths', 'ccs') +sys.path.append(ccs_path) + +import ccs_function_lib as cfl lm = GtkSource.LanguageManager() lngg = lm.get_language('python') @@ -65,7 +73,7 @@ class Board(Gtk.Box): * a instance of a grid is added * drag and drop is set up """ - assert isinstance(model, data_model.TestSpecification) + #assert isinstance(model, data_model.TestSpecification) self.model = model self.app = app self._filename = filename @@ -83,6 +91,10 @@ class Board(Gtk.Box): self.test_meta_data_labels.set_orientation(Gtk.Orientation.VERTICAL) self.test_meta_data_entries = Gtk.Box() self.test_meta_data_entries.set_orientation(Gtk.Orientation.VERTICAL) + self.test_meta_data_pre_post_con = Gtk.Box() + self.test_meta_data_pre_post_con.set_orientation(Gtk.Orientation.VERTICAL) + self.test_meta_data_pre_post_con_edit = Gtk.Box() + self.test_meta_data_pre_post_con_edit.set_orientation(Gtk.Orientation.VERTICAL) # name of the test self.test_meta_data_name_label = Gtk.Label() self.test_meta_data_name_label.set_text('Name of the test:') @@ -95,7 +107,7 @@ class Board(Gtk.Box): self.test_meta_data_desc_label.set_text('Description of the test:') self.test_meta_data_labels.pack_start(self.test_meta_data_desc_label, True, True, 0) self.test_meta_data_desc = Gtk.Entry() - self.test_meta_data_name.set_placeholder_text('< description of the test>') + self.test_meta_data_desc.set_placeholder_text('< description of the test>') self.test_meta_data_entries.pack_start(self.test_meta_data_desc, True, True, 0) # version self.test_meta_data_version_label = Gtk.Label() @@ -111,9 +123,41 @@ class Board(Gtk.Box): self.text_meta_data_test_is_locked = Gtk.CheckButton() self.test_meta_data_entries.pack_start(self.text_meta_data_test_is_locked, True, True, 0) + # Add pre post condition selections + # Pre conditions + self.precon_selection_label = Gtk.Label() + self.precon_selection_label.set_text('Pre-Conditions:') + self.precon_selection = Gtk.ComboBoxText() + self.set_precon_model() + self.precon_selection.connect("changed", self.on_precon_changed) + # Post conditions + self.postcon_selection_label = Gtk.Label() + self.postcon_selection_label.set_text('Post-Conditions:') + self.postcon_selection = Gtk.ComboBoxText() + self.set_postcon_model() + self.postcon_selection.connect("changed", self.on_postcon_changed) + + # add to pre post box + self.test_meta_data_pre_post_con.pack_start(self.precon_selection_label, False, True, 0) + self.test_meta_data_pre_post_con.pack_start(self.precon_selection, False, True, 0) + self.test_meta_data_pre_post_con.pack_start(self.postcon_selection_label, False, True, 0) + self.test_meta_data_pre_post_con.pack_start(self.postcon_selection, False, True, 0) + self.test_meta_data_box.set_spacing(20) + + # Add Edit Buttons + self.precon_edit_button = Gtk.Button.new_with_label('Edit') + self.precon_edit_button.connect("clicked", self.precon_edit_clicked) + self.postcon_edit_button = Gtk.Button.new_with_label('Edit') + self.postcon_edit_button.connect("clicked", self.postcon_edit_clicked) + + self.test_meta_data_pre_post_con_edit.pack_start(self.precon_edit_button, False, True, 17) + self.test_meta_data_pre_post_con_edit.pack_start(self.postcon_edit_button, False, True, 0) + # add the meta data self.test_meta_data_box.pack_start(self.test_meta_data_labels, False, True, 0) self.test_meta_data_box.pack_start(self.test_meta_data_entries, False, True, 0) + self.test_meta_data_box.pack_start(self.test_meta_data_pre_post_con, False, True, 0) + self.test_meta_data_box.pack_start(self.test_meta_data_pre_post_con_edit, False, True, 0) self.pack_start(self.test_meta_data_box, False, True, 0) # making the toolbar @@ -243,6 +287,56 @@ class Board(Gtk.Box): self.update_widget_data() self.app.update_model_viewer() + def set_precon_model(self): + section_dict = generator.get_precon_sections() + for section_name in section_dict.keys(): + self.precon_selection.append_text(section_name) + self.precon_selection.set_active(0) + self.on_precon_changed(self.precon_selection) + return + + def on_precon_changed(self, widget): + # get the name out of the widget + precon_name = widget.get_active_text() + # update the model + self.model.precon = precon_name + # update the data model viewer + self.app.update_model_viewer() + return + + def set_postcon_model(self): + section_dict = generator.get_postcon_sections() + for section_name in section_dict.keys(): + self.postcon_selection.append_text(section_name) + self.postcon_selection.set_active(0) + self.on_postcon_changed(self.postcon_selection) + return + + def on_postcon_changed(self, widget): + # get the name out of the widget + postcon_name = widget.get_active_text() + # update the model + self.model.postcon = postcon_name + # update the data model viewer + self.app.update_model_viewer() + return + + def precon_edit_clicked(self, widget): + dialog = Edit_Pre_Post_Con_Dialog(self, 'pre') + response = dialog.run() + if response == Gtk.ResponseType.OK: + dialog.destroy() + elif response == Gtk.ResponseType.CANCEL: + dialog.destroy() + + def postcon_edit_clicked(self, widget): + dialog = Edit_Pre_Post_Con_Dialog(self, 'post') + response = dialog.run() + if response == Gtk.ResponseType.OK: + dialog.destroy() + elif response == Gtk.ResponseType.CANCEL: + dialog.destroy() + def on_test_name_change(self, widget): """ if the name of test specification is changed update the model and the model viewer @@ -917,10 +1011,19 @@ class StepWidget(Gtk.EventBox): def on_exec_commands(self, button): # get the code of the commands out of the buffer of the widget - commands = self.get_commands_from_widget() - import editor - x = editor.CcsEditor() - x._to_console_via_socket(commands) + commands = str(self.get_commands_from_widget()) + #Check if CCS is open + if not cfl.is_open('editor'): + print('CCS-Editor has to be started first') + logger.info('CCS-Editor has to be running if a step should be executed') + return + + # Connect to the editor and send the commands to the terminal via D-Bus + ed = cfl.dbus_connection('editor') + cfl.Functions(ed, '_to_console_via_socket', commands) + #import editor + #x = editor.CcsEditor() + #x._to_console_via_socket(commands) def on_exec_verification(self, button): # get the code of the commands out of the buffer of the widget @@ -929,7 +1032,14 @@ class StepWidget(Gtk.EventBox): #print(ack) def on_execute_step(self, *args): - print('on_execute_step') + if not cfl.is_open('editor'): + print('CCS-Editor has to be started first') + logger.info('CCS-Editor has to be running if a step should be executed') + return + + commands = str(self.get_commands_from_widget()) + ed = cfl.dbus_connection('editor') + cfl.Functions(ed, '_to_console_via_socket', commands) def on_toggle_detail(self, toolbutton, *args): """ @@ -1232,3 +1342,158 @@ class StepRightClickMenu(Gtk.Menu): step_clicked_on = step_widget.step_number step_widget.model.get_sequence(step_widget.sequence).add_step_below(reference_step_position=step_clicked_on) self.step_widget.board.update_widget_data() + +class Edit_Pre_Post_Con_Dialog(Gtk.Dialog): + def __init__(self, parent, pre_post): + #Gtk.Dialog.__init__(self, title='PRE-Conditions', transient_for=parent, flags=0) + Gtk.Dialog.__init__(self, title=pre_post.upper() + ' -Conditions') + self.add_buttons( + Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK + ) + self.set_default_size(200, 200) + self.win = parent + self.file_path = os.path.join(confignator.get_option('paths', 'tst'), + 'tst/generator_templates/co_'+pre_post+'_condition_entry.py') + + if pre_post == 'pre': + self.section_dict = generator.get_precon_sections() + else: + self.section_dict = generator.get_postcon_sections() + + self.view() + + self.show_all() + + def view(self): + self.main_box = Gtk.Box() + self.main_box.set_orientation(Gtk.Orientation.VERTICAL) + + self.selection_box = Gtk.Box() + self.selection_box.set_orientation(Gtk.Orientation.HORIZONTAL) + + self.make_text_viewer() + + self.selection = Gtk.ComboBox.new_with_model_and_entry(self.get_con_sections_model()) + self.selection.connect("changed", self.on_name_combo_changed) + self.selection.set_entry_text_column(0) + + self.save_button = Gtk.Button.new_with_label('Save') + self.save_button.connect("clicked", self.save_button_clicked) + + self.selection_box.pack_start(self.selection, False, True, 0) + self.selection_box.pack_start(self.save_button, False, True, 0) + + box = self.get_content_area() + box.pack_start(self.selection_box, True, True, 0) + box.pack_start(self.scrolled_window, True, True, 0) + + + def get_con_sections_model(self): + data_model = Gtk.ListStore(str, int, int) + for section_name in self.section_dict.keys(): + + data_model.append([section_name, self.section_dict[section_name][0], self.section_dict[section_name][1]]) + + return data_model + + def on_name_combo_changed(self, widget): + buffer = self.textview.get_buffer() + tree_iter = widget.get_active_iter() + if tree_iter is not None: + model = widget.get_model() + name = model[tree_iter][0] + else: + #entry = widget.get_child() + #name = entry.get_text() + name = None + self.read_section(name) + buffer.set_text(self.read_section(name)) + return + + def save_button_clicked(self, widget): + buffer = self.textview.get_buffer() + tree_iter = self.selection.get_active_iter() + if tree_iter is not None: + model = self.selection.get_model() + name, start_line, end_line = model[tree_iter] + new = False + else: + entry = widget.get_child() + name = entry.get_text() + new = True + + buf = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), True) + + if new: + with open(self.file_path, 'a') as entry_file_obj: + entry_file_obj.write('#####-'+name+'-#####\n') + entry_file_obj.write(buf + '\n') + entry_file_obj.close() + else: + with open(self.file_path, 'r') as entry_file_obj: + file_lines = entry_file_obj.readlines() + entry_file_obj.close() + file_lines[start_line:end_line-1] = buf + + with open(self.file_path, 'w') as entry_file_obj: + file_lines = "".join(file_lines) + entry_file_obj.write(file_lines) + entry_file_obj.close() + + add_lines_count = 0 + with open(self.file_path, 'r') as entry_file_obj: + file_lines = entry_file_obj.readlines() + if file_lines[-1]: + add_lines_count = 2 + elif file_lines[-2]: + add_lines_count = 1 + entry_file_obj.close() + if add_lines_count > 0: + with open(self.file_path, 'a') as entry_file_obj: + entry_file_obj.write('\n'*add_lines_count) + entry_file_obj.close() + + + return + + def make_text_viewer(self): + # a scrollbar for the child widget (that is going to be the textview) + self.scrolled_window = Gtk.ScrolledWindow() + self.scrolled_window.set_border_width(5) + # we scroll only if needed + self.scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) + + # a text buffer (stores text) + buffer = Gtk.TextBuffer() + + # a textview (displays the buffer) + self.textview = Gtk.TextView(buffer=buffer) + # wrap the text, if needed, breaking lines in between words + self.textview.set_wrap_mode(Gtk.WrapMode.WORD) + + # textview is scrolled + self.scrolled_window.add(self.textview) + + box = self.get_content_area() + box.add(self.selection_box) + + return + + def read_section(self, name=None): + if not name: + return '' + + # add the condition function + with open(self.file_path,'r') as entry_file_obj: + # Get the needed section and read only those lines + position = self.section_dict[name] + entry_array = entry_file_obj.readlines()[position[0]: position[1]-1] + entry = '' + # Make a string to combine it with the co_conditions file, add tabs for the additonal lines in form of space so the CCS can read it + for count, line in enumerate(entry_array): + entry += line + entry_file_obj.close() + + return entry + +