blob: fb6dc32a340b63132af2eef63af371f67d770424 [file] [log] [blame]
#!/usr/bin/python
# Copyright (c) 2012 The Native Client 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 optparse
import os
import re
import sys
import tempfile
sys.path.append(os.path.join(os.path.dirname(__file__), '../../'))
import pynacl.file_tools
import corpus_errors
import corpus_utils
def TestAppStartup(options, crx_path, app_path, profile_path):
"""Run the validator on a nexe, check if the result is expected.
Args:
options: bag of options.
crx_path: path to the crx.
app_path: path to the extracted crx.
profile_path: path to a temporary profile dir.
"""
expected_result = corpus_errors.ExpectedCrxResult(crx_path)
try:
manifest = corpus_utils.LoadManifest(app_path)
start_path = manifest.get('app').get('launch').get('local_path')
except:
if expected_result.Matches(corpus_errors.BAD_MANIFEST):
return True
else:
print "'%s': %s," % (
corpus_utils.Sha1FromFilename(crx_path), corpus_errors.BAD_MANIFEST)
return False
start_url = 'chrome-extension://%s/%s' % (
corpus_utils.ChromeAppIdFromPath(app_path), start_path)
cmd = [options.browser,
'--disable-web-resources',
'--disable-preconnect',
'--no-first-run',
'--no-default-browser-check',
'--enable-logging',
'--log-level=1',
'--safebrowsing-disable-auto-update',
'--enable-nacl',
'--load-extension=' + app_path,
'--user-data-dir=' + profile_path, start_url]
process_stdout, process_stderr, retcode = corpus_utils.RunWithTimeout(
cmd, options.duration)
# Check for errors we don't like.
result = corpus_errors.GOOD
errs = re.findall(':ERROR:[^\n]+', process_stderr)
for err in errs:
if 'extension_prefs.cc' in err or 'gles2_cmd_decoder.cc' in err:
continue
if 'Extension error: Could not load extension from' in err:
result = result.Merge(corpus_errors.COULD_NOT_LOAD)
continue
if 'NaCl process exited with' in process_stderr:
result = result.Merge(corpus_errors.MODULE_CRASHED)
continue
result = result.Merge(corpus_errors.CrxResult(
'custom', custom=err, precidence=20))
if 'NaClMakePcrelThunk:' not in process_stderr:
result = result.Merge(corpus_errors.MODULE_DIDNT_START)
# Check if result is what we expect.
if not expected_result.Matches(result):
print "'%s': %s," % (corpus_utils.Sha1FromFilename(crx_path), result)
if options.verbose:
print '-' * 70
print 'Return code: %s' % retcode
print '>>> STDOUT'
print process_stdout
print '>>> STDERR'
print process_stderr
print '-' * 70
return False
return True
def TestApps(options, work_dir):
"""Test a browser on a corpus of crxs.
Args:
options: bag of options.
work_dir: directory to operate in.
"""
profile_path = os.path.join(work_dir, 'profile_temp')
app_path = os.path.join(work_dir, 'app_temp')
list_filename = os.path.join(work_dir, 'naclapps.all')
filenames = corpus_utils.DownloadCorpusList(list_filename)
filenames = [f for f in filenames if f.endswith('.crx')]
progress = corpus_utils.Progress(len(filenames))
for filename in filenames:
progress.Tally()
corpus_utils.PrimeCache(options.cache_dir, filename)
# Stop here if downloading only.
if options.download_only:
continue
# Stop here if isn't a bad app but testing only bad apps.
if options.bad_only and corpus_errors.ExpectedCrxResult(filename) == 'GOOD':
continue
# Unzip the app.
corpus_utils.ExtractFromCache(options.cache_dir, filename, app_path)
try:
progress.Result(
TestAppStartup(options, filename, app_path, profile_path))
finally:
pynacl.file_tools.RemoveDirectoryIfPresent(app_path)
pynacl.file_tools.RemoveDirectoryIfPresent(profile_path)
progress.Summary()
def Main():
# TODO(bradnelson): Stderr scraping doesn't work on windows, find another
# way if we want to run there.
if sys.platform in ['cygwin', 'win32']:
raise Exception('Platform not yet supported')
parser = optparse.OptionParser()
parser.add_option(
'--download-only', dest='download_only',
default=False, action='store_true',
help='download to cache without running the tests')
parser.add_option(
'--duration', dest='duration', default=30,
help='how long to run each app for')
parser.add_option(
'--browser', dest='browser',
help='browser to run')
parser.add_option(
'-v', '--verbose', dest='verbose', default=False, action='store_true',
help='run in verbose mode')
parser.add_option(
'--bad-only', dest='bad_only', default=False, action='store_true',
help='test only known bad apps')
parser.add_option(
'--cache-dir', dest='cache_dir',
default=corpus_utils.DefaultCacheDirectory(),
help='directory to cache downloads in')
options, args = parser.parse_args()
if args:
parser.error('unused arguments')
if not options.download_only:
if not options.browser:
parser.error('no browser specified')
work_dir = tempfile.mkdtemp(suffix='startup_crxs', prefix='tmp')
work_dir = os.path.realpath(work_dir)
try:
TestApps(options, work_dir)
finally:
pynacl.file_tools.RemoveDirectoryIfPresent(work_dir)
if __name__ == '__main__':
Main()