From fd2142f3bfeeba274d551a4050fb096fc6491285 Mon Sep 17 00:00:00 2001 From: Przemek Wirkus Date: Wed, 22 Oct 2014 15:12:24 +0100 Subject: [PATCH 1/9] Host test plugins: First draft with working pluging for mbed (serial sendBreak command for reset) --- workspace_tools/host_tests/host_test.py | 79 +++---------------- .../host_tests/host_tests_plugins/__init__.py | 38 +++++++++ .../host_tests_plugins/host_test_plugins.py | 24 ++++++ .../host_tests_plugins/host_test_registry.py | 65 +++++++++++++++ .../host_tests_plugins/module_reset_mbed.py | 60 ++++++++++++++ .../host_tests_plugins/module_reset_mps2.py | 59 ++++++++++++++ .../host_tests_plugins/module_reset_silabs.py | 64 +++++++++++++++ 7 files changed, 320 insertions(+), 69 deletions(-) create mode 100644 workspace_tools/host_tests/host_tests_plugins/__init__.py create mode 100644 workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py create mode 100644 workspace_tools/host_tests/host_tests_plugins/host_test_registry.py create mode 100644 workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py create mode 100644 workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py create mode 100644 workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py diff --git a/workspace_tools/host_tests/host_test.py b/workspace_tools/host_tests/host_test.py index 02fc52102c..8f1063c927 100644 --- a/workspace_tools/host_tests/host_test.py +++ b/workspace_tools/host_tests/host_test.py @@ -23,9 +23,12 @@ except ImportError, e: exit(-1) import os -from optparse import OptionParser -from time import sleep, time from sys import stdout +from time import sleep, time +from optparse import OptionParser +from subprocess import call + +import host_tests_plugins # This is a little tricky. We need to add upper directory to path so # we can find packages we want from the same level as other files do @@ -156,27 +159,6 @@ class Mbed: result = None return result - def safe_sendBreak(self, serial): - """ Wraps serial.sendBreak() to avoid serial::serialposix.py exception on Linux - Traceback (most recent call last): - File "make.py", line 189, in - serial.sendBreak() - File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 511, in sendBreak - termios.tcsendbreak(self.fd, int(duration/0.25)) - error: (32, 'Broken pipe') - """ - result = True - try: - serial.sendBreak() - except: - # In linux a termios.error is raised in sendBreak and in setBreak. - # The following setBreak() is needed to release the reset signal on the target mcu. - try: - serial.setBreak(False) - except: - result = False - return result - def touch_file(self, path): """ Touch file and set timestamp to items """ @@ -190,56 +172,15 @@ class Mbed: sleep(1) def reset(self): - """ Reset function. - Supports: - - 'standard' send break command via Mbed's CDC, - - also handles other reset modes: - - E.g. reset by touching file with specific file name: - reboot.txt - startup from standby state, reboots when in run mode. - shutdown.txt - shutdown from run mode - reset.txt - reset FPGA during run mode - - eACommander for reset of SiLabs Gecko baords. + """ Calls proper reset plugin to do the job. + Please refer to host_test_plugins functionality """ if self.options.forced_reset_type: - if self.options.forced_reset_type == 'eACommander': - # For this copy method 'disk' will be 'serialno' for eACommander command line parameters - # Note: Commands are executed in the order they are specified on the command line - cmd = [EACOMMANDER_CMD, - '--serialno', self.disk.rstrip('/\\'), - '--resettype', '2', '--reset',] - try: - self.flush() - ret = call(cmd, shell=True) - if ret: - resutl_msg = "Return code: %d. Command: "% ret + " ".join(cmd) - result = False - except Exception, e: - resutl_msg = e - result = False - elif self.options.forced_reset_type == 'eACommander-usb': - # For this copy method 'disk' will be 'usb address' for eACommander command line parameters - # Note: Commands are executed in the order they are specified on the command line - cmd = [EACOMMANDER_CMD, - '--usb', self.disk.rstrip('/\\'), - '--resettype', '2', '--reset',] - try: - self.flush() - ret = call(cmd, shell=True) - if ret: - resutl_msg = "Return code: %d. Command: "% ret + " ".join(cmd) - result = False - except Exception, e: - resutl_msg = e - result = False - elif self.options.forced_reset_type.endswith('.txt'): - reset_file_path = os.path.join(self.disk, self.options.forced_reset_type.lower()) - self.touch_file(reset_file_path) - self.flush() + host_tests_plugins.call_plugin('ResetMethod', self.options.forced_reset_type, disk=self.disk) else: - self.safe_sendBreak(self.serial) # Instead of serial.sendBreak() - self.flush() + host_tests_plugins.call_plugin('ResetMethod', 'default', serial=self.serial) # Flush serials to get only input after reset - #self.flush() + self.flush() # Give time to wait for the image loading reset_tout_s = self.options.forced_reset_timeout if self.options.forced_reset_timeout is not None else self.DEFAULT_RESET_TOUT self.reset_timeout(reset_tout_s) diff --git a/workspace_tools/host_tests/host_tests_plugins/__init__.py b/workspace_tools/host_tests/host_tests_plugins/__init__.py new file mode 100644 index 0000000000..c0f4ed47b5 --- /dev/null +++ b/workspace_tools/host_tests/host_tests_plugins/__init__.py @@ -0,0 +1,38 @@ +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +import host_test_registry +import module_reset_mbed +import module_reset_mps2 +import module_reset_silabs + + +# Plugin registry instance +HOST_TEST_PLUGIN_REGISTRY = host_test_registry.HostTestRegistry() + +# Static plugin registration +# TODO: extend to files with name module_*.py loaded ad-hoc +HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_reset_mbed.load_plugin()) +HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_reset_mps2.load_plugin()) +HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_reset_silabs.load_plugin()) + +def call_plugin(type, capability, *args, **kwargs): + """ Interface to call plugin registry functional way + """ + HOST_TEST_PLUGIN_REGISTRY.call_plugin(type, capability, *args, **kwargs) + +#print HOST_TEST_PLUGIN_REGISTRY.get_string() diff --git a/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py b/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py new file mode 100644 index 0000000000..b39084b328 --- /dev/null +++ b/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py @@ -0,0 +1,24 @@ +# Interfaces and utils for host test plugin architecture + + +def construct_enum(**enums): + """ Create your own pseudo-enums + """ + return type('Enum', (), enums) + + +class HostTestPluginBase: + """ Base class for all plug-ins used with host tests. + """ + def register(self, *args, **kwargs): + pass + + def unregister(self): + pass + + # Attributes defining plugin name, type etc. + # This values across plugin should be unique + name = "HostTestPluginBase" + type = "BasePlugin" + capabilities = [] + diff --git a/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py b/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py new file mode 100644 index 0000000000..5366b182c6 --- /dev/null +++ b/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py @@ -0,0 +1,65 @@ +# Registry storing plugins + +""" +module_example.py: + +def plugin_main(*args, **kwargs): + print args, kwargs + +loader.py: + +def load_plugin(name): + mod = __import__("module_%s" % name) + return mod + +def call_plugin(name, *args, **kwargs): + plugin = load_plugin(name) + plugin.plugin_main(*args, **kwargs) + +call_plugin("example", 1234) +""" + + +class HostTestRegistry: + """ Simple class used to register and store + host test plugins for further usage + """ + # Here we actually store all the plugins + PLUGINS = {} + + def print_error(self, text): + print "Plugin load failed. Reason: %s"% text + + def register_plugin(self, plugin): + # TODO: + # - check for unique caps for specified type + if plugin.name not in self.PLUGINS: + plugin.setup() # Setup plugin + self.PLUGINS[plugin.name] = plugin + else: + self.print_error("%s already loaded"% plugin.name) + + def call_plugin(self, type, capability, *args, **kwargs): + """ Execute plugin functionality respectively to its purpose + """ + for plugin_name in self.PLUGINS: + plugin = self.PLUGINS[plugin_name] + if plugin.type == type and capability in plugin.capabilities: + return plugin.execute(capability, *args, **kwargs) + return False + + def get_string(self): + """ User friendly printing method to show hooked plugins + """ + from prettytable import PrettyTable + column_names = ['name', 'type', 'capabilities'] + pt = PrettyTable(column_names) + for column in column_names: + pt.align[column] = 'l' + for plugin_name in self.PLUGINS: + name = self.PLUGINS[plugin_name].name + type = self.PLUGINS[plugin_name].type + capabilities = ', '.join(self.PLUGINS[plugin_name].capabilities) + row = [name, type, capabilities] + pt.add_row(row) + return pt.get_string() diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py new file mode 100644 index 0000000000..757f9c475a --- /dev/null +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py @@ -0,0 +1,60 @@ +# Interfaces and utils for host test plugin architecture + +from subprocess import call +from host_test_plugins import HostTestPluginBase + + +class HostTestPluginResetMethod_Mbed(HostTestPluginBase): + + def safe_sendBreak(self, serial): + """ Wraps serial.sendBreak() to avoid serial::serialposix.py exception on Linux + Traceback (most recent call last): + File "make.py", line 189, in + serial.sendBreak() + File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 511, in sendBreak + termios.tcsendbreak(self.fd, int(duration/0.25)) + error: (32, 'Broken pipe') + """ + result = True + try: + serial.sendBreak() + except: + # In linux a termios.error is raised in sendBreak and in setBreak. + # The following setBreak() is needed to release the reset signal on the target mcu. + try: + serial.setBreak(False) + except: + result = False + return result + + # Plugin interface + name = 'HostTestPluginResetMethod_Mbed' + type = 'ResetMethod' + capabilities = ['default'] + required_parameters = ['serial'] + + def setup(self, *args, **kwargs): + pass + + def execute(self, capabilitity, *args, **kwargs): + """ Executes capability by name. + Each capability may directly just call some command line + program or execute building pythonic function + """ + for parameter in self.required_parameters: + if parameter not in kwargs: + print "Plugin parameter '%s' missing"% parameter + return False + + if capabilitity == 'default': + serial = kwargs['serial'] + self.safe_sendBreak(serial) + else: + return False + return True + + +def load_plugin(): + """ Returns plugin available in this module + """ + return HostTestPluginResetMethod_Mbed() diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py new file mode 100644 index 0000000000..3da783070a --- /dev/null +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py @@ -0,0 +1,59 @@ +# Interfaces and utils for host test plugin architecture + +import os +from host_test_plugins import HostTestPluginBase + + +class HostTestPluginResetMethod_MPS2(HostTestPluginBase): + """ + Supports: + reboot.txt - startup from standby state, reboots when in run mode. + shutdown.txt - shutdown from run mode. + reset.txt - reset FPGA during run mode. + """ + def touch_file(self, path): + """ Touch file and set timestamp to items + """ + with open(path, 'a'): + os.utime(path, None) + + # Plugin interface + name = 'HostTestPluginResetMethod_MPS2' + type = 'ResetMethod' + capabilities = ['reboot.txt', 'shutdown.txt', 'reset.txt'] + required_parameters = ['disk'] + + def setup(self, *args, **kwargs): + """ Prepare / configure plugin to work. + This method can receive plugin specific parameters by kwargs and + ignore other parameters which may affect other plugins. + """ + pass + + def execute(self, capabilitity, *args, **kwargs): + """ Executes capability by name. + Each capability may directly just call some command line + program or execute building pythonic function + """ + for parameter in self.required_parameters: + if parameter not in kwargs: + print "%s. Plugin parameter '%s' missing"% (self.name, parameter) + return False + + if capabilitity == 'reboot.txt': + pass + + elif capabilitity == 'shutdown.txt': + pass + + elif capabilitity == 'reset.txt': + pass + + else: + return False + return True + +def load_plugin(): + """ Returns plugin available in this module + """ + return HostTestPluginResetMethod_MPS2() diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py new file mode 100644 index 0000000000..a7b943c055 --- /dev/null +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py @@ -0,0 +1,64 @@ +# Interfaces and utils for host test plugin architecture + +from subprocess import call +from host_test_plugins import HostTestPluginBase + + +class HostTestPluginResetMethod_SiLabs(HostTestPluginBase): + # Plugin interface + name = 'HostTestPluginResetMethod_SiLabs' + type = 'ResetMethod' + capabilities = ['eACommander', 'eACommander-usb'] + required_parameters = ['disk'] + + def setup(self, *args, **kwargs): + self.EACOMMANDER_CMD = 'c:/SiliconLabs/SimplicityStudio/v2/commander/eACommander.exe' + pass + + def execute(self, capabilitity, *args, **kwargs): + """ Executes capability by name. + Each capability may directly just call some command line + program or execute building pythonic function + """ + + for parameter in self.required_parameters: + if parameter not in kwargs: + print "Plugin parameter '%s' missing"% parameter + return False + + disk = kwargs['disk'].rstrip('/\\') + + if capabilitity == 'eACommander': + # For this copy method 'disk' will be 'serialno' for eACommander command line parameters + # Note: Commands are executed in the order they are specified on the command line + cmd = [self.EACOMMANDER_CMD, + '--serialno', disk, + '--resettype', '2', '--reset',] + try: + ret = call(cmd, shell=True) + if ret: + print "Return code: %d. Command: "% ret + " ".join(cmd) + except Exception, e: + print str(e) + + elif capabilitity == 'eACommander-usb': + # For this copy method 'disk' will be 'usb address' for eACommander command line parameters + # Note: Commands are executed in the order they are specified on the command line + cmd = [self.EACOMMANDER_CMD, + '--usb', disk, + '--resettype', '2', '--reset',] + try: + ret = call(cmd, shell=True) + if ret: + print "Return code: %d. Command: "% ret + " ".join(cmd) + except Exception, e: + print(e) + else: + return False + return True + + +def load_plugin(): + """ Returns plugin available in this module + """ + return HostTestPluginResetMethod_SiLabs() From 8af8250b48aec411ce632256fa2e0b31851927de Mon Sep 17 00:00:00 2001 From: Przemek Wirkus Date: Wed, 22 Oct 2014 15:30:45 +0100 Subject: [PATCH 2/9] Host test plugins: Cleaned preliminary code before next round of refactoring and improvements --- .../host_tests_plugins/host_test_plugins.py | 33 +++++++++++-------- .../host_tests_plugins/host_test_registry.py | 20 +++++++++-- .../host_tests_plugins/module_reset_mbed.py | 2 ++ .../host_tests_plugins/module_reset_mps2.py | 6 +++- .../host_tests_plugins/module_reset_silabs.py | 3 +- 5 files changed, 45 insertions(+), 19 deletions(-) diff --git a/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py b/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py index b39084b328..a436a28781 100644 --- a/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py +++ b/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py @@ -1,24 +1,29 @@ # Interfaces and utils for host test plugin architecture -def construct_enum(**enums): - """ Create your own pseudo-enums - """ - return type('Enum', (), enums) - - class HostTestPluginBase: """ Base class for all plug-ins used with host tests. """ - def register(self, *args, **kwargs): - pass - def unregister(self): - pass + ########################################################################### + # Interface + ########################################################################### + ########################################################################### # Attributes defining plugin name, type etc. - # This values across plugin should be unique - name = "HostTestPluginBase" - type = "BasePlugin" - capabilities = [] + ########################################################################### + name = "HostTestPluginBase" # Plugin name, can be plugin class name + type = "BasePlugin" # Plugin type: ResetMethod, Copymethod etc. + capabilities = [] # Capabilities names: what plugin can achieve (e.g. reset using some external command line tool) + def setup(self, *args, **kwargs): + """ Configure plugin, this function should be called before plugin execute() method is used. + """ + pass + + def execute(self, capabilitity, *args, **kwargs): + """ Executes capability by name. + Each capability e.g. may directly just call some command line + program or execute building pythonic function + """ + return False diff --git a/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py b/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py index 5366b182c6..b5ac995140 100644 --- a/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py +++ b/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py @@ -31,13 +31,21 @@ class HostTestRegistry: print "Plugin load failed. Reason: %s"% text def register_plugin(self, plugin): + """ Registers and stores plugin inside registry for further use. + Method also calls plugin's setup() function to configure plugin if needed. + + Note: Different groups of plugins may demand different extra parameter. Plugins + should be at least for one type of plugin configured with the same parameters + because we do not know which of them will actually use particular parameter. + """ # TODO: # - check for unique caps for specified type if plugin.name not in self.PLUGINS: plugin.setup() # Setup plugin self.PLUGINS[plugin.name] = plugin - else: - self.print_error("%s already loaded"% plugin.name) + return True + self.print_error("%s already loaded"% plugin.name) + return False def call_plugin(self, type, capability, *args, **kwargs): """ Execute plugin functionality respectively to its purpose @@ -48,7 +56,13 @@ class HostTestRegistry: return plugin.execute(capability, *args, **kwargs) return False - def get_string(self): + def load_plugin(self.name): + """ Used to load module from + """ + mod = __import__("module_%s"% name) + return mod + + def __str__(self): """ User friendly printing method to show hooked plugins """ from prettytable import PrettyTable diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py index 757f9c475a..11ab964759 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py @@ -34,6 +34,8 @@ class HostTestPluginResetMethod_Mbed(HostTestPluginBase): required_parameters = ['serial'] def setup(self, *args, **kwargs): + """ Configure plugin, this function should be called before plugin execute() method is used. + """ pass def execute(self, capabilitity, *args, **kwargs): diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py index 3da783070a..2f29fad6e4 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py @@ -3,9 +3,10 @@ import os from host_test_plugins import HostTestPluginBase +# Note: This plugin is not fully functional, needs improvements class HostTestPluginResetMethod_MPS2(HostTestPluginBase): - """ + """ Plugin used to reset ARM_MPS2 platform Supports: reboot.txt - startup from standby state, reboots when in run mode. shutdown.txt - shutdown from run mode. @@ -41,12 +42,15 @@ class HostTestPluginResetMethod_MPS2(HostTestPluginBase): return False if capabilitity == 'reboot.txt': + # TODO: Implement touch file for reboot pass elif capabilitity == 'shutdown.txt': + # TODO: Implement touch file for shutdown pass elif capabilitity == 'reset.txt': + # TODO: Implement touch file for reset pass else: diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py index a7b943c055..ac3e917f3f 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py @@ -12,8 +12,9 @@ class HostTestPluginResetMethod_SiLabs(HostTestPluginBase): required_parameters = ['disk'] def setup(self, *args, **kwargs): + """ Configure plugin, this function should be called before plugin execute() method is used. + """ self.EACOMMANDER_CMD = 'c:/SiliconLabs/SimplicityStudio/v2/commander/eACommander.exe' - pass def execute(self, capabilitity, *args, **kwargs): """ Executes capability by name. From 3f00c5903064bdc9d192cbea6beca555a8cae804 Mon Sep 17 00:00:00 2001 From: Przemek Wirkus Date: Wed, 22 Oct 2014 15:35:36 +0100 Subject: [PATCH 3/9] Host test plugins: Added license and fxed one parsing issue --- .../host_tests/host_tests_plugins/__init__.py | 2 +- .../host_tests_plugins/host_test_plugins.py | 28 ++++++++++++++---- .../host_tests_plugins/host_test_registry.py | 29 ++++++++----------- .../host_tests_plugins/module_reset_mbed.py | 17 ++++++++++- .../host_tests_plugins/module_reset_mps2.py | 17 ++++++++++- .../host_tests_plugins/module_reset_silabs.py | 17 ++++++++++- 6 files changed, 83 insertions(+), 27 deletions(-) diff --git a/workspace_tools/host_tests/host_tests_plugins/__init__.py b/workspace_tools/host_tests/host_tests_plugins/__init__.py index c0f4ed47b5..76cc61ec1a 100644 --- a/workspace_tools/host_tests/host_tests_plugins/__init__.py +++ b/workspace_tools/host_tests/host_tests_plugins/__init__.py @@ -35,4 +35,4 @@ def call_plugin(type, capability, *args, **kwargs): """ HOST_TEST_PLUGIN_REGISTRY.call_plugin(type, capability, *args, **kwargs) -#print HOST_TEST_PLUGIN_REGISTRY.get_string() +#print HOST_TEST_PLUGIN_REGISTRY diff --git a/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py b/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py index a436a28781..57ac5aa773 100644 --- a/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py +++ b/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py @@ -1,26 +1,42 @@ -# Interfaces and utils for host test plugin architecture +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" class HostTestPluginBase: """ Base class for all plug-ins used with host tests. """ - ########################################################################### - # Interface + # Interface: ########################################################################### ########################################################################### - # Attributes defining plugin name, type etc. + # Interface attributes defining plugin name, type etc. ########################################################################### - name = "HostTestPluginBase" # Plugin name, can be plugin class name + name = "HostTestPluginBase" # Plugin name, can be plugin class name type = "BasePlugin" # Plugin type: ResetMethod, Copymethod etc. capabilities = [] # Capabilities names: what plugin can achieve (e.g. reset using some external command line tool) + ########################################################################### + # Interface methods + ########################################################################### def setup(self, *args, **kwargs): """ Configure plugin, this function should be called before plugin execute() method is used. """ pass - + def execute(self, capabilitity, *args, **kwargs): """ Executes capability by name. Each capability e.g. may directly just call some command line diff --git a/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py b/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py index b5ac995140..426d651d14 100644 --- a/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py +++ b/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py @@ -1,25 +1,20 @@ -# Registry storing plugins - """ -module_example.py: +mbed SDK +Copyright (c) 2011-2013 ARM Limited -def plugin_main(*args, **kwargs): - print args, kwargs +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at -loader.py: + http://www.apache.org/licenses/LICENSE-2.0 -def load_plugin(name): - mod = __import__("module_%s" % name) - return mod - -def call_plugin(name, *args, **kwargs): - plugin = load_plugin(name) - plugin.plugin_main(*args, **kwargs) - -call_plugin("example", 1234) +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. """ - class HostTestRegistry: """ Simple class used to register and store host test plugins for further usage @@ -56,7 +51,7 @@ class HostTestRegistry: return plugin.execute(capability, *args, **kwargs) return False - def load_plugin(self.name): + def load_plugin(self, name): """ Used to load module from """ mod = __import__("module_%s"% name) diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py index 11ab964759..ab75c67250 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py @@ -1,4 +1,19 @@ -# Interfaces and utils for host test plugin architecture +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" from subprocess import call from host_test_plugins import HostTestPluginBase diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py index 2f29fad6e4..ffb43828b4 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py @@ -1,4 +1,19 @@ -# Interfaces and utils for host test plugin architecture +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" import os from host_test_plugins import HostTestPluginBase diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py index ac3e917f3f..3c337cf3e8 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py @@ -1,4 +1,19 @@ -# Interfaces and utils for host test plugin architecture +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" from subprocess import call from host_test_plugins import HostTestPluginBase From 7591cf5caf7599232463c653aac56db5b91c3d97 Mon Sep 17 00:00:00 2001 From: Przemek Wirkus Date: Wed, 22 Oct 2014 16:59:07 +0100 Subject: [PATCH 4/9] Host test plugins: added return values to setup() and execute() interface methods --- .../host_tests/host_tests_plugins/__init__.py | 9 ++++++++- .../host_tests/host_tests_plugins/host_test_plugins.py | 2 +- .../host_tests/host_tests_plugins/host_test_registry.py | 2 +- .../host_tests/host_tests_plugins/module_reset_mbed.py | 2 +- .../host_tests/host_tests_plugins/module_reset_mps2.py | 2 +- .../host_tests/host_tests_plugins/module_reset_silabs.py | 2 ++ 6 files changed, 14 insertions(+), 5 deletions(-) diff --git a/workspace_tools/host_tests/host_tests_plugins/__init__.py b/workspace_tools/host_tests/host_tests_plugins/__init__.py index 76cc61ec1a..776522d5b7 100644 --- a/workspace_tools/host_tests/host_tests_plugins/__init__.py +++ b/workspace_tools/host_tests/host_tests_plugins/__init__.py @@ -30,9 +30,16 @@ HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_reset_mbed.load_plugin()) HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_reset_mps2.load_plugin()) HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_reset_silabs.load_plugin()) + +############################################################################### +# Functional interface for host test plugin registry +############################################################################### def call_plugin(type, capability, *args, **kwargs): """ Interface to call plugin registry functional way """ HOST_TEST_PLUGIN_REGISTRY.call_plugin(type, capability, *args, **kwargs) -#print HOST_TEST_PLUGIN_REGISTRY +def print_plugin_info(): + """ Prints plugins' information in user friendly way + """ + print HOST_TEST_PLUGIN_REGISTRY diff --git a/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py b/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py index 57ac5aa773..4bc1c59e03 100644 --- a/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py +++ b/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py @@ -35,7 +35,7 @@ class HostTestPluginBase: def setup(self, *args, **kwargs): """ Configure plugin, this function should be called before plugin execute() method is used. """ - pass + return False def execute(self, capabilitity, *args, **kwargs): """ Executes capability by name. diff --git a/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py b/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py index 426d651d14..19e3bc3761 100644 --- a/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py +++ b/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py @@ -20,7 +20,7 @@ class HostTestRegistry: host test plugins for further usage """ # Here we actually store all the plugins - PLUGINS = {} + PLUGINS = {} # 'Plugin Name' : Plugin Object def print_error(self, text): print "Plugin load failed. Reason: %s"% text diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py index ab75c67250..3f9b711df7 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py @@ -51,7 +51,7 @@ class HostTestPluginResetMethod_Mbed(HostTestPluginBase): def setup(self, *args, **kwargs): """ Configure plugin, this function should be called before plugin execute() method is used. """ - pass + return True def execute(self, capabilitity, *args, **kwargs): """ Executes capability by name. diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py index ffb43828b4..7263e6051d 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py @@ -44,7 +44,7 @@ class HostTestPluginResetMethod_MPS2(HostTestPluginBase): This method can receive plugin specific parameters by kwargs and ignore other parameters which may affect other plugins. """ - pass + return True def execute(self, capabilitity, *args, **kwargs): """ Executes capability by name. diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py index 3c337cf3e8..f8e9c84844 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py @@ -20,6 +20,7 @@ from host_test_plugins import HostTestPluginBase class HostTestPluginResetMethod_SiLabs(HostTestPluginBase): + # Plugin interface name = 'HostTestPluginResetMethod_SiLabs' type = 'ResetMethod' @@ -30,6 +31,7 @@ class HostTestPluginResetMethod_SiLabs(HostTestPluginBase): """ Configure plugin, this function should be called before plugin execute() method is used. """ self.EACOMMANDER_CMD = 'c:/SiliconLabs/SimplicityStudio/v2/commander/eACommander.exe' + return True def execute(self, capabilitity, *args, **kwargs): """ Executes capability by name. From efb46ca7de62e45e9757ce12365ac393000c4cb8 Mon Sep 17 00:00:00 2001 From: Przemek Wirkus Date: Wed, 22 Oct 2014 17:49:54 +0100 Subject: [PATCH 5/9] Host test plugins: moved serial port flashing just before plugin reset call --- workspace_tools/host_tests/host_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workspace_tools/host_tests/host_test.py b/workspace_tools/host_tests/host_test.py index 8f1063c927..12494bbb82 100644 --- a/workspace_tools/host_tests/host_test.py +++ b/workspace_tools/host_tests/host_test.py @@ -175,12 +175,12 @@ class Mbed: """ Calls proper reset plugin to do the job. Please refer to host_test_plugins functionality """ + # Flush serials to get only input after reset + self.flush() if self.options.forced_reset_type: host_tests_plugins.call_plugin('ResetMethod', self.options.forced_reset_type, disk=self.disk) else: host_tests_plugins.call_plugin('ResetMethod', 'default', serial=self.serial) - # Flush serials to get only input after reset - self.flush() # Give time to wait for the image loading reset_tout_s = self.options.forced_reset_timeout if self.options.forced_reset_timeout is not None else self.DEFAULT_RESET_TOUT self.reset_timeout(reset_tout_s) From 6a1bdb588edcd6d0be3fc78278b2ee66320ade35 Mon Sep 17 00:00:00 2001 From: Przemek Wirkus Date: Thu, 23 Oct 2014 16:30:17 +0100 Subject: [PATCH 6/9] Host test plugins: added copy pligins, and removed Selenium and eACommander dependency from Test API --- workspace_tools/host_tests/host_test.py | 1 - .../host_tests/host_tests_plugins/__init__.py | 17 +++- .../host_tests_plugins/host_test_plugins.py | 30 +++++++ .../host_tests_plugins/host_test_registry.py | 8 +- .../host_tests_plugins/module_copy_firefox.py | 73 +++++++++++++++ .../host_tests_plugins/module_copy_mbed.py | 67 ++++++++++++++ .../host_tests_plugins/module_copy_shell.py | 58 ++++++++++++ .../host_tests_plugins/module_copy_silabs.py | 63 +++++++++++++ .../host_tests_plugins/module_reset_mbed.py | 17 ++-- .../host_tests_plugins/module_reset_silabs.py | 57 +++++------- workspace_tools/settings.py | 3 - workspace_tools/test_api.py | 89 +++---------------- 12 files changed, 347 insertions(+), 136 deletions(-) create mode 100644 workspace_tools/host_tests/host_tests_plugins/module_copy_firefox.py create mode 100644 workspace_tools/host_tests/host_tests_plugins/module_copy_mbed.py create mode 100644 workspace_tools/host_tests/host_tests_plugins/module_copy_shell.py create mode 100644 workspace_tools/host_tests/host_tests_plugins/module_copy_silabs.py diff --git a/workspace_tools/host_tests/host_test.py b/workspace_tools/host_tests/host_test.py index 12494bbb82..86e6eed715 100644 --- a/workspace_tools/host_tests/host_test.py +++ b/workspace_tools/host_tests/host_test.py @@ -34,7 +34,6 @@ import host_tests_plugins # we can find packages we want from the same level as other files do import sys sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../..'))) -from workspace_tools.settings import EACOMMANDER_CMD class Mbed: diff --git a/workspace_tools/host_tests/host_tests_plugins/__init__.py b/workspace_tools/host_tests/host_tests_plugins/__init__.py index 776522d5b7..b28b81e253 100644 --- a/workspace_tools/host_tests/host_tests_plugins/__init__.py +++ b/workspace_tools/host_tests/host_tests_plugins/__init__.py @@ -16,6 +16,13 @@ limitations under the License. """ import host_test_registry + +import module_copy_mbed +import module_copy_shell +import module_copy_firefox +import module_copy_silabs + +# Plugins used to import module_reset_mbed import module_reset_mps2 import module_reset_silabs @@ -25,11 +32,17 @@ import module_reset_silabs HOST_TEST_PLUGIN_REGISTRY = host_test_registry.HostTestRegistry() # Static plugin registration -# TODO: extend to files with name module_*.py loaded ad-hoc +HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_copy_mbed.load_plugin()) +HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_copy_shell.load_plugin()) +HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_copy_firefox.load_plugin()) +HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_copy_silabs.load_plugin()) HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_reset_mbed.load_plugin()) + +# Extra supported by default platforms HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_reset_mps2.load_plugin()) HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_reset_silabs.load_plugin()) +# TODO: extend plugin loading to files with name module_*.py loaded ad-hoc ############################################################################### # Functional interface for host test plugin registry @@ -37,7 +50,7 @@ HOST_TEST_PLUGIN_REGISTRY.register_plugin(module_reset_silabs.load_plugin()) def call_plugin(type, capability, *args, **kwargs): """ Interface to call plugin registry functional way """ - HOST_TEST_PLUGIN_REGISTRY.call_plugin(type, capability, *args, **kwargs) + return HOST_TEST_PLUGIN_REGISTRY.call_plugin(type, capability, *args, **kwargs) def print_plugin_info(): """ Prints plugins' information in user friendly way diff --git a/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py b/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py index 4bc1c59e03..02e2c266df 100644 --- a/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py +++ b/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py @@ -15,6 +15,9 @@ See the License for the specific language governing permissions and limitations under the License. """ +from subprocess import call + + class HostTestPluginBase: """ Base class for all plug-ins used with host tests. """ @@ -43,3 +46,30 @@ class HostTestPluginBase: program or execute building pythonic function """ return False + + ########################################################################### + # Interface helper methods - overload only if you need to have custom behaviour + ########################################################################### + def check_parameters(self, capabilitity, *args, **kwargs): + """ This function should be ran each time we call execute() + to check if none of the required parameters is missing. + """ + for parameter in self.required_parameters: + if parameter not in kwargs: + print "%s::%s: Plugin parameter '%s' missing!"% (self.name, self.type, parameter) + return False + return True + + def run_command(self, cmd, shell=True): + """ Runs command from command line. + """ + result = True + try: + ret = call(cmd, shell=shell) + if ret: + print "%s::%s: [ret=%d] Command: %s"% (self.name, self.type, ret, " ".join(cmd)) + except Exception, e: + result = False + print "%s::%s: [ret=%d] Command: %s"% (self.name, self.type, ret, " ".join(cmd)) + print "%s::%s: " + str(e) + return result diff --git a/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py b/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py index 19e3bc3761..0d86642674 100644 --- a/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py +++ b/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py @@ -36,9 +36,11 @@ class HostTestRegistry: # TODO: # - check for unique caps for specified type if plugin.name not in self.PLUGINS: - plugin.setup() # Setup plugin - self.PLUGINS[plugin.name] = plugin - return True + if plugin.setup(): # Setup plugin can be completed without errors + self.PLUGINS[plugin.name] = plugin + return True + else: + self.print_error("%s setup failed"% plugin.name) self.print_error("%s already loaded"% plugin.name) return False diff --git a/workspace_tools/host_tests/host_tests_plugins/module_copy_firefox.py b/workspace_tools/host_tests/host_tests_plugins/module_copy_firefox.py new file mode 100644 index 0000000000..d53b8a1b7a --- /dev/null +++ b/workspace_tools/host_tests/host_tests_plugins/module_copy_firefox.py @@ -0,0 +1,73 @@ +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from os.path import join, basename +from host_test_plugins import HostTestPluginBase + + +class HostTestPluginCopyMethod_Firefox(HostTestPluginBase): + + def file_store_firefox(self, file_path, dest_disk): + from selenium import webdriver + profile = webdriver.FirefoxProfile() + profile.set_preference('browser.download.folderList', 2) # custom location + profile.set_preference('browser.download.manager.showWhenStarting', False) + profile.set_preference('browser.download.dir', dest_disk) + profile.set_preference('browser.helperApps.neverAsk.saveToDisk', 'application/octet-stream') + # Launch browser with profile and get file + browser = webdriver.Firefox(profile) + browser.get(file_path) + browser.close() + + + # Plugin interface + name = 'HostTestPluginCopyMethod_Firefox' + type = 'CopyMethod' + capabilities = ['firefox'] + required_parameters = ['image_path', 'destination_disk'] + + def setup(self, *args, **kwargs): + """ Configure plugin, this function should be called before plugin execute() method is used. + """ + try: + from selenium import webdriver + except ImportError, e: + print "Error: firefox copy method requires selenium library. %s"% e + return False + return True + + def execute(self, capabilitity, *args, **kwargs): + """ Executes capability by name. + Each capability may directly just call some command line + program or execute building pythonic function + """ + result = False + if self.check_parameters(capabilitity, *args, **kwargs) is True: + image_path = kwargs['image_path'] + destination_disk = kwargs['destination_disk'] + # Prepare correct command line parameter values + image_base_name = basename(image_path) + destination_path = join(destination_disk, image_base_name) + if capabilitity == 'firefox': + self.file_store_firefox(image_path, destination_path) + return result + + +def load_plugin(): + """ Returns plugin available in this module + """ + return HostTestPluginCopyMethod_Firefox() diff --git a/workspace_tools/host_tests/host_tests_plugins/module_copy_mbed.py b/workspace_tools/host_tests/host_tests_plugins/module_copy_mbed.py new file mode 100644 index 0000000000..cd4a5885ef --- /dev/null +++ b/workspace_tools/host_tests/host_tests_plugins/module_copy_mbed.py @@ -0,0 +1,67 @@ +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from shutil import copy +from host_test_plugins import HostTestPluginBase + + +class HostTestPluginCopyMethod_Mbed(HostTestPluginBase): + + def generic_mbed_copy(self, image_path, destination_disk): + """ Generic mbed copy method for "mbed enabled" devices. + It uses standard python shuitl function to copy + image_file (target specific binary) to device's disk. + """ + result = True + if not destination_disk.endswith('/') and not destination_disk.endswith('\\'): + destination_disk += '/' + try: + copy(image_path, destination_disk) + except Exception, e: + print str(e) + result = False + return result + + # Plugin interface + name = 'HostTestPluginCopyMethod_Mbed' + type = 'CopyMethod' + capabilities = ['default'] + required_parameters = ['image_path', 'destination_disk'] + + def setup(self, *args, **kwargs): + """ Configure plugin, this function should be called before plugin execute() method is used. + """ + return True + + def execute(self, capabilitity, *args, **kwargs): + """ Executes capability by name. + Each capability may directly just call some command line + program or execute building pythonic function + """ + result = False + if self.check_parameters(capabilitity, *args, **kwargs) is True: + if capabilitity == 'default': + image_path = kwargs['image_path'] + destination_disk = kwargs['destination_disk'] + result = self.generic_mbed_copy(image_path, destination_disk) + return result + + +def load_plugin(): + """ Returns plugin available in this module + """ + return HostTestPluginCopyMethod_Mbed() diff --git a/workspace_tools/host_tests/host_tests_plugins/module_copy_shell.py b/workspace_tools/host_tests/host_tests_plugins/module_copy_shell.py new file mode 100644 index 0000000000..d72c154392 --- /dev/null +++ b/workspace_tools/host_tests/host_tests_plugins/module_copy_shell.py @@ -0,0 +1,58 @@ +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from os.path import join, basename +from subprocess import call +from host_test_plugins import HostTestPluginBase + + +class HostTestPluginCopyMethod_Shell(HostTestPluginBase): + + # Plugin interface + name = 'HostTestPluginCopyMethod_Shell' + type = 'CopyMethod' + capabilities = ['cp', 'copy', 'xcopy'] + required_parameters = ['image_path', 'destination_disk'] + + def setup(self, *args, **kwargs): + """ Configure plugin, this function should be called before plugin execute() method is used. + """ + return True + + def execute(self, capabilitity, *args, **kwargs): + """ Executes capability by name. + Each capability may directly just call some command line + program or execute building pythonic function + """ + result = False + if self.check_parameters(capabilitity, *args, **kwargs) is True: + image_path = kwargs['image_path'] + destination_disk = kwargs['destination_disk'] + # Prepare correct command line parameter values + image_base_name = basename(image_path) + destination_path = join(destination_disk, image_base_name) + if capabilitity == 'cp' or capabilitity == 'copy' or capabilitity == 'copy': + copy_method = capabilitity + cmd = [copy_method, image_path, destination_path] + result = self.run_command(cmd) + return result + + +def load_plugin(): + """ Returns plugin available in this module + """ + return HostTestPluginCopyMethod_Shell() diff --git a/workspace_tools/host_tests/host_tests_plugins/module_copy_silabs.py b/workspace_tools/host_tests/host_tests_plugins/module_copy_silabs.py new file mode 100644 index 0000000000..3d2b6e71a9 --- /dev/null +++ b/workspace_tools/host_tests/host_tests_plugins/module_copy_silabs.py @@ -0,0 +1,63 @@ +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from os.path import join, basename +from subprocess import call +from host_test_plugins import HostTestPluginBase + + +class HostTestPluginCopyMethod_Silabs(HostTestPluginBase): + + # Plugin interface + name = 'HostTestPluginCopyMethod_Silabs' + type = 'CopyMethod' + capabilities = ['eACommander', 'eACommander-usb'] + required_parameters = ['image_path', 'destination_disk'] + + def setup(self, *args, **kwargs): + """ Configure plugin, this function should be called before plugin execute() method is used. + """ + self.EACOMMANDER_CMD = 'eACommander.exe' + return True + + def execute(self, capabilitity, *args, **kwargs): + """ Executes capability by name. + Each capability may directly just call some command line + program or execute building pythonic function + """ + result = False + if self.check_parameters(capabilitity, *args, **kwargs) is True: + image_path = kwargs['image_path'] + destination_disk = kwargs['destination_disk'] + if capabilitity == 'eACommander': + cmd = [self.EACOMMANDER_CMD, + '--serialno', destination_disk, + '--flash', image_path, + '--resettype', '2', '--reset'] + result = self.run_command(cmd) + elif capabilitity == 'eACommander-usb': + cmd = [self.EACOMMANDER_CMD, + '--usb', destination_disk, + '--flash', image_path] + result = self.run_command(cmd) + return result + + +def load_plugin(): + """ Returns plugin available in this module + """ + return HostTestPluginCopyMethod_Silabs() diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py index 3f9b711df7..05185cccbb 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py @@ -58,17 +58,12 @@ class HostTestPluginResetMethod_Mbed(HostTestPluginBase): Each capability may directly just call some command line program or execute building pythonic function """ - for parameter in self.required_parameters: - if parameter not in kwargs: - print "Plugin parameter '%s' missing"% parameter - return False - - if capabilitity == 'default': - serial = kwargs['serial'] - self.safe_sendBreak(serial) - else: - return False - return True + result = False + if self.check_parameters(capabilitity, *args, **kwargs) is True: + if capabilitity == 'default': + serial = kwargs['serial'] + result = self.safe_sendBreak(serial) + return result def load_plugin(): diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py index f8e9c84844..876342795b 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py @@ -15,7 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. """ -from subprocess import call from host_test_plugins import HostTestPluginBase @@ -30,7 +29,8 @@ class HostTestPluginResetMethod_SiLabs(HostTestPluginBase): def setup(self, *args, **kwargs): """ Configure plugin, this function should be called before plugin execute() method is used. """ - self.EACOMMANDER_CMD = 'c:/SiliconLabs/SimplicityStudio/v2/commander/eACommander.exe' + # Note you need to have eACommander.exe on your system path! + self.EACOMMANDER_CMD = 'eACommander.exe' return True def execute(self, capabilitity, *args, **kwargs): @@ -38,42 +38,25 @@ class HostTestPluginResetMethod_SiLabs(HostTestPluginBase): Each capability may directly just call some command line program or execute building pythonic function """ + result = False + if self.check_parameters(capabilitity, *args, **kwargs) is True: + disk = kwargs['disk'].rstrip('/\\') - for parameter in self.required_parameters: - if parameter not in kwargs: - print "Plugin parameter '%s' missing"% parameter - return False - - disk = kwargs['disk'].rstrip('/\\') - - if capabilitity == 'eACommander': - # For this copy method 'disk' will be 'serialno' for eACommander command line parameters - # Note: Commands are executed in the order they are specified on the command line - cmd = [self.EACOMMANDER_CMD, - '--serialno', disk, - '--resettype', '2', '--reset',] - try: - ret = call(cmd, shell=True) - if ret: - print "Return code: %d. Command: "% ret + " ".join(cmd) - except Exception, e: - print str(e) - - elif capabilitity == 'eACommander-usb': - # For this copy method 'disk' will be 'usb address' for eACommander command line parameters - # Note: Commands are executed in the order they are specified on the command line - cmd = [self.EACOMMANDER_CMD, - '--usb', disk, - '--resettype', '2', '--reset',] - try: - ret = call(cmd, shell=True) - if ret: - print "Return code: %d. Command: "% ret + " ".join(cmd) - except Exception, e: - print(e) - else: - return False - return True + if capabilitity == 'eACommander': + # For this copy method 'disk' will be 'serialno' for eACommander command line parameters + # Note: Commands are executed in the order they are specified on the command line + cmd = [self.EACOMMANDER_CMD, + '--serialno', disk, + '--resettype', '2', '--reset',] + result = self.run_command(cmd) + elif capabilitity == 'eACommander-usb': + # For this copy method 'disk' will be 'usb address' for eACommander command line parameters + # Note: Commands are executed in the order they are specified on the command line + cmd = [self.EACOMMANDER_CMD, + '--usb', disk, + '--resettype', '2', '--reset',] + result = self.run_command(cmd) + return result def load_plugin(): diff --git a/workspace_tools/settings.py b/workspace_tools/settings.py index 1195e9c26a..4a3266e058 100644 --- a/workspace_tools/settings.py +++ b/workspace_tools/settings.py @@ -76,9 +76,6 @@ GOANNA_PATH = "c:/Program Files (x86)/RedLizards/Goanna Central 3.2.3/bin" CPPCHECK_CMD = ["cppcheck", "--enable=all"] CPPCHECK_MSG_FORMAT = ["--template=[{severity}] {file}@{line}: {id}:{message}"] -# SiliconLabs energyAware Commander 2.84 path -EACOMMANDER_CMD = 'c:/SiliconLabs/SimplicityStudio/v2/commander/eACommander.exe' - BUILD_OPTIONS = [] # mbed.org username diff --git a/workspace_tools/test_api.py b/workspace_tools/test_api.py index 573d6148b2..b9844aa470 100644 --- a/workspace_tools/test_api.py +++ b/workspace_tools/test_api.py @@ -32,7 +32,6 @@ from prettytable import PrettyTable from time import sleep, time from Queue import Queue, Empty -from shutil import copy from os.path import join, exists, basename from threading import Thread from subprocess import Popen, PIPE, call @@ -46,7 +45,6 @@ from workspace_tools.utils import ToolException from workspace_tools.utils import construct_enum from workspace_tools.targets import TARGET_MAP from workspace_tools.test_db import BaseDBAccess -from workspace_tools.settings import EACOMMANDER_CMD from workspace_tools.build_api import build_project, build_mbed_libs, build_lib from workspace_tools.build_api import get_target_supported_toolchains from workspace_tools.libraries import LIBRARIES, LIBRARY_MAP @@ -54,6 +52,9 @@ from workspace_tools.toolchains import TOOLCHAIN_BIN_PATH from workspace_tools.test_exporters import ReportExporter, ResultExporterType +import workspace_tools.host_tests.host_tests_plugins as host_tests_plugins + + class ProcessObserver(Thread): def __init__(self, proc): Thread.__init__(self) @@ -591,22 +592,6 @@ class SingleTestRunner(object): result = self.TEST_LOOPS_DICT[test_id] return result - def file_store_firefox(self, file_path, dest_disk): - try: - from selenium import webdriver - except ImportError, e: - print "Error: firefox copy method requires selenium library. %s"% e - exit(-1) - profile = webdriver.FirefoxProfile() - profile.set_preference('browser.download.folderList', 2) # custom location - profile.set_preference('browser.download.manager.showWhenStarting', False) - profile.set_preference('browser.download.dir', dest_disk) - profile.set_preference('browser.helperApps.neverAsk.saveToDisk', 'application/octet-stream') - # Launch browser with profile and get file - browser = webdriver.Firefox(profile) - browser.get(file_path) - browser.close() - def image_copy_method_selector(self, target_name, image_path, disk, copy_method, images_config=None, image_dest=None, verbose=False): """ Function copied image file and fiddles with image configuration files in needed. @@ -629,68 +614,14 @@ class SingleTestRunner(object): """ Copy file depending on method you want to use. Handles exception and return code from shell copy commands. """ - result = True - resutl_msg = "" - if copy_method == 'cp' or copy_method == 'copy' or copy_method == 'xcopy': - source_path = image_path.encode('ascii', 'ignore') - image_base_name = basename(image_path).encode('ascii', 'ignore') - destination_path = os.path.join(disk.encode('ascii', 'ignore'), image_dest, image_base_name) - cmd = [copy_method, source_path, destination_path] - try: - ret = call(cmd, shell=True) - if ret: - resutl_msg = "Return code: %d. Command: "% (ret + " ".join(cmd)) - result = False - except Exception, e: - resutl_msg = e - result = False - elif copy_method == 'firefox': - try: - source_path = image_path.encode('ascii', 'ignore') - destination_path = os.path.join(disk.encode('ascii', 'ignore'), image_dest) - self.file_store_firefox(source_path, destination_path) - except Exception, e: - resutl_msg = e - result = False - elif copy_method == 'eACommander': - # For this copy method 'disk' will be 'serialno' for eACommander command line parameters - # Note: Commands are executed in the order they are specified on the command line - cmd = [EACOMMANDER_CMD, - '--serialno', disk.rstrip('/\\'), - '--flash', image_path.encode('ascii', 'ignore'), - '--resettype', '2', '--reset'] - try: - ret = call(cmd, shell=True) - if ret: - resutl_msg = "Return code: %d. Command: "% ret + " ".join(cmd) - result = False - except Exception, e: - resutl_msg = e - result = False - elif copy_method == 'eACommander-usb': - # For this copy method 'disk' will be 'usb address' for eACommander command line parameters - # Note: Commands are executed in the order they are specified on the command line - cmd = [EACOMMANDER_CMD, - '--usb', disk.rstrip('/\\'), - '--flash', image_path.encode('ascii', 'ignore')] - try: - ret = call(cmd, shell=True) - if ret: - resutl_msg = "Return code: %d. Command: "% ret + " ".join(cmd) - result = False - except Exception, e: - resutl_msg = e - result = False + result = False + resutl_msg = '' # TODO: pass result_msg from plugin to test suite + if copy_method is not None: + # image_path - Where is binary with target's firmware + result = host_tests_plugins.call_plugin('CopyMethod', copy_method, image_path=image_path, destination_disk=disk) else: - copy_method = "shutils.copy()" - # Default python method - try: - if not disk.endswith('/') and not disk.endswith('\\'): - disk += '/' - copy(image_path, disk) - except Exception, e: - resutl_msg = e - result = False + copy_method = 'default' + result = host_tests_plugins.call_plugin('CopyMethod', copy_method, image_path=image_path, destination_disk=disk) return result, resutl_msg, copy_method def delete_file(self, file_path): From 17f42519f0293482a10615e147c9e3b1ed1b7067 Mon Sep 17 00:00:00 2001 From: Przemek Wirkus Date: Thu, 23 Oct 2014 16:56:05 +0100 Subject: [PATCH 7/9] Host test plugins: Added MPS2 and Firfox copy methods (both not stable and require further development) Host test plugins: Added 'stable' attribute to each plugin, by default all plugins are not stable Moved all MPS2 related functions to MPS2 plugins in host test directory --- workspace_tools/host_tests/host_test.py | 1 - .../host_tests/host_tests_plugins/__init__.py | 3 +- .../host_tests_plugins/host_test_plugins.py | 6 +- .../host_tests_plugins/host_test_registry.py | 7 +- .../host_tests_plugins/module_copy_firefox.py | 25 ++-- .../host_tests_plugins/module_copy_mbed.py | 1 + .../host_tests_plugins/module_copy_mps2.py | 108 ++++++++++++++++++ .../host_tests_plugins/module_copy_shell.py | 2 +- .../host_tests_plugins/module_copy_silabs.py | 2 - .../host_tests_plugins/module_reset_mbed.py | 2 +- .../host_tests_plugins/module_reset_silabs.py | 1 + workspace_tools/test_api.py | 60 +--------- 12 files changed, 137 insertions(+), 81 deletions(-) create mode 100644 workspace_tools/host_tests/host_tests_plugins/module_copy_mps2.py diff --git a/workspace_tools/host_tests/host_test.py b/workspace_tools/host_tests/host_test.py index 86e6eed715..24dcd98829 100644 --- a/workspace_tools/host_tests/host_test.py +++ b/workspace_tools/host_tests/host_test.py @@ -26,7 +26,6 @@ import os from sys import stdout from time import sleep, time from optparse import OptionParser -from subprocess import call import host_tests_plugins diff --git a/workspace_tools/host_tests/host_tests_plugins/__init__.py b/workspace_tools/host_tests/host_tests_plugins/__init__.py index b28b81e253..e3cf27508e 100644 --- a/workspace_tools/host_tests/host_tests_plugins/__init__.py +++ b/workspace_tools/host_tests/host_tests_plugins/__init__.py @@ -17,12 +17,13 @@ limitations under the License. import host_test_registry +# This plugins provide 'flashing' methods to host test scripts import module_copy_mbed import module_copy_shell import module_copy_firefox import module_copy_silabs -# Plugins used to +# Plugins used to reset certain platform import module_reset_mbed import module_reset_mps2 import module_reset_silabs diff --git a/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py b/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py index 02e2c266df..db71293e5c 100644 --- a/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py +++ b/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py @@ -29,8 +29,10 @@ class HostTestPluginBase: # Interface attributes defining plugin name, type etc. ########################################################################### name = "HostTestPluginBase" # Plugin name, can be plugin class name - type = "BasePlugin" # Plugin type: ResetMethod, Copymethod etc. - capabilities = [] # Capabilities names: what plugin can achieve (e.g. reset using some external command line tool) + type = "BasePlugin" # Plugin type: ResetMethod, Copymethod etc. + capabilities = [] # Capabilities names: what plugin can achieve + # (e.g. reset using some external command line tool) + stable = False # Determine if plugin is stable and can be used ########################################################################### # Interface methods diff --git a/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py b/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py index 0d86642674..39e1e420e1 100644 --- a/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py +++ b/workspace_tools/host_tests/host_tests_plugins/host_test_registry.py @@ -63,14 +63,15 @@ class HostTestRegistry: """ User friendly printing method to show hooked plugins """ from prettytable import PrettyTable - column_names = ['name', 'type', 'capabilities'] + column_names = ['name', 'type', 'capabilities', 'stable'] pt = PrettyTable(column_names) for column in column_names: pt.align[column] = 'l' - for plugin_name in self.PLUGINS: + for plugin_name in sorted(self.PLUGINS.keys()): name = self.PLUGINS[plugin_name].name type = self.PLUGINS[plugin_name].type + stable = self.PLUGINS[plugin_name].stable capabilities = ', '.join(self.PLUGINS[plugin_name].capabilities) - row = [name, type, capabilities] + row = [name, type, capabilities, stable] pt.add_row(row) return pt.get_string() diff --git a/workspace_tools/host_tests/host_tests_plugins/module_copy_firefox.py b/workspace_tools/host_tests/host_tests_plugins/module_copy_firefox.py index d53b8a1b7a..6f917277b7 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_copy_firefox.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_copy_firefox.py @@ -22,17 +22,20 @@ from host_test_plugins import HostTestPluginBase class HostTestPluginCopyMethod_Firefox(HostTestPluginBase): def file_store_firefox(self, file_path, dest_disk): - from selenium import webdriver - profile = webdriver.FirefoxProfile() - profile.set_preference('browser.download.folderList', 2) # custom location - profile.set_preference('browser.download.manager.showWhenStarting', False) - profile.set_preference('browser.download.dir', dest_disk) - profile.set_preference('browser.helperApps.neverAsk.saveToDisk', 'application/octet-stream') - # Launch browser with profile and get file - browser = webdriver.Firefox(profile) - browser.get(file_path) - browser.close() - + try: + from selenium import webdriver + profile = webdriver.FirefoxProfile() + profile.set_preference('browser.download.folderList', 2) # custom location + profile.set_preference('browser.download.manager.showWhenStarting', False) + profile.set_preference('browser.download.dir', dest_disk) + profile.set_preference('browser.helperApps.neverAsk.saveToDisk', 'application/octet-stream') + # Launch browser with profile and get file + browser = webdriver.Firefox(profile) + browser.get(file_path) + browser.close() + except: + return False + return True # Plugin interface name = 'HostTestPluginCopyMethod_Firefox' diff --git a/workspace_tools/host_tests/host_tests_plugins/module_copy_mbed.py b/workspace_tools/host_tests/host_tests_plugins/module_copy_mbed.py index cd4a5885ef..2532071918 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_copy_mbed.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_copy_mbed.py @@ -39,6 +39,7 @@ class HostTestPluginCopyMethod_Mbed(HostTestPluginBase): # Plugin interface name = 'HostTestPluginCopyMethod_Mbed' type = 'CopyMethod' + stable = True capabilities = ['default'] required_parameters = ['image_path', 'destination_disk'] diff --git a/workspace_tools/host_tests/host_tests_plugins/module_copy_mps2.py b/workspace_tools/host_tests/host_tests_plugins/module_copy_mps2.py new file mode 100644 index 0000000000..04101e2deb --- /dev/null +++ b/workspace_tools/host_tests/host_tests_plugins/module_copy_mps2.py @@ -0,0 +1,108 @@ +""" +mbed SDK +Copyright (c) 2011-2013 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +from shutil import copy +from os.path import join +from host_test_plugins import HostTestPluginBase + + +class HostTestPluginCopyMethod_MPS2(HostTestPluginBase): + + # MPS2 specific flashing / binary setup funcitons + def mps2_set_board_image_file(self, disk, images_cfg_path, image0file_path, image_name='images.txt'): + """ This function will alter image cfg file. + Main goal of this function is to change number of images to 1, comment all + existing image entries and append at the end of file new entry with test path. + @return True when all steps succeed. + """ + MBED_SDK_TEST_STAMP = 'test suite entry' + image_path = join(disk, images_cfg_path, image_name) + new_file_lines = [] # New configuration file lines (entries) + + # Check each line of the image configuration file + try: + with open(image_path, 'r') as file: + for line in file: + if re.search('^TOTALIMAGES', line): + # Check number of total images, should be 1 + new_file_lines.append(re.sub('^TOTALIMAGES:[\t ]*[\d]+', 'TOTALIMAGES: 1', line)) + pass + elif re.search('; - %s[\n\r]*$'% MBED_SDK_TEST_STAMP, line): + # Look for test suite entries and remove them + pass # Omit all test suite entries + elif re.search('^IMAGE[\d]+FILE', line): + # Check all image entries and mark the ';' + new_file_lines.append(';' + line) # Comment non test suite lines + else: + # Append line to new file + new_file_lines.append(line) + except IOError as e: + return False + + # Add new image entry with proper commented stamp + new_file_lines.append('IMAGE0FILE: %s ; - %s\r\n'% (image0file_path, MBED_SDK_TEST_STAMP)) + + # Write all lines to file + try: + with open(image_path, 'w') as file: + for line in new_file_lines: + file.write(line), + except IOError: + return False + + return True + + def mps2_select_core(self, disk, mobo_config_name=""): + """ Function selects actual core + """ + # TODO: implement core selection + pass + + def mps2_switch_usb_auto_mounting_after_restart(self, disk, usb_config_name=""): + """ Function alters configuration to allow USB MSD to be mounted after restarts + """ + # TODO: implement USB MSD restart detection + pass + + # Plugin interface + name = 'HostTestPluginCopyMethod_MPS2' + type = 'CopyMethod' + capabilities = ['mps2'] + required_parameters = ['image_path', 'destination_disk'] + + def setup(self, *args, **kwargs): + """ Configure plugin, this function should be called before plugin execute() method is used. + """ + return True + + def execute(self, capabilitity, *args, **kwargs): + """ Executes capability by name. + Each capability may directly just call some command line + program or execute building pythonic function + """ + result = False + if self.check_parameters(capabilitity, *args, **kwargs) is True: + if capabilitity == 'mps2': + # TODO: Implement MPS2 firmware setup here + pass + return result + + +def load_plugin(): + """ Returns plugin available in this module + """ + return HostTestPluginCopyMethod_MPS2() diff --git a/workspace_tools/host_tests/host_tests_plugins/module_copy_shell.py b/workspace_tools/host_tests/host_tests_plugins/module_copy_shell.py index d72c154392..9d57a56d30 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_copy_shell.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_copy_shell.py @@ -16,7 +16,6 @@ limitations under the License. """ from os.path import join, basename -from subprocess import call from host_test_plugins import HostTestPluginBase @@ -25,6 +24,7 @@ class HostTestPluginCopyMethod_Shell(HostTestPluginBase): # Plugin interface name = 'HostTestPluginCopyMethod_Shell' type = 'CopyMethod' + stable = True capabilities = ['cp', 'copy', 'xcopy'] required_parameters = ['image_path', 'destination_disk'] diff --git a/workspace_tools/host_tests/host_tests_plugins/module_copy_silabs.py b/workspace_tools/host_tests/host_tests_plugins/module_copy_silabs.py index 3d2b6e71a9..1572bbc6ee 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_copy_silabs.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_copy_silabs.py @@ -15,8 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. """ -from os.path import join, basename -from subprocess import call from host_test_plugins import HostTestPluginBase diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py index 05185cccbb..0390d84ba6 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_mbed.py @@ -15,7 +15,6 @@ See the License for the specific language governing permissions and limitations under the License. """ -from subprocess import call from host_test_plugins import HostTestPluginBase @@ -45,6 +44,7 @@ class HostTestPluginResetMethod_Mbed(HostTestPluginBase): # Plugin interface name = 'HostTestPluginResetMethod_Mbed' type = 'ResetMethod' + stable = True capabilities = ['default'] required_parameters = ['serial'] diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py index 876342795b..2c05cb21c3 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_silabs.py @@ -23,6 +23,7 @@ class HostTestPluginResetMethod_SiLabs(HostTestPluginBase): # Plugin interface name = 'HostTestPluginResetMethod_SiLabs' type = 'ResetMethod' + stable = True capabilities = ['eACommander', 'eACommander-usb'] required_parameters = ['disk'] diff --git a/workspace_tools/test_api.py b/workspace_tools/test_api.py index b9844aa470..5402864e13 100644 --- a/workspace_tools/test_api.py +++ b/workspace_tools/test_api.py @@ -34,7 +34,7 @@ from time import sleep, time from Queue import Queue, Empty from os.path import join, exists, basename from threading import Thread -from subprocess import Popen, PIPE, call +from subprocess import Popen, PIPE # Imports related to mbed build api from workspace_tools.tests import TESTS @@ -1255,64 +1255,6 @@ def singletest_in_cli_mode(single_test): report_exporter.report_to_file(test_summary_ext, single_test.opts_report_junit_file_name, test_suite_properties=test_suite_properties_ext) -def mps2_set_board_image_file(disk, images_cfg_path, image0file_path, image_name='images.txt'): - """ This function will alter image cfg file. - Main goal of this function is to change number of images to 1, comment all - existing image entries and append at the end of file new entry with test path. - @return True when all steps succeed. - """ - MBED_SDK_TEST_STAMP = 'test suite entry' - image_path = os.path.join(disk, images_cfg_path, image_name) - new_file_lines = [] # New configuration file lines (entries) - - # Check each line of the image configuration file - try: - with open(image_path, 'r') as file: - for line in file: - if re.search('^TOTALIMAGES', line): - # Check number of total images, should be 1 - new_file_lines.append(re.sub('^TOTALIMAGES:[\t ]*[\d]+', 'TOTALIMAGES: 1', line)) - pass - elif re.search('; - %s[\n\r]*$'% MBED_SDK_TEST_STAMP, line): - # Look for test suite entries and remove them - pass # Omit all test suite entries - elif re.search('^IMAGE[\d]+FILE', line): - # Check all image entries and mark the ';' - new_file_lines.append(';' + line) # Comment non test suite lines - else: - # Append line to new file - new_file_lines.append(line) - except IOError as e: - return False - - # Add new image entry with proper commented stamp - new_file_lines.append('IMAGE0FILE: %s ; - %s\r\n'% (image0file_path, MBED_SDK_TEST_STAMP)) - - # Write all lines to file - try: - with open(image_path, 'w') as file: - for line in new_file_lines: - file.write(line), - except IOError: - return False - - return True - - -def mps2_select_core(disk, mobo_config_name=""): - """ Function selects actual core - """ - # TODO: implement core selection - pass - - -def mps2_switch_usb_auto_mounting_after_restart(disk, usb_config_name=""): - """ Function alters configuration to allow USB MSD to be mounted after restarts - """ - # TODO: implement USB MSD restart detection - pass - - class TestLogger(): """ Super-class for logging and printing ongoing events for test suite pass """ From 2f03b85bfcf2ede29471aa3a9ba0c3c588b12c47 Mon Sep 17 00:00:00 2001 From: Przemek Wirkus Date: Thu, 23 Oct 2014 17:14:18 +0100 Subject: [PATCH 8/9] Host test plugins: Added generic error printing to host test plugin base class --- .../host_tests_plugins/host_test_plugins.py | 19 +++++++++---- .../host_tests_plugins/module_copy_firefox.py | 2 +- .../host_tests_plugins/module_copy_mbed.py | 2 +- .../host_tests_plugins/module_reset_mps2.py | 28 ++++++++----------- workspace_tools/test_api.py | 8 ------ 5 files changed, 28 insertions(+), 31 deletions(-) diff --git a/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py b/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py index db71293e5c..3119b49405 100644 --- a/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py +++ b/workspace_tools/host_tests/host_tests_plugins/host_test_plugins.py @@ -52,14 +52,23 @@ class HostTestPluginBase: ########################################################################### # Interface helper methods - overload only if you need to have custom behaviour ########################################################################### + def print_plugin_error(self, text): + """ Function prints error in console and exits always with False + """ + print "Plugin error: %s::%s: %s"% (self.name, self.type, text) + return False + def check_parameters(self, capabilitity, *args, **kwargs): """ This function should be ran each time we call execute() to check if none of the required parameters is missing. """ + missing_parameters = [] for parameter in self.required_parameters: if parameter not in kwargs: - print "%s::%s: Plugin parameter '%s' missing!"% (self.name, self.type, parameter) - return False + missing_parameters.append(parameter) + if len(missing_parameters) > 0: + self.print_plugin_error("execute parameter(s) '%s' missing!"% (', '.join(parameter))) + return False return True def run_command(self, cmd, shell=True): @@ -69,9 +78,9 @@ class HostTestPluginBase: try: ret = call(cmd, shell=shell) if ret: - print "%s::%s: [ret=%d] Command: %s"% (self.name, self.type, ret, " ".join(cmd)) + self.print_plugin_error("[ret=%d] Command: %s"% (self.name, self.type, ret, ' '.join(cmd))) except Exception, e: result = False - print "%s::%s: [ret=%d] Command: %s"% (self.name, self.type, ret, " ".join(cmd)) - print "%s::%s: " + str(e) + self.print_plugin_error("[ret=%d] Command: %s"% (self.name, self.type, ret, " ".join(cmd))) + self.print_plugin_error("%s::%s: " + str(e)) return result diff --git a/workspace_tools/host_tests/host_tests_plugins/module_copy_firefox.py b/workspace_tools/host_tests/host_tests_plugins/module_copy_firefox.py index 6f917277b7..360835e498 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_copy_firefox.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_copy_firefox.py @@ -49,7 +49,7 @@ class HostTestPluginCopyMethod_Firefox(HostTestPluginBase): try: from selenium import webdriver except ImportError, e: - print "Error: firefox copy method requires selenium library. %s"% e + self.print_plugin_error("Error: firefox copy method requires selenium library. %s"% e) return False return True diff --git a/workspace_tools/host_tests/host_tests_plugins/module_copy_mbed.py b/workspace_tools/host_tests/host_tests_plugins/module_copy_mbed.py index 2532071918..f0d050b6a0 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_copy_mbed.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_copy_mbed.py @@ -32,7 +32,7 @@ class HostTestPluginCopyMethod_Mbed(HostTestPluginBase): try: copy(image_path, destination_disk) except Exception, e: - print str(e) + self.print_plugin_error("shutil.copy(%s, %s) failed: %s"% (image_path, destination_disk, str(e))) result = False return result diff --git a/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py b/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py index 7263e6051d..22938090bb 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_reset_mps2.py @@ -51,26 +51,22 @@ class HostTestPluginResetMethod_MPS2(HostTestPluginBase): Each capability may directly just call some command line program or execute building pythonic function """ - for parameter in self.required_parameters: - if parameter not in kwargs: - print "%s. Plugin parameter '%s' missing"% (self.name, parameter) - return False + result = False + if self.check_parameters(capabilitity, *args, **kwargs) is True: - if capabilitity == 'reboot.txt': - # TODO: Implement touch file for reboot - pass + if capabilitity == 'reboot.txt': + # TODO: Implement touch file for reboot + pass - elif capabilitity == 'shutdown.txt': - # TODO: Implement touch file for shutdown - pass + elif capabilitity == 'shutdown.txt': + # TODO: Implement touch file for shutdown + pass - elif capabilitity == 'reset.txt': - # TODO: Implement touch file for reset - pass + elif capabilitity == 'reset.txt': + # TODO: Implement touch file for reset + pass - else: - return False - return True + return result def load_plugin(): """ Returns plugin available in this module diff --git a/workspace_tools/test_api.py b/workspace_tools/test_api.py index 5402864e13..73e41db8a0 100644 --- a/workspace_tools/test_api.py +++ b/workspace_tools/test_api.py @@ -600,14 +600,6 @@ class SingleTestRunner(object): """ image_dest = image_dest if image_dest is not None else '' _copy_res, _err_msg, _copy_method = self.file_copy_method_selector(image_path, disk, copy_method, image_dest=image_dest, verbose=verbose) - - if images_config is not None: - # For different targets additional configuration file has to be changed - # Here we select target and proper function to handle configuration change - if target_name == 'ARM_MPS2': - images_cfg_path = images_config - image0file_path = os.path.join(disk, image_dest, basename(image_path)) - mps2_set_board_image_file(disk, images_cfg_path, image0file_path) return _copy_res, _err_msg, _copy_method def file_copy_method_selector(self, image_path, disk, copy_method, image_dest='', verbose=False): From 69cc2fb86aad8eba612a7d191cd482480f6e8e48 Mon Sep 17 00:00:00 2001 From: Przemek Wirkus Date: Thu, 23 Oct 2014 17:24:51 +0100 Subject: [PATCH 9/9] Host test plugins: removed unused pass statement --- .../host_tests/host_tests_plugins/module_copy_mps2.py | 1 - 1 file changed, 1 deletion(-) diff --git a/workspace_tools/host_tests/host_tests_plugins/module_copy_mps2.py b/workspace_tools/host_tests/host_tests_plugins/module_copy_mps2.py index 04101e2deb..6db90f540e 100644 --- a/workspace_tools/host_tests/host_tests_plugins/module_copy_mps2.py +++ b/workspace_tools/host_tests/host_tests_plugins/module_copy_mps2.py @@ -40,7 +40,6 @@ class HostTestPluginCopyMethod_MPS2(HostTestPluginBase): if re.search('^TOTALIMAGES', line): # Check number of total images, should be 1 new_file_lines.append(re.sub('^TOTALIMAGES:[\t ]*[\d]+', 'TOTALIMAGES: 1', line)) - pass elif re.search('; - %s[\n\r]*$'% MBED_SDK_TEST_STAMP, line): # Look for test suite entries and remove them pass # Omit all test suite entries