| #!/usr/bin/env python |
| # Copyright (c) 2012 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. |
| |
| """Verify perf_expectations.json can be loaded using simplejson. |
| |
| perf_expectations.json is a JSON-formatted file. This script verifies |
| that simplejson can load it correctly. It should catch most common |
| formatting problems. |
| """ |
| |
| import subprocess |
| import sys |
| import os |
| import unittest |
| import re |
| |
| simplejson = None |
| |
| def OnTestsLoad(): |
| old_path = sys.path |
| script_path = os.path.dirname(sys.argv[0]) |
| load_path = None |
| global simplejson |
| |
| # This test script should be stored in src/tools/perf_expectations/. That |
| # directory will most commonly live in 2 locations: |
| # |
| # - a regular Chromium checkout, in which case src/third_party |
| # is where to look for simplejson |
| # |
| # - a buildbot checkout, in which case .../pylibs is where |
| # to look for simplejson |
| # |
| # Locate and install the correct path based on what we can find. |
| # |
| for path in ('../../../third_party', '../../../../../pylibs'): |
| path = os.path.join(script_path, path) |
| if os.path.exists(path) and os.path.isdir(path): |
| load_path = os.path.abspath(path) |
| break |
| |
| if load_path is None: |
| msg = "%s expects to live within a Chromium checkout" % sys.argv[0] |
| raise Exception, "Error locating simplejson load path (%s)" % msg |
| |
| # Try importing simplejson once. If this succeeds, we found it and will |
| # load it again later properly. Fail if we cannot load it. |
| sys.path.append(load_path) |
| try: |
| import simplejson as Simplejson |
| simplejson = Simplejson |
| except ImportError, e: |
| msg = "%s expects to live within a Chromium checkout" % sys.argv[0] |
| raise Exception, "Error trying to import simplejson from %s (%s)" % \ |
| (load_path, msg) |
| finally: |
| sys.path = old_path |
| return True |
| |
| def LoadJsonFile(filename): |
| f = open(filename, 'r') |
| try: |
| data = simplejson.load(f) |
| except ValueError, e: |
| f.seek(0) |
| print "Error reading %s:\n%s" % (filename, |
| f.read()[:50]+'...') |
| raise e |
| f.close() |
| return data |
| |
| OnTestsLoad() |
| |
| CONFIG_JSON = os.path.join(os.path.dirname(sys.argv[0]), |
| '../chromium_perf_expectations.cfg') |
| MAKE_EXPECTATIONS = os.path.join(os.path.dirname(sys.argv[0]), |
| '../make_expectations.py') |
| PERF_EXPECTATIONS = os.path.join(os.path.dirname(sys.argv[0]), |
| '../perf_expectations.json') |
| |
| |
| class PerfExpectationsUnittest(unittest.TestCase): |
| def testPerfExpectations(self): |
| # Test data is dictionary. |
| perf_data = LoadJsonFile(PERF_EXPECTATIONS) |
| if not isinstance(perf_data, dict): |
| raise Exception('perf expectations is not a dict') |
| |
| # Test the 'load' key. |
| if not 'load' in perf_data: |
| raise Exception("perf expectations is missing a load key") |
| if not isinstance(perf_data['load'], bool): |
| raise Exception("perf expectations load key has non-bool value") |
| |
| # Test all key values are dictionaries. |
| bad_keys = [] |
| for key in perf_data: |
| if key == 'load': |
| continue |
| if not isinstance(perf_data[key], dict): |
| bad_keys.append(key) |
| if len(bad_keys) > 0: |
| msg = "perf expectations keys have non-dict values" |
| raise Exception("%s: %s" % (msg, bad_keys)) |
| |
| # Test all key values have delta and var keys. |
| for key in perf_data: |
| if key == 'load': |
| continue |
| |
| # First check if regress/improve is in the key's data. |
| if 'regress' in perf_data[key]: |
| if 'improve' not in perf_data[key]: |
| bad_keys.append(key) |
| if (not isinstance(perf_data[key]['regress'], int) and |
| not isinstance(perf_data[key]['regress'], float)): |
| bad_keys.append(key) |
| if (not isinstance(perf_data[key]['improve'], int) and |
| not isinstance(perf_data[key]['improve'], float)): |
| bad_keys.append(key) |
| else: |
| # Otherwise check if delta/var is in the key's data. |
| if 'delta' not in perf_data[key] or 'var' not in perf_data[key]: |
| bad_keys.append(key) |
| if (not isinstance(perf_data[key]['delta'], int) and |
| not isinstance(perf_data[key]['delta'], float)): |
| bad_keys.append(key) |
| if (not isinstance(perf_data[key]['var'], int) and |
| not isinstance(perf_data[key]['var'], float)): |
| bad_keys.append(key) |
| |
| if len(bad_keys) > 0: |
| msg = "perf expectations key values missing or invalid delta/var" |
| raise Exception("%s: %s" % (msg, bad_keys)) |
| |
| # Test all keys have the correct format. |
| for key in perf_data: |
| if key == 'load': |
| continue |
| # tools/buildbot/scripts/master/log_parser.py should have a matching |
| # regular expression. |
| if not re.match(r"^([\w\.-]+)/([\w\.-]+)/([\w\.-]+)/([\w\.-]+)$", key): |
| bad_keys.append(key) |
| if len(bad_keys) > 0: |
| msg = "perf expectations keys in bad format, expected a/b/c/d" |
| raise Exception("%s: %s" % (msg, bad_keys)) |
| |
| def testNoUpdatesNeeded(self): |
| p = subprocess.Popen([MAKE_EXPECTATIONS, '-s'], stdout=subprocess.PIPE) |
| p.wait(); |
| self.assertEqual(p.returncode, 0, |
| msg='Update expectations first by running ./make_expectations.py') |
| |
| def testConfigFile(self): |
| # Test that the config file can be parsed as JSON. |
| config = LoadJsonFile(CONFIG_JSON) |
| # Require the following keys. |
| if 'base_url' not in config: |
| raise Exception('base_url not specified in config file') |
| if 'perf_file' not in config: |
| raise Exception('perf_file not specified in config file') |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |