Chromium Code Reviews| 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_utils | |
| 13 | |
| 14 | |
| 15 BAD_MANIFEST = r'^BAD MANIFEST!$' | |
|
Nick Bray
2012/04/03 20:34:29
Gratuitous raw string.
bradn
2012/04/12 17:45:54
Done.
| |
| 16 NACL_MODULE_CRASHED = '^nacl module crashed$' | |
| 17 NACL_MODULE_DIDNT_START = '^nacl module not started$' | |
| 18 KNOWN_BAD = { | |
|
Nick Bray
2012/04/03 20:34:29
Very optional: you could split this config stuff o
bradn
2012/04/12 17:45:54
Done.
| |
| 19 # Bad manifest | |
| 20 '0937b653af5553856532454ec340d0e0075bc0b4': BAD_MANIFEST, | |
| 21 '09ffe3793113fe564b71800a5844189c00bd8210': BAD_MANIFEST, | |
| 22 '14f389a8c406d60e0fc05a1ec0189a652a1f006e': BAD_MANIFEST, | |
| 23 '2f97cec9f13b0f774d1f49490f26f32213e4e0a5': BAD_MANIFEST, | |
| 24 '3d6832749c8c1346c65b30f4b191930dec5f04a3': BAD_MANIFEST, | |
| 25 '612a5aaa821b4b636168025f027e721c0f046e7c': BAD_MANIFEST, | |
| 26 '81a4a3de69dd4ad169b1d4a7268b44c78ea5ffa8': BAD_MANIFEST, | |
| 27 'a8aa42d699dbef3e1403e4fdc49325e89a91f653': BAD_MANIFEST, | |
| 28 'c6d40d4f3c8dccc710d8c09bfd074b2d20a504d2': BAD_MANIFEST, | |
| 29 'ced1fea90b71b0a8da08c1a1e6cb35975cc84f52': BAD_MANIFEST, | |
| 30 # Bad permissions | |
| 31 '8de65668cc7280ffb70ffd2fa5b2a22112156966': ( | |
| 32 r'^unknown error: :ERROR:extension_error_reporter.cc\(.*\)\] ' | |
| 33 r'Extension error: Could not load extension from \'.*\'\. ' | |
| 34 r'Access to permission \'terminalPrivate\' denied\.$'), | |
| 35 # No nacl module | |
| 36 '1f861c0d8c173b64df3e70cfa1a5cd710ba59430': NACL_MODULE_DIDNT_START, | |
| 37 '48ac71edfeac0c79d5e2b651e082abfa76da25f9': NACL_MODULE_DIDNT_START, | |
| 38 '4beecff67651f13e013c12a5bf3661041ded323c': NACL_MODULE_DIDNT_START, | |
| 39 '57be161e5ff7011d2283e507a70f9005c448002b': NACL_MODULE_DIDNT_START, | |
| 40 '5b9f0f7f7401cb666015090908d97346f5b6bccb': NACL_MODULE_DIDNT_START, | |
| 41 'cfd62adf6790eed0520da2deb2246fc02e70c57e': NACL_MODULE_DIDNT_START, | |
| 42 'd1f33ad38f9f6e78150d30c2103b5c77a9f0adcd': NACL_MODULE_DIDNT_START, | |
| 43 'd51802b12a503f7fdfbec60d96e27a5ffa09d002': NACL_MODULE_DIDNT_START, | |
| 44 # Nacl module crash | |
| 45 'ab0692192976dc6693212582364c6f23b6551d1a': NACL_MODULE_CRASHED, | |
| 46 'b458cd57c8b4e6c313b18f370fad59779f573afc': NACL_MODULE_CRASHED, | |
| 47 } | |
| 48 # Precompile the above regexs. | |
| 49 for key in KNOWN_BAD: | |
| 50 KNOWN_BAD[key] = re.compile(KNOWN_BAD[key]) | |
| 51 | |
| 52 | |
| 53 def ExpectedResult(path): | |
| 54 """Checks what the expected result for this app is. | |
| 55 | |
| 56 Args: | |
| 57 path: path to the crx. | |
| 58 Returns: | |
| 59 Reg-ex that matches the expected status. | |
| 60 """ | |
| 61 return KNOWN_BAD.get( | |
| 62 corpus_utils.Sha1FromFilename(path), re.compile('^GOOD$')) | |
| 63 | |
| 64 | |
| 65 def TestAppStartup(options, crx_path, app_path, profile_path): | |
| 66 """Run the validator on a nexe, check if the result is expected. | |
| 67 | |
| 68 Args: | |
| 69 options: bag of options. | |
| 70 crx_path: path to the crx. | |
| 71 app_path: path to the extracted crx. | |
| 72 profile_path: path to a temporary profile dir. | |
| 73 """ | |
| 74 expected_result = ExpectedResult(crx_path) | |
| 75 try: | |
| 76 manifest = corpus_utils.LoadManifest(app_path) | |
| 77 start_path = manifest.get('app').get('launch').get('local_path') | |
| 78 except: | |
| 79 if expected_result.match('BAD MANIFEST!'): | |
|
Nick Bray
2012/04/03 20:34:29
This is a little sketchy, but I don't have a good
bradn
2012/04/12 17:45:54
Added a CrxResult class.
| |
| 80 return True | |
| 81 else: | |
| 82 print "'%s': 'BAD MANIFEST!'," % corpus_utils.Sha1FromFilename(crx_path) | |
| 83 return False | |
| 84 start_url = 'chrome-extension://%s/%s' % ( | |
| 85 corpus_utils.ChromeAppIdFromPath(app_path), start_path) | |
| 86 cmd = [options.browser, | |
| 87 '--enable-nacl', | |
|
Nick Bray
2012/04/03 20:34:29
Check out toosl/browser_tester/browsertester/brows
bradn
2012/04/12 17:45:54
Done.
| |
| 88 '--load-extension=' + app_path, | |
| 89 '--user-data-dir=' + profile_path, start_url] | |
| 90 process_stdout, process_stderr, retcode = corpus_utils.RunWithTimeout( | |
| 91 cmd, options.duration) | |
| 92 # Check for errors we don't like. | |
| 93 result = 'GOOD' | |
| 94 if 'NaCl process exited with' in process_stderr: | |
| 95 result = 'nacl module crashed' | |
| 96 errs = re.findall(':ERROR:[^\n]+', process_stderr) | |
| 97 if result == 'GOOD': | |
| 98 for err in errs: | |
| 99 if ('extension_prefs.cc' not in err and | |
| 100 'gles2_cmd_decoder.cc' not in err): | |
| 101 result = 'unknown error: ' + err | |
| 102 break | |
| 103 if result == 'GOOD' and 'NaClMakePcrelThunk:' not in process_stderr: | |
| 104 result = 'nacl module not started' | |
| 105 # Check if result is what we expect. | |
| 106 if not expected_result.match(result): | |
| 107 print "'%s': '%s'," % (corpus_utils.Sha1FromFilename(crx_path), result) | |
| 108 if options.verbose: | |
| 109 print '-' * 70 | |
| 110 print 'Return code: %s' % retcode | |
| 111 print '>>> STDOUT' | |
| 112 print process_stdout | |
| 113 print '>>> STDERR' | |
| 114 print process_stderr | |
| 115 print '-' * 70 | |
| 116 return False | |
| 117 return True | |
| 118 | |
| 119 | |
| 120 def TestApps(options, work_dir): | |
| 121 """Test a browser on a corpus of crxs. | |
| 122 | |
| 123 Args: | |
| 124 options: bag of options. | |
| 125 work_dir: directory to operate in. | |
| 126 """ | |
| 127 profile_path = os.path.join(work_dir, 'profile_temp') | |
| 128 app_path = os.path.join(work_dir, 'app_temp') | |
| 129 | |
| 130 list_filename = os.path.join(work_dir, 'naclapps.all') | |
| 131 filenames = corpus_utils.DownloadCorpusTotalList(list_filename) | |
| 132 progress = corpus_utils.Progress(len(filenames)) | |
| 133 for filename in filenames: | |
| 134 progress.Tally() | |
| 135 corpus_utils.PrimeCache(options, filename) | |
| 136 # Stop here if downloading only. | |
| 137 if options.download_only: | |
| 138 continue | |
| 139 # Stop here if isn't a bad app but testing only bad apps. | |
| 140 if options.bad_only and ExpectedResult(filename) == 'GOOD': | |
| 141 continue | |
| 142 # Unzip the app. | |
| 143 corpus_utils.ExtractFromCache(options, filename, app_path) | |
| 144 try: | |
| 145 progress.Result( | |
| 146 TestAppStartup(options, filename, app_path, profile_path)) | |
| 147 finally: | |
| 148 corpus_utils.RemoveDir(app_path) | |
| 149 corpus_utils.RemoveDir(profile_path) | |
| 150 progress.Summary() | |
| 151 | |
| 152 | |
| 153 def Main(): | |
| 154 if sys.platform in ['cygwin', 'win32']: | |
| 155 raise Exception('Platform not yet supported') | |
|
Nick Bray
2012/04/03 20:34:29
Comment: why?
bradn
2012/04/12 17:45:54
Done.
| |
| 156 | |
| 157 parser = optparse.OptionParser() | |
| 158 corpus_utils.SetupOptions(parser) | |
| 159 parser.add_option( | |
| 160 '--download-only', dest='download_only', | |
| 161 default=False, action='store_true', | |
| 162 help='download to cache without running the tests') | |
| 163 parser.add_option( | |
| 164 '--duration', dest='duration', default=30, | |
| 165 help='how long to run each app for') | |
| 166 parser.add_option( | |
| 167 '--browser', dest='browser', | |
| 168 help='browser to run') | |
| 169 parser.add_option( | |
| 170 '-v', '--verbose', dest='verbose', default=False, action='store_true', | |
| 171 help='run in verbose mode') | |
| 172 parser.add_option( | |
| 173 '--bad-only', dest='bad_only', default=False, action='store_true', | |
| 174 help='test only known bad apps') | |
| 175 options, args = parser.parse_args() | |
| 176 if args: | |
| 177 parser.error('unused arguments') | |
| 178 if not options.download_only: | |
| 179 if not options.browser: | |
| 180 parser.error('no browser specified') | |
| 181 | |
| 182 work_dir = tempfile.mkdtemp(suffix='startup_crxs', prefix='tmp') | |
| 183 work_dir = os.path.realpath(work_dir) | |
| 184 try: | |
| 185 TestApps(options, work_dir) | |
| 186 finally: | |
| 187 corpus_utils.RemoveDir(work_dir) | |
| 188 | |
| 189 | |
| 190 if __name__ == '__main__': | |
| 191 Main() | |
| OLD | NEW |