OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 # Copyright (c) 2012 The Native Client Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 import optparse |
| 7 import os |
| 8 import re |
| 9 import sys |
| 10 import tempfile |
| 11 |
| 12 import corpus_errors |
| 13 import corpus_utils |
| 14 |
| 15 |
| 16 def TestAppStartup(options, crx_path, app_path, profile_path): |
| 17 """Run the validator on a nexe, check if the result is expected. |
| 18 |
| 19 Args: |
| 20 options: bag of options. |
| 21 crx_path: path to the crx. |
| 22 app_path: path to the extracted crx. |
| 23 profile_path: path to a temporary profile dir. |
| 24 """ |
| 25 expected_result = corpus_errors.ExpectedCrxResult(crx_path) |
| 26 try: |
| 27 manifest = corpus_utils.LoadManifest(app_path) |
| 28 start_path = manifest.get('app').get('launch').get('local_path') |
| 29 except: |
| 30 if expected_result.Matches(corpus_errors.BAD_MANIFEST): |
| 31 return True |
| 32 else: |
| 33 print "'%s': %s," % ( |
| 34 corpus_utils.Sha1FromFilename(crx_path), corpus_errors.BAD_MANIFEST) |
| 35 return False |
| 36 start_url = 'chrome-extension://%s/%s' % ( |
| 37 corpus_utils.ChromeAppIdFromPath(app_path), start_path) |
| 38 cmd = [options.browser, |
| 39 '--disable-web-resources', |
| 40 '--disable-preconnect', |
| 41 '--no-first-run', |
| 42 '--no-default-browser-check', |
| 43 '--enable-logging', |
| 44 '--log-level=1', |
| 45 '--safebrowsing-disable-auto-update', |
| 46 '--enable-nacl', |
| 47 '--load-extension=' + app_path, |
| 48 '--user-data-dir=' + profile_path, start_url] |
| 49 process_stdout, process_stderr, retcode = corpus_utils.RunWithTimeout( |
| 50 cmd, options.duration) |
| 51 # Check for errors we don't like. |
| 52 result = corpus_errors.GOOD |
| 53 errs = re.findall(':ERROR:[^\n]+', process_stderr) |
| 54 for err in errs: |
| 55 if 'extension_prefs.cc' in err or 'gles2_cmd_decoder.cc' in err: |
| 56 continue |
| 57 if 'Extension error: Could not load extension from' in err: |
| 58 result = result.Merge(corpus_errors.COULD_NOT_LOAD) |
| 59 continue |
| 60 if 'NaCl process exited with' in process_stderr: |
| 61 result = result.Merge(corpus_errors.MODULE_CRASHED) |
| 62 continue |
| 63 result = result.Merge(corpus_errors.CrxResult( |
| 64 'custom', custom=err, precidence=20)) |
| 65 if 'NaClMakePcrelThunk:' not in process_stderr: |
| 66 result = result.Merge(corpus_errors.MODULE_DIDNT_START) |
| 67 # Check if result is what we expect. |
| 68 if not expected_result.Matches(result): |
| 69 print "'%s': %s," % (corpus_utils.Sha1FromFilename(crx_path), result) |
| 70 if options.verbose: |
| 71 print '-' * 70 |
| 72 print 'Return code: %s' % retcode |
| 73 print '>>> STDOUT' |
| 74 print process_stdout |
| 75 print '>>> STDERR' |
| 76 print process_stderr |
| 77 print '-' * 70 |
| 78 return False |
| 79 return True |
| 80 |
| 81 |
| 82 def TestApps(options, work_dir): |
| 83 """Test a browser on a corpus of crxs. |
| 84 |
| 85 Args: |
| 86 options: bag of options. |
| 87 work_dir: directory to operate in. |
| 88 """ |
| 89 profile_path = os.path.join(work_dir, 'profile_temp') |
| 90 app_path = os.path.join(work_dir, 'app_temp') |
| 91 |
| 92 list_filename = os.path.join(work_dir, 'naclapps.all') |
| 93 filenames = corpus_utils.DownloadCorpusCRXList(list_filename) |
| 94 progress = corpus_utils.Progress(len(filenames)) |
| 95 for filename in filenames: |
| 96 progress.Tally() |
| 97 corpus_utils.PrimeCache(options.cache_dir, filename) |
| 98 # Stop here if downloading only. |
| 99 if options.download_only: |
| 100 continue |
| 101 # Stop here if isn't a bad app but testing only bad apps. |
| 102 if options.bad_only and corpus_errors.ExpectedCrxResult(filename) == 'GOOD': |
| 103 continue |
| 104 # Unzip the app. |
| 105 corpus_utils.ExtractFromCache(options.cache_dir, filename, app_path) |
| 106 try: |
| 107 progress.Result( |
| 108 TestAppStartup(options, filename, app_path, profile_path)) |
| 109 finally: |
| 110 corpus_utils.RemoveDir(app_path) |
| 111 corpus_utils.RemoveDir(profile_path) |
| 112 progress.Summary() |
| 113 |
| 114 |
| 115 def Main(): |
| 116 # TODO(bradnelson): Stderr scraping doesn't work on windows, find another |
| 117 # way if we want to run there. |
| 118 if sys.platform in ['cygwin', 'win32']: |
| 119 raise Exception('Platform not yet supported') |
| 120 |
| 121 parser = optparse.OptionParser() |
| 122 parser.add_option( |
| 123 '--download-only', dest='download_only', |
| 124 default=False, action='store_true', |
| 125 help='download to cache without running the tests') |
| 126 parser.add_option( |
| 127 '--duration', dest='duration', default=30, |
| 128 help='how long to run each app for') |
| 129 parser.add_option( |
| 130 '--browser', dest='browser', |
| 131 help='browser to run') |
| 132 parser.add_option( |
| 133 '-v', '--verbose', dest='verbose', default=False, action='store_true', |
| 134 help='run in verbose mode') |
| 135 parser.add_option( |
| 136 '--bad-only', dest='bad_only', default=False, action='store_true', |
| 137 help='test only known bad apps') |
| 138 parser.add_option( |
| 139 '--cache-dir', dest='cache_dir', |
| 140 default=corpus_utils.DefaultCacheDirectory(), |
| 141 help='directory to cache downloads in') |
| 142 options, args = parser.parse_args() |
| 143 if args: |
| 144 parser.error('unused arguments') |
| 145 if not options.download_only: |
| 146 if not options.browser: |
| 147 parser.error('no browser specified') |
| 148 |
| 149 work_dir = tempfile.mkdtemp(suffix='startup_crxs', prefix='tmp') |
| 150 work_dir = os.path.realpath(work_dir) |
| 151 try: |
| 152 TestApps(options, work_dir) |
| 153 finally: |
| 154 corpus_utils.RemoveDir(work_dir) |
| 155 |
| 156 |
| 157 if __name__ == '__main__': |
| 158 Main() |
OLD | NEW |