Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(136)

Side by Side Diff: recipe_engine/test.py

Issue 2844153002: [recipes.py] move test arg parsing to its module (Closed)
Patch Set: rebase Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | recipes.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2017 The LUCI Authors. All rights reserved. 1 # Copyright 2017 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0 2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file. 3 # that can be found in the LICENSE file.
4 4
5 from __future__ import print_function 5 from __future__ import print_function
6 6
7 import bdb 7 import bdb
8 import cStringIO 8 import cStringIO
9 import contextlib 9 import contextlib
10 import copy 10 import copy
11 import coverage
12 import datetime 11 import datetime
13 import difflib 12 import difflib
14 import fnmatch 13 import fnmatch
15 import functools 14 import functools
16 import json 15 import json
17 import multiprocessing 16 import multiprocessing
18 import os 17 import os
19 import pdb 18 import pdb
20 import pprint 19 import pprint
21 import re 20 import re
22 import shutil 21 import shutil
23 import signal 22 import signal
24 import sys 23 import sys
25 import tempfile 24 import tempfile
26 import traceback 25 import traceback
27 26
28 from google.protobuf import json_format
29
30 from . import checker 27 from . import checker
31 from . import config_types 28 from . import config_types
32 from . import loader 29 from . import loader
30 from . import package
33 from . import run 31 from . import run
34 from . import step_runner 32 from . import step_runner
35 from . import stream 33 from . import stream
34
35 from . import env
36
37 from google.protobuf import json_format
38
36 from . import test_result_pb2 39 from . import test_result_pb2
37 40
38 from . import env 41 from . import env
39 42
40 import argparse # this is vendored 43 import argparse # this is vendored
41 44
42 45
43 # These variables must be set in the dynamic scope of the functions in this 46 # These variables must be set in the dynamic scope of the functions in this
44 # file. We do this instead of passing because they're not picklable, and 47 # file. We do this instead of passing because they're not picklable, and
45 # that's required by multiprocessing. 48 # that's required by multiprocessing.
(...skipping 15 matching lines...) Expand all
61 64
62 65
63 class PostProcessError(ValueError): 66 class PostProcessError(ValueError):
64 """Exception raised when any of the post-process hooks fails.""" 67 """Exception raised when any of the post-process hooks fails."""
65 pass 68 pass
66 69
67 70
68 @contextlib.contextmanager 71 @contextlib.contextmanager
69 def coverage_context(include=None, enable=True): 72 def coverage_context(include=None, enable=True):
70 """Context manager that records coverage data.""" 73 """Context manager that records coverage data."""
74 # TODO(iannucci): once we're always bootstrapping, move this to the top.
75 import coverage
71 c = coverage.coverage(config_file=False, include=include) 76 c = coverage.coverage(config_file=False, include=include)
72 77
73 if not enable: 78 if not enable:
74 yield c 79 yield c
75 return 80 return
76 81
77 # Sometimes our strict include lists will result in a run 82 # Sometimes our strict include lists will result in a run
78 # not adding any coverage info. That's okay, avoid output spam. 83 # not adding any coverage info. That's okay, avoid output spam.
79 c._warn_no_data = False 84 c._warn_no_data = False
80 85
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 v['name'] = k 343 v['name'] = k
339 raw_expectations = rslt 344 raw_expectations = rslt
340 345
341 # empty means drop expectation 346 # empty means drop expectation
342 result_data = raw_expectations.values() if raw_expectations else None 347 result_data = raw_expectations.values() if raw_expectations else None
343 return (result_data, failed_checks, coverage_data) 348 return (result_data, failed_checks, coverage_data)
344 349
345 350
346 def get_tests(test_filter=None): 351 def get_tests(test_filter=None):
347 """Returns a list of tests for current recipe package.""" 352 """Returns a list of tests for current recipe package."""
353 # TODO(iannucci): once we're always bootstrapping, move this to the top.
354 import coverage
355
348 tests = [] 356 tests = []
349 coverage_data = coverage.CoverageData() 357 coverage_data = coverage.CoverageData()
350 358
351 all_modules = set(_UNIVERSE_VIEW.loop_over_recipe_modules()) 359 all_modules = set(_UNIVERSE_VIEW.loop_over_recipe_modules())
352 covered_modules = set() 360 covered_modules = set()
353 361
354 base_covers = [] 362 base_covers = []
355 363
356 coverage_include = os.path.join(_UNIVERSE_VIEW.module_dir, '*', '*.py') 364 coverage_include = os.path.join(_UNIVERSE_VIEW.module_dir, '*', '*.py')
357 for module in all_modules: 365 for module in all_modules:
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 # Exclude recipe engine files from simulation test coverage. Simulation tests 545 # Exclude recipe engine files from simulation test coverage. Simulation tests
538 # should cover "user space" recipe code (recipes and modules), not the engine. 546 # should cover "user space" recipe code (recipes and modules), not the engine.
539 # The engine is covered by unit tests, not simulation tests. 547 # The engine is covered by unit tests, not simulation tests.
540 omit.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '*')) 548 omit.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '*'))
541 549
542 return omit 550 return omit
543 551
544 552
545 def report_coverage_version(): 553 def report_coverage_version():
546 """Prints info about coverage module (for debugging).""" 554 """Prints info about coverage module (for debugging)."""
555 # TODO(iannucci): once we're always bootstrapping, move this to the top.
556 import coverage
557
547 print('Using coverage %s from %r' % (coverage.__version__, coverage.__file__)) 558 print('Using coverage %s from %r' % (coverage.__version__, coverage.__file__))
548 559
549 560
550 @contextlib.contextmanager 561 @contextlib.contextmanager
551 def scoped_override(obj, attr, override): 562 def scoped_override(obj, attr, override):
552 """Sets |obj|.|attr| to |override| in scope of the context manager.""" 563 """Sets |obj|.|attr| to |override| in scope of the context manager."""
553 orig = getattr(obj, attr) 564 orig = getattr(obj, attr)
554 setattr(obj, attr, override) 565 setattr(obj, attr, override)
555 yield 566 yield
556 setattr(obj, attr, orig) 567 setattr(obj, attr, orig)
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 continue 615 continue
605 full_subentry = os.path.join(full_entry, subentry) 616 full_subentry = os.path.join(full_entry, subentry)
606 collected_expectations.add(full_subentry) 617 collected_expectations.add(full_subentry)
607 elif entry.endswith('.json'): 618 elif entry.endswith('.json'):
608 collected_expectations.add(full_entry) 619 collected_expectations.add(full_entry)
609 return collected_expectations 620 return collected_expectations
610 621
611 622
612 def run_run(test_filter, jobs=None, debug=False, train=False, json_file=None): 623 def run_run(test_filter, jobs=None, debug=False, train=False, json_file=None):
613 """Implementation of the 'run' command.""" 624 """Implementation of the 'run' command."""
625 # TODO(iannucci): once we're always bootstrapping, move this to the top.
626 import coverage
627
614 start_time = datetime.datetime.now() 628 start_time = datetime.datetime.now()
615 629
616 report_coverage_version() 630 report_coverage_version()
617 631
618 rc = 0 632 rc = 0
619 results_proto = test_result_pb2.TestResult() 633 results_proto = test_result_pb2.TestResult()
620 results_proto.version = 1 634 results_proto.version = 1
621 results_proto.valid = True 635 results_proto.valid = True
622 636
623 tests, coverage_data, uncovered_modules = get_tests(test_filter) 637 tests, coverage_data, uncovered_modules = get_tests(test_filter)
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
896 help='glob filter for the tests to run; ' 910 help='glob filter for the tests to run; '
897 'can be specified multiple times; ' 911 'can be specified multiple times; '
898 'the globs have the form of ' 912 'the globs have the form of '
899 '`<recipe_name_glob>[.<test_name_glob>]`. If `.<test_name_glob>` ' 913 '`<recipe_name_glob>[.<test_name_glob>]`. If `.<test_name_glob>` '
900 'is omitted, it is implied to be `*.*`, i.e. any recipe with this ' 914 'is omitted, it is implied to be `*.*`, i.e. any recipe with this '
901 'prefix and all tests.)') 915 'prefix and all tests.)')
902 916
903 return parser.parse_args(args) 917 return parser.parse_args(args)
904 918
905 919
906 def main(universe_view, raw_args, engine_flags): 920 def add_subparser(parser):
921 # TODO(iannucci): add actual subparsers here, make main argparse parser to do
922 # full commandline parsing to allow --help to work correctly.
923 test_p = parser.add_parser(
924 'test',
925 description='Generate or check expectations by simulation')
926 test_p.add_argument('args', nargs=argparse.REMAINDER)
927
928 def postprocess_func(_parser, args):
929 # Auto-enable bootstrap for test command invocations (necessary to get
930 # recent enough version of coverage package), unless explicitly disabled.
931 if args.use_bootstrap is None:
932 args.use_bootstrap = True
933
934 test_p.set_defaults(command='test', func=main,
935 postprocess_func=postprocess_func)
936
937
938 def main(package_deps, args):
907 """Runs simulation tests on a given repo of recipes. 939 """Runs simulation tests on a given repo of recipes.
908 940
909 Args: 941 Args:
910 universe_view: an UniverseView object to operate on 942 universe_view: an UniverseView object to operate on
911 raw_args: command line arguments to the 'test' command 943 raw_args: command line arguments to the 'test' command
912 engine_flags: recipe engine command-line flags 944 engine_flags: recipe engine command-line flags
913 Returns: 945 Returns:
914 Exit code 946 Exit code
915 """ 947 """
948 universe = loader.RecipeUniverse(package_deps, args.package)
949 universe_view = loader.UniverseView(universe, package_deps.root_package)
950 raw_args=args.args
951 engine_flags=args.operational_args.engine_flags
952
953 # Prevent flakiness caused by stale pyc files.
954 package.cleanup_pyc(package_deps.root_package.recipes_dir)
955
916 global _UNIVERSE_VIEW 956 global _UNIVERSE_VIEW
917 _UNIVERSE_VIEW = universe_view 957 _UNIVERSE_VIEW = universe_view
918 global _ENGINE_FLAGS 958 global _ENGINE_FLAGS
919 _ENGINE_FLAGS = engine_flags 959 _ENGINE_FLAGS = engine_flags
920 960
921 args = parse_args(raw_args) 961 args = parse_args(raw_args)
922 return args.func(args) 962 return args.func(args)
OLDNEW
« no previous file with comments | « no previous file | recipes.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698