1
0
mirror of https://github.com/ARM-software/workload-automation.git synced 2025-01-19 04:21:17 +00:00

Merge pull request #241 from jimboatarm/skype_uxperf

Add Skype workload
This commit is contained in:
Sebastian Goscik 2016-09-08 13:34:57 +01:00 committed by GitHub
commit 793af6253f
11 changed files with 330 additions and 232 deletions

View File

@ -138,6 +138,11 @@ class ApkWorkload(Workload):
:view: The class of the main view pane of the app. This needs to be defined in order
to collect SurfaceFlinger-derived statistics (such as FPS) for the app, but
may otherwise be left as ``None``.
:launch_main: If ``False``, the default activity will not be launched (during setup),
allowing workloads to start the app with an intent of their choice in
the run step. This is useful for apps without a launchable default/main
activity or those where it cannot be launched without intent data (which
is provided at the run phase).
:install_timeout: Timeout for the installation of the APK. This may vary wildly based on
the size and nature of a specific APK, and so should be defined on
per-workload basis.
@ -160,6 +165,7 @@ class ApkWorkload(Workload):
min_apk_version = None
max_apk_version = None
supported_platforms = ['android']
launch_main = True
parameters = [
Parameter('install_timeout', kind=int, default=300,
@ -214,7 +220,8 @@ class ApkWorkload(Workload):
if self.check_apk:
self.check_apk_version()
self.launch_package()
if self.launch_main:
self.launch_package() # launch default activity without intent data
self.device.execute('am kill-all') # kill all *background* activities
self.device.clear_logcat()

View File

@ -0,0 +1,99 @@
# 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 time
from wlauto import AndroidUxPerfWorkload, Parameter
class Skype(AndroidUxPerfWorkload):
name = 'skype'
description = '''
A workload to perform standard productivity tasks within Skype. The
workload logs in to the Skype application, selects a recipient from the
contacts list and then initiates either a voice or video call.
Test description:
1. Open Skype application
2. Log in to a pre-defined account
3. Select a recipient from the Contacts list
4. Initiate either a ``voice`` or ``video`` call for ``duration`` time (in seconds)
**Skype Setup**
- You should install Skype client from Google Play Store on the device
(this was tested with client version 7.01.0.669; other recent versions
should also work).
- You must have a Skype account set up.
- The contact to be called must be added (and has accepted) to the
account. It's possible to have multiple contacts in the list, however
the contact to be called *must* be visible on initial navigation to the
list.
- For video calls the contact must be able to received the call. This
means that there must be a Skype client running (somewhere) with the
contact logged in and that client must have been configured to
auto-accept calls from the account on the device (how to set this
varies between different versions of Skype and between platforms --
please search online for specific instructions).
https://support.skype.com/en/faq/FA3751/can-i-automatically-answer-all-my-calls-with-video-in-skype-for-windows-desktop
'''
package = 'com.skype.raider'
min_apk_version = '7.01.0.669'
view = [package + '/com.skype.android.app.calling.CallActivity',
package + '/com.skype.android.app.calling.PreCallActivity',
package + '/com.skype.android.app.chat.ChatActivity',
package + '/com.skype.android.app.main.HubActivity',
package + '/com.skype.android.app.main.SplashActivity',
package + '/com.skype.android.app.signin.SignInActivity',
package + '/com.skype.android.app.signin.UnifiedLandingPageActivity']
activity = '' # Skype has no default 'main' activity
launch_main = False # overrides extended class
parameters = [
Parameter('login_name', kind=str, mandatory=True,
description='''
Account to use when logging into the device from which the call will be made
'''),
Parameter('login_pass', kind=str, mandatory=True,
description='Password associated with the account to log into the device'),
Parameter('contact_name', kind=str, mandatory=True, default='Echo / Sound Test Service',
description='This is the contact display name as it appears in the people list'),
Parameter('duration', kind=int, default=10,
description='This is the duration of the call in seconds'),
Parameter('action', kind=str, allowed_values=['voice', 'video'], default='voice',
description='Action to take - either voice call (default) or video'),
]
# This workload relies on the internet so check that there is a working
# internet connection
requires_network = True
def __init__(self, device, **kwargs):
super(Skype, self).__init__(device, **kwargs)
self.run_timeout = self.duration + 240
def validate(self):
super(Skype, self).validate()
self.uiauto_params['my_id'] = self.login_name
self.uiauto_params['my_pwd'] = self.login_pass
self.uiauto_params['name'] = self.contact_name.replace(' ', '0space0')
self.uiauto_params['duration'] = self.duration
self.uiauto_params['action'] = self.action
def setup(self, context):
super(Skype, self).setup(context)
self.device.execute('am start -W -a android.intent.action.VIEW -d skype:dummy?dummy')

Binary file not shown.

View File

@ -0,0 +1,39 @@
#!/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
# 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.skype.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

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="com.arm.wlauto.uiauto.skypevideo" default="help">
<project name="com.arm.wlauto.uiauto.skype" 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

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.
*/
package com.arm.wlauto.uiauto.skype;
import android.os.Bundle;
// Import the uiautomator libraries
import com.android.uiautomator.core.UiObject;
import com.android.uiautomator.core.UiObjectNotFoundException;
import com.android.uiautomator.core.UiSelector;
import com.android.uiautomator.core.UiWatcher;
import com.arm.wlauto.uiauto.UxPerfUiAutomation;
import java.util.concurrent.TimeUnit;
public class UiAutomation extends UxPerfUiAutomation {
public static final String TEXT_VIEW = "android.widget.TextView";
public Bundle parameters;
public String packageName;
public String packageID;
// Creates a watcher for when a pop up dialog appears with a dismiss button.
private UiWatcher createInfoPopUpWatcher() throws Exception {
UiWatcher infoPopUpWatcher = new UiWatcher() {
@Override
public boolean checkForCondition() {
UiObject dismissButton =
new UiObject(new UiSelector().resourceId(packageID + "dismiss_button"));
if (dismissButton.exists()) {
try {
dismissButton.click();
} catch (UiObjectNotFoundException e) {
e.printStackTrace();
}
Long viewTimeout = TimeUnit.SECONDS.toMillis(10);
boolean dismissed = dismissButton.waitUntilGone(viewTimeout);
return dismissed;
}
return false;
}
};
return infoPopUpWatcher;
}
public void runUiAutomation() throws Exception {
// Override superclass value
this.uiAutoTimeout = TimeUnit.SECONDS.toMillis(10);
// Get Params
parameters = getParams();
packageName = parameters.getString("package");
packageID = packageName + ":id/";
String loginName = parameters.getString("my_id");
String loginPass = parameters.getString("my_pwd");
String contactName = parameters.getString("name").replace("0space0", " ");
int callDuration = Integer.parseInt(parameters.getString("duration"));
String callType = parameters.getString("action");
String resultsFile = parameters.getString("results_file");
setScreenOrientation(ScreenOrientation.NATURAL);
UiWatcher infoPopUpWatcher = createInfoPopUpWatcher();
registerWatcher("infoPopUpWatcher", infoPopUpWatcher);
runWatchers();
// Run tests
handleLoginScreen(loginName, loginPass);
searchForContact(contactName);
if ("video".equalsIgnoreCase(callType)) {
videoCallTest(callDuration);
} else if ("voice".equalsIgnoreCase(callType)) {
voiceCallTest(callDuration);
}
removeWatcher("infoPopUpWatcher");
unsetScreenOrientation();
}
public void handleLoginScreen(String username, String password) throws Exception {
String useridResoureId = packageID + "sign_in_userid";
String nextButtonResourceId = packageID + "sign_in_next_btn";
UiObject useridField = new UiObject(new UiSelector().resourceId(useridResoureId));
UiObject nextButton = new UiObject(new UiSelector().resourceId(nextButtonResourceId));
useridField.setText(username);
nextButton.clickAndWaitForNewWindow();
String passwordResoureId = packageID + "signin_password";
String signinButtonResourceId = packageID + "sign_in_btn";
UiObject passwordField = new UiObject(new UiSelector().resourceId(passwordResoureId));
UiObject signinButton = new UiObject(new UiSelector().resourceId(signinButtonResourceId));
passwordField.setText(password);
signinButton.clickAndWaitForNewWindow();
}
public void searchForContact(String name) throws Exception {
UiObject menuSearch = new UiObject(new UiSelector().resourceId(packageID + "menu_search"));
boolean sharingResource = false;
// If searching for a contact from Skype directly we need
// to click the menu search button to display the contact search box.
if (menuSearch.waitForExists(uiAutoTimeout)) {
menuSearch.click();
// If sharing a resource from another app the contact search box is shown
// by default.
} else {
sharingResource = true;
}
UiObject search = getUiObjectByText("Search", "android.widget.EditText");
search.setText(name);
UiObject peopleItem = getUiObjectByText(name, "android.widget.TextView");
peopleItem.waitForExists(uiAutoTimeout);
peopleItem.click();
UiObject avatarPresence =
new UiObject(new UiSelector().resourceId(packageID + "skype_avatar_presence"));
// On some devices two clicks are needed to select a contact.
if (!avatarPresence.waitUntilGone(uiAutoTimeout)) {
peopleItem.click();
}
// Before sharing a resource from another app we first need to
// confirm our selection.
if (sharingResource) {
UiObject confirm =
new UiObject(new UiSelector().resourceId(packageID + "fab"));
confirm.click();
}
}
private void voiceCallTest(int duration) throws Exception {
String testTag = "call_voice";
ActionLogger logger = new ActionLogger(testTag, parameters);
logger.start();
makeCall(duration, false, testTag);
logger.stop();
}
private void videoCallTest(int duration) throws Exception {
String testTag = "call_video";
ActionLogger logger = new ActionLogger(testTag, parameters);
logger.start();
makeCall(duration, true, testTag);
logger.stop();
}
private void makeCall(int duration, boolean video, String testTag) throws Exception {
String description = video ? "Video call" : "Call options";
UiObject callButton = new UiObject(new UiSelector().descriptionContains(description));
callButton.clickAndWaitForNewWindow();
UiObject muteButton = new UiObject(new UiSelector().descriptionContains("Mute"));
muteButton.click();
sleep(duration);
}
}

View File

@ -1,130 +0,0 @@
# Copyright 2014-2015 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.
#
# pylint: disable=E1101,W0201,E0203
import time
from wlauto import UiAutomatorWorkload, Parameter
from wlauto.utils.types import boolean
class SkypeVideo(UiAutomatorWorkload):
name = 'skypevideo'
description = """
Initiates Skype video call to a specified contact for a pre-determined duration.
(Note: requires Skype to be set up appropriately).
This workload is intended for monitoring the behaviour of a device while a Skype
video call is in progress (a common use case). It does not produce any score or
metric and the intention is that some addition instrumentation is enabled while
running this workload.
This workload, obviously, requires a network connection (ideally, wifi).
This workload accepts the following parameters:
**Skype Setup**
- You should install Skype client from Google Play Store on the device
(this was tested with client version 4.5.0.39600; other recent versions
should also work).
- You must have an account set up and logged into Skype on the device.
- The contact to be called must be added (and has accepted) to the
account. It's possible to have multiple contacts in the list, however
the contact to be called *must* be visible on initial navigation to the
list.
- The contact must be able to received the call. This means that there
must be a Skype client running (somewhere) with the contact logged in
and that client must have been configured to auto-accept calls from the
account on the device (how to set this varies between different versions
of Skype and between platforms -- please search online for specific
instructions).
https://support.skype.com/en/faq/FA3751/can-i-automatically-answer-all-my-calls-with-video-in-skype-for-windows-desktop
"""
package = 'com.skype.raider'
parameters = [
Parameter('duration', kind=int, default=300,
description='Duration of the video call in seconds.'),
Parameter('contact', mandatory=True,
description="""
The name of the Skype contact to call. The contact must be already
added (see below). *If use_gui is set*, then this must be the skype
ID of the contact, *otherwise*, this must be the name of the
contact as it appears in Skype client's contacts list. In the latter case
it *must not* contain underscore characters (``_``); it may, however, contain
spaces. There is no default, you **must specify the name of the contact**.
.. note:: You may alternatively specify the contact name as
``skype_contact`` setting in your ``config.py``. If this is
specified, the ``contact`` parameter is optional, though
it may still be specified (in which case it will override
``skype_contact`` setting).
"""),
Parameter('use_gui', kind=boolean, default=False,
description="""
Specifies whether the call should be placed directly through a
Skype URI, or by navigating the GUI. The URI is the recommended way
to place Skype calls on a device, but that does not seem to work
correctly on some devices (the URI seems to just start Skype, but not
place the call), so an alternative exists that will start the Skype app
and will then navigate the UI to place the call (incidentally, this method
does not seem to work on all devices either, as sometimes Skype starts
backgrounded...). Please note that the meaning of ``contact`` prameter
is different depending on whether this is set. Defaults to ``False``.
.. note:: You may alternatively specify this as ``skype_use_gui`` setting
in your ``config.py``.
"""),
]
def __init__(self, device, **kwargs):
super(SkypeVideo, self).__init__(device, **kwargs)
if self.use_gui:
self.uiauto_params['name'] = self.contact.replace(' ', '_')
self.uiauto_params['duration'] = self.duration
self.run_timeout = self.duration + 30
def setup(self, context):
if self.use_gui:
super(SkypeVideo, self).setup(context)
self.device.execute('am force-stop {}'.format(self.package))
self.device.execute('am start -W -a android.intent.action.VIEW -d skype:')
else:
self.device.execute('am force-stop {}'.format(self.package))
def run(self, context):
if self.use_gui:
super(SkypeVideo, self).run(context)
else:
command = "am start -W -a android.intent.action.VIEW -d \"skype:{}?call&video=true\""
self.logger.debug(self.device.execute(command.format(self.contact)))
self.logger.debug('Call started; waiting for {} seconds...'.format(self.duration))
time.sleep(self.duration)
self.device.execute('am force-stop com.skype.raider')
def update_result(self, context):
pass
def teardown(self, context):
if self.use_gui:
super(SkypeVideo, self).teardown(context)
self.device.execute('am force-stop {}'.format(self.package))

View File

@ -1,28 +0,0 @@
#!/bin/bash
# Copyright 2014-2015 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_dir=bin/classes/com/arm/wlauto/uiauto
base_class=`python -c "import os, wlauto; print os.path.join(os.path.dirname(wlauto.__file__), 'common', 'android', 'BaseUiAutomation.class')"`
mkdir -p $class_dir
cp $base_class $class_dir
ant build
if [[ -f bin/com.arm.wlauto.uiauto.skypevideo.jar ]]; then
cp bin/com.arm.wlauto.uiauto.skypevideo.jar ..
fi

View File

@ -1,72 +0,0 @@
/* Copyright 2014-2015 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.
*/
package com.arm.wlauto.uiauto.skypevideo;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
// Import the uiautomator libraries
import com.android.uiautomator.core.UiObject;
import com.android.uiautomator.core.UiObjectNotFoundException;
import com.android.uiautomator.core.UiScrollable;
import com.android.uiautomator.core.UiSelector;
import com.android.uiautomator.testrunner.UiAutomatorTestCase;
import com.arm.wlauto.uiauto.BaseUiAutomation;
public class UiAutomation extends BaseUiAutomation {
public static String TAG = "skypevideo";
public static String videoCallButtonResourceId = "com.skype.raider:id/chat_menu_item_call_video";
public static String noContactMessage = "Could not find contact \"%s\" in the contacts list.";
public void runUiAutomation() throws Exception {
Bundle parameters = getParams();
String contactName = parameters.getString("name").replace('_', ' ');
int duration = Integer.parseInt(parameters.getString("duration"));
selectContact(contactName);
initiateCall(duration);
}
public void selectContact(String name) throws Exception {
UiSelector selector = new UiSelector();
UiObject peopleTab = new UiObject(selector.text("People"));
peopleTab.click();
sleep(1); // tab transition
// Note: this assumes that the contact is in view and does not attempt to scroll to find it.
// The expectation is that this automation will be used with a dedicated account that was set
// up for the purpose and so would only have the intended target plus one or two other contacts
// at most in the list. If that is not the case, then this needs to be re-written to scroll to
// find the contact if necessary.
UiObject contactCard = new UiObject(selector.text(name));
if (!contactCard.exists()) {
throw new UiObjectNotFoundException(String.format(noContactMessage, name));
}
contactCard.clickAndWaitForNewWindow();
}
public void initiateCall(int duration) throws Exception {
UiSelector selector = new UiSelector();
UiObject videoCallButton = new UiObject(selector.resourceId(videoCallButtonResourceId));
videoCallButton.click();
sleep(duration);
}
}