1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2024-10-06 19:01:15 +01:00

Multiapp Workload: Workload to test how responsive a device is when context switching between appplication tasks. It combines workflows from googlephotos, gmail and skype.

Added tagName to give unique logger name for multiple share attempts. Turn off markers_enabled for subclasses

Renamed multiapp to appshare. Description is now more accurate

Changed appshare to use class instances for each sub workload. This allows APKs to be setup correctly on the device

Photos changed function name
This commit is contained in:
Michael McGeagh 2016-09-27 15:48:32 +01:00
parent b1e375a676
commit 51f07c4473
6 changed files with 481 additions and 0 deletions

View File

@ -0,0 +1,183 @@
# Copyright 2014-2016 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 wlauto import AndroidUxPerfWorkload, Parameter, ExtensionLoader
from wlauto import AndroidUiAutoBenchmark, UiAutomatorWorkload
from wlauto.exceptions import ValidationError
class AppShare(AndroidUxPerfWorkload):
name = 'appshare'
package = []
activity = None
view = []
description = '''
Workload to test how responsive a device is when context switching between
application tasks. It combines workflows from googlephotos, gmail and
skype.
** Setup **
Credentials for the user account used to log into the Skype app have to be provided
in the agenda, as well as the display name of the contact to call.
For reliable testing, this workload requires a good and stable internet connection,
preferably on Wi-Fi.
Although this workload attempts to be network independent it requires a
network connection (ideally, wifi) to run. This is because the welcome
screen UI is dependent on an existing connection.
Test description:
1. GooglePhotos is started in offline access mode
1.1. The welcome screen is dismissed
1.2. Any promotion popup is dismissed
1.3. The provided ``test_image`` is selected and displayed
2. The image is then shared across apps to Gmail
2.1. The first run dialogue is dismissed
2.2. Enter recipient details in the To field
2.3. Enter text in the Subject field
2.4. Enter text in the Body field
2.5. Click the Send mail button
3. Return to Googlephotos and login to Skype via share action
4. Return to Googlephotos and share the ``test_image`` with Skype
4.1. Search for the ``skype_contact_name`` from the Contacts list
4.2. Dismiss any update popup that appears
4.3. The image is posted in the Chat
'''
parameters = [
Parameter('test_image', kind=str, default='uxperf_1600x1200.jpg',
description='''
An image to be copied onto the device that will be shared
across multiple apps
'''),
Parameter('email_recipient', kind=str, default='wa-devnull@mailinator.com',
description='''
The email address of the recipient to recieve the shared image
'''),
Parameter('skype_login_name', kind=str, mandatory=True,
description='''
Account to use when logging into skype from which to share the image
'''),
Parameter('skype_login_pass', kind=str, mandatory=True,
description='''
Password associated with the skype account
'''),
Parameter('skype_contact_name', kind=str, default='Echo / Sound Test Service',
description='''
This is the contact display name as it appears in the people list
'''),
]
# This workload relies on the internet so check that there is a working
# internet connection
requires_network = True
def __init__(self, device, **kwargs):
super(AppShare, self).__init__(device, **kwargs)
self.deployable_assets = [self.test_image]
self.clean_assets = True
loader = ExtensionLoader()
# Initialise googlephotos
args_googlephotos = dict(kwargs)
del args_googlephotos['test_image']
del args_googlephotos['email_recipient']
del args_googlephotos['skype_login_name']
del args_googlephotos['skype_login_pass']
del args_googlephotos['skype_contact_name']
args_googlephotos['markers_enabled'] = False
self.wl_googlephotos = loader.get_workload('googlephotos', device, **args_googlephotos)
self.view += self.wl_googlephotos.view
self.package.append(self.wl_googlephotos.package)
# Initialise gmail
args_gmail = dict(kwargs)
del args_gmail['test_image']
args_gmail['recipient'] = args_gmail.pop('email_recipient')
del args_gmail['skype_login_name']
del args_gmail['skype_login_pass']
del args_gmail['skype_contact_name']
args_gmail['markers_enabled'] = False
self.wl_gmail = loader.get_workload('gmail', device, **args_gmail)
self.view += self.wl_gmail.view
self.package.append(self.wl_gmail.package)
# Initialise skype
args_skype = dict(kwargs)
del args_skype['test_image']
del args_skype['email_recipient']
args_skype['login_name'] = args_skype.pop('skype_login_name')
args_skype['login_pass'] = args_skype.pop('skype_login_pass')
args_skype['contact_name'] = args_skype.pop('skype_contact_name')
args_skype['markers_enabled'] = False
self.wl_skype = loader.get_workload('skype', device, **args_skype)
self.view += self.wl_skype.view
self.package.append(self.wl_skype.package)
def validate(self):
super(AppShare, self).validate()
# Set package to None as it doesnt allow it to be a list,
# and we are not using it in the java side, only in wa itself.
self.uiauto_params['package'] = None
self.uiauto_params['googlephotos_package'] = self.wl_googlephotos.package
self.uiauto_params['gmail_package'] = self.wl_gmail.package
self.uiauto_params['skype_package'] = self.wl_skype.package
self.uiauto_params['recipient'] = self.email_recipient
self.uiauto_params['my_id'] = self.skype_login_name
self.uiauto_params['my_pwd'] = self.skype_login_pass
self.uiauto_params['name'] = self.skype_contact_name.replace(' ', '0space0')
# Only accept certain image formats
if os.path.splitext(self.test_image.lower())[1] not in ['.jpg', '.jpeg', '.png']:
raise ValidationError('{} must be a JPEG or PNG file'.format(self.test_image))
def setup(self, context):
self.logger.info('Checking dependency Skype')
self.wl_skype.launch_main = False
self.wl_skype.deployable_assets = []
self.wl_skype.init_resources(context)
# Bypass running skype through intent
AndroidUxPerfWorkload.setup(self.wl_skype, context)
self.logger.info('Checking dependency Gmail')
self.wl_gmail.launch_main = False
self.wl_gmail.deployable_assets = []
self.wl_gmail.init_resources(context)
self.wl_gmail.setup(context)
self.logger.info('Checking dependency Googlephotos')
self.wl_googlephotos.launch_main = True
self.wl_googlephotos.deployable_assets = []
self.wl_googlephotos.init_resources(context)
# Bypass googlephoto's asset setup
AndroidUxPerfWorkload.setup(self.wl_googlephotos, context)
self.logger.info('Checking dependency AppShare')
super(AppShare, self).init_resources(context)
# Only setup uiautomator side, then push assets
# This prevents the requirement that AppShare must have an APK
UiAutomatorWorkload.setup(self, context)
self.push_assets(context)
def teardown(self, context):
self.wl_skype.teardown(context)
self.wl_gmail.teardown(context)
# Bypass googlephoto's asset teardown
AndroidUxPerfWorkload.teardown(self.wl_googlephotos, context)
super(AppShare, self).teardown(context)

View File

@ -0,0 +1,49 @@
#!/bin/bash
# CD into build dir if possible - allows building from any directory
script_path='.'
if `readlink -f $0 &>/dev/null`; then
script_path=`readlink -f $0 2>/dev/null`
fi
script_dir=`dirname $script_path`
cd $script_dir
# Ensure build.xml exists before starting
if [[ ! -f build.xml ]]; then
echo 'Ant build.xml file not found! Check that you are in the right directory.'
exit 9
fi
# Copy base classes from wlauto dist
class_dir=bin/classes/com/arm/wlauto/uiauto
base_classes=`python -c "import os, wlauto; print os.path.join(os.path.dirname(wlauto.__file__), 'common', 'android', '*.class')"`
mkdir -p $class_dir
cp $base_classes $class_dir
# Add appshare workload dependencies
apps=("googlephotos" "gmail" "skype")
for app in "${apps[@]}"; do
module_path="wlauto.workloads.${app}"
app_path="'uiauto/bin/classes/com/arm/wlauto/uiauto/${app}'"
app_class_dir=`python -c "import os, ${module_path}; print os.path.join(os.path.dirname(${module_path}.__file__), ${app_path})"`
cp -r $app_class_dir $class_dir
done
# Build and return appropriate exit code if failed
ant build
exit_code=$?
if [[ $exit_code -ne 0 ]]; then
echo "ERROR: 'ant build' exited with code $exit_code"
exit $exit_code
fi
# If successful move JAR file to workload folder (overwrite previous)
package=com.arm.wlauto.uiauto.appshare.jar
rm -f ../$package
if [[ -f bin/$package ]]; then
cp bin/$package ..
else
echo 'ERROR: UiAutomator JAR could not be found!'
exit 9
fi

View File

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="com.arm.wlauto.uiauto.appshare" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- if sdk.dir was not set from one of the property file, then
get it from the ANDROID_HOME env var.
This must be done before we load project.properties since
the proguard config can use sdk.dir -->
<property environment="env" />
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
<isset property="env.ANDROID_HOME" />
</condition>
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: VERSION_TAG -->
<import file="${sdk.dir}/tools/ant/uibuild.xml" />
</project>

View File

@ -0,0 +1,14 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-18

View File

@ -0,0 +1,143 @@
package com.arm.wlauto.uiauto.appshare;
import android.os.Bundle;
// Import the uiautomator libraries
import com.android.uiautomator.core.UiObject;
import com.android.uiautomator.core.UiScrollable;
import com.android.uiautomator.core.UiSelector;
import com.arm.wlauto.uiauto.UxPerfUiAutomation;
import static com.arm.wlauto.uiauto.BaseUiAutomation.FindByCriteria.BY_ID;
import static com.arm.wlauto.uiauto.BaseUiAutomation.FindByCriteria.BY_TEXT;
import static com.arm.wlauto.uiauto.BaseUiAutomation.FindByCriteria.BY_DESC;
import java.util.concurrent.TimeUnit;
public class UiAutomation extends UxPerfUiAutomation {
// Create UIAutomation objects
private com.arm.wlauto.uiauto.googlephotos.UiAutomation googlephotos =
new com.arm.wlauto.uiauto.googlephotos.UiAutomation();
private com.arm.wlauto.uiauto.gmail.UiAutomation gmail =
new com.arm.wlauto.uiauto.gmail.UiAutomation();
private com.arm.wlauto.uiauto.skype.UiAutomation skype =
new com.arm.wlauto.uiauto.skype.UiAutomation();
public Bundle parameters;
public void runUiAutomation() throws Exception {
// Override superclass value
this.uiAutoTimeout = TimeUnit.SECONDS.toMillis(10);
parameters = getParams();
// Setup the three uiautomator classes with the correct information
// Also create a dummy parameter to disable marker api as they
// should not log actions themselves.
Bundle dummyParams = new Bundle();
dummyParams.putString("markers_enabled", "false");
googlephotos.parameters = dummyParams;
googlephotos.packageName = parameters.getString("googlephotos_package");
googlephotos.packageID = googlephotos.packageName + ":id/";
gmail.parameters = dummyParams;
gmail.packageName = parameters.getString("gmail_package");
gmail.packageID = gmail.packageName + ":id/";
skype.parameters = dummyParams;
skype.packageName = parameters.getString("skype_package");
skype.packageID = skype.packageName + ":id/";
String recipient = parameters.getString("recipient");
String loginName = parameters.getString("my_id");
String loginPass = parameters.getString("my_pwd");
String contactName = parameters.getString("name").replace("0space0", " ");
setScreenOrientation(ScreenOrientation.NATURAL);
setupGooglePhotos();
sendToGmail(recipient);
logIntoSkype(loginName, loginPass);
// Skype won't allow us to login and share on first visit so invoke
// once more from googlephotos
pressBack();
pressBack();
sendToSkype(contactName);
unsetScreenOrientation();
}
private void setupGooglePhotos() throws Exception {
googlephotos.dismissWelcomeView();
googlephotos.closePromotionPopUp();
selectGalleryFolder("wa-working");
googlephotos.selectFirstImage();
}
private void sendToGmail(String recipient) throws Exception {
String gID = gmail.packageID;
shareUsingApp("Gmail", "gmail");
gmail.clearFirstRunDialogues();
UiObject composeView =
new UiObject(new UiSelector().resourceId(gID + "compose"));
if (!composeView.waitForExists(uiAutoTimeout)) {
// After the initial share request on some devices Gmail returns back
// to the launching app, so we need to share the photo once more and
// wait for Gmail to sync.
shareUsingApp("Gmail", "gmail_retry");
gmail.clearFirstRunDialogues();
}
gmail.setToField(recipient);
gmail.setSubjectField();
gmail.setComposeField();
gmail.clickSendButton();
}
private void logIntoSkype(String loginName, String loginPass) throws Exception {
shareUsingApp("Skype", "skype_setup");
skype.handleLoginScreen(loginName, loginPass);
sleep(10); // Pause while the app settles before returning
}
private void sendToSkype(String contactName) throws Exception {
shareUsingApp("Skype", "skype");
skype.searchForContact(contactName);
skype.dismissUpdatePopupIfPresent();
sleep(10); // Pause while the app settles before returning
}
private void shareUsingApp(String appName, String tagName) throws Exception {
String testTag = "share";
ActionLogger logger = new ActionLogger(testTag + "_" + tagName, parameters);
clickUiObject(BY_DESC, "Share", "android.widget.ImageView");
UiScrollable applicationGrid =
new UiScrollable(new UiSelector().resourceId(googlephotos.packageID + "application_grid"));
UiObject openApp =
new UiObject(new UiSelector().text(appName)
.className("android.widget.TextView"));
// On some devices the application_grid has many entries, se we have to swipe up to make
// sure all the entries are visable. This will also stop entries at the bottom being
// obscured by the bottom action bar.
applicationGrid.swipeUp(10);
while (!openApp.exists()) {
// In the rare case the grid is larger than the screen swipe up
applicationGrid.swipeUp(10);
}
logger.start();
openApp.clickAndWaitForNewWindow();
logger.stop();
}
}