Host test plugins: added copy pligins, and removed Selenium and eACommander dependency from Test API

pull/597/head
Przemek Wirkus 2014-10-23 16:30:17 +01:00
parent efb46ca7de
commit 6a1bdb588e
12 changed files with 347 additions and 136 deletions

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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
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

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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
result = False
if self.check_parameters(capabilitity, *args, **kwargs) is True:
if capabilitity == 'default':
serial = kwargs['serial']
self.safe_sendBreak(serial)
else:
return False
return True
result = self.safe_sendBreak(serial)
return result
def load_plugin():

View File

@ -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,12 +38,8 @@ class HostTestPluginResetMethod_SiLabs(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
result = False
if self.check_parameters(capabilitity, *args, **kwargs) is True:
disk = kwargs['disk'].rstrip('/\\')
if capabilitity == 'eACommander':
@ -52,28 +48,15 @@ class HostTestPluginResetMethod_SiLabs(HostTestPluginBase):
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)
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',]
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
result = self.run_command(cmd)
return result
def load_plugin():

View File

@ -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

View File

@ -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
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):