1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-09-02 19:32:34 +01:00

workload: adding basic UIAutomator workload implementation

Added a workload type to handle workloads that have both an APK with an
application and associated automation JAR. Added benchmarkpi
implementation using using the new workload.
This commit is contained in:
Sergei Trofimov
2017-03-28 09:58:48 +01:00
parent 6fba05503d
commit 18e7ffb826
16 changed files with 670 additions and 64 deletions

View File

@@ -13,9 +13,11 @@
# limitations under the License.
#
import logging
import os
import time
from wa.framework.plugin import TargetedPlugin
from wa.framework.resource import JarFile, ReventFile, NO_ONE
from wa.framework.resource import ApkFile, JarFile, ReventFile, NO_ONE
from wa.framework.exception import WorkloadError
from devlib.utils.android import ApkInfo
@@ -91,53 +93,117 @@ class Workload(TargetedPlugin):
return '<Workload {}>'.format(self.name)
class UiAutomatorGUI(object):
class ApkUiautoWorkload(Workload):
platform = 'android'
def __init__(self, target, package='', klass='UiAutomation',
method='runUiAutoamtion'):
self.target = target
self.uiauto_package = package
self.uiauto_class = klass
self.uiauto_method = method
self.uiauto_file = None
self.target_uiauto_file = None
self.command = None
self.uiauto_params = {}
def __init__(self, target, **kwargs):
super(ApkUiautoWorkload, self).__init__(target, **kwargs)
self.apk = ApkHander(self)
self.gui = UiAutomatorGUI(self)
def init_resources(self, context):
self.uiauto_file = context.resolver.get(JarFile(self))
self.target_uiauto_file = self.target.path.join(self.target.working_directory,
os.path.basename(self.uiauto_file))
if not self.uiauto_package:
self.uiauto_package = os.path.splitext(os.path.basename(self.uiauto_file))[0]
self.apk.init_resources(context.resolver)
self.gui.init_resources(context.resolver)
self.gui.init_commands()
def validate(self):
if not self.uiauto_file:
raise WorkloadError('No UI automation JAR file found for workload {}.'.format(self.name))
if not self.uiauto_package:
raise WorkloadError('No UI automation package specified for workload {}.'.format(self.name))
def initialize(self, context):
self.gui.deploy()
def setup(self, context):
method_string = '{}.{}#{}'.format(self.uiauto_package, self.uiauto_class, self.uiauto_method)
self.apk.setup(context)
self.gui.setup()
def run(self, context):
self.gui.run()
def extract_results(self, context):
self.gui.extract_results()
def teardown(self, context):
self.gui.teardown()
self.apk.teardown()
def finalize(self, context):
self.gui.remove()
class UiAutomatorGUI(object):
stages = ['setup', 'runWorkload', 'extractResults', 'teardown']
def __init__(self, owner, package=None, klass='UiAutomation', timeout=600):
self.owner = owner
self.target = self.owner.target
self.uiauto_package = package
self.uiauto_class = klass
self.timeout = timeout
self.logger = logging.getLogger('gui')
self.jar_file = None
self.target_jar_file = None
self.commands = {}
self.uiauto_params = {}
def init_resources(self, resolver):
self.jar_file = resolver.get(JarFile(self.owner))
jar_name = os.path.basename(self.jar_file)
self.target_jar_file = self.target.get_workpath(jar_name)
if not self.uiauto_package:
package = os.path.splitext(os.path.basename(self.jar_file))[0]
self.uiauto_package = package
def init_commands(self):
params_dict = self.uiauto_params
params_dict['workdir'] = self.target.working_directory
params = ''
for k, v in self.uiauto_params.iteritems():
params += ' -e {} {}'.format(k, v)
self.command = 'uiautomator runtest {}{} -c {}'.format(self.target_uiauto_file, params, method_string)
self.target.push_file(self.uiauto_file, self.target_uiauto_file)
self.target.killall('uiautomator')
def run(self, context):
result = self.target.execute(self.command, self.run_timeout)
for stage in self.stages:
method_string = '{}.{}#{}'.format(self.uiauto_package,
self.uiauto_class,
stage)
cmd_template = 'uiautomator runtest {}{} -c {}'
self.commands[stage] = cmd_template.format(self.target_jar_file,
params, method_string)
def deploy(self):
self.target.push(self.jar_file, self.target_jar_file)
def set(self, name, value):
self.uiauto_params[name] = value
def setup(self, timeout=None):
if not self.commands:
raise RuntimeError('Commands have not been initialized')
self.target.killall('uiautomator')
self._execute('setup', timeout or self.timeout)
def run(self, timeout=None):
if not self.commands:
raise RuntimeError('Commands have not been initialized')
self._execute('runWorkload', timeout or self.timeout)
def extract_results(self, timeout=None):
if not self.commands:
raise RuntimeError('Commands have not been initialized')
self._execute('extractResults', timeout or self.timeout)
def teardown(self, timeout=None):
if not self.commands:
raise RuntimeError('Commands have not been initialized')
self._execute('teardown', timeout or self.timeout)
def remove(self):
self.target.remove(self.target_jar_file)
def _execute(self, stage, timeout):
result = self.target.execute(self.commands[stage], timeout)
if 'FAILURE' in result:
raise WorkloadError(result)
else:
self.logger.debug(result)
time.sleep(DELAY)
def teardown(self, context):
self.target.delete_file(self.target_uiauto_file)
time.sleep(2)
class ReventGUI(object):
@@ -197,21 +263,27 @@ class ReventGUI(object):
class ApkHander(object):
def __init__(self, owner, target, view, install_timeout=300, version=None,
def __init__(self, owner, install_timeout=300, version=None, variant=None,
strict=True, force_install=False, uninstall=False):
self.logger = logging.getLogger('apk')
self.owner = owner
self.target = target
self.target = self.owner.target
self.install_timeout = install_timeout
self.version = version
self.variant = variant
self.strict = strict
self.force_install = force_install
self.uninstall = uninstall
self.apk_file = None
self.apk_info = None
self.apk_version = None
self.logcat_log = None
def init_resources(self, context):
self.apk_file = context.resolver.get(ApkFile(self.owner),
version=self.version,
strict=strict)
def init_resources(self, resolver):
self.apk_file = resolver.get(ApkFile(self.owner,
variant=self.variant,
version=self.version),
strict=self.strict)
self.apk_info = ApkInfo(self.apk_file)
def setup(self, context):
@@ -226,16 +298,17 @@ class ApkHander(object):
self.initialize_with_host_apk(context, installed_version)
else:
if not installed_version:
message = '''{} not found found on the device and check_apk is set to "False"
so host version was not checked.'''
raise WorkloadError(message.format(self.package))
message = '{} not found found on the device and check_apk is set '\
'to "False" so host version was not checked.'
raise WorkloadError(message.format(self.apk_info.package))
message = 'Version {} installed on device; skipping host APK check.'
self.logger.debug(message.format(installed_version))
self.reset(context)
self.version = installed_version
def initialize_with_host_apk(self, context, installed_version):
if installed_version != self.apk_file.version_name:
host_version = self.apk_info.version_name
if installed_version != host_version:
if installed_version:
message = '{} host version: {}, device version: {}; re-installing...'
self.logger.debug(message.format(os.path.basename(self.apk_file),
@@ -251,42 +324,38 @@ class ApkHander(object):
host_version))
if self.force_install:
if installed_version:
self.device.uninstall(self.package)
self.target.uninstall_package(self.apk_info.package)
self.install_apk(context)
else:
self.reset(context)
self.apk_version = host_version
def start_activity(self):
output = self.device.execute('am start -W -n {}/{}'.format(self.package, self.activity))
cmd = 'am start -W -n {}/{}'
output = self.target.execute(cmd.format(self.apk_info.package,
self.apk_info.activity))
if 'Error:' in output:
self.device.execute('am force-stop {}'.format(self.package)) # this will dismiss any erro dialogs
# this will dismiss any error dialogs
self.target.execute('am force-stop {}'.format(self.apk_info.package))
raise WorkloadError(output)
self.logger.debug(output)
def reset(self, context): # pylint: disable=W0613
self.device.execute('am force-stop {}'.format(self.package))
self.device.execute('pm clear {}'.format(self.package))
self.target.execute('am force-stop {}'.format(self.apk_info.package))
self.target.execute('pm clear {}'.format(self.apk_info.package))
def install_apk(self, context):
output = self.device.install(self.apk_file, self.install_timeout)
output = self.target.install_apk(self.apk_file, self.install_timeout)
if 'Failure' in output:
if 'ALREADY_EXISTS' in output:
self.logger.warn('Using already installed APK (did not unistall properly?)')
msg = 'Using already installed APK (did not unistall properly?)'
self.logger.warn(msg)
else:
raise WorkloadError(output)
else:
self.logger.debug(output)
def update_result(self, context):
self.logcat_log = os.path.join(context.output_directory, 'logcat.log')
self.device.dump_logcat(self.logcat_log)
context.add_iteration_artifact(name='logcat',
path='logcat.log',
kind='log',
description='Logact dump for the run.')
def teardown(self, context):
self.device.execute('am force-stop {}'.format(self.package))
if self.uninstall_apk:
self.device.uninstall(self.package)
def teardown(self):
self.target.execute('am force-stop {}'.format(self.apk_info.package))
if self.uninstall:
self.target.uninstall_package(self.apk_info.package)