0

[Android] Translate Android expectation into metadata when running WPT

The wpt runner uses metadata files to get test expectations. In
the chromium repository we use test expectation files. This CL will
translate the test expectation files into WPT metadata before running
wpt on Android.

TBR=lpz@chromium.org

Bug: 1050754
Change-Id: I3c2ed6dc9b793242076ea2aa8fe617989928ec1c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2070826
Reviewed-by: Rakib Hasan <rmhasan@google.com>
Reviewed-by: Andrew Luo <aluo@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Reviewed-by: Robert Ma <robertma@chromium.org>
Commit-Queue: Rakib Hasan <rmhasan@google.com>
Cr-Commit-Position: refs/heads/master@{#752310}
This commit is contained in:
Rakib M. Hasan
2020-03-21 20:22:17 +00:00
committed by Commit Bot
parent c70197bbf9
commit 84af0e4a18
18 changed files with 14709 additions and 87 deletions

@@ -1021,7 +1021,6 @@ if (!is_ios) {
] ]
deps = [ deps = [
"//third_party/blink/tools:wpt_tests_isolate", "//third_party/blink/tools:wpt_tests_isolate",
"//third_party/catapult/third_party/typ",
] ]
} }
} }

@@ -39,8 +39,8 @@ if (public_android_sdk) {
"//android_webview:system_webview_apk", "//android_webview:system_webview_apk",
"//android_webview/tools/system_webview_shell:system_webview_shell_layout_test_apk", "//android_webview/tools/system_webview_shell:system_webview_shell_layout_test_apk",
"//chrome/test/chromedriver:chromedriver($host_toolchain)", "//chrome/test/chromedriver:chromedriver($host_toolchain)",
"//third_party/blink/tools:wpt_tests_android_isolate",
] ]
data = [ "//third_party/blink/web_tests/external/" ]
} }
} }

@@ -2403,11 +2403,11 @@ if (public_android_sdk) {
python_library("chrome_public_wpt") { python_library("chrome_public_wpt") {
testonly = true testonly = true
pydeps_file = "//testing/scripts/run_android_wpt.pydeps" pydeps_file = "//testing/scripts/run_android_wpt.pydeps"
data = [ "//third_party/blink/web_tests/external/" ]
data_deps = [ data_deps = [
":chrome_public_apk", ":chrome_public_apk",
"//build/android:test_runner_py", "//build/android:test_runner_py",
"//chrome/test/chromedriver:chromedriver($host_toolchain)", "//chrome/test/chromedriver:chromedriver($host_toolchain)",
"//third_party/blink/tools:wpt_tests_android_isolate",
] ]
} }

@@ -484,7 +484,7 @@
"--product=chrome_android", "--product=chrome_android",
"--apk=apks/ChromePublic.apk", "--apk=apks/ChromePublic.apk",
"--webdriver-binary=clang_x64/chromedriver", "--webdriver-binary=clang_x64/chromedriver",
"-vvv", "-v",
], ],
}, },
"chrome_sandbox": { "chrome_sandbox": {
@@ -1608,7 +1608,7 @@
"--apk=apks/SystemWebView.apk", "--apk=apks/SystemWebView.apk",
"--system-webview-shell=apks/SystemWebViewShell.apk", "--system-webview-shell=apks/SystemWebViewShell.apk",
"--webdriver-binary=clang_x64/chromedriver", "--webdriver-binary=clang_x64/chromedriver",
"-vvv", "-v",
], ],
}, },
"telemetry_gpu_integration_test": { "telemetry_gpu_integration_test": {
@@ -1866,7 +1866,7 @@
"--weblayer-shell=apks/WebLayerShell.apk", "--weblayer-shell=apks/WebLayerShell.apk",
"--weblayer-support=apks/WebLayerSupport.apk", "--weblayer-support=apks/WebLayerSupport.apk",
"--webdriver-binary=clang_x64/chromedriver", "--webdriver-binary=clang_x64/chromedriver",
"-vvv", "-v",
], ],
}, },
"webview_cts_tests": { "webview_cts_tests": {

@@ -35,7 +35,8 @@ import common
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
SRC_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')) SRC_DIR = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
BUILD_ANDROID = os.path.join(SRC_DIR, 'build', 'android') BUILD_ANDROID = os.path.join(SRC_DIR, 'build', 'android')
@@ -50,9 +51,17 @@ from devil.android import device_utils
from devil.android.tools import system_app from devil.android.tools import system_app
from devil.android.tools import webview_app from devil.android.tools import webview_app
CATAPULT_DIR = os.path.join(SRC_DIR, 'third_party', 'catapult')
PYUTILS = os.path.join(CATAPULT_DIR, 'common', 'py_utils')
DEFAULT_WPT = os.path.join(SRC_DIR, 'third_party', 'blink', 'web_tests', if PYUTILS not in sys.path:
'external', 'wpt', 'wpt') sys.path.append(PYUTILS)
from py_utils.tempfile_ext import NamedTemporaryDirectory
BLINK_TOOLS_DIR = os.path.join(SRC_DIR, 'third_party', 'blink', 'tools')
WEB_TESTS_DIR = os.path.join(BLINK_TOOLS_DIR, os.pardir, 'web_tests')
DEFAULT_WPT = os.path.join(WEB_TESTS_DIR, 'external', 'wpt', 'wpt')
SYSTEM_WEBVIEW_SHELL_PKG = 'org.chromium.webview_shell' SYSTEM_WEBVIEW_SHELL_PKG = 'org.chromium.webview_shell'
WEBLAYER_SHELL_PKG = 'org.chromium.weblayer.shell' WEBLAYER_SHELL_PKG = 'org.chromium.weblayer.shell'
@@ -61,6 +70,7 @@ WEBLAYER_SUPPORT_PKG = 'org.chromium.weblayer.support'
# List of supported products. # List of supported products.
PRODUCTS = ['android_weblayer', 'android_webview', 'chrome_android'] PRODUCTS = ['android_weblayer', 'android_webview', 'chrome_android']
class PassThroughArgs(argparse.Action): class PassThroughArgs(argparse.Action):
pass_through_args = [] pass_through_args = []
def __call__(self, parser, namespace, values, option_string=None): def __call__(self, parser, namespace, values, option_string=None):
@@ -80,10 +90,27 @@ class PassThroughArgs(argparse.Action):
class WPTAndroidAdapter(common.BaseIsolatedScriptArgsAdapter): class WPTAndroidAdapter(common.BaseIsolatedScriptArgsAdapter):
def __init__(self): def __init__(self):
self.pass_through_wpt_args = [] self.pass_through_wpt_args = []
self.pass_through_binary_args = [] self.pass_through_binary_args = []
self._metadata_dir = None
self._test_apk = None
self._missing_test_apk_arg = None
super(WPTAndroidAdapter, self).__init__() super(WPTAndroidAdapter, self).__init__()
# Arguments from add_extra_argumentsparse were added so
# its safe to parse the arguments and set self._options
self.parse_args()
@classmethod
def get_adapter(cls):
product = cls().options.product
if product == 'android_weblayer':
return WPTWeblayerAdapter()
elif product == 'android_webview':
return WPTWebviewAdapter()
else:
return WPTClankAdapter()
def generate_test_output_args(self, output): def generate_test_output_args(self, output):
return ['--log-chromium', output] return ['--log-chromium', output]
@@ -112,8 +139,11 @@ class WPTAndroidAdapter(common.BaseIsolatedScriptArgsAdapter):
"--no-pause-after-test", "--no-pause-after-test",
"--no-capture-stdio", "--no-capture-stdio",
"--no-manifest-download", "--no-manifest-download",
"--no-fail-on-unexpected",
]) ])
# if metadata was created then add the metadata directory
# to the list of wpt arguments
if self._metadata_dir:
rest_args.extend(['--metadata', self._metadata_dir])
# Default to the apk's package name for chrome_android # Default to the apk's package name for chrome_android
if not self.options.package_name: if not self.options.package_name:
@@ -139,6 +169,40 @@ class WPTAndroidAdapter(common.BaseIsolatedScriptArgsAdapter):
return rest_args return rest_args
def _extra_metadata_builder_args(self):
raise NotImplementedError
def _maybe_build_metadata(self):
if not self._test_apk:
assert self._missing_test_apk_arg, (
'self._missing_test_apk_arg was not set.')
logger.info('%s was not set, skipping metadata generation.' %
self._missing_test_apk_arg)
return
metadata_builder_cmd = [
sys.executable,
os.path.join(BLINK_TOOLS_DIR, 'build_wpt_metadata.py'),
'--android-apk',
self._test_apk,
'--metadata-output-dir',
self._metadata_dir,
'--additional-expectations',
os.path.join(WEB_TESTS_DIR, 'android', 'AndroidWPTNeverFixTests')
]
metadata_builder_cmd.extend(self._extra_metadata_builder_args())
common.run_command(metadata_builder_cmd)
def run_test(self):
with NamedTemporaryDirectory() as self._metadata_dir:
self._maybe_build_metadata()
return super(WPTAndroidAdapter, self).run_test()
def clean_up_after_test_run(self):
# Avoid having a dangling reference to the temp directory
# which was deleted
self._metadata_dir = None
def add_extra_arguments(self, parser): def add_extra_arguments(self, parser):
# TODO: |pass_through_args| are broke and need to be supplied by way of # TODO: |pass_through_args| are broke and need to be supplied by way of
# --binary-arg". # --binary-arg".
@@ -206,6 +270,47 @@ class WPTAndroidAdapter(common.BaseIsolatedScriptArgsAdapter):
help='Force trial params for Chromium features.') help='Force trial params for Chromium features.')
class WPTWebviewAdapter(WPTAndroidAdapter):
def __init__(self):
super(WPTWebviewAdapter, self).__init__()
self._test_apk = self.options.system_webview_shell
self._missing_test_apk_arg = '--system-webview-shell'
def _extra_metadata_builder_args(self):
return [
'--additional-expectations',
os.path.join(
WEB_TESTS_DIR, 'android', 'WebviewWPTOverrideExpectations')]
class WPTWeblayerAdapter(WPTAndroidAdapter):
def __init__(self):
super(WPTWeblayerAdapter, self).__init__()
self._test_apk = self.options.weblayer_shell
self._missing_test_apk_arg = '--weblayer-shell'
def _extra_metadata_builder_args(self):
return [
'--additional-expectations',
os.path.join(WEB_TESTS_DIR,
'android', 'WeblayerWPTOverrideExpectations')]
class WPTClankAdapter(WPTAndroidAdapter):
def __init__(self):
super(WPTClankAdapter, self).__init__()
self._test_apk = self.options.apk
self._missing_test_apk_arg = '--apk'
def _extra_metadata_builder_args(self):
return [
'--additional-expectations',
os.path.join(WEB_TESTS_DIR, 'android', 'ClankWPTOverrideExpectations')]
def run_android_weblayer(device, adapter): def run_android_weblayer(device, adapter):
if adapter.options.package_name: if adapter.options.package_name:
logger.warn('--package-name has no effect for weblayer, provider' logger.warn('--package-name has no effect for weblayer, provider'
@@ -312,7 +417,7 @@ def main_compile_targets(args):
def main(): def main():
adapter = WPTAndroidAdapter() adapter = WPTAndroidAdapter.get_adapter()
adapter.parse_args() adapter.parse_args()
if adapter.options.verbose: if adapter.options.verbose:
@@ -333,11 +438,13 @@ def main():
os.environ['PATH'].split(':')) os.environ['PATH'].split(':'))
if adapter.options.product == 'android_weblayer': if adapter.options.product == 'android_weblayer':
run_android_weblayer(device, adapter) return run_android_weblayer(device, adapter)
elif adapter.options.product == 'android_webview': elif adapter.options.product == 'android_webview':
run_android_webview(device, adapter) return run_android_webview(device, adapter)
elif adapter.options.product == 'chrome_android': elif adapter.options.product == 'chrome_android':
run_chrome_android(device, adapter) return run_chrome_android(device, adapter)
else:
return 1
if __name__ == '__main__': if __name__ == '__main__':

@@ -7,13 +7,13 @@ group("wpt_tests_isolate") {
testonly = true testonly = true
data = [ data = [
"//testing/scripts/common.py", "//testing/scripts/common.py",
"//testing/scripts/run_wpt_tests.py",
"//testing/xvfb.py", "//testing/xvfb.py",
# Include blinkpy tools for setting up expectations. # Include blinkpy tools for setting up expectations.
"//third_party/blink/tools/build_wpt_metadata.py", "//third_party/blink/tools/build_wpt_metadata.py",
"//third_party/blink/tools/update_wpt_output.py", "//third_party/blink/tools/update_wpt_output.py",
"//third_party/blink/tools/blinkpy/", "//third_party/blink/tools/blinkpy/",
"//third_party/catapult/third_party/typ/",
# The web_tests/external directory contains all WPT components including # The web_tests/external directory contains all WPT components including
# the test runner codebase, manifest file, and the tests themselves. # the test runner codebase, manifest file, and the tests themselves.
@@ -38,4 +38,18 @@ group("wpt_tests_isolate") {
if (is_win) { if (is_win) {
data_deps = [ "//build/win:copy_cdb_to_output" ] data_deps = [ "//build/win:copy_cdb_to_output" ]
} }
if (!is_android) {
data += [ "//testing/scripts/run_wpt_tests.py" ]
}
}
group("wpt_tests_android_isolate") {
testonly = true
data_deps = [ "//third_party/blink/tools:wpt_tests_isolate" ]
data = [
"//third_party/blink/web_tests/android/WeblayerWPTOverrideExpectations",
"//third_party/blink/web_tests/android/ClankWPTOverrideExpectations",
"//third_party/blink/web_tests/android/WebviewWPTOverrideExpectations",
"//third_party/blink/web_tests/android/AndroidWPTNeverFixTests",
]
} }

@@ -61,8 +61,27 @@ def PresubmitCheckTestExpectations(input_api, output_api):
def lint(host, options): def lint(host, options):
ports_to_lint = [host.port_factory.get(name) for name in host.port_factory.all_port_names(options.platform)] port = host.port_factory.get(options.platform)
files_linted = set()
# Add all extra expectation files to be linted.
options.additional_expectations.extend([
host.filesystem.join(
port.web_tests_dir(), 'android', 'ClankWPTOverrideExpectations'),
host.filesystem.join(
port.web_tests_dir(), 'android', 'WebviewWPTOverrideExpectations'),
host.filesystem.join(
port.web_tests_dir(), 'android', 'WeblayerWPTOverrideExpectations'),
host.filesystem.join(
port.web_tests_dir(), 'android', 'AndroidWPTNeverFixTests'),
host.filesystem.join(
port.web_tests_dir(), 'WPTOverrideExpectations'),
host.filesystem.join(
port.web_tests_dir(), 'WebGPUExpectations'),
])
ports_to_lint = [
host.port_factory.get(name, options=options)
for name in host.port_factory.all_port_names(options.platform)]
# In general, the set of TestExpectation files should be the same for # In general, the set of TestExpectation files should be the same for
# all ports. However, the method used to list expectations files is # all ports. However, the method used to list expectations files is
@@ -71,20 +90,12 @@ def lint(host, options):
# (the default Port for this host) and it would work the same. # (the default Port for this host) and it would work the same.
failures = [] failures = []
wpt_overrides_exps_path = host.filesystem.join(
ports_to_lint[0].web_tests_dir(), 'WPTOverrideExpectations')
web_gpu_exps_path = host.filesystem.join(
ports_to_lint[0].web_tests_dir(), 'WebGPUExpectations')
paths = [wpt_overrides_exps_path, web_gpu_exps_path]
expectations_dict = {} expectations_dict = {}
all_system_specifiers = set() all_system_specifiers = set()
all_build_specifiers = set(ports_to_lint[0].ALL_BUILD_TYPES) all_build_specifiers = set(ports_to_lint[0].ALL_BUILD_TYPES)
# TODO(crbug.com/986447) Remove the checks below after migrating the expectations # TODO(crbug.com/986447) Remove the checks below after migrating the expectations
# parsing to Typ. All the checks below can be handled by Typ. # parsing to Typ. All the checks below can be handled by Typ.
for path in paths:
if host.filesystem.exists(path):
expectations_dict[path] = host.filesystem.read_text_file(path)
for port in ports_to_lint: for port in ports_to_lint:
expectations_dict.update(port.all_expectations_dict()) expectations_dict.update(port.all_expectations_dict())
@@ -96,8 +107,8 @@ def lint(host, options):
for path in port.extra_expectations_files(): for path in port.extra_expectations_files():
if host.filesystem.exists(path): if host.filesystem.exists(path):
expectations_dict[path] = host.filesystem.read_text_file(path) expectations_dict[path] = host.filesystem.read_text_file(path)
for path, content in expectations_dict.items():
for path, content in expectations_dict.items():
# check for expectations which start with the Bug(...) token # check for expectations which start with the Bug(...) token
exp_lines = content.split('\n') exp_lines = content.split('\n')
for lineno, line in enumerate(exp_lines, 1): for lineno, line in enumerate(exp_lines, 1):
@@ -243,6 +254,9 @@ def main(argv, stderr, host=None):
parser.add_option('--json', help='Path to JSON output file') parser.add_option('--json', help='Path to JSON output file')
parser.add_option('--verbose', action='store_true', default=False, parser.add_option('--verbose', action='store_true', default=False,
help='log extra details that may be helpful when debugging') help='log extra details that may be helpful when debugging')
parser.add_option('--additional-expectations', action='append', default=[],
help='paths to additional expectation files to lint.')
options, _ = parser.parse_args(argv) options, _ = parser.parse_args(argv)
if not host: if not host:

@@ -107,14 +107,15 @@ class LintTest(LoggingTestCase):
FakePort(host, 'b', 'path-to-b'), FakePort(host, 'b', 'path-to-b'),
FakePort(host, 'b-win', 'path-to-b'))) FakePort(host, 'b-win', 'path-to-b')))
options = optparse.Values({'platform': None}) options = optparse.Values({'platform': 'a', 'additional_expectations': []})
res = lint_test_expectations.lint(host, options) res = lint_test_expectations.lint(host, options)
self.assertEqual(res, []) self.assertEqual(res, [])
self.assertEqual(host.ports_parsed, ['a', 'b', 'b-win']) self.assertEqual(host.ports_parsed, ['a', 'b', 'b-win'])
@unittest.skip('crbug.com/986447, re-enable after merging crrev.com/c/1918294') @unittest.skip('crbug.com/986447, re-enable after merging crrev.com/c/1918294')
def test_lint_test_files(self): def test_lint_test_files(self):
options = optparse.Values({'platform': 'test-mac-mac10.10'}) options = optparse.Values({
'additional_expectations': [], 'platform': 'test-mac-mac10.10'})
host = MockHost() host = MockHost()
host.port_factory.all_port_names = lambda platform=None: [platform] host.port_factory.all_port_names = lambda platform=None: [platform]
@@ -123,7 +124,8 @@ class LintTest(LoggingTestCase):
self.assertEqual(res, []) self.assertEqual(res, [])
def test_lint_test_files_errors(self): def test_lint_test_files_errors(self):
options = optparse.Values({'platform': 'test', 'debug_rwt_logging': False}) options = optparse.Values({
'additional_expectations': [], 'platform': 'test', 'debug_rwt_logging': False})
host = MockHost() host = MockHost()
port = host.port_factory.get(options.platform, options=options) port = host.port_factory.get(options.platform, options=options)
@@ -140,7 +142,8 @@ class LintTest(LoggingTestCase):
self.assertIn('bar', all_logs) self.assertIn('bar', all_logs)
def test_extra_files_errors(self): def test_extra_files_errors(self):
options = optparse.Values({'platform': 'test', 'debug_rwt_logging': False}) options = optparse.Values({
'additional_expectations': [], 'platform': 'test', 'debug_rwt_logging': False})
host = MockHost() host = MockHost()
port = host.port_factory.get(options.platform, options=options) port = host.port_factory.get(options.platform, options=options)
@@ -157,7 +160,8 @@ class LintTest(LoggingTestCase):
self.assertIn('LeakExpectations', all_logs) self.assertIn('LeakExpectations', all_logs)
def test_lint_flag_specific_expectation_errors(self): def test_lint_flag_specific_expectation_errors(self):
options = optparse.Values({'platform': 'test', 'debug_rwt_logging': False}) options = optparse.Values({
'platform': 'test', 'debug_rwt_logging': False, 'additional_expectations': []})
host = MockHost() host = MockHost()
port = host.port_factory.get(options.platform, options=options) port = host.port_factory.get(options.platform, options=options)
@@ -175,7 +179,8 @@ class LintTest(LoggingTestCase):
self.assertNotIn('noproblem', all_logs) self.assertNotIn('noproblem', all_logs)
def test_lint_conflicts_in_test_expectations_between_os_and_os_version(self): def test_lint_conflicts_in_test_expectations_between_os_and_os_version(self):
options = optparse.Values({'platform': 'test', 'debug_rwt_logging': False}) options = optparse.Values({
'additional_expectations': [], 'platform': 'test', 'debug_rwt_logging': False})
host = MockHost() host = MockHost()
port = host.port_factory.get(options.platform, options=options) port = host.port_factory.get(options.platform, options=options)

@@ -64,6 +64,8 @@ intent = None
perf_control = None perf_control = None
# pylint: enable=invalid-name # pylint: enable=invalid-name
_friendly_browser_names = {
'weblayershell': 'weblayer', 'systemwebviewshell': 'webview', 'chromepublic': 'chromium'}
def _import_android_packages_if_necessary(): def _import_android_packages_if_necessary():
# pylint: disable=invalid-name # pylint: disable=invalid-name
@@ -143,8 +145,20 @@ TEST_RESOURCES_TO_PUSH = [
] ]
class DriverDetails(object):
def __init__(self, apk):
self._apk = apk
def apk_name(self):
return self._apk
# Information required when running web tests using content_shell as the test runner. # Information required when running web tests using content_shell as the test runner.
class ContentShellDriverDetails(): class ContentShellDriverDetails(DriverDetails):
def __init__(self):
super(ContentShellDriverDetails, self).__init__('apks/ContentShell.apk')
def device_cache_directory(self): def device_cache_directory(self):
return self.device_directory() + 'cache/' return self.device_directory() + 'cache/'
@@ -155,9 +169,6 @@ class ContentShellDriverDetails():
def device_fifo_directory(self): def device_fifo_directory(self):
return '/data/data/' + self.package_name() + '/files/' return '/data/data/' + self.package_name() + '/files/'
def apk_name(self):
return 'apks/ContentShell.apk'
def package_name(self): def package_name(self):
return 'org.chromium.content_shell_apk' return 'org.chromium.content_shell_apk'
@@ -244,36 +255,41 @@ class AndroidPort(base.Port):
BUILD_REQUIREMENTS_URL = 'https://www.chromium.org/developers/how-tos/android-build-instructions' BUILD_REQUIREMENTS_URL = 'https://www.chromium.org/developers/how-tos/android-build-instructions'
def __init__(self, host, port_name, **kwargs): def __init__(self, host, port_name='', apk='', options=None, **kwargs):
_import_android_packages_if_necessary() super(AndroidPort, self).__init__(host, port_name, options=options, **kwargs)
super(AndroidPort, self).__init__(host, port_name, **kwargs)
self._operating_system = 'android' self._operating_system = 'android'
self._version = 'kitkat' self._version = 'kitkat'
fs = host.filesystem
self._local_port = factory.PortFactory(host).get(**kwargs)
self._host_port = factory.PortFactory(host).get(**kwargs) if apk:
self._driver_details = DriverDetails(apk)
browser_type = fs.splitext(fs.basename(apk))[0].lower()
self._browser_type = _friendly_browser_names.get(browser_type, browser_type)
else:
# The legacy test runner will be used to run web tests on Android.
# So we need to initialize several port member variables.
_import_android_packages_if_necessary()
self._driver_details = ContentShellDriverDetails()
self._browser_type = 'content_shell'
self._debug_logging = self.get_option('android_logging')
self.server_process_constructor = self._android_server_process_constructor self.server_process_constructor = self._android_server_process_constructor
if not self.get_option('disable_breakpad'): if not self.get_option('disable_breakpad'):
self._dump_reader = DumpReaderAndroid(host, self._build_path()) self._dump_reader = DumpReaderAndroid(host, self._build_path())
if self.driver_name() != self.CONTENT_SHELL_NAME:
raise AssertionError('Web tests on Android only support content_shell as the driver.')
self._driver_details = ContentShellDriverDetails()
# Initialize the AndroidDevices class which tracks available devices. # Initialize the AndroidDevices class which tracks available devices.
default_devices = None default_devices = None
if hasattr(self._options, 'adb_devices') and len(self._options.adb_devices): if hasattr(self._options, 'adb_devices') and len(self._options.adb_devices):
default_devices = self._options.adb_devices default_devices = self._options.adb_devices
self._debug_logging = self.get_option('android_logging')
self._devices = AndroidDevices(default_devices, self._debug_logging) self._devices = AndroidDevices(default_devices, self._debug_logging)
devil_chromium.Initialize( devil_chromium.Initialize(
output_directory=self._build_path(), output_directory=self._build_path(),
adb_path=self._path_from_chromium_base( adb_path=self._path_from_chromium_base(
'third_party', 'android_sdk', 'public', 'platform-tools', 'adb')) 'third_party', 'android_sdk', 'public', 'platform-tools', 'adb'))
devil_env.config.InitializeLogging( devil_env.config.InitializeLogging(
logging.DEBUG logging.DEBUG
if self._debug_logging and self.get_option('debug_rwt_logging') if self._debug_logging and self.get_option('debug_rwt_logging')
@@ -283,6 +299,10 @@ class AndroidPort(base.Port):
for serial in prepared_devices: for serial in prepared_devices:
self._devices.set_device_prepared(serial) self._devices.set_device_prepared(serial)
def get_platform_tags(self):
_sanitize_tag = lambda t: t.replace('_', '-').replace(' ', '-')
return frozenset(['android', 'android-' + _sanitize_tag(self._browser_type)])
def default_smoke_test_only(self): def default_smoke_test_only(self):
return True return True
@@ -489,25 +509,25 @@ class AndroidPort(base.Port):
# Overridden protected methods. # Overridden protected methods.
def _build_path(self, *comps): def _build_path(self, *comps):
return self._host_port._build_path(*comps) return self._local_port._build_path(*comps)
def _build_path_with_target(self, target, *comps): def _build_path_with_target(self, target, *comps):
return self._host_port._build_path_with_target(target, *comps) return self._local_port._build_path_with_target(target, *comps)
def path_to_apache(self): def path_to_apache(self):
return self._host_port.path_to_apache() return self._local_port.path_to_apache()
def path_to_apache_config_file(self): def path_to_apache_config_file(self):
return self._host_port.path_to_apache_config_file() return self._local_port.path_to_apache_config_file()
def _path_to_driver(self, target=None): def _path_to_driver(self, target=None):
return self._build_path_with_target(target, self._driver_details.apk_name()) return self._build_path_with_target(target, self._driver_details.apk_name())
def _path_to_image_diff(self): def _path_to_image_diff(self):
return self._host_port._path_to_image_diff() return self._local_port._path_to_image_diff()
def _shut_down_http_server(self, pid): def _shut_down_http_server(self, pid):
return self._host_port._shut_down_http_server(pid) return self._local_port._shut_down_http_server(pid)
def _driver_class(self): def _driver_class(self):
return ChromiumAndroidDriver return ChromiumAndroidDriver

@@ -104,11 +104,6 @@ class AndroidPortTest(port_testcase.PortTestCase):
# FIXME: Do something useful here, but testing the full logic would be hard. # FIXME: Do something useful here, but testing the full logic would be hard.
pass pass
# Test that content_shell currently is the only supported driver.
def test_non_content_shell_driver(self):
with self.assertRaises(Exception):
self.make_port(options=optparse.Values({'driver_name': 'foobar'}))
# Test that the number of child processes to create depends on the devices. # Test that the number of child processes to create depends on the devices.
def test_default_child_processes(self): def test_default_child_processes(self):
port_default = self.make_port(device_count=5) port_default = self.make_port(device_count=5)
@@ -117,6 +112,16 @@ class AndroidPortTest(port_testcase.PortTestCase):
self.assertEquals(6, port_default.default_child_processes()) self.assertEquals(6, port_default.default_child_processes())
self.assertEquals(1, port_fixed_device.default_child_processes()) self.assertEquals(1, port_fixed_device.default_child_processes())
def test_weblayer_expectation_tags(self):
host = MockSystemHost()
port = android.AndroidPort(host, apk='apks/WebLayerShell.apk')
self.assertEqual(port.get_platform_tags(), set(['android', 'android-weblayer']))
def test_content_shell_expectation_tags(self):
host = MockSystemHost()
port = android.AndroidPort(host)
self.assertEqual(port.get_platform_tags(), set(['android', 'android-content-shell']))
# Test that an HTTP server indeed is required by Android (as we serve all tests over them) # Test that an HTTP server indeed is required by Android (as we serve all tests over them)
def test_requires_http_server(self): def test_requires_http_server(self):
self.assertTrue(self.make_port(device_count=1).requires_http_server()) self.assertTrue(self.make_port(device_count=1).requires_http_server())
@@ -128,7 +133,7 @@ class AndroidPortTest(port_testcase.PortTestCase):
def test_path_to_apache_config_file(self): def test_path_to_apache_config_file(self):
port = self.make_port() port = self.make_port()
port._host_port.path_to_apache_config_file = lambda: '/host/apache/conf' # pylint: disable=protected-access port._local_port.path_to_apache_config_file = lambda: '/host/apache/conf' # pylint: disable=protected-access
self.assertEqual(port.path_to_apache_config_file(), '/host/apache/conf') self.assertEqual(port.path_to_apache_config_file(), '/host/apache/conf')
@@ -201,9 +206,11 @@ class ChromiumAndroidDriverTwoDriversTest(unittest.TestCase):
def test_two_drivers(self): def test_two_drivers(self):
port = android.AndroidPort(MockSystemHost(executive=MockExecutive()), 'android') port = android.AndroidPort(MockSystemHost(executive=MockExecutive()), 'android')
driver0 = android.ChromiumAndroidDriver(port, worker_number=0, driver0 = android.ChromiumAndroidDriver(port, worker_number=0,
driver_details=android.ContentShellDriverDetails(), android_devices=port._devices) driver_details=android.ContentShellDriverDetails(),
android_devices=port._devices)
driver1 = android.ChromiumAndroidDriver(port, worker_number=1, driver1 = android.ChromiumAndroidDriver(port, worker_number=1,
driver_details=android.ContentShellDriverDetails(), android_devices=port._devices) driver_details=android.ContentShellDriverDetails(),
android_devices=port._devices)
self.assertEqual(['adb', '-s', '123456789ABCDEF0', 'shell'], driver0.cmd_line([])) self.assertEqual(['adb', '-s', '123456789ABCDEF0', 'shell'], driver0.cmd_line([]))
self.assertEqual(['adb', '-s', '123456789ABCDEF1', 'shell'], driver1.cmd_line(['anything'])) self.assertEqual(['adb', '-s', '123456789ABCDEF1', 'shell'], driver1.cmd_line(['anything']))

@@ -1428,6 +1428,9 @@ class Port(object):
_log.debug("reading additional_expectations from path '%s'", path) _log.debug("reading additional_expectations from path '%s'", path)
expectations[path] = self._filesystem.read_text_file(expanded_path) expectations[path] = self._filesystem.read_text_file(expanded_path)
else: else:
# TODO(rmhasan): Fix additional expectation paths for
# not_site_per_process_blink_web_tests, then change this back
# to raising exceptions for incorrect expectation paths.
_log.warning("additional_expectations path '%s' does not exist", path) _log.warning("additional_expectations path '%s' does not exist", path)
return expectations return expectations

@@ -371,12 +371,6 @@ class PortTest(LoggingTestCase):
{'additional_expectations': ['/tmp/additional-expectations-1.txt']}) {'additional_expectations': ['/tmp/additional-expectations-1.txt']})
self.assertEqual(port.expectations_dict().values(), ['content1\n']) self.assertEqual(port.expectations_dict().values(), ['content1\n'])
def test_additional_expectations_nonexistent_and_1(self):
port = self._make_port_for_test_additional_expectations(
{'additional_expectations': ['/tmp/nonexistent-file',
'/tmp/additional-expectations-1.txt']})
self.assertEqual(port.expectations_dict().values(), ['content1\n'])
def test_additional_expectations_2(self): def test_additional_expectations_2(self):
port = self._make_port_for_test_additional_expectations( port = self._make_port_for_test_additional_expectations(
{'additional_expectations': ['/tmp/additional-expectations-1.txt', {'additional_expectations': ['/tmp/additional-expectations-1.txt',

@@ -8,6 +8,7 @@ import optparse
import sys import sys
from blinkpy.common.host import Host from blinkpy.common.host import Host
from blinkpy.web_tests.port.android import AndroidPort
from blinkpy.w3c.wpt_metadata_builder import WPTMetadataBuilder from blinkpy.w3c.wpt_metadata_builder import WPTMetadataBuilder
from blinkpy.web_tests.models.test_expectations import TestExpectations from blinkpy.web_tests.models.test_expectations import TestExpectations
@@ -16,10 +17,18 @@ def main(args):
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--additional-expectations", action="append", parser.add_argument("--additional-expectations", action="append",
help="Paths to additional expectations files for WPT.") help="Paths to additional expectations files for WPT.")
known_args, rest_args = parser.parse_known_args(args) parser.add_argument("--android-apk", default=None,
help="Path to Android APK that is being tested")
known_args, rest_args = parser.parse_known_args(args)
options = optparse.Values(vars(known_args))
host = Host() host = Host()
port = host.port_factory.get(options=optparse.Values(vars(known_args)))
if known_args.android_apk:
port = AndroidPort(host, apk=known_args.android_apk, options=options)
else:
port = host.port_factory.get(options=options)
expectations = TestExpectations(port) expectations = TestExpectations(port)
metadata_builder = WPTMetadataBuilder(expectations, port) metadata_builder = WPTMetadataBuilder(expectations, port)
sys.exit(metadata_builder.run(rest_args)) sys.exit(metadata_builder.run(rest_args))

@@ -0,0 +1,6 @@
# tags: [ android-weblayer ]
# results: [ Skip ]
# This expectations file will disable tests for functionality which there are no
# plans to implement in any of the Android browsers.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@@ -207,6 +207,6 @@ python_library("weblayer_shell_wpt") {
":weblayer_support_apk", ":weblayer_support_apk",
"//build/android:test_runner_py", "//build/android:test_runner_py",
"//chrome/test/chromedriver:chromedriver($host_toolchain)", "//chrome/test/chromedriver:chromedriver($host_toolchain)",
"//third_party/blink/tools:wpt_tests_android_isolate",
] ]
data = [ "//third_party/blink/web_tests/external/" ]
} }