Index: tests/validator_regression/validator_regression_test.py |
diff --git a/tests/validator_regression/validator_regression_test.py b/tests/validator_regression/validator_regression_test.py |
deleted file mode 100755 |
index 9b32ac5e74acbd7eda48f1c262293986c1cb3d06..0000000000000000000000000000000000000000 |
--- a/tests/validator_regression/validator_regression_test.py |
+++ /dev/null |
@@ -1,332 +0,0 @@ |
-#!/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 hashlib |
-import optparse |
-import os |
-import shutil |
-import struct |
-import subprocess |
-import sys |
-import tempfile |
-import time |
- |
- |
-KNOWN_BAD_NEXES = set(['naclapps/nexes/' + i for i in [ |
- ('kgegkcnohlcckapfehpogebcncidcdbe/' |
- '1c2b051cb60367cf103128c9cd76769ffa1cf356.nexe'), |
- ('noiedkpkpicokakliamgmmbmhkmkcdgj/' |
- '1c2b051cb60367cf103128c9cd76769ffa1cf356.nexe'), |
-]]) |
- |
- |
-SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) |
-TESTS_DIR = os.path.dirname(SCRIPT_DIR) |
-NACL_DIR = os.path.dirname(TESTS_DIR) |
- |
- |
-# Imports from the build directory. |
-sys.path.insert(0, os.path.join(NACL_DIR, 'build')) |
-import download_utils |
- |
- |
-def NexeArchitecture(filename): |
- """Decide the architecture of a nexe. |
- |
- Args: |
- filename: filename of the nexe. |
- Returns: |
- Architecture string (x86-32 / x86-64) or None. |
- """ |
- fh = open(filename, 'rb') |
- head = fh.read(20) |
- # Must not be too short. |
- if len(head) != 20: |
- print 'ERROR - header too short' |
- return None |
- # Must have ELF header. |
- if head[0:4] != '\x7fELF': |
- print 'ERROR - no elf header' |
- return None |
- # Decode e_machine |
- machine = struct.unpack('<H', head[18:])[0] |
- return { |
- 3: 'x86-32', |
- #40: 'arm', # TODO(bradnelson): handle arm. |
- 62: 'x86-64', |
- }.get(machine) |
- |
- |
-def GsutilCopySilent(src, dst): |
- """Invoke gsutil cp, swallowing the output, with retry. |
- |
- Args: |
- src: src url. |
- dst: dst path. |
- """ |
- for _ in range(3): |
- env = os.environ.copy() |
- env['PATH'] = '/b/build/scripts/slave' + os.pathsep + env['PATH'] |
- process = subprocess.Popen( |
- ['gsutil', 'cp', src, dst], |
- env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
- process_stdout, process_stderr = process.communicate() |
- if process.returncode == 0: |
- return |
- print 'Unexpected return code: %s' % process.returncode |
- print '>>> STDOUT' |
- print process_stdout |
- print '>>> STDERR' |
- print process_stderr |
- print '-' * 70 |
- sys.exit(1) |
- |
- |
-def DownloadNexeList(filename): |
- """Download list of NEXEs. |
- |
- Args: |
- filename: destination filename. |
- """ |
- GsutilCopySilent('gs://nativeclient-snaps/naclapps.list', filename) |
- |
- |
-def DownloadNexe(src_path, dst_filename): |
- """Download list of NEXEs. |
- |
- Args: |
- src_path: datastore relative path to download from. |
- dst_filename: destination filename. |
- """ |
- GsutilCopySilent('gs://nativeclient-snaps/%s' % src_path, dst_filename) |
- |
- |
-def Sha1Sum(path): |
- """Determine the sha1 hash of a file's contents given its path.""" |
- m = hashlib.sha1() |
- fh = open(path, 'rb') |
- m.update(fh.read()) |
- fh.close() |
- return m.hexdigest() |
- |
- |
-def ValidateNexe(options, path, src_path, expect_pass, print_errors): |
- """Run the validator on a nexe, check if the result is expected. |
- |
- Args: |
- options: bag of options. |
- path: path to the nexe. |
- src_path: path to nexe on server. |
- expect_pass: boolean indicating if the nexe is expected to validate. |
- print_errors: boolean indicating if detailed failure should be emitted. |
- Returns: |
- True if validation matches expectations. |
- """ |
- process = subprocess.Popen( |
- [options.validator, path], |
- stdout=subprocess.PIPE, |
- stderr=subprocess.PIPE) |
- process_stdout, process_stderr = process.communicate() |
- # Check if result is what we expect. |
- did_pass = (process.returncode == 0) |
- if expect_pass != did_pass: |
- if print_errors: |
- print '-' * 70 |
- print 'Validating: %s' % path |
- print 'From: %s' % src_path |
- print 'Size: %d' % os.path.getsize(path) |
- print 'SHA1: %s' % Sha1Sum(path) |
- print 'Validator: %s' % options.validator |
- print 'Unexpected return code: %s' % process.returncode |
- print '>>> STDOUT' |
- print process_stdout |
- print '>>> STDERR' |
- print process_stderr |
- print '-' * 70 |
- return False |
- return True |
- |
- |
-def NexeShouldValidate(path): |
- """Checks a blacklist to decide if a nexe should validate. |
- |
- Args: |
- path: path to the nexe. |
- Returns: |
- Boolean indicating if the nexe should validate. |
- """ |
- return path not in KNOWN_BAD_NEXES |
- |
- |
-def CachedPath(options, filename): |
- """Find the full path of a cached file, a cache root relative path. |
- |
- Args: |
- options: bags of options. |
- filename: filename relative to the top of the download url / cache. |
- Returns: |
- Absolute path of where the file goes in the cache. |
- """ |
- return os.path.join(options.cache_dir, 'nacl_validator_test_cache', filename) |
- |
- |
-def Sha1FromFilename(filename): |
- """Get the expected sha1 of a file path. |
- |
- Throughout we use the convention that files are store to a name of the form: |
- <path_to_file>/<sha1hex>[.<some_extention>] |
- This function extracts the expected sha1. |
- |
- Args: |
- filename: filename to extract. |
- Returns: |
- Excepted sha1. |
- """ |
- return os.path.splitext(os.path.basename(filename))[0] |
- |
- |
-def PrimeCache(options, filename): |
- """Attempt to add a file to the cache directory if its not already there. |
- |
- Args: |
- options: bag of options. |
- filename: filename relative to the top of the download url / cache. |
- """ |
- dpath = CachedPath(options, filename) |
- if not os.path.exists(dpath) or Sha1Sum(dpath) != Sha1FromFilename(filename): |
- # Try to make the directory, fail is ok, let the download fail instead. |
- try: |
- os.makedirs(os.path.basename(dpath)) |
- except OSError: |
- pass |
- DownloadNexe(filename, dpath) |
- |
- |
-def CopyFromCache(options, filename, dest_filename): |
- """Copy an item from the cache. |
- |
- Args: |
- options: bag of options. |
- filename: filename relative to the top of the download url / cache. |
- dest_filename: location to copy the file to. |
- """ |
- dpath = CachedPath(options, filename) |
- shutil.copy(dpath, dest_filename) |
- assert Sha1Sum(dest_filename) == Sha1FromFilename(filename) |
- |
- |
-def TestValidators(options, work_dir): |
- """Test x86 validators on current snapshot. |
- |
- Args: |
- options: bag of options. |
- work_dir: directory to operate in. |
- """ |
- list_filename = os.path.join(work_dir, 'naclapps.list') |
- nexe_filename = os.path.join(work_dir, 'test.nexe') |
- DownloadNexeList(list_filename) |
- fh = open(list_filename) |
- filenames = fh.read().splitlines() |
- fh.close() |
- failures = 0 |
- successes = 0 |
- start = time.time() |
- count = len(filenames) |
- for index, filename in enumerate(filenames): |
- tm = time.time() |
- if index > 0: |
- eta = (count - index) * (tm - start) / index |
- eta_minutes = int(eta / 60) |
- eta_seconds = int(eta - eta_minutes * 60) |
- eta_str = ' (ETA %d:%02d)' % (eta_minutes, eta_seconds) |
- else: |
- eta_str = '' |
- print 'Processing %d of %d%s...' % (index + 1, count, eta_str) |
- PrimeCache(options, filename) |
- # Stop here if downloading only. |
- if options.download_only: |
- continue |
- # Skip if not the right architecture. |
- architecture = NexeArchitecture(CachedPath(options, filename)) |
- if architecture != options.architecture: |
- continue |
- # Validate a copy in case validator is mutating. |
- CopyFromCache(options, filename, nexe_filename) |
- try: |
- result = ValidateNexe( |
- options, nexe_filename, filename, |
- NexeShouldValidate(filename), failures < 1) |
- if result: |
- successes += 1 |
- else: |
- failures += 1 |
- if not result and not options.keep_going: |
- break |
- finally: |
- try: |
- os.remove(nexe_filename) |
- except OSError: |
- print 'ERROR - unable to remove %s' % nexe_filename |
- print 'Ran validator on %d of %d NEXEs' % ( |
- successes + failures, len(filenames)) |
- if failures: |
- # Our alternate validators don't currently cover everything. |
- # For now, don't fail just emit warning (and a tally of failures). |
- print '@@@STEP_WARNINGS@@@' |
- print '@@@STEP_TEXT@FAILED %d times (%.1f%% are incorrect)@@@' % ( |
- failures, failures * 100 / (successes + failures)) |
- else: |
- print 'SUCCESS' |
- |
- |
-def Main(): |
- # Decide a default cache directory. |
- # Prefer /b (for the bots) |
- # Failing that, use scons-out. |
- # Failing that, use the current users's home dir. |
- default_cache_dir = '/b' |
- if not os.path.isdir(default_cache_dir): |
- default_cache_dir = os.path.join(NACL_DIR, 'scons-out') |
- if not os.path.isdir(default_cache_dir): |
- default_cache_dir = os.path.expanduser('~/') |
- default_cache_dir = os.path.abspath(default_cache_dir) |
- assert os.path.isdir(default_cache_dir) |
- |
- parser = optparse.OptionParser() |
- parser.add_option( |
- '--cache-dir', dest='cache_dir', default=default_cache_dir, |
- help='directory to cache downloads in') |
- parser.add_option( |
- '--download-only', dest='download_only', |
- default=False, action='store_true', |
- help='download to cache without running the tests') |
- parser.add_option( |
- '-k', '--keep-going', dest='keep_going', |
- default=False, action='store_true', |
- help='keep going on failure') |
- parser.add_option( |
- '--validator', dest='validator', |
- help='location of validator executable') |
- parser.add_option( |
- '--arch', dest='architecture', |
- help='architecture of validator') |
- options, args = parser.parse_args() |
- if args: |
- parser.error('unused arguments') |
- if not options.download_only: |
- if not options.validator: |
- parser.error('no validator specified') |
- if not options.architecture: |
- parser.error('no architecture specified') |
- |
- work_dir = tempfile.mkdtemp(suffix='validate_nexes', prefix='tmp') |
- try: |
- TestValidators(options, work_dir) |
- finally: |
- download_utils.RemoveDir(work_dir) |
- |
- |
-if __name__ == '__main__': |
- Main() |