| Index: experimental/telemetry_mini/android_go_stories.py
|
| diff --git a/experimental/telemetry_mini/android_go_stories.py b/experimental/telemetry_mini/android_go_stories.py
|
| index 7d9c57b929c93a3c30713396c359973e7a029078..07a17ed8ebd971752e7af457226feb8f0dc1da95 100755
|
| --- a/experimental/telemetry_mini/android_go_stories.py
|
| +++ b/experimental/telemetry_mini/android_go_stories.py
|
| @@ -4,6 +4,7 @@
|
| # found in the LICENSE file.
|
|
|
| import argparse
|
| +import fnmatch
|
| import logging
|
| import os
|
| import sys
|
| @@ -31,81 +32,6 @@ BROWSERS = {
|
| }
|
|
|
|
|
| -class ProcessWatcher(object):
|
| - def __init__(self, device):
|
| - self.device = device
|
| - self._process_pid = {}
|
| -
|
| - def StartWatching(self, process_name):
|
| - """Register a process or android app to keep track of its PID."""
|
| - if isinstance(process_name, telemetry_mini.AndroidApp):
|
| - process_name = process_name.PACKAGE_NAME
|
| -
|
| - @telemetry_mini.RetryOn(returns_falsy=True)
|
| - def GetPids():
|
| - # Returns an empty list if the process name is not found.
|
| - return self.device.ProcessStatus()[process_name]
|
| -
|
| - assert process_name not in self._process_pid
|
| - pids = GetPids()
|
| - assert pids, 'PID for %s not found' % process_name
|
| - assert len(pids) == 1, 'Single PID for %s expected, but found: %s' % (
|
| - process_name, pids)
|
| - logging.info('Started watching %s (PID=%d)', process_name, pids[0])
|
| - self._process_pid[process_name] = pids[0]
|
| -
|
| - def AssertAllAlive(self):
|
| - """Check that all watched processes remain alive and were not restarted."""
|
| - status = self.device.ProcessStatus()
|
| - all_alive = True
|
| - for process_name, old_pid in sorted(self._process_pid.iteritems()):
|
| - new_pids = status[process_name]
|
| - if not new_pids:
|
| - all_alive = False
|
| - logging.error('Process %s died (PID=%d).', process_name, old_pid)
|
| - elif new_pids != [old_pid]:
|
| - all_alive = False
|
| - logging.error(
|
| - 'Process %s restarted (PID=%d -> %s).', process_name,
|
| - old_pid, new_pids)
|
| - else:
|
| - logging.info('Process %s still alive (PID=%d)', process_name, old_pid)
|
| - assert all_alive, 'Some watched processes died or got restarted'
|
| -
|
| -
|
| -def EnsureSingleBrowser(device, browser_name, force_install=False):
|
| - """Ensure a single Chrome browser is installed and available on the device.
|
| -
|
| - Having more than one Chrome browser available may produce results which are
|
| - confusing or unreliable (e.g. unclear which browser will respond by default
|
| - to intents triggered by other apps).
|
| -
|
| - This function ensures only the selected browser is available, installing it
|
| - if necessary, and uninstalling/disabling others.
|
| - """
|
| - browser = BROWSERS[browser_name](device)
|
| - available_browsers = set(device.ListPackages('chrome', only_enabled=True))
|
| -
|
| - # Install or enable if needed.
|
| - if force_install or browser.PACKAGE_NAME not in available_browsers:
|
| - browser.Install()
|
| -
|
| - # Uninstall disable other browser apps.
|
| - for other_browser in BROWSERS.itervalues():
|
| - if (other_browser.PACKAGE_NAME != browser.PACKAGE_NAME and
|
| - other_browser.PACKAGE_NAME in available_browsers):
|
| - other_browser(device).Uninstall()
|
| -
|
| - # Finally check that only the selected browser is actually available.
|
| - available_browsers = device.ListPackages('chrome', only_enabled=True)
|
| - assert browser.PACKAGE_NAME in available_browsers, (
|
| - 'Unable to make %s available' % browser.PACKAGE_NAME)
|
| - available_browsers.remove(browser.PACKAGE_NAME)
|
| - assert not available_browsers, (
|
| - 'Other browsers may intefere with the test: %s' % available_browsers)
|
| - return browser
|
| -
|
| -
|
| class TwitterApp(telemetry_mini.AndroidApp):
|
| PACKAGE_NAME = 'com.twitter.android'
|
|
|
| @@ -115,6 +41,14 @@ class InstagramApp(telemetry_mini.AndroidApp):
|
|
|
|
|
| class TwitterFlipkartStory(telemetry_mini.UserStory):
|
| + """Load Chrome Custom Tab from another application.
|
| +
|
| + The flow of the story is:
|
| + - Start Twitter app to view the @flipkart profile.
|
| + - Tap on a link to open Flipkart in a Chrome Custom Tab.
|
| + - Return to Twitter app.
|
| + """
|
| + NAME = 'twitter_flipkart'
|
| FLIPKART_TWITTER_LINK = [
|
| ('package', 'com.twitter.android'),
|
| ('class', 'android.widget.TextView'),
|
| @@ -149,6 +83,16 @@ class TwitterFlipkartStory(telemetry_mini.UserStory):
|
|
|
|
|
| class FlipkartInstagramStory(telemetry_mini.UserStory):
|
| + """Interaction between Chrome, PWAs and a WebView-based app.
|
| +
|
| + The flow of the story is:
|
| + - Launch the Flipkart PWA.
|
| + - Go back home and launch the Instagram app.
|
| + - Use the app switcher to return to Flipkart.
|
| + - Go back home and launch Cricbuzz from a shortcut.
|
| + """
|
| + NAME = 'flipkart_instagram'
|
| +
|
| def __init__(self, *args, **kwargs):
|
| super(FlipkartInstagramStory, self).__init__(*args, **kwargs)
|
| self.watcher = ProcessWatcher(self.device)
|
| @@ -187,6 +131,87 @@ class FlipkartInstagramStory(telemetry_mini.UserStory):
|
| self.instagram.ForceStop()
|
|
|
|
|
| +STORIES = (
|
| + TwitterFlipkartStory,
|
| + FlipkartInstagramStory
|
| +)
|
| +
|
| +
|
| +class ProcessWatcher(object):
|
| + def __init__(self, device):
|
| + self.device = device
|
| + self._process_pid = {}
|
| +
|
| + def StartWatching(self, process_name):
|
| + """Register a process or android app to keep track of its PID."""
|
| + if isinstance(process_name, telemetry_mini.AndroidApp):
|
| + process_name = process_name.PACKAGE_NAME
|
| +
|
| + @telemetry_mini.RetryOn(returns_falsy=True)
|
| + def GetPids():
|
| + # Returns an empty list if the process name is not found.
|
| + return self.device.ProcessStatus()[process_name]
|
| +
|
| + assert process_name not in self._process_pid
|
| + pids = GetPids()
|
| + assert pids, 'PID for %s not found' % process_name
|
| + assert len(pids) == 1, 'Single PID for %s expected, but found: %s' % (
|
| + process_name, pids)
|
| + logging.info('Started watching %s (PID=%d)', process_name, pids[0])
|
| + self._process_pid[process_name] = pids[0]
|
| +
|
| + def AssertAllAlive(self):
|
| + """Check that all watched processes remain alive and were not restarted."""
|
| + status = self.device.ProcessStatus()
|
| + all_alive = True
|
| + for process_name, old_pid in sorted(self._process_pid.iteritems()):
|
| + new_pids = status[process_name]
|
| + if not new_pids:
|
| + all_alive = False
|
| + logging.error('Process %s died (PID=%d).', process_name, old_pid)
|
| + elif new_pids != [old_pid]:
|
| + all_alive = False
|
| + logging.error(
|
| + 'Process %s restarted (PID=%d -> %s).', process_name,
|
| + old_pid, new_pids)
|
| + else:
|
| + logging.info('Process %s still alive (PID=%d)', process_name, old_pid)
|
| + assert all_alive, 'Some watched processes died or got restarted'
|
| +
|
| +
|
| +def EnsureSingleBrowser(device, browser_name, force_install=False):
|
| + """Ensure a single Chrome browser is installed and available on the device.
|
| +
|
| + Having more than one Chrome browser available may produce results which are
|
| + confusing or unreliable (e.g. unclear which browser will respond by default
|
| + to intents triggered by other apps).
|
| +
|
| + This function ensures only the selected browser is available, installing it
|
| + if necessary, and uninstalling/disabling others.
|
| + """
|
| + browser = BROWSERS[browser_name](device)
|
| + available_browsers = set(device.ListPackages('chrome', only_enabled=True))
|
| +
|
| + # Install or enable if needed.
|
| + if force_install or browser.PACKAGE_NAME not in available_browsers:
|
| + browser.Install()
|
| +
|
| + # Uninstall disable other browser apps.
|
| + for other_browser in BROWSERS.itervalues():
|
| + if (other_browser.PACKAGE_NAME != browser.PACKAGE_NAME and
|
| + other_browser.PACKAGE_NAME in available_browsers):
|
| + other_browser(device).Uninstall()
|
| +
|
| + # Finally check that only the selected browser is actually available.
|
| + available_browsers = device.ListPackages('chrome', only_enabled=True)
|
| + assert browser.PACKAGE_NAME in available_browsers, (
|
| + 'Unable to make %s available' % browser.PACKAGE_NAME)
|
| + available_browsers.remove(browser.PACKAGE_NAME)
|
| + assert not available_browsers, (
|
| + 'Other browsers may intefere with the test: %s' % available_browsers)
|
| + return browser
|
| +
|
| +
|
| def main():
|
| browser_names = sorted(BROWSERS)
|
| default_browser = 'android-chrome'
|
| @@ -201,6 +226,15 @@ def main():
|
| help='one of: %s' % ', '.join(
|
| '%s (default)' % b if b == default_browser else b
|
| for b in browser_names))
|
| + parser.add_argument('--story-filter', metavar='PATTERN', default='*',
|
| + help='run the matching stories only (allows Unix'
|
| + ' shell-style wildcards)')
|
| + parser.add_argument('--repeat', metavar='NUM', type=int, default=1,
|
| + help='repeat the story set a number of times'
|
| + ' (default: %(default)d)')
|
| + parser.add_argument('--output-dir', metavar='PATH',
|
| + help='path to directory for placing output trace files'
|
| + ' (defaults to current directory)')
|
| parser.add_argument('--force-install', action='store_true',
|
| help='install APK even if browser is already available')
|
| parser.add_argument('--apks-dir', metavar='PATH',
|
| @@ -215,6 +249,17 @@ def main():
|
| if args.verbose:
|
| logging.getLogger().setLevel(logging.INFO)
|
|
|
| + stories = [s for s in STORIES if fnmatch.fnmatch(s.NAME, args.story_filter)]
|
| + if not stories:
|
| + return 'No matching stories'
|
| +
|
| + if args.output_dir is None:
|
| + args.output_dir = os.getcwd()
|
| + else:
|
| + args.output_dir = os.path.realpath(args.output_dir)
|
| + if not os.path.isdir(args.output_dir):
|
| + return 'Output directory does not exit'
|
| +
|
| if args.apks_dir is None:
|
| args.apks_dir = os.path.realpath(os.path.join(
|
| os.path.dirname(__file__), '..', '..', '..', '..',
|
| @@ -233,10 +278,10 @@ def main():
|
| device.RunCommand('wait-for-device')
|
|
|
| browser = EnsureSingleBrowser(device, args.browser, args.force_install)
|
| + browser.SetBrowserFlags(BROWSER_FLAGS)
|
| + browser.SetTraceConfig(TRACE_CONFIG)
|
| browser.SetDevToolsLocalPort(args.port)
|
| -
|
| - story = FlipkartInstagramStory(browser)
|
| - story.Run(BROWSER_FLAGS, TRACE_CONFIG, 'trace.json')
|
| + telemetry_mini.RunStories(browser, stories, args.repeat, args.output_dir)
|
|
|
|
|
| if __name__ == '__main__':
|
|
|