Skip to content

Commit

Permalink
test_mapper does not use SchedulerTestBase
Browse files Browse the repository at this point in the history
  • Loading branch information
illicitonion committed Jun 7, 2018
1 parent cafcf8f commit 04ea823
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 53 deletions.
77 changes: 47 additions & 30 deletions src/python/pants/init/engine_initializer.py
Expand Up @@ -122,17 +122,22 @@ class EngineInitializer(object):
@staticmethod
def setup_legacy_graph(native, bootstrap_options, build_config):
"""Construct and return the components necessary for LegacyBuildGraph construction."""
graph_rules, symbol_table = EngineInitializer.create_graph_rules_and_tasks(
build_file_imports_behavior=bootstrap_options.build_file_imports,
build_file_aliases=build_config.registered_aliases(),
build_ignore_patterns=bootstrap_options.build_ignore,
exclude_target_regexps=bootstrap_options.exclude_target_regexp,
subproject_roots=bootstrap_options.subproject_roots,
)

return EngineInitializer.setup_legacy_graph_extended(
bootstrap_options.pants_ignore,
bootstrap_options.pants_workdir,
bootstrap_options.build_file_imports,
build_config.registered_aliases(),
graph_rules,
symbol_table,
native=native,
glob_match_error_behavior=bootstrap_options.glob_expansion_failure,
rules=build_config.rules(),
build_ignore_patterns=bootstrap_options.build_ignore,
exclude_target_regexps=bootstrap_options.exclude_target_regexp,
subproject_roots=bootstrap_options.subproject_roots,
extra_rules=build_config.rules(),
include_trace_on_error=bootstrap_options.print_exception_stacktrace,
remote_store_server=bootstrap_options.remote_store_server,
remote_execution_server=bootstrap_options.remote_execution_server,
Expand All @@ -142,18 +147,15 @@ def setup_legacy_graph(native, bootstrap_options, build_config):
def setup_legacy_graph_extended(
pants_ignore_patterns,
workdir,
build_file_imports_behavior,
build_file_aliases,
graph_rules,
symbol_table,
build_root=None,
native=None,
glob_match_error_behavior=None,
rules=None,
build_ignore_patterns=None,
exclude_target_regexps=None,
subproject_roots=None,
extra_rules=None,
include_trace_on_error=True,
remote_store_server=None,
remote_execution_server=None
remote_execution_server=None,
):
"""Construct and return the components necessary for LegacyBuildGraph construction.
Expand Down Expand Up @@ -182,37 +184,26 @@ def setup_legacy_graph_extended(

build_root = build_root or get_buildroot()

if not rules:
rules = []

symbol_table = LegacySymbolTable(build_file_aliases)
if not extra_rules:
extra_rules = []

project_tree = FileSystemProjectTree(build_root, pants_ignore_patterns)

# Register "literal" subjects required for these rules.
parser = LegacyPythonCallbacksParser(
symbol_table,
build_file_aliases,
build_file_imports_behavior
)
address_mapper = AddressMapper(parser=parser,
build_ignore_patterns=build_ignore_patterns,
exclude_target_regexps=exclude_target_regexps,
subproject_roots=subproject_roots)
if graph_rules is None:
graph_rules = EngineInitializer.create_graph_rules()

# Load the native backend.
native = native or Native.create()

# Create a Scheduler containing graph and filesystem rules, with no installed goals. The
# LegacyBuildGraph will explicitly request the products it needs.
rules = (
create_legacy_graph_tasks(symbol_table) +
create_fs_rules() +
create_process_rules() +
create_graph_rules(address_mapper, symbol_table) +
graph_rules +
[SingletonRule(GlobMatchErrorBehavior,
GlobMatchErrorBehavior.create(glob_match_error_behavior))] +
rules
extra_rules
)

scheduler = Scheduler(
Expand All @@ -226,3 +217,29 @@ def setup_legacy_graph_extended(
)

return LegacyGraphScheduler(scheduler, symbol_table)

@classmethod
def create_graph_rules_and_tasks(
cls,
build_file_imports_behavior,
build_file_aliases,
build_ignore_patterns,
exclude_target_regexps,
subproject_roots,
):
symbol_table = LegacySymbolTable(build_file_aliases)

# Register "literal" subjects required for these rules.
parser = LegacyPythonCallbacksParser(
symbol_table,
build_file_aliases,
build_file_imports_behavior
)
address_mapper = AddressMapper(parser=parser,
build_ignore_patterns=build_ignore_patterns,
exclude_target_regexps=exclude_target_regexps,
subproject_roots=subproject_roots)

rules = create_legacy_graph_tasks(symbol_table) + create_graph_rules(address_mapper, symbol_table)

return rules, symbol_table
2 changes: 1 addition & 1 deletion tests/python/pants_test/engine/BUILD
Expand Up @@ -153,13 +153,13 @@ python_tests(
name='mapper',
sources=['test_mapper.py'],
dependencies=[
':scheduler_test_base',
':util',
'src/python/pants/build_graph',
'src/python/pants/engine:build_files',
'src/python/pants/engine:mapper',
'src/python/pants/engine:struct',
'src/python/pants/util:dirutil',
'tests/python/pants_test:test_base',
'tests/python/pants_test/engine/examples:mapper_test',
'tests/python/pants_test/engine/examples:parsers',
]
Expand Down
13 changes: 11 additions & 2 deletions tests/python/pants_test/engine/legacy/test_graph.py
Expand Up @@ -57,12 +57,21 @@ def graph_helper(self,
with temporary_dir() as work_dir:
path_ignore_patterns = path_ignore_patterns or []
build_file_aliases = build_file_aliases or self._default_build_file_aliases()

graph_rules, symbol_table = EngineInitializer.create_graph_rules_and_tasks(
build_file_imports_behavior,
build_file_aliases,
build_ignore_patterns=None,
exclude_target_regexps=None,
subproject_roots=None,
)

# TODO: This test should be swapped to using TestBase.
graph_helper = EngineInitializer.setup_legacy_graph_extended(
path_ignore_patterns,
work_dir,
build_file_imports_behavior,
build_file_aliases=build_file_aliases,
graph_rules,
symbol_table,
native=self._native,
include_trace_on_error=include_trace_on_error
)
Expand Down
40 changes: 26 additions & 14 deletions tests/python/pants_test/engine/test_mapper.py
Expand Up @@ -14,7 +14,6 @@
from pants.build_graph.address import Address
from pants.engine.addressable import BuildFileAddresses
from pants.engine.build_files import UnhydratedStruct, create_graph_rules
from pants.engine.fs import create_fs_rules
from pants.engine.mapper import (AddressFamily, AddressMap, AddressMapper, DifferingFamiliesError,
DuplicateNameError, UnaddressableObjectError)
from pants.engine.parser import SymbolTable
Expand All @@ -23,9 +22,10 @@
from pants.engine.struct import Struct
from pants.util.dirutil import safe_open
from pants.util.objects import Collection
from pants.util.process_handler import subprocess
from pants_test.engine.examples.parsers import JsonParser
from pants_test.engine.scheduler_test_base import SchedulerTestBase
from pants_test.engine.util import Target, TargetTable
from pants_test.test_base import TestBase


class Thing(object):
Expand Down Expand Up @@ -145,21 +145,33 @@ def unhydrated_structs(build_file_addresses):
yield UnhydratedStructs(uhs)


class AddressMapperTest(unittest.TestCase, SchedulerTestBase):
class AddressMapperTest(TestBase, unittest.TestCase):
@classmethod
def extra_rules(cls):
# We add the `unhydrated_structs` rule because it is otherwise not used in the core engine.
return [unhydrated_structs]

def setUp(self):
# Set up a scheduler that supports address mapping.
symbol_table = TargetTable()
address_mapper = AddressMapper(parser=JsonParser(symbol_table),
build_patterns=('*.BUILD.json',))
TestBase.setUp(self)

# We add the `unhydrated_structs` rule because it is otherwise not used in the core engine.
rules = [
unhydrated_structs
] + create_fs_rules() + create_graph_rules(address_mapper, symbol_table)
# None of Python's ways of copying directories are cool with the destination already existing.
# cp -r is.
subprocess.check_call([
'cp',
'-r',
os.path.join(os.path.dirname(__file__), 'examples/mapper_test/'),
self.build_root,
])

project_tree = self.mk_fs_tree(os.path.join(os.path.dirname(__file__), 'examples/mapper_test'))
self.build_root = project_tree.build_root
self.scheduler = self.mk_scheduler(rules=rules, project_tree=project_tree)
# Set up a scheduler that supports address mapping.
symbol_table = TargetTable()
address_mapper = AddressMapper(
parser=JsonParser(symbol_table),
build_patterns=('*.BUILD.json',),
)
graph_rules = create_graph_rules(address_mapper, symbol_table)
self.reset_scheduler()
self._init_engine(graph_rules=graph_rules, symbol_table=symbol_table)

self.a_b = Address.parse('a/b')
self.a_b_target = Target(name='b',
Expand Down
7 changes: 7 additions & 0 deletions tests/python/pants_test/engine/util.py
Expand Up @@ -11,6 +11,7 @@

from pants.base.file_system_project_tree import FileSystemProjectTree
from pants.binaries.binary_util import BinaryUtil
from pants.build_graph.build_file_aliases import BuildFileAliases
from pants.engine.addressable import addressable_list
from pants.engine.native import Native
from pants.engine.parser import SymbolTable
Expand Down Expand Up @@ -118,10 +119,16 @@ def configurations(self):


class TargetTable(SymbolTable):
def __init__(self):
self._aliases = BuildFileAliases()

@classmethod
def table(cls):
return {'struct': Struct, 'target': Target}

def aliases(self):
return self._aliases


def assert_equal_with_printing(test_case, expected, actual):
"""Asserts equality, but also prints the values so they can be compared on failure.
Expand Down
30 changes: 24 additions & 6 deletions tests/python/pants_test/test_base.py
Expand Up @@ -296,12 +296,18 @@ def scan():
return set(scan())

def _reset_engine(self):
if self._scheduler is not None:
if self._build_graph is not None:
self._build_graph.reset()
if self._scheduler is not None:
# Eagerly free file handles, threads, connections, etc, held by the scheduler. In theory,
# dropping the scheduler is equivalent, but it's easy for references to the scheduler to leak.
self._scheduler.pre_fork()

def reset_scheduler(self):
self._reset_engine()
self.__class__._build_graph = None
self.__class__._scheduler = None

@property
def build_root(self):
return self._build_root()
Expand All @@ -327,20 +333,32 @@ def extra_rules(cls):
return []

@classmethod
def _init_engine(cls):
def _init_engine(cls, graph_rules=None, symbol_table=None):
if cls._scheduler is not None:
return

if graph_rules is None and symbol_table is None:
graph_rules, symbol_table = EngineInitializer.create_graph_rules_and_tasks(
build_file_imports_behavior='allow',
build_file_aliases=cls.alias_groups(),
build_ignore_patterns=None,
exclude_target_regexps=None,
subproject_roots=None,
)
elif graph_rules is not None and symbol_table is not None:
pass
else:
raise Exception("Must pass either neither or both of graph_rules and symbol_table")

# NB: This uses the long form of initialization because it needs to directly specify
# `cls.alias_groups` rather than having them be provided by bootstrap options.
graph_session = EngineInitializer.setup_legacy_graph_extended(
pants_ignore_patterns=None,
workdir=cls._pants_workdir(),
build_file_imports_behavior='allow',
native=init_native(),
build_file_aliases=cls.alias_groups(),
build_ignore_patterns=None,
rules=cls.extra_rules(),
extra_rules=cls.extra_rules(),
graph_rules=graph_rules,
symbol_table=symbol_table,
).new_session()
cls._scheduler = graph_session.scheduler_session
cls._build_graph, cls._address_mapper = graph_session.create_build_graph(
Expand Down

0 comments on commit 04ea823

Please sign in to comment.