168 lines
5.6 KiB
Python
168 lines
5.6 KiB
Python
|
#!/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()
|