def test_ruleset_with_explicit_type_constraint(self): rules = [(Exactly(A), (Select(B), ), noop), (B, (Select(A), ), noop)] validator = RulesetValidator(NodeBuilder.create(rules), goal_to_product=dict(), root_subject_types=tuple()) validator.validate()
def test_ruleset_with_selector_only_provided_as_root_subject(self): rules = [(A, (Select(B),), noop)] validator = RulesetValidator(RuleIndex.create(rules, tuple()), goal_to_product={}, root_subject_fns={k: lambda p: Select(p) for k in (B,)}) validator.validate()
def test_ruleset_with_selector_only_provided_as_root_subject(self): rules = [(A, (Select(B),), noop)] validator = RulesetValidator(NodeBuilder.create(rules, tuple()), goal_to_product={}, root_subject_fns={k: lambda p: Select(p) for k in (B,)}) validator.validate()
def test_ruleset_with_with_selector_only_provided_as_root_subject(self): validator = RulesetValidator( NodeBuilder.create([(A, (Select(B),), noop)]), goal_to_product=dict(), root_subject_types=(B,) ) validator.validate()
def test_ruleset_with_with_selector_only_provided_as_root_subject(self): validator = RulesetValidator(NodeBuilder.create([(A, (Select(B), ), noop)]), goal_to_product=dict(), root_subject_types=(B, )) validator.validate()
def test_ruleset_with_explicit_type_constraint(self): rules = [(Exactly(A), (Select(B), ), noop), (B, (Select(A), ), noop)] validator = RulesetValidator( RuleIndex.create(rules, tuple()), goal_to_product={}, root_subject_fns={k: lambda p: Select(p) for k in (SubA, )}) validator.validate()
def test_ruleset_with_explicit_type_constraint(self): rules = [ (Exactly(A), (Select(B),), noop), (B, (Select(A),), noop) ] validator = RulesetValidator(RuleIndex.create(rules, tuple()), goal_to_product={}, root_subject_fns={k: lambda p: Select(p) for k in (SubA,)}) validator.validate()
def test_ruleset_with_goal_not_produced(self): rules = [(B, (Select(SubA), ), noop)] validator = RulesetValidator(NodeBuilder.create(rules), goal_to_product={'goal-name': AGoal}, root_subject_types=tuple()) with self.assertRaises(ValueError) as cm: validator.validate() self.assertEquals( "no task for product used by goal \"goal-name\": <class 'pants_test.engine.test_rules.AGoal'>", str(cm.exception))
def test_ruleset_with_goal_not_produced(self): rules = [(B, (Select(SubA),), noop)] validator = RulesetValidator( NodeBuilder.create(rules), goal_to_product={"goal-name": AGoal}, root_subject_types=tuple() ) with self.assertRaises(ValueError) as cm: validator.validate() self.assertEquals( "no task for product used by goal \"goal-name\": <class 'pants_test.engine.test_rules.AGoal'>", str(cm.exception), )
def test_ruleset_with_missing_product_type(self): rules = [(A, (Select(B), ), noop)] validator = RulesetValidator(NodeBuilder.create(rules), goal_to_product=dict(), root_subject_types=tuple()) with self.assertRaises(ValueError) as cm: validator.validate() self.assertEquals( dedent(""" Found 1 rules with errors: (A, (Select(B),), noop) There is no producer of Select(B) """).strip(), str(cm.exception))
def test_ruleset_with_missing_product_type(self): rules = [(A, (Select(B),), noop)] validator = RulesetValidator(NodeBuilder.create(rules, tuple()), goal_to_product={}, root_subject_fns={k: lambda p: Select(p) for k in (SubA,)}) with self.assertRaises(ValueError) as cm: validator.validate() self.assert_equal_with_printing(dedent(""" Rules with errors: 1 (A, (Select(B),), noop): no matches for Select(B) with subject types: SubA """).strip(), str(cm.exception))
def test_ruleset_with_missing_product_type(self): rules = [(A, (Select(B),), noop)] validator = RulesetValidator(RuleIndex.create(rules, tuple()), goal_to_product={}, root_subject_fns={k: lambda p: Select(p) for k in (SubA,)}) with self.assertRaises(ValueError) as cm: validator.validate() self.assert_equal_with_printing(dedent(""" Rules with errors: 1 (A, (Select(B),), noop): no matches for Select(B) with subject types: SubA """).strip(), str(cm.exception))
def test_ruleset_with_goal_not_produced(self): # The graph is complete, but the goal 'goal-name' requests A, # which is not produced by any rule. rules = [ (B, (Select(SubA),), noop) ] validator = RulesetValidator(NodeBuilder.create(rules, tuple()), goal_to_product={'goal-name': AGoal}, root_subject_fns={k: lambda p: Select(p) for k in (SubA,)}) with self.assertRaises(ValueError) as cm: validator.validate() self.assert_equal_with_printing("no task for product used by goal \"goal-name\": AGoal", str(cm.exception))
def test_ruleset_with_goal_not_produced(self): # The graph is complete, but the goal 'goal-name' requests A, # which is not produced by any rule. rules = [ (B, (Select(SubA),), noop) ] validator = RulesetValidator(RuleIndex.create(rules, tuple()), goal_to_product={'goal-name': AGoal}, root_subject_fns={k: lambda p: Select(p) for k in (SubA,)}) with self.assertRaises(ValueError) as cm: validator.validate() self.assert_equal_with_printing("no task for product used by goal \"goal-name\": AGoal", str(cm.exception))
def test_ruleset_with_missing_product_type(self): rules = [(A, (Select(B),), noop)] validator = RulesetValidator(NodeBuilder.create(rules), goal_to_product=dict(), root_subject_types=tuple()) with self.assertRaises(ValueError) as cm: validator.validate() self.assertEquals( dedent( """ Found 1 rules with errors: (A, (Select(B),), noop) There is no producer of Select(B) """ ).strip(), str(cm.exception), )
def test_initial_select_projection_failure(self): rules = [ (Exactly(A), (SelectProjection(B, D, ('some',), C),), noop), ] validator = RulesetValidator(RuleIndex.create(rules, tuple()), goal_to_product={}, root_subject_fns=_suba_root_subject_fns) with self.assertRaises(ValueError) as cm: validator.validate() self.assert_equal_with_printing(dedent(""" Rules with errors: 1 (Exactly(A), (SelectProjection(B, D, (u'some',), C),), noop): no matches for Select(C) when resolving SelectProjection(B, D, (u'some',), C) with subject types: SubA """).strip(), str(cm.exception))
def test_secondary_select_projection_failure(self): rules = [(Exactly(A), (SelectProjection(B, D, ('some', ), C), ), noop), (C, tuple(), noop)] validator = RulesetValidator(RuleIndex.create(rules, tuple()), goal_to_product={}, root_subject_fns=_suba_root_subject_fns) with self.assertRaises(ValueError) as cm: validator.validate() self.assert_equal_with_printing( dedent(""" Rules with errors: 1 (Exactly(A), (SelectProjection(B, D, (u'some',), C),), noop): no matches for Select(B) when resolving SelectProjection(B, D, (u'some',), C) with subject types: D """).strip(), str(cm.exception))
def test_ruleset_with_superclass_of_selected_type_produced_fails(self): rules = [(A, (Select(B), ), noop), (B, (Select(SubA), ), noop)] validator = RulesetValidator( RuleIndex.create(rules, tuple()), goal_to_product={}, root_subject_fns={k: lambda p: Select(p) for k in (C, )}) with self.assertRaises(ValueError) as cm: validator.validate() self.assert_equal_with_printing( dedent(""" Rules with errors: 2 (A, (Select(B),), noop): depends on unfulfillable (B, (Select(SubA),), noop) of C with subject types: C (B, (Select(SubA),), noop): no matches for Select(SubA) with subject types: C """).strip(), str(cm.exception))
def __init__(self, goals, tasks, project_tree, native, graph_lock=None): """ :param goals: A dict from a goal name to a product type. A goal is just an alias for a particular (possibly synthetic) product. :param tasks: A set of (output, input selection clause, task function) triples which is used to compute values in the product graph. :param project_tree: An instance of ProjectTree for the current build root. :param native: An instance of engine.subsystem.native.Native. :param graph_lock: A re-entrant lock to use for guarding access to the internal product Graph instance. Defaults to creating a new threading.RLock(). """ self._products_by_goal = goals self._project_tree = project_tree self._native = native self._product_graph_lock = graph_lock or threading.RLock() self._run_count = 0 # Create a handle for the ExternContext (which must be kept alive as long as this object), and # the native Scheduler. self._context = ExternContext() self._context_handle = native.new_handle(self._context) # TODO: The only (?) case where we use inheritance rather than exact type unions. has_products_constraint = TypeConstraint( self._to_id(SubclassesOf(HasProducts))) scheduler = native.lib.scheduler_create( self._context_handle, extern_key_for, extern_id_to_str, extern_val_to_str, extern_satisfied_by, extern_store_list, extern_project, extern_project_multi, self._to_key('name'), self._to_key('products'), self._to_key('default'), self._to_constraint(Address), has_products_constraint, self._to_constraint(Variants)) self._scheduler = native.gc(scheduler, native.lib.scheduler_destroy) self._execution_request = None # Validate and register all provided and intrinsic tasks. select_product = lambda product: Select(product) # TODO: This bounding of input Subject types allows for closed-world validation, but is not # strictly necessary for execution. We might eventually be able to remove it by only executing # validation below the execution roots (and thus not considering paths that aren't in use). root_selector_fns = { Address: select_product, AscendantAddresses: select_product, DescendantAddresses: select_product, PathGlobs: select_product, SiblingAddresses: select_product, SingleAddress: select_product, } intrinsics = create_fs_intrinsics( project_tree) + create_snapshot_intrinsics(project_tree) singletons = create_snapshot_singletons(project_tree) node_builder = NodeBuilder.create(tasks, intrinsics, singletons) RulesetValidator(node_builder, goals, root_selector_fns).validate() self._register_tasks(node_builder.tasks) self._register_intrinsics(node_builder.intrinsics) self._register_singletons(node_builder.singletons)
def test_ruleset_with_superclass_of_selected_type_produced_fails(self): rules = [ (A, (Select(B),), noop), (B, (Select(SubA),), noop) ] validator = RulesetValidator(RuleIndex.create(rules, tuple()), goal_to_product={}, root_subject_fns={k: lambda p: Select(p) for k in (C,)}) with self.assertRaises(ValueError) as cm: validator.validate() self.assert_equal_with_printing(dedent(""" Rules with errors: 2 (A, (Select(B),), noop): depends on unfulfillable (B, (Select(SubA),), noop) of C with subject types: C (B, (Select(SubA),), noop): no matches for Select(SubA) with subject types: C """).strip(), str(cm.exception))
def test_ruleset_unreachable_due_to_product_of_select_dependencies(self): rules = [ (A, (SelectDependencies(B, SubA, field_types=(D,)),), noop), ] intrinsics = [ (B, C, noop), ] validator = RulesetValidator(RuleIndex.create(rules, intrinsics), goal_to_product={}, root_subject_fns={k: lambda p: Select(p) for k in (A,)}) with self.assertRaises(ValueError) as cm: validator.validate() self.assert_equal_with_printing(dedent(""" Rules with errors: 1 (A, (SelectDependencies(B, SubA, field_types=(D,)),), noop): Unreachable with subject types: Any """).strip(), str(cm.exception))
def test_fails_if_root_subject_types_empty(self): rules = [ (A, (Select(B),), noop), ] with self.assertRaises(ValueError) as cm: RulesetValidator(NodeBuilder.create(rules, tuple()), goal_to_product={}, root_subject_fns={}) self.assertEquals(dedent(""" root_subject_fns must not be empty """).strip(), str(cm.exception))
def test_ruleset_unreachable_due_to_product_of_select_dependencies(self): rules = [ (A, (SelectDependencies(B, SubA, field_types=(D,)),), noop), ] intrinsics = [ (B, C, noop), ] validator = RulesetValidator(NodeBuilder.create(rules, intrinsics), goal_to_product={}, root_subject_fns={k: lambda p: Select(p) for k in (A,)}) with self.assertRaises(ValueError) as cm: validator.validate() self.assert_equal_with_printing(dedent(""" Rules with errors: 1 (A, (SelectDependencies(B, SubA, u'dependencies', field_types=(D,)),), noop): Unreachable with subject types: Any """).strip(), str(cm.exception))
def test_ruleset_with_failure_due_to_incompatible_subject_for_intrinsic(self): rules = [ (D, (Select(C),), noop) ] intrinsics = [ (B, C, noop), ] validator = RulesetValidator(NodeBuilder.create(rules, intrinsics), goal_to_product={}, root_subject_fns={k: lambda p: Select(p) for k in (A,)}) with self.assertRaises(ValueError) as cm: validator.validate() self.assert_equal_with_printing(dedent(""" Rules with errors: 1 (D, (Select(C),), noop): no matches for Select(C) with subject types: A """).strip(), str(cm.exception))
def test_not_fulfillable_duplicated_dependency(self): # If a rule depends on another rule+subject in two ways, and one of them is unfulfillable # Only the unfulfillable one should be in the errors. rules = [ (B, (Select(D),), noop), (D, (Select(A), SelectDependencies(A, SubA, field_types=(C,))), noop), (A, (Select(SubA),), noop) ] validator = RulesetValidator(RuleIndex.create(rules, tuple()), goal_to_product={}, root_subject_fns=_suba_root_subject_fns) with self.assertRaises(ValueError) as cm: validator.validate() self.assert_equal_with_printing(dedent(""" Rules with errors: 2 (B, (Select(D),), noop): depends on unfulfillable (D, (Select(A), SelectDependencies(A, SubA, field_types=(C,))), noop) of SubA with subject types: SubA (D, (Select(A), SelectDependencies(A, SubA, field_types=(C,))), noop): depends on unfulfillable (A, (Select(SubA),), noop) of C with subject types: SubA""").strip(), str(cm.exception))
def test_not_fulfillable_duplicated_dependency(self): # If a rule depends on another rule+subject in two ways, and one of them is unfulfillable # Only the unfulfillable one should be in the errors. rules = [(B, (Select(D), ), noop), (D, (Select(A), SelectDependencies(A, SubA, field_types=(C, ))), noop), (A, (Select(SubA), ), noop)] validator = RulesetValidator(RuleIndex.create(rules, tuple()), goal_to_product={}, root_subject_fns=_suba_root_subject_fns) with self.assertRaises(ValueError) as cm: validator.validate() self.assert_equal_with_printing( dedent(""" Rules with errors: 2 (B, (Select(D),), noop): depends on unfulfillable (D, (Select(A), SelectDependencies(A, SubA, field_types=(C,))), noop) of SubA with subject types: SubA (D, (Select(A), SelectDependencies(A, SubA, field_types=(C,))), noop): depends on unfulfillable (A, (Select(SubA),), noop) of C with subject types: SubA""" ).strip(), str(cm.exception))
def __init__(self, goals, tasks, project_tree, native, graph_lock=None): """ :param goals: A dict from a goal name to a product type. A goal is just an alias for a particular (possibly synthetic) product. :param tasks: A set of (output, input selection clause, task function) triples which is used to compute values in the product graph. :param project_tree: An instance of ProjectTree for the current build root. :param native: An instance of engine.subsystem.native.Native. :param graph_lock: A re-entrant lock to use for guarding access to the internal product Graph instance. Defaults to creating a new threading.RLock(). """ self._products_by_goal = goals self._project_tree = project_tree self._native = native self._product_graph_lock = graph_lock or threading.RLock() self._run_count = 0 # TODO: The only (?) case where we use inheritance rather than exact type unions. has_products_constraint = SubclassesOf(HasProducts) # Create the ExternContext, and the native Scheduler. self._scheduler = native.new_scheduler(has_products_constraint, constraint_for(Address), constraint_for(Variants)) self._execution_request = None # Validate and register all provided and intrinsic tasks. # TODO: This bounding of input Subject types allows for closed-world validation, but is not # strictly necessary for execution. We might eventually be able to remove it by only executing # validation below the execution roots (and thus not considering paths that aren't in use). select_product = lambda product: Select(product) root_selector_fns = { Address: select_product, AscendantAddresses: select_product, DescendantAddresses: select_product, PathGlobs: select_product, SiblingAddresses: select_product, SingleAddress: select_product, } intrinsics = create_fs_intrinsics(project_tree) + create_snapshot_intrinsics(project_tree) singletons = create_snapshot_singletons(project_tree) rule_index = RuleIndex.create(tasks, intrinsics, singletons) RulesetValidator(rule_index, goals, root_selector_fns).validate() self._register_tasks(rule_index.tasks) self._register_intrinsics(rule_index.intrinsics) self._register_singletons(rule_index.singletons)
def __init__(self, goals, tasks, project_tree, graph_lock=None, inline_nodes=True, graph_validator=None): """ :param goals: A dict from a goal name to a product type. A goal is just an alias for a particular (possibly synthetic) product. :param tasks: A set of (output, input selection clause, task function) triples which is used to compute values in the product graph. :param project_tree: An instance of ProjectTree for the current build root. :param graph_lock: A re-entrant lock to use for guarding access to the internal ProductGraph instance. Defaults to creating a new threading.RLock(). :param inline_nodes: Whether to inline execution of `inlineable` Nodes. This improves performance, but can make debugging more difficult because the entire execution history is not recorded in the ProductGraph. :param graph_validator: A validator that runs over the entire graph after every scheduling attempt. Very expensive, very experimental. """ self._products_by_goal = goals self._project_tree = project_tree self._node_builder = NodeBuilder.create(tasks) self._graph_validator = graph_validator self._product_graph = ProductGraph() self._product_graph_lock = graph_lock or threading.RLock() self._inline_nodes = inline_nodes select_product = lambda product: Select(product) select_dep_addrs = lambda product: SelectDependencies( product, Addresses, field_types=(Address, )) self._root_selector_fns = { Address: select_product, PathGlobs: select_product, SingleAddress: select_dep_addrs, SiblingAddresses: select_dep_addrs, AscendantAddresses: select_dep_addrs, DescendantAddresses: select_dep_addrs, } RulesetValidator(self._node_builder, goals, self._root_selector_fns.keys()).validate()
def test_ruleset_with_explicit_type_constraint(self): rules = [(Exactly(A), (Select(B),), noop), (B, (Select(A),), noop)] validator = RulesetValidator(NodeBuilder.create(rules), goal_to_product=dict(), root_subject_types=tuple()) validator.validate()