Commit c10750cf authored by Peter Kotwicz's avatar Peter Kotwicz Committed by Commit Bot

Convert monochrome_apk_checker.py to typ

The benefit of converting the test to typ is that it makes adding other
monochrome tests easier.

BUG=1115604

Change-Id: Id36ae6cc9e60efa27d54a1f37f39f7004b9c3619
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2456189
Commit-Queue: Peter Kotwicz <pkotwicz@chromium.org>
Reviewed-by: default avatarAndrew Grieve <agrieve@chromium.org>
Reviewed-by: default avatarDirk Pranke <dpranke@google.com>
Cr-Commit-Position: refs/heads/master@{#814863}
parent 8e18b7f3
......@@ -4,7 +4,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import re
import os
import posixpath
......@@ -14,6 +13,16 @@ import subprocess
from contextlib import closing
CUR_DIR = os.path.dirname(os.path.realpath(__file__))
SRC_DIR = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.dirname(CUR_DIR))))
TYP_DIR = os.path.join(
SRC_DIR, 'third_party', 'catapult', 'third_party', 'typ')
if TYP_DIR not in sys.path:
sys.path.insert(0, TYP_DIR)
import typ
def BuildFileMatchRegex(*file_matchers):
return re.compile('^' + '|'.join(file_matchers) + '$')
......@@ -141,7 +150,13 @@ def DumpAPK(apk):
match.group('cmpr') == 0))
return apk_entries
def VerifySameFile(monochrome_dict, apk, changes, apk_name):
def DeobfuscateFilename(obfuscated_filename, pathmap):
return pathmap.get(obfuscated_filename, obfuscated_filename)
class MonochromeApkCheckerTest(typ.TestCase):
def VerifySameFile(self, monochrome_dict, apk, changes, apk_name):
"""Verify apk file content matches same files in monochrome.
Verify files from apk are same as those in monochrome except files
......@@ -153,17 +168,15 @@ def VerifySameFile(monochrome_dict, apk, changes, apk_name):
m = monochrome_dict.get(a.filename)
if m and m.CRC != a.CRC and not changes.match(m.filename):
diff.append(a.filename)
if len(diff):
msg = """\
self.assertEquals(len(diff), 0, """\
Unless specifcially excepted, all files in {0} should be exactly the same as
the similarly named file in Monochrome. However these files were present in
both monochrome and {0}, but had different contents:
{1}
""".format(apk_name, '\n'.join(diff))
raise Exception(msg)
""".format(apk_name, '\n'.join(diff)))
def VerifyUncompressed(monochrome, apk, apk_name):
def VerifyUncompressed(self, monochrome, apk, apk_name):
"""Verify uncompressed files in apk are a subset of those in monochrome.
Verify files not being compressed in apk are also uncompressed in
......@@ -172,16 +185,14 @@ def VerifyUncompressed(monochrome, apk, apk_name):
uncompressed = [i.filename for i in apk if i.uncompressed ]
monochrome_uncompressed = [i.filename for i in monochrome if i.uncompressed]
compressed = [u for u in uncompressed if u not in monochrome_uncompressed]
if len(compressed):
msg = """\
self.assertEquals(len(compressed), 0, """\
Uncompressed files in {0} should also be uncompressed in Monochrome.
However these files were uncompressed in {0} but compressed in Monochrome:
{1}
""".format(apk_name, '\n'.join(compressed))
raise Exception(msg)
""".format(apk_name, '\n'.join(compressed)))
def SuperSetOf(monochrome, apk, apk_name):
def SuperSetOf(self, monochrome, apk, apk_name):
"""Verify Monochrome is super set of apk."""
def exists_in_some_form(f):
......@@ -198,21 +209,19 @@ def SuperSetOf(monochrome, apk, apk_name):
return any(x.endswith(name) for x in monochrome)
missing_files = [f for f in apk if not exists_in_some_form(f)]
if len(missing_files):
msg = """\
self.assertEquals(len(missing_files), 0, """\
Monochrome is expected to have a superset of the files in {0}.
However these files were present in {0} but not in Monochrome:
{1}
""".format(apk_name, '\n'.join(missing_files))
raise Exception(msg)
""".format(apk_name, '\n'.join(missing_files)))
def RemoveSpecific(apk_entries, specific):
def RemoveSpecific(self, apk_entries, specific):
return [i for i in apk_entries
if not specific.search(i.filename) ]
def LoadPathmap(pathmap_path):
def LoadPathmap(self, pathmap_path):
"""Load the pathmap of obfuscated resource paths.
Returns: A dict mapping from obfuscated paths to original paths or an
......@@ -232,87 +241,41 @@ def LoadPathmap(pathmap_path):
return pathmap
def DeobfuscateFilename(obfuscated_filename, pathmap):
return pathmap.get(obfuscated_filename, obfuscated_filename)
def testApkChecker(self):
options = self.context
def ParseArgs(args):
"""Parses command line options.
Returns:
An Namespace from argparse.parse_args()
"""
parser = argparse.ArgumentParser(
prog='monochrome_apk_checker',
description='This script enforces expectations about similarities '
'between Chrome, Monochrome and Webview APKs.',
epilog='If the release APK is obfuscated, you will find its pathmap next '
'to the apk in your output directory, ending with ".pathmap".')
required_args = parser.add_argument_group('required arguments')
required_args.add_argument(
'--monochrome-apk', required=True, help='The path to the monochrome APK.')
parser.add_argument(
'--monochrome-pathmap', help='The monochrome APK resources pathmap path.')
required_args.add_argument(
'--chrome-apk',
required=True,
help='The path to the chrome APK.')
parser.add_argument(
'--chrome-pathmap', help='The chrome APK resources pathmap path.')
required_args.add_argument(
'--system-webview-apk',
required=True,
help='The path to the system webview APK.')
parser.add_argument(
'--system-webview-pathmap',
help='The system webview APK resources pathmap path.')
# This script is called from test bots that sometimes would add extra unneeded
# arguments. Just ignore unknown ones. crbug.com/1084351
parsed, _ = parser.parse_known_args(args)
return parsed
def main():
options = ParseArgs(sys.argv[1:])
monochrome = DumpAPK(options.monochrome_apk)
monochrome_pathmap = LoadPathmap(options.monochrome_pathmap)
monochrome_pathmap = self.LoadPathmap(options.monochrome_pathmap)
monochrome_files = [
DeobfuscateFilename(f.filename, monochrome_pathmap) for f in monochrome
DeobfuscateFilename(f.filename, monochrome_pathmap)
for f in monochrome
]
monochrome_dict = dict([(DeobfuscateFilename(i.filename, monochrome_pathmap),
i) for i in monochrome])
chrome = RemoveSpecific(DumpAPK(options.chrome_apk),
chrome = self.RemoveSpecific(DumpAPK(options.chrome_apk),
CHROME_SPECIFIC)
if len(chrome) == 0:
raise Exception(
self.assertTrue(len(chrome) > 0,
'Chrome should have common files with Monochrome. However the passed '
'in APKs do not have any files in common. Are you sure you are passing '
'in the right arguments?')
webview = RemoveSpecific(DumpAPK(options.system_webview_apk),
webview = self.RemoveSpecific(DumpAPK(options.system_webview_apk),
WEBVIEW_SPECIFIC)
if len(webview) == 0:
raise Exception(
self.assertTrue(len(webview) > 0,
'Webview should have common files with Monochrome. However the passed '
'in APKs do not have any files in common. Are you sure you are passing '
'in the right arguments?')
def check_apk(apk, pathmap, apk_name):
apk_files = [DeobfuscateFilename(f.filename, pathmap) for f in apk]
SuperSetOf(monochrome_files, apk_files, apk_name)
VerifyUncompressed(monochrome, apk, apk_name)
self.SuperSetOf(monochrome_files, apk_files, apk_name)
self.VerifyUncompressed(monochrome, apk, apk_name)
chrome_pathmap = LoadPathmap(options.chrome_pathmap)
chrome_pathmap = self.LoadPathmap(options.chrome_pathmap)
check_apk(chrome, chrome_pathmap, 'Chrome')
VerifySameFile(monochrome_dict, chrome, CHROME_CHANGES, 'Chrome')
self.VerifySameFile(monochrome_dict, chrome, CHROME_CHANGES, 'Chrome')
webview_pathmap = LoadPathmap(options.system_webview_pathmap)
webview_pathmap = self.LoadPathmap(options.system_webview_pathmap)
check_apk(webview, webview_pathmap, 'Webview')
VerifySameFile(monochrome_dict, webview, WEBVIEW_CHANGES, 'Webview')
if __name__ == '__main__':
sys.exit(main())
self.VerifySameFile(monochrome_dict, webview, WEBVIEW_CHANGES, 'Webview')
#!/usr/bin/env python2.7
#
# Copyright 2020 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import sys
CUR_DIR = os.path.dirname(os.path.realpath(__file__))
SRC_DIR = os.path.dirname(
os.path.dirname(os.path.dirname(os.path.dirname(CUR_DIR))))
TYP_DIR = os.path.join(
SRC_DIR, 'third_party', 'catapult', 'third_party', 'typ')
if TYP_DIR not in sys.path:
sys.path.insert(0, TYP_DIR)
import typ
def create_argument_parser():
""" Creates command line parser. """
parser = typ.ArgumentParser()
required_args = parser.add_argument_group('required arguments')
required_args.add_argument(
'--monochrome-apk', required=True, help='The path to the monochrome APK.')
parser.add_argument(
'--monochrome-pathmap', help='The monochrome APK resources pathmap path.')
required_args.add_argument(
'--chrome-apk',
required=True,
help='The path to the chrome APK.')
parser.add_argument(
'--chrome-pathmap', help='The chrome APK resources pathmap path.')
required_args.add_argument(
'--system-webview-apk',
required=True,
help='The path to the system webview APK.')
parser.add_argument(
'--system-webview-pathmap',
help='The system webview APK resources pathmap path.')
return parser
def main(argv):
argument_parser = create_argument_parser()
runner = typ.Runner()
runner.parse_args(argument_parser, argv[1:])
runner.args.top_level_dirs = [ os.path.dirname(__file__) ]
runner.context = runner.args
# Needs to be set to enable customizing runner.context
runner.win_multiprocessing = typ.WinMultiprocessing.importable
return_code, _, _ = runner.run()
return return_code
if __name__ == '__main__':
sys.exit(main(sys.argv))
......@@ -1249,8 +1249,7 @@
},
"monochrome_apk_checker": {
"args": [
"--script",
"../../chrome/android/monochrome/scripts/monochrome_apk_checker.py",
"../../chrome/android/monochrome/scripts/monochrome_python_tests.py",
"--chrome-apk",
"apks/ChromePublic.apk",
"--chrome-pathmap",
......@@ -1265,7 +1264,7 @@
"apks/MonochromePublic.apk.pathmap.txt",
],
"label": "//chrome/android/monochrome:monochrome_apk_checker",
"script": "//testing/scripts/monochrome_apk_checker_wrapper.py",
"script": "//testing/scripts/run_isolated_script_test.py",
"type": "script",
},
"monochrome_public_test_ar_apk": {
......
#!/usr/bin/env python
#
# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# This is just a wrapper script around monochrome_apk_checker.py that
# understands and uses the isolated-script arguments
import argparse
import json
import os
import sys
import subprocess
import time
import common
def _PathExists(path):
return path is not None and os.path.exists(path)
def _ForwardOptionalArgs(args):
forwardable_args = []
if _PathExists(args.monochrome_pathmap):
forwardable_args += ['--monochrome-pathmap', args.monochrome_pathmap]
if _PathExists(args.chrome_pathmap):
forwardable_args += ['--chrome-pathmap', args.chrome_pathmap]
if _PathExists(args.system_webview_pathmap):
forwardable_args += [
'--system-webview-pathmap', args.system_webview_pathmap
]
return forwardable_args
def main():
parser = argparse.ArgumentParser(prog='monochrome_apk_checker_wrapper')
parser.add_argument('--script',
required=True,
help='The path to the monochrome_apk_checker.py script')
parser.add_argument('--isolated-script-test-output',
required=True)
# Only run one test, we check that it's the test we expect.
parser.add_argument('--isolated-script-test-filter')
# Ignored, but required to satisfy the isolated_script interface.
# We aren't a perf test, so don't have any perf output.
parser.add_argument('--isolated-script-test-perf-output')
# We must intercept the pathmap args since they are always passed by the
# trybots but the files in question may not actually exist (path shortening
# may not be enabled for all apks). Check if the files exist and forward the
# arg iff they are.
parser.add_argument(
'--monochrome-pathmap', help='The monochrome APK resources pathmap path.')
parser.add_argument(
'--chrome-pathmap', help='The chrome APK resources pathmap path.')
parser.add_argument(
'--system-webview-pathmap',
help='The system webview APK resources pathmap path.')
args, extra = parser.parse_known_args(sys.argv[1:])
if args.isolated_script_test_filter and (
'monochrome_apk_checker' not in args.isolated_script_test_filter):
parser.error('isolated-script-test-filter has invalid test: %s' %
(args.isolated_script_test_filter))
cmd = [args.script] + extra + _ForwardOptionalArgs(args)
start_time = time.time()
ret = subprocess.call(cmd)
success = ret == 0
# Schema is at //docs/testing/json_test_results_format.md
with open(args.isolated_script_test_output, 'w') as fp:
test = {
'expected': 'PASS',
'actual': 'PASS' if success else 'FAIL',
}
if not success:
test['is_unexpected'] = True
json.dump({
'version': 3,
'interrupted': False,
'path_delimiter': '/',
'seconds_since_epoch': start_time,
'num_failures_by_type': {
'PASS': int(success),
'FAIL': int(not success),
},
'tests': {
'monochrome_apk_checker': test,
}
}, fp)
return ret
# This is not really a "script test" so does not need to manually add
# any additional compile targets.
def main_compile_targets(args):
json.dump([], args.output)
if __name__ == '__main__':
# Conform minimally to the protocol defined by ScriptTest.
if 'compile_targets' in sys.argv:
funcs = {
'run': None,
'compile_targets': main_compile_targets,
}
sys.exit(common.run_script(sys.argv[1:], funcs))
sys.exit(main())
......@@ -59,6 +59,7 @@ KNOWN_TYP_TEST_RUNNERS = {
'metrics_python_tests.py',
'run_mac_signing_tests.py',
'run_polymer_tools_tests.py',
'monochrome_python_tests.py',
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment