0

[Android] Switch gtests to platform mode. (RELAND)

BUG=428729

Review URL: https://codereview.chromium.org/1358593002

Cr-Commit-Position: refs/heads/master@{#349931}
This commit is contained in:
jbudorick
2015-09-21 08:32:47 -07:00
committed by Commit bot
parent 61dd5d4b91
commit 566592abb5
12 changed files with 114 additions and 66 deletions

@ -3,9 +3,9 @@
# found in the LICENSE file.
from pylib.gtest import gtest_test_instance
from pylib.gtest import local_device_gtest_run
from pylib.instrumentation import instrumentation_test_instance
from pylib.local.device import local_device_environment
from pylib.local.device import local_device_gtest_run
from pylib.local.device import local_device_instrumentation_test_run
from pylib.remote.device import remote_device_environment
from pylib.remote.device import remote_device_gtest_run

@ -23,6 +23,8 @@ BROWSER_TEST_SUITES = [
'content_browsertests',
]
RUN_IN_SUB_THREAD_TEST_SUITES = ['net_unittests']
_DEFAULT_ISOLATE_FILE_PATHS = {
'base_unittests': 'base/base_unittests.isolate',
@ -73,6 +75,8 @@ _DEPS_EXCLUSION_LIST = [
_EXTRA_NATIVE_TEST_ACTIVITY = (
'org.chromium.native_test.NativeTestInstrumentationTestRunner.'
'NativeTestActivity')
_EXTRA_RUN_IN_SUB_THREAD = (
'org.chromium.native_test.NativeTestActivity.RunInSubThread')
_EXTRA_SHARD_SIZE_LIMIT = (
'org.chromium.native_test.NativeTestInstrumentationTestRunner.'
'ShardSizeLimit')
@ -148,6 +152,8 @@ class GtestTestInstance(test_instance.TestInstance):
self._extras = {
_EXTRA_NATIVE_TEST_ACTIVITY: self._activity,
}
if self._suite in RUN_IN_SUB_THREAD_TEST_SUITES:
self._extras[_EXTRA_RUN_IN_SUB_THREAD] = 1
if self._suite in BROWSER_TEST_SUITES:
self._extras[_EXTRA_SHARD_SIZE_LIMIT] = 1

@ -16,8 +16,8 @@ from devil.android.sdk import intent
from pylib import constants
from pylib import pexpect
from pylib.gtest import gtest_test_instance
from pylib.gtest import local_device_gtest_run
from pylib.gtest.test_package import TestPackage
from pylib.local.device import local_device_gtest_run
class TestPackageApk(TestPackage):
@ -40,7 +40,9 @@ class TestPackageApk(TestPackage):
self._package_info = constants.PACKAGE_INFO['gtest']
if suite_name == 'net_unittests':
self._extras = {'RunInSubThread': None}
self._extras = {
'org.chromium.native_test.NativeTestActivity.RunInSubThread': None
}
else:
self._extras = []

@ -2,6 +2,9 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
import threading
from devil.android import device_blacklist
from devil.android import device_errors
from devil.android import device_utils
@ -17,6 +20,7 @@ class LocalDeviceEnvironment(environment.Environment):
if args.blacklist_file
else None)
self._device_serial = args.test_device
self._devices_lock = threading.Lock()
self._devices = []
self._max_tries = 1 + args.num_retries
self._tool_name = args.tool
@ -38,11 +42,13 @@ class LocalDeviceEnvironment(environment.Environment):
@property
def devices(self):
if not self._devices:
raise device_errors.NoDevicesError()
return self._devices
@property
def parallel_devices(self):
return parallelizer.SyncParallelizer(self._devices)
return parallelizer.SyncParallelizer(self.devices)
@property
def max_tries(self):
@ -56,3 +62,15 @@ class LocalDeviceEnvironment(environment.Environment):
def TearDown(self):
pass
def BlacklistDevice(self, device):
if not self._blacklist:
logging.warning(
'Attempted to blacklist %s, but no blacklist was provided.',
str(device))
return
device_serial = device.adb.GetDeviceSerial()
self._blacklist.Extend([device_serial])
with self._devices_lock:
self._devices = [d for d in self._devices if str(d) != device_serial]

@ -3,7 +3,6 @@
# found in the LICENSE file.
import itertools
import logging
import os
import posixpath
@ -108,10 +107,13 @@ class _ExeDelegate(object):
device.PushChangedFiles(host_device_tuples)
def Run(self, test, device, flags=None, **kwargs):
cmd = [
self._test_run.GetTool(device).GetTestWrapper(),
self._exe_device_path,
]
tool = self._test_run.GetTool(device).GetTestWrapper()
if tool:
cmd = [tool]
else:
cmd = []
cmd.append(self._exe_device_path)
if test:
cmd.append('--gtest_filter=%s' % ':'.join(test))
if flags:
@ -130,14 +132,8 @@ class _ExeDelegate(object):
except (device_errors.CommandFailedError, KeyError):
pass
# TODO(jbudorick): Switch to just RunShellCommand once perezju@'s CL
# for long shell commands lands.
with device_temp_file.DeviceTempFile(device.adb) as script_file:
script_contents = ' '.join(cmd)
logging.info('script contents: %r', script_contents)
device.WriteFile(script_file.name, script_contents)
output = device.RunShellCommand(['sh', script_file.name], cwd=cwd,
env=env, **kwargs)
output = device.RunShellCommand(
cmd, cwd=cwd, env=env, check_return=True, large_output=True, **kwargs)
return output
def PullAppFiles(self, device, files, directory):
@ -168,6 +164,7 @@ class LocalDeviceGtestRun(local_device_test_run.LocalDeviceTestRun):
#override
def SetUp(self):
@local_device_test_run.handle_shard_failures
def individual_device_set_up(dev, host_device_tuples):
# Install test APK.
self._delegate.Install(dev)
@ -207,10 +204,16 @@ class LocalDeviceGtestRun(local_device_test_run.LocalDeviceTestRun):
#override
def _GetTests(self):
tests = self._delegate.Run(
None, self._env.devices[0], flags='--gtest_list_tests')
tests = gtest_test_instance.ParseGTestListTests(tests)
tests = self._test_instance.FilterTests(tests)
@local_device_test_run.handle_shard_failures
def list_tests(dev):
tests = self._delegate.Run(
None, dev, flags='--gtest_list_tests', timeout=10)
tests = gtest_test_instance.ParseGTestListTests(tests)
tests = self._test_instance.FilterTests(tests)
return tests
test_lists = self._env.parallel_devices.pMap(list_tests).pGet(None)
tests = list(sorted(set().union(*[set(tl) for tl in test_lists if tl])))
return tests
#override
@ -233,6 +236,7 @@ class LocalDeviceGtestRun(local_device_test_run.LocalDeviceTestRun):
#override
def TearDown(self):
@local_device_test_run.handle_shard_failures
def individual_device_tear_down(dev):
for s in self._servers[str(dev)]:
s.TearDown()

@ -11,6 +11,27 @@ from pylib.base import test_run
from pylib.base import test_collection
def handle_shard_failures(f):
"""A decorator that handles device failures for per-device functions.
Args:
f: the function being decorated. The function must take at least one
argument, and that argument must be the device.
"""
def wrapper(dev, *args, **kwargs):
try:
return f(dev, *args, **kwargs)
except device_errors.CommandFailedError:
logging.exception('Shard failed: %s(%s)', f.__name__, str(dev))
except device_errors.CommandTimeoutError:
logging.exception('Shard timed out: %s(%s)', f.__name__, str(dev))
except device_errors.DeviceUnreachableError:
logging.exception('Shard died: %s(%s)', f.__name__, str(dev))
return None
return wrapper
class LocalDeviceTestRun(test_run.TestRun):
def __init__(self, env, test_instance):
@ -21,6 +42,7 @@ class LocalDeviceTestRun(test_run.TestRun):
def RunTests(self):
tests = self._GetTests()
@handle_shard_failures
def run_tests_on_device(dev, tests, results):
for test in tests:
try:
@ -52,21 +74,14 @@ class LocalDeviceTestRun(test_run.TestRun):
for t in tests:
logging.debug(' %s', t)
try:
try_results = base_test_result.TestRunResults()
if self._ShouldShard():
tc = test_collection.TestCollection(self._CreateShards(tests))
self._env.parallel_devices.pMap(
run_tests_on_device, tc, try_results).pGet(None)
else:
self._env.parallel_devices.pMap(
run_tests_on_device, tests, try_results).pGet(None)
except device_errors.CommandFailedError:
logging.exception('Shard terminated: command failed')
except device_errors.CommandTimeoutError:
logging.exception('Shard terminated: command timed out')
except device_errors.DeviceUnreachableError:
logging.exception('Shard terminated: device became unreachable')
try_results = base_test_result.TestRunResults()
if self._ShouldShard():
tc = test_collection.TestCollection(self._CreateShards(tests))
self._env.parallel_devices.pMap(
run_tests_on_device, tc, try_results).pGet(None)
else:
self._env.parallel_devices.pMap(
run_tests_on_device, tests, try_results).pGet(None)
for result in try_results.GetAll():
if result.GetType() in (base_test_result.ResultType.PASS,

@ -32,8 +32,6 @@ from pylib.base import test_dispatcher
from pylib.base import test_instance_factory
from pylib.base import test_run_factory
from pylib.gtest import gtest_config
# TODO(jbudorick): Remove this once we stop selectively enabling platform mode.
from pylib.gtest import gtest_test_instance
from pylib.gtest import setup as gtest_setup
from pylib.gtest import test_options as gtest_test_options
from pylib.linker import setup as linker_setup
@ -944,9 +942,7 @@ def RunTestsCommand(args, parser): # pylint: disable=too-many-return-statements
raise Exception('Failed to reset test server port.')
if command == 'gtest':
if args.suite_name[0] in gtest_test_instance.BROWSER_TEST_SUITES:
return RunTestsInPlatformMode(args, parser)
return _RunGTests(args, devices)
return RunTestsInPlatformMode(args, parser)
elif command == 'linker':
return _RunLinkerTests(args, devices)
elif command == 'instrumentation':
@ -975,13 +971,16 @@ _SUPPORTED_IN_PLATFORM_MODE = [
def RunTestsInPlatformMode(args, parser):
if args.command not in _SUPPORTED_IN_PLATFORM_MODE:
parser.error('%s is not yet supported in platform mode' % args.command)
def infra_error(message):
parser.exit(status=constants.INFRA_EXIT_CODE, message=message)
with environment_factory.CreateEnvironment(args, parser.error) as env:
with test_instance_factory.CreateTestInstance(args, parser.error) as test:
if args.command not in _SUPPORTED_IN_PLATFORM_MODE:
infra_error('%s is not yet supported in platform mode' % args.command)
with environment_factory.CreateEnvironment(args, infra_error) as env:
with test_instance_factory.CreateTestInstance(args, infra_error) as test:
with test_run_factory.CreateTestRun(
args, env, test, parser.error) as test_run:
args, env, test, infra_error) as test_run:
results = test_run.RunTests()
if args.environment == 'remote_device' and args.trigger:

@ -24,7 +24,8 @@ found in the LICENSE file.
android:name="org.chromium.base.BaseChromiumApplication">
<activity android:name=".NativeUnitTestActivity"
android:label="NativeTest"
android:configChanges="orientation|keyboardHidden">
android:configChanges="orientation|keyboardHidden"
android:process=":test_process">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

@ -15,7 +15,7 @@ import java.io.File;
*/
public abstract class NativeBrowserTestActivity extends NativeTestActivity {
private static final String TAG = "cr.native_test";
private static final String TAG = "cr_NativeTest";
private static final String BROWSER_TESTS_FLAGS[] = {
// content::kSingleProcessTestsFlag

@ -32,13 +32,14 @@ public class NativeTestActivity extends Activity {
"org.chromium.native_test.NativeTestActivity.CommandLineFile";
public static final String EXTRA_COMMAND_LINE_FLAGS =
"org.chromium.native_test.NativeTestActivity.CommandLineFlags";
public static final String EXTRA_RUN_IN_SUB_THREAD =
"org.chromium.native_test.NativeTestActivity.RunInSubThread";
public static final String EXTRA_SHARD =
"org.chromium.native_test.NativeTestActivity.Shard";
public static final String EXTRA_STDOUT_FILE =
"org.chromium.native_test.NativeTestActivity.StdoutFile";
private static final String TAG = "cr.native_test";
private static final String EXTRA_RUN_IN_SUB_THREAD = "RunInSubThread";
private static final String TAG = "cr_NativeTest";
private String mCommandLineFilePath;
private StringBuilder mCommandLineFlags = new StringBuilder();
@ -57,6 +58,12 @@ public class NativeTestActivity extends Activity {
}
private void parseArgumentsFromIntent(Intent intent) {
Log.i(TAG, "Extras:");
Bundle extras = intent.getExtras();
for (String s : extras.keySet()) {
Log.i(TAG, " %s", s);
}
mCommandLineFilePath = intent.getStringExtra(EXTRA_COMMAND_LINE_FILE);
if (mCommandLineFilePath == null) {
mCommandLineFilePath = "";

@ -52,7 +52,7 @@ public class NativeTestInstrumentationTestRunner extends Instrumentation {
public static final String EXTRA_TEST_LIST_FILE =
"org.chromium.native_test.NativeTestInstrumentationTestRunner.TestList";
private static final String TAG = "cr.native_test";
private static final String TAG = "cr_NativeTest";
private static final long DEFAULT_SHARD_NANO_TIMEOUT = 60 * 1000000000L;
// Default to no size limit.
@ -63,11 +63,10 @@ public class NativeTestInstrumentationTestRunner extends Instrumentation {
Pattern.compile("\\[ *([^ ]*) *\\] ?([^ ]+)( .*)?$");
private ResultsBundleGenerator mBundleGenerator = new RobotiumBundleGenerator();
private String mCommandLineFile;
private String mCommandLineFlags;
private Handler mHandler = new Handler();
private String mNativeTestActivity;
private Bundle mLogBundle = new Bundle();
private SparseArray<ShardMonitor> mMonitors = new SparseArray<ShardMonitor>();
private String mNativeTestActivity;
private TestStatusReceiver mReceiver;
private Map<String, ResultsBundleGenerator.TestResult> mResults =
new HashMap<String, ResultsBundleGenerator.TestResult>();
@ -75,20 +74,23 @@ public class NativeTestInstrumentationTestRunner extends Instrumentation {
private long mShardNanoTimeout = DEFAULT_SHARD_NANO_TIMEOUT;
private int mShardSizeLimit = DEFAULT_SHARD_SIZE_LIMIT;
private File mStdoutFile;
private SparseArray<ShardMonitor> mMonitors = new SparseArray<ShardMonitor>();
private Bundle mTransparentArguments;
@Override
public void onCreate(Bundle arguments) {
mCommandLineFile = arguments.getString(NativeTestActivity.EXTRA_COMMAND_LINE_FILE);
mCommandLineFlags = arguments.getString(NativeTestActivity.EXTRA_COMMAND_LINE_FLAGS);
mTransparentArguments = new Bundle(arguments);
mNativeTestActivity = arguments.getString(EXTRA_NATIVE_TEST_ACTIVITY);
if (mNativeTestActivity == null) mNativeTestActivity = DEFAULT_NATIVE_TEST_ACTIVITY;
mTransparentArguments.remove(EXTRA_NATIVE_TEST_ACTIVITY);
String shardNanoTimeout = arguments.getString(EXTRA_SHARD_NANO_TIMEOUT);
if (shardNanoTimeout != null) mShardNanoTimeout = Long.parseLong(shardNanoTimeout);
mTransparentArguments.remove(EXTRA_SHARD_NANO_TIMEOUT);
String shardSizeLimit = arguments.getString(EXTRA_SHARD_SIZE_LIMIT);
if (shardSizeLimit != null) mShardSizeLimit = Integer.parseInt(shardSizeLimit);
mTransparentArguments.remove(EXTRA_SHARD_SIZE_LIMIT);
String testListFilePath = arguments.getString(EXTRA_TEST_LIST_FILE);
if (testListFilePath != null) {
@ -116,6 +118,7 @@ public class NativeTestInstrumentationTestRunner extends Instrumentation {
Log.e(TAG, "Error reading %s", testListFile.getAbsolutePath(), e);
}
}
mTransparentArguments.remove(EXTRA_TEST_LIST_FILE);
try {
mStdoutFile = File.createTempFile(
@ -220,14 +223,7 @@ public class NativeTestInstrumentationTestRunner extends Instrumentation {
Intent i = new Intent(Intent.ACTION_MAIN);
i.setComponent(new ComponentName(getContext().getPackageName(), mNativeTestActivity));
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (mCommandLineFile != null) {
Log.i(TAG, "Passing command line file extra: %s", mCommandLineFile);
i.putExtra(NativeTestActivity.EXTRA_COMMAND_LINE_FILE, mCommandLineFile);
}
if (mCommandLineFlags != null) {
Log.i(TAG, "Passing command line flag extra: %s", mCommandLineFlags);
i.putExtra(NativeTestActivity.EXTRA_COMMAND_LINE_FLAGS, mCommandLineFlags);
}
i.putExtras(mTransparentArguments);
if (mShards != null && !mShards.isEmpty()) {
ArrayList<String> shard = mShards.remove();
i.putStringArrayListExtra(NativeTestActivity.EXTRA_SHARD, shard);

@ -17,7 +17,7 @@ import org.chromium.base.library_loader.NativeLibraries;
*/
public class NativeUnitTestActivity extends NativeTestActivity {
private static final String TAG = "cr.native_test";
private static final String TAG = "cr_NativeTest";
@Override
public void onCreate(Bundle savedInstanceState) {