Index: scripts/slave/unittests/recipes_test.py |
diff --git a/scripts/slave/unittests/recipes_test.py b/scripts/slave/unittests/recipes_test.py |
index b3792e673d16ae32606effe0c6f355ba9e398c64..eec7801c26b12ba477d160a40b07adbed7c11ab6 100755 |
--- a/scripts/slave/unittests/recipes_test.py |
+++ b/scripts/slave/unittests/recipes_test.py |
@@ -36,7 +36,6 @@ Additionally, this test cannot pass unless every recipe in ../recipes has 100% |
code coverage when executed via the tests in ../recipes_test. |
""" |
-import collections |
import contextlib |
import json |
import os |
@@ -44,7 +43,7 @@ import sys |
from glob import glob |
-import test_env # pylint: disable=W0611 |
+import test_env # pylint: disable=F0401,W0611 |
import coverage |
@@ -52,24 +51,17 @@ import common.python26_polyfill # pylint: disable=W0611 |
import unittest |
from common import annotator |
+from slave import recipe_util |
+from slave import annotated_run |
+from slave import recipe_loader |
SCRIPT_PATH = os.path.abspath(os.path.dirname(__file__)) |
ROOT_PATH = os.path.abspath(os.path.join(SCRIPT_PATH, os.pardir, os.pardir, |
os.pardir)) |
SLAVE_DIR = os.path.join(ROOT_PATH, 'slave', 'fake_slave', 'build') |
-INTERNAL_DIR = os.path.join(ROOT_PATH, os.pardir, 'build_internal') |
-BASE_DIRS = { |
- 'Public': os.path.dirname(SCRIPT_PATH), |
- 'Internal': os.path.join(INTERNAL_DIR, 'scripts', 'slave'), |
-} |
-# TODO(iannucci): Check for duplicate recipe names when we have more than one |
-# base_dir |
-COVERAGE = coverage.coverage( |
- include=([os.path.join(x, 'recipes', '*') for x in BASE_DIRS.values()]+ |
- [os.path.join(SCRIPT_PATH, os.pardir, 'recipe_modules', |
- '*', 'api.py')]) |
-) |
+BASE_DIRS = recipe_util.BASE_DIRS |
+COVERAGE = None |
@contextlib.contextmanager |
@@ -80,64 +72,6 @@ def cover(): |
finally: |
COVERAGE.stop() |
-with cover(): |
- from slave import annotated_run |
- from slave import recipe_api |
- |
-class TestAPI(object): |
- @staticmethod |
- def properties_generic(**kwargs): |
- """ |
- Merge kwargs into a typical buildbot properties blob, and return the blob. |
- """ |
- ret = { |
- 'blamelist': 'cool_dev1337@chromium.org,hax@chromium.org', |
- 'blamelist_real': ['cool_dev1337@chromium.org', 'hax@chromium.org'], |
- 'buildername': 'TestBuilder', |
- 'buildnumber': 571, |
- 'mastername': 'chromium.testing.master', |
- 'slavename': 'TestSlavename', |
- 'workdir': '/path/to/workdir/TestSlavename', |
- } |
- ret.update(kwargs) |
- return ret |
- |
- @staticmethod |
- def properties_scheduled(**kwargs): |
- """ |
- Merge kwargs into a typical buildbot properties blob for a job fired off |
- by a chrome/trunk svn scheduler, and return the blob. |
- """ |
- ret = TestAPI.properties_generic( |
- branch='TestBranch', |
- project='', |
- repository='svn://svn-mirror.golo.chromium.org/chrome/trunk', |
- revision='204787', |
- ) |
- ret.update(kwargs) |
- return ret |
- |
- @staticmethod |
- def properties_tryserver(**kwargs): |
- """ |
- Merge kwargs into a typical buildbot properties blob for a job fired off |
- by a rietveld tryjob on the tryserver, and return the blob. |
- """ |
- ret = TestAPI.properties_generic( |
- branch='', |
- issue=12853011, |
- patchset=1, |
- project='chrome', |
- repository='', |
- requester='commit-bot@chromium.org', |
- revision='HEAD', |
- rietveld='https://codereview.chromium.org', |
- root='src', |
- ) |
- ret.update(kwargs) |
- return ret |
- |
- |
def expected_for(recipe_path, test_name): |
root, name = os.path.split(recipe_path) |
name = os.path.splitext(name)[0] |
@@ -152,53 +86,49 @@ def exec_test_file(recipe_path): |
with cover(): |
execfile(recipe_path, gvars) |
try: |
- gen = gvars['GenTests'](TestAPI()) |
+ test_api = recipe_loader.CreateTestApi(gvars['DEPS']) |
+ gen = gvars['GenTests'](test_api) |
except Exception, e: |
print "Caught exception while processing %s: %s" % (recipe_path, e) |
raise |
try: |
while True: |
with cover(): |
- name, test_data = next(gen) |
- yield name, test_data |
+ test_data = next(gen) |
+ yield test_data |
except StopIteration: |
pass |
+ except: |
+ print 'Exception while processing "%s"!' % recipe_path |
+ raise |
def execute_test_case(test_data, recipe_path, recipe_name): |
- test_data = test_data.copy() |
- props = test_data.pop('properties', {}).copy() |
- td = test_data.pop('step_mocks', {}).copy() |
- props['recipe'] = recipe_name |
- |
- mock_data = test_data.pop('mock', {}) |
- mock_data = collections.defaultdict(lambda: collections.defaultdict(dict), |
- mock_data) |
- |
- assert not test_data, 'Got leftover test data: %s' % test_data |
+ try: |
+ props = test_data.properties |
+ props['recipe'] = recipe_name |
- stream = annotator.StructuredAnnotationStream(stream=open(os.devnull, 'w')) |
+ stream = annotator.StructuredAnnotationStream(stream=open(os.devnull, 'w')) |
- def api(*args, **kwargs): |
- return recipe_api.CreateRecipeApi(mocks=mock_data, *args, **kwargs) |
+ def api(*args, **kwargs): |
+ return recipe_loader.CreateRecipeApi(test_data=test_data, *args, **kwargs) |
- with cover(): |
- try: |
+ with cover(): |
step_data = annotated_run.run_steps( |
- stream, props, props, api, td).steps_ran.values() |
+ stream, props, props, api, test_data).steps_ran.values() |
return [s.step for s in step_data] |
- except: |
- print 'Exception while processing "%s"!' % recipe_path |
- raise |
+ except: |
+ print 'Exception while processing "%s"!' % recipe_path |
+ raise |
def train_from_tests((recipe_path, recipe_name)): |
for path in glob(expected_for(recipe_path, '*')): |
os.unlink(path) |
- for name, test_data in exec_test_file(recipe_path): |
+ for test_data in exec_test_file(recipe_path): |
steps = execute_test_case(test_data, recipe_path, recipe_name) |
- expected_path = expected_for(recipe_path, name) |
+ expected_path = expected_for(recipe_path, test_data.name) |
print 'Writing', expected_path |
with open(expected_path, 'wb') as f: |
json.dump(steps, f, sort_keys=True, indent=2, separators=(',', ': ')) |
@@ -212,8 +142,8 @@ def load_tests(loader, _standard_tests, _pattern): |
class RecipeTest(unittest.TestCase): |
@classmethod |
def add_test_methods(cls): |
- for name, test_data in exec_test_file(recipe_path): |
- expected_path = expected_for(recipe_path, name) |
+ for test_data in exec_test_file(recipe_path): |
+ expected_path = expected_for(recipe_path, test_data.name) |
def add_test(test_data, expected_path, recipe_name): |
def test_(self): |
steps = execute_test_case(test_data, recipe_path, recipe_name) |
@@ -222,7 +152,7 @@ def load_tests(loader, _standard_tests, _pattern): |
with open(expected_path, 'rb') as f: |
expected = json.load(f) |
self.assertEqual(steps, expected) |
- test_.__name__ += name |
+ test_.__name__ += test_data.name |
setattr(cls, test_.__name__, test_) |
add_test(test_data, expected_path, recipe_name) |
@@ -233,31 +163,11 @@ def load_tests(loader, _standard_tests, _pattern): |
return RecipeTest |
suite = unittest.TestSuite() |
- for test_class in map(create_test_class, loop_over_recipes()): |
+ for test_class in map(create_test_class, recipe_loader.loop_over_recipes()): |
suite.addTest(loader.loadTestsFromTestCase(test_class)) |
return suite |
-def find_recipes(path, predicate): |
- for root, _dirs, files in os.walk(path): |
- for recipe in (f for f in files if predicate(f)): |
- recipe_path = os.path.join(root, recipe) |
- yield recipe_path |
- |
- |
-def loop_over_recipes(): |
- for _name, path in BASE_DIRS.iteritems(): |
- recipe_dir = os.path.join(path, 'recipes') |
- for recipe in find_recipes( |
- recipe_dir, lambda f: f.endswith('.py') and f[0] != '_'): |
- yield recipe, recipe[len(recipe_dir)+1:-len('.py')] |
- module_dir = os.path.join(path, 'recipe_modules') |
- for recipe in find_recipes( |
- module_dir, lambda f: f.endswith('example.py')): |
- module_name = os.path.dirname(recipe)[len(module_dir)+1:] |
- yield recipe, '%s:example' % module_name |
- |
- |
def main(argv): |
if not os.path.exists(SLAVE_DIR): |
os.makedirs(SLAVE_DIR) |
@@ -275,11 +185,18 @@ def main(argv): |
training = True |
if '--external' in argv: |
argv.remove('--external') |
- del BASE_DIRS['Internal'] |
+ BASE_DIRS[:] = [d for d in BASE_DIRS if 'internal' not in d] |
+ global COVERAGE |
+ COVERAGE = coverage.coverage( |
+ include=( |
+ [os.path.join(x, '*') for x in recipe_util.RECIPE_DIRS()] + |
+ [os.path.join(x, '*', '*api.py') for x in recipe_util.MODULE_DIRS()] |
+ ) |
+ ) |
had_errors = False |
if training and not is_help: |
- for result in map(train_from_tests, loop_over_recipes()): |
+ for result in map(train_from_tests, recipe_loader.loop_over_recipes()): |
had_errors = had_errors or result |
if had_errors: |
break |