Esempio n. 1
0
class TestEndpointManager(BaseTestCase):
    def setUp(self):
        super(TestEndpointManager, self).setUp()
        self.config = load_config("felix_default.cfg", env_dict={
            "FELIX_FELIXHOSTNAME": "hostname"})
        self.m_updater = Mock(spec=IptablesUpdater)
        self.m_dispatch = Mock(spec=DispatchChains)
        self.m_rules_mgr = Mock(spec=RulesManager)
        self.m_status_reporter = Mock(spec=EtcdStatusReporter)
        self.mgr = EndpointManager(self.config, "IPv4", self.m_updater,
                                   self.m_dispatch, self.m_rules_mgr,
                                   self.m_status_reporter)
        self.mgr.get_and_incref = Mock()
        self.mgr.decref = Mock()

    def test_create(self):
        obj = self.mgr._create(ENDPOINT_ID)
        self.assertTrue(isinstance(obj, LocalEndpoint))

    def test_on_started(self):
        ep = {"name": "tap1234"}
        self.mgr.on_endpoint_update(ENDPOINT_ID,
                                    ep,
                                    async=True)
        self.step_actor(self.mgr)
        m_endpoint = Mock(spec=LocalEndpoint)
        self.mgr._on_object_started(ENDPOINT_ID, m_endpoint)
        self.assertEqual(
            m_endpoint.on_endpoint_update.mock_calls,
            [mock.call(ep, async=True)]
        )

    def test_on_datamodel_in_sync(self):
        ep = {"name": "tap1234"}
        self.mgr.on_endpoint_update(ENDPOINT_ID,
                                    ep,
                                    async=True)
        self.step_actor(self.mgr)
        self.mgr.on_datamodel_in_sync(async=True)
        self.step_actor(self.mgr)
        self.assertEqual(
            self.m_dispatch.apply_snapshot.mock_calls,
            [mock.call(frozenset(["tap1234"]), async=True)]
        )
        # Second call should have no effect.
        self.m_dispatch.apply_snapshot.reset_mock()
        self.mgr.on_datamodel_in_sync(async=True)
        self.step_actor(self.mgr)
        self.assertEqual(self.m_dispatch.apply_snapshot.mock_calls, [])

    def test_endpoint_update_not_our_host(self):
        ep = {"name": "tap1234"}
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            self.mgr.on_endpoint_update(EndpointId("notus", "b", "c", "d"),
                                        ep,
                                        async=True)
            self.step_actor(self.mgr)
        self.assertFalse(m_sol.called)

    def test_endpoint_live_obj(self):
        ep = {"name": "tap1234"}
        # First send in an update to trigger creation.
        self.mgr.on_endpoint_update(ENDPOINT_ID, ep, async=True)
        self.step_actor(self.mgr)
        self.assertEqual(self.mgr.get_and_incref.mock_calls,
                         [mock.call(ENDPOINT_ID)])
        m_endpoint = Mock(spec=LocalEndpoint)
        self.mgr.objects_by_id[ENDPOINT_ID] = m_endpoint
        # Then send a second update to check that it gets passed on to the
        # LocalEndpoint.
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            m_sol.return_value = True
            self.mgr.on_endpoint_update(ENDPOINT_ID, ep, async=True)
            self.step_actor(self.mgr)
        self.assertEqual(m_sol.mock_calls, [mock.call(ENDPOINT_ID)])
        self.assertEqual(m_endpoint.on_endpoint_update.mock_calls,
                         [mock.call(ep, force_reprogram=False,
                                    async=True)])
        self.assertTrue(ENDPOINT_ID in self.mgr.local_endpoint_ids)
        # Finally, send in a deletion.
        m_endpoint.on_endpoint_update.reset_mock()
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            m_sol.return_value = True
            self.mgr.on_endpoint_update(ENDPOINT_ID, None, async=True)
            self.step_actor(self.mgr)
        self.assertEqual(m_endpoint.on_endpoint_update.mock_calls,
                         [mock.call(None, force_reprogram=False,
                                    async=True)])
        self.assertEqual(self.mgr.decref.mock_calls, [mock.call(ENDPOINT_ID)])
        self.assertFalse(ENDPOINT_ID in self.mgr.local_endpoint_ids)

    def test_on_interface_update_unknown(self):
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            self.mgr.on_interface_update("foo", True, async=True)
            self.step_actor(self.mgr)
        self.assertFalse(m_sol.called)

    def test_on_interface_update_known(self):
        ep = {"name": "tap1234"}
        m_endpoint = Mock(spec=LocalEndpoint)
        self.mgr.objects_by_id[ENDPOINT_ID] = m_endpoint
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            m_sol.return_value = True
            self.mgr.on_endpoint_update(ENDPOINT_ID, ep, async=True)
            self.mgr.on_interface_update("tap1234", True, async=True)
            self.step_actor(self.mgr)
        self.assertEqual(
            m_endpoint.on_interface_update.mock_calls,
            [mock.call(True, async=True)]
        )

    def test_on_interface_update_known_but_not_live(self):
        ep = {"name": "tap1234"}
        m_endpoint = Mock(spec=LocalEndpoint)
        self.mgr.objects_by_id[ENDPOINT_ID] = m_endpoint
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            m_sol.return_value = False
            self.mgr.on_endpoint_update(ENDPOINT_ID, ep, async=True)
            self.mgr.on_interface_update("tap1234", True, async=True)
            self.step_actor(self.mgr)
        self.assertEqual(m_endpoint.on_interface_update.mock_calls, [])
Esempio n. 2
0
class TestEndpointManager(BaseTestCase):
    def setUp(self):
        super(TestEndpointManager, self).setUp()
        self.config = load_config("felix_default.cfg", env_dict={
            "FELIX_FELIXHOSTNAME": "hostname"})
        self.m_updater = Mock(spec=IptablesUpdater)
        self.m_dispatch = Mock(spec=DispatchChains)
        self.m_rules_mgr = Mock(spec=RulesManager)
        self.m_fip_manager = Mock(spec=FloatingIPManager)
        self.m_status_reporter = Mock(spec=EtcdStatusReporter)
        self.mgr = EndpointManager(self.config, "IPv4", self.m_updater,
                                   self.m_dispatch, self.m_rules_mgr,
                                   self.m_fip_manager, self.m_status_reporter)
        self.mgr.get_and_incref = Mock()
        self.mgr.decref = Mock()

    def test_create(self):
        obj = self.mgr._create(ENDPOINT_ID)
        self.assertTrue(isinstance(obj, LocalEndpoint))

    def test_on_started(self):
        ep = {"name": "tap1234"}
        self.mgr.on_endpoint_update(ENDPOINT_ID,
                                    ep,
                                    async=True)
        self.step_actor(self.mgr)
        m_endpoint = Mock(spec=LocalEndpoint)
        self.mgr.objects_by_id[ENDPOINT_ID] = m_endpoint
        self.mgr._on_object_started(ENDPOINT_ID, m_endpoint)
        self.assertEqual(
            m_endpoint.on_endpoint_update.mock_calls,
            [mock.call(ep, async=True)]
        )

    def test_on_datamodel_in_sync(self):
        ep = {"name": "tap1234"}
        self.mgr.on_endpoint_update(ENDPOINT_ID,
                                    ep,
                                    async=True)
        self.step_actor(self.mgr)
        self.mgr.on_datamodel_in_sync(async=True)
        self.step_actor(self.mgr)
        self.assertEqual(
            self.m_dispatch.apply_snapshot.mock_calls,
            [mock.call(frozenset(["tap1234"]), async=True)]
        )
        # Second call should have no effect.
        self.m_dispatch.apply_snapshot.reset_mock()
        self.mgr.on_datamodel_in_sync(async=True)
        self.step_actor(self.mgr)
        self.assertEqual(self.m_dispatch.apply_snapshot.mock_calls, [])

    def test_tiered_policy_ordering_and_updates(self):
        """
        Check that the tier_sequence ordering is updated correctly as we
        add and remove tiers and policies.
        """
        # Make sure we have an endpoint so that we can check that it gets
        # put in the dirty set.
        self.mgr.on_datamodel_in_sync(async=True)
        self.mgr.on_endpoint_update(ENDPOINT_ID,
                                    {"name": "tap12345"},
                                    async=True)
        self.step_actor(self.mgr)

        # Pretend that the endpoint is alive so that we'll send updates to id.
        m_endpoint = Mock(spec=LocalEndpoint)
        self.mgr.objects_by_id[ENDPOINT_ID] = m_endpoint
        self.mgr._is_starting_or_live = Mock(return_value=True)

        # Add a profile into the tier so it'll apply to the endpoint.
        pol_id_a = TieredPolicyId("a", "a1")
        self.mgr.on_policy_selector_update(pol_id_a, parse_selector("all()"),
                                           10, async=True)
        pol_id_b = TieredPolicyId("b", "b1")
        self.mgr.on_policy_selector_update(pol_id_b, parse_selector("all()"),
                                           10, async=True)
        pol_id_c1 = TieredPolicyId("c1", "c1")
        self.mgr.on_policy_selector_update(pol_id_c1, parse_selector("all()"),
                                           10, async=True)
        pol_id_c2 = TieredPolicyId("c2", "c2")
        self.mgr.on_policy_selector_update(pol_id_c2, parse_selector("all()"),
                                           10, async=True)
        pol_id_c3 = TieredPolicyId("c3", "c3")
        self.mgr.on_policy_selector_update(pol_id_c3, parse_selector("all()"),
                                           10, async=True)
        self.step_actor(self.mgr)
        # Since we haven't set the tier ID yet, the policy won't get applied...
        self.assertEqual(m_endpoint.on_tiered_policy_update.mock_calls,
                         [mock.call(OrderedDict(), async=True)] * 5)
        m_endpoint.on_tiered_policy_update.reset_mock()

        # Adding a tier should trigger an update, adding the tier and policy.
        self.mgr.on_tier_data_update("a", {"order": 1}, async=True)
        self.step_actor(self.mgr)
        self.assertEqual(self.mgr.endpoints_with_dirty_policy, set())
        tiers = OrderedDict()
        tiers["a"] = [pol_id_a]
        self.assertEqual(m_endpoint.on_tiered_policy_update.mock_calls,
                         [mock.call(tiers, async=True)])
        m_endpoint.on_tiered_policy_update.reset_mock()

        # Idempotent update should get squashed.
        self.mgr.on_tier_data_update("a", {"order": 2}, async=True)
        self.mgr.on_tier_data_update("a", {"order": 2}, async=True)
        self.step_actor(self.mgr)
        self.assertEqual(m_endpoint.on_tiered_policy_update.mock_calls, [])

        # Adding another tier should trigger an update.
        self.mgr.on_tier_data_update("b", {"order": 3}, async=True)
        self.step_actor(self.mgr)
        tiers = OrderedDict()
        tiers["a"] = [pol_id_a]
        tiers["b"] = [pol_id_b]
        self.assertEqual(m_endpoint.on_tiered_policy_update.mock_calls,
                         [mock.call(tiers, async=True)])
        m_endpoint.on_tiered_policy_update.reset_mock()

        # Swapping the order should trigger an update.
        self.mgr.on_tier_data_update("b", {"order": 1}, async=True)
        self.step_actor(self.mgr)
        tiers = OrderedDict()
        tiers["b"] = [pol_id_b]
        tiers["a"] = [pol_id_a]
        self.assertEqual(m_endpoint.on_tiered_policy_update.mock_calls,
                         [mock.call(tiers, async=True)])
        m_endpoint.on_tiered_policy_update.reset_mock()

        # Check deletion and that it's idempotent.
        self.mgr.on_tier_data_update("b", None, async=True)
        self.step_actor(self.mgr)
        self.mgr.on_policy_selector_update(pol_id_b, None, None, async=True)
        self.mgr.on_policy_selector_update(pol_id_b, None, None, async=True)
        self.step_actor(self.mgr)
        self.mgr.on_tier_data_update("b", None, async=True)
        self.step_actor(self.mgr)
        self.mgr.on_policy_selector_update(pol_id_b, None, None, async=True)
        self.mgr.on_policy_selector_update(pol_id_b, None, None, async=True)
        self.step_actor(self.mgr)
        tiers = OrderedDict()
        tiers["a"] = [pol_id_a]
        self.assertEqual(
            m_endpoint.on_tiered_policy_update.mock_calls,
            [mock.call(tiers, async=True)] * 2  # One for policy, one for tier.
        )
        m_endpoint.on_tiered_policy_update.reset_mock()

        # Check lexicographic tie-breaker.
        self.mgr.on_tier_data_update("c1", {"order": 0}, async=True)
        self.mgr.on_tier_data_update("c2", {"order": 0}, async=True)
        self.mgr.on_tier_data_update("c3", {"order": 0}, async=True)
        self.step_actor(self.mgr)
        tiers = OrderedDict()
        # All 'c's should sort before 'a' due to explicit ordering but 'c's
        # should sort in lexicographic order.
        tiers["c1"] = [pol_id_c1]
        tiers["c2"] = [pol_id_c2]
        tiers["c3"] = [pol_id_c3]
        tiers["a"] = [pol_id_a]
        actual_call = m_endpoint.on_tiered_policy_update.mock_calls[-1]
        expected_call = mock.call(tiers, async=True)
        self.assertEqual(actual_call, expected_call,
                         msg="\nExpected: %s\n Got:     %s" %
                             (expected_call, actual_call))
        m_endpoint.on_tiered_policy_update.reset_mock()

    def test_label_inheritance(self):
        # Make sure we have an endpoint so that we can check that it gets
        # put in the dirty set.  These have no labels at all so we test
        # that no labels gets translated to an empty dict.
        self.mgr.on_endpoint_update(ENDPOINT_ID, {"name": "tap12345",
                                                  "profile_ids": ["prof1"]},
                                    async=True)
        self.mgr.on_endpoint_update(ENDPOINT_ID_2, {"name": "tap23456",
                                                    "profile_ids": ["prof2"]},
                                    async=True)
        # And we need a selector to pick out one of the endpoints by the labels
        # attached to its parent.
        self.mgr.on_policy_selector_update(TieredPolicyId("a", "b"),
                                           parse_selector('a == "b"'),
                                           10,
                                           async=True)
        self.step_actor(self.mgr)

        with mock.patch.object(self.mgr, "_update_dirty_policy") as m_update:
            self.mgr.on_prof_labels_set("prof1", {"a": "b"}, async=True)
            self.step_actor(self.mgr)
            # Only the first endpoint should end up matching the selector.
            self.assertEqual(self.mgr.endpoints_with_dirty_policy,
                             set([ENDPOINT_ID]))
            # And an update should be triggered.
            self.assertEqual(m_update.mock_calls, [mock.call()])

    def test_endpoint_update_not_our_host(self):
        ep = {"name": "tap1234"}
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            self.mgr.on_endpoint_update(EndpointId("notus", "b", "c", "d"),
                                        ep,
                                        async=True)
            self.step_actor(self.mgr)
        self.assertFalse(m_sol.called)

    def test_endpoint_live_obj(self):
        ep = {"name": "tap1234"}
        # First send in an update to trigger creation.
        self.mgr.on_endpoint_update(ENDPOINT_ID, ep, async=True)
        self.step_actor(self.mgr)
        self.assertEqual(self.mgr.get_and_incref.mock_calls,
                         [mock.call(ENDPOINT_ID)])
        m_endpoint = Mock(spec=LocalEndpoint)
        self.mgr.objects_by_id[ENDPOINT_ID] = m_endpoint
        # Then send a second update to check that it gets passed on to the
        # LocalEndpoint.
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            m_sol.return_value = True
            self.mgr.on_endpoint_update(ENDPOINT_ID, ep, async=True)
            self.step_actor(self.mgr)
        self.assertEqual(m_sol.mock_calls, [mock.call(ENDPOINT_ID)])
        self.assertEqual(m_endpoint.on_endpoint_update.mock_calls,
                         [mock.call(ep, force_reprogram=False,
                                    async=True)])
        self.assertTrue(ENDPOINT_ID in self.mgr.local_endpoint_ids)
        # Finally, send in a deletion.
        m_endpoint.on_endpoint_update.reset_mock()
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            m_sol.return_value = True
            self.mgr.on_endpoint_update(ENDPOINT_ID, None, async=True)
            self.step_actor(self.mgr)
        self.assertEqual(m_endpoint.on_endpoint_update.mock_calls,
                         [mock.call(None, force_reprogram=False,
                                    async=True)])
        self.assertEqual(self.mgr.decref.mock_calls, [mock.call(ENDPOINT_ID)])
        self.assertFalse(ENDPOINT_ID in self.mgr.local_endpoint_ids)

    def test_on_interface_update_unknown(self):
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            self.mgr.on_interface_update("foo", True, async=True)
            self.step_actor(self.mgr)
        self.assertFalse(m_sol.called)

    def test_on_interface_update_known(self):
        ep = {"name": "tap1234"}
        m_endpoint = Mock(spec=LocalEndpoint)
        self.mgr.objects_by_id[ENDPOINT_ID] = m_endpoint
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            m_sol.return_value = True
            self.mgr.on_endpoint_update(ENDPOINT_ID, ep, async=True)
            self.mgr.on_interface_update("tap1234", True, async=True)
            self.step_actor(self.mgr)
        self.assertEqual(
            m_endpoint.on_interface_update.mock_calls,
            [mock.call(True, async=True)]
        )

    def test_on_interface_update_known_but_not_live(self):
        ep = {"name": "tap1234"}
        m_endpoint = Mock(spec=LocalEndpoint)
        self.mgr.objects_by_id[ENDPOINT_ID] = m_endpoint
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            m_sol.return_value = False
            self.mgr.on_endpoint_update(ENDPOINT_ID, ep, async=True)
            self.mgr.on_interface_update("tap1234", True, async=True)
            self.step_actor(self.mgr)
        self.assertEqual(m_endpoint.on_interface_update.mock_calls, [])
Esempio n. 3
0
class TestEndpointManager(BaseTestCase):
    def setUp(self):
        super(TestEndpointManager, self).setUp()
        self.config = load_config("felix_default.cfg",
                                  env_dict={"FELIX_FELIXHOSTNAME": "hostname"})
        self.m_updater = Mock(spec=IptablesUpdater)
        self.m_dispatch = Mock(spec=DispatchChains)
        self.m_rules_mgr = Mock(spec=RulesManager)
        self.m_status_reporter = Mock(spec=EtcdStatusReporter)
        self.mgr = EndpointManager(self.config, "IPv4", self.m_updater,
                                   self.m_dispatch, self.m_rules_mgr,
                                   self.m_status_reporter)
        self.mgr.get_and_incref = Mock()
        self.mgr.decref = Mock()

    def test_create(self):
        obj = self.mgr._create(ENDPOINT_ID)
        self.assertTrue(isinstance(obj, LocalEndpoint))

    def test_on_started(self):
        ep = {"name": "tap1234"}
        self.mgr.on_endpoint_update(ENDPOINT_ID, ep, async=True)
        self.step_actor(self.mgr)
        m_endpoint = Mock(spec=LocalEndpoint)
        self.mgr._on_object_started(ENDPOINT_ID, m_endpoint)
        self.assertEqual(m_endpoint.on_endpoint_update.mock_calls,
                         [mock.call(ep, async=True)])

    def test_on_datamodel_in_sync(self):
        ep = {"name": "tap1234"}
        self.mgr.on_endpoint_update(ENDPOINT_ID, ep, async=True)
        self.step_actor(self.mgr)
        self.mgr.on_datamodel_in_sync(async=True)
        self.step_actor(self.mgr)
        self.assertEqual(self.m_dispatch.apply_snapshot.mock_calls,
                         [mock.call(frozenset(["tap1234"]), async=True)])
        # Second call should have no effect.
        self.m_dispatch.apply_snapshot.reset_mock()
        self.mgr.on_datamodel_in_sync(async=True)
        self.step_actor(self.mgr)
        self.assertEqual(self.m_dispatch.apply_snapshot.mock_calls, [])

    def test_endpoint_update_not_our_host(self):
        ep = {"name": "tap1234"}
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            self.mgr.on_endpoint_update(EndpointId("notus", "b", "c", "d"),
                                        ep,
                                        async=True)
            self.step_actor(self.mgr)
        self.assertFalse(m_sol.called)

    def test_endpoint_live_obj(self):
        ep = {"name": "tap1234"}
        # First send in an update to trigger creation.
        self.mgr.on_endpoint_update(ENDPOINT_ID, ep, async=True)
        self.step_actor(self.mgr)
        self.assertEqual(self.mgr.get_and_incref.mock_calls,
                         [mock.call(ENDPOINT_ID)])
        m_endpoint = Mock(spec=LocalEndpoint)
        self.mgr.objects_by_id[ENDPOINT_ID] = m_endpoint
        # Then send a second update to check that it gets passed on to the
        # LocalEndpoint.
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            m_sol.return_value = True
            self.mgr.on_endpoint_update(ENDPOINT_ID, ep, async=True)
            self.step_actor(self.mgr)
        self.assertEqual(m_sol.mock_calls, [mock.call(ENDPOINT_ID)])
        self.assertEqual(m_endpoint.on_endpoint_update.mock_calls,
                         [mock.call(ep, force_reprogram=False, async=True)])
Esempio n. 4
0
class TestEndpointManager(BaseTestCase):
    def setUp(self):
        super(TestEndpointManager, self).setUp()
        self.config = load_config("felix_default.cfg", env_dict={
            "FELIX_FELIXHOSTNAME": "hostname"})
        self.m_updater = Mock(spec=IptablesUpdater)
        self.m_dispatch = Mock(spec=DispatchChains)
        self.m_rules_mgr = Mock(spec=RulesManager)
        self.m_fip_manager = Mock(spec=FloatingIPManager)
        self.m_status_reporter = Mock(spec=EtcdStatusReporter)
        self.mgr = EndpointManager(self.config, "IPv4", self.m_updater,
                                   self.m_dispatch, self.m_rules_mgr,
                                   self.m_fip_manager, self.m_status_reporter)
        self.mgr.get_and_incref = Mock()
        self.mgr.decref = Mock()

    def test_create(self):
        obj = self.mgr._create(ENDPOINT_ID)
        self.assertTrue(isinstance(obj, LocalEndpoint))

    def test_on_started(self):
        ep = {"name": "tap1234"}
        self.mgr.on_endpoint_update(ENDPOINT_ID,
                                    ep,
                                    async=True)
        self.step_actor(self.mgr)
        m_endpoint = Mock(spec=LocalEndpoint)
        self.mgr.objects_by_id[ENDPOINT_ID] = m_endpoint
        self.mgr._on_object_started(ENDPOINT_ID, m_endpoint)
        self.assertEqual(
            m_endpoint.on_endpoint_update.mock_calls,
            [mock.call(ep, async=True)]
        )

    def test_on_datamodel_in_sync(self):
        ep = {"name": "tap1234"}
        self.mgr.on_endpoint_update(ENDPOINT_ID,
                                    ep,
                                    async=True)
        self.step_actor(self.mgr)
        self.mgr.on_datamodel_in_sync(async=True)
        self.step_actor(self.mgr)
        self.assertEqual(
            self.m_dispatch.apply_snapshot.mock_calls,
            [mock.call(frozenset(["tap1234"]), async=True)]
        )
        # Second call should have no effect.
        self.m_dispatch.apply_snapshot.reset_mock()
        self.mgr.on_datamodel_in_sync(async=True)
        self.step_actor(self.mgr)
        self.assertEqual(self.m_dispatch.apply_snapshot.mock_calls, [])

    def test_tiered_policy_ordering_and_updates(self):
        """
        Check that the tier_sequence ordering is updated correctly as we
        add and remove tiers and policies.
        """
        # Make sure we have an endpoint so that we can check that it gets
        # put in the dirty set.
        self.mgr.on_datamodel_in_sync(async=True)
        self.mgr.on_endpoint_update(ENDPOINT_ID,
                                    {"name": "tap12345"},
                                    async=True)
        self.step_actor(self.mgr)

        # Pretend that the endpoint is alive so that we'll send updates to id.
        m_endpoint = Mock(spec=LocalEndpoint)
        self.mgr.objects_by_id[ENDPOINT_ID] = m_endpoint
        self.mgr._is_starting_or_live = Mock(return_value=True)

        # Add a profile into the tier so it'll apply to the endpoint.
        pol_id_a = TieredPolicyId("a", "a1")
        self.mgr.on_policy_selector_update(pol_id_a, parse_selector("all()"),
                                           10, async=True)
        pol_id_b = TieredPolicyId("b", "b1")
        self.mgr.on_policy_selector_update(pol_id_b, parse_selector("all()"),
                                           10, async=True)
        pol_id_c1 = TieredPolicyId("c1", "c1")
        self.mgr.on_policy_selector_update(pol_id_c1, parse_selector("all()"),
                                           10, async=True)
        pol_id_c2 = TieredPolicyId("c2", "c2")
        self.mgr.on_policy_selector_update(pol_id_c2, parse_selector("all()"),
                                           10, async=True)
        pol_id_c3 = TieredPolicyId("c3", "c3")
        self.mgr.on_policy_selector_update(pol_id_c3, parse_selector("all()"),
                                           10, async=True)
        self.step_actor(self.mgr)
        # Since we haven't set the tier ID yet, the policy won't get applied...
        self.assertEqual(m_endpoint.on_tiered_policy_update.mock_calls,
                         [mock.call(OrderedDict(), async=True)] * 5)
        m_endpoint.on_tiered_policy_update.reset_mock()

        # Adding a tier should trigger an update, adding the tier and policy.
        self.mgr.on_tier_data_update("a", {"order": 1}, async=True)
        self.step_actor(self.mgr)
        self.assertEqual(self.mgr.endpoints_with_dirty_policy, set())
        tiers = OrderedDict()
        tiers["a"] = [pol_id_a]
        self.assertEqual(m_endpoint.on_tiered_policy_update.mock_calls,
                         [mock.call(tiers, async=True)])
        m_endpoint.on_tiered_policy_update.reset_mock()

        # Idempotent update should get squashed.
        self.mgr.on_tier_data_update("a", {"order": 2}, async=True)
        self.mgr.on_tier_data_update("a", {"order": 2}, async=True)
        self.step_actor(self.mgr)
        self.assertEqual(m_endpoint.on_tiered_policy_update.mock_calls, [])

        # Adding another tier should trigger an update.
        self.mgr.on_tier_data_update("b", {"order": 3}, async=True)
        self.step_actor(self.mgr)
        tiers = OrderedDict()
        tiers["a"] = [pol_id_a]
        tiers["b"] = [pol_id_b]
        self.assertEqual(m_endpoint.on_tiered_policy_update.mock_calls,
                         [mock.call(tiers, async=True)])
        m_endpoint.on_tiered_policy_update.reset_mock()

        # Swapping the order should trigger an update.
        self.mgr.on_tier_data_update("b", {"order": 1}, async=True)
        self.step_actor(self.mgr)
        tiers = OrderedDict()
        tiers["b"] = [pol_id_b]
        tiers["a"] = [pol_id_a]
        self.assertEqual(m_endpoint.on_tiered_policy_update.mock_calls,
                         [mock.call(tiers, async=True)])
        m_endpoint.on_tiered_policy_update.reset_mock()

        # Check deletion and that it's idempotent.
        self.mgr.on_tier_data_update("b", None, async=True)
        self.step_actor(self.mgr)
        self.mgr.on_policy_selector_update(pol_id_b, None, None, async=True)
        self.mgr.on_policy_selector_update(pol_id_b, None, None, async=True)
        self.step_actor(self.mgr)
        self.mgr.on_tier_data_update("b", None, async=True)
        self.step_actor(self.mgr)
        self.mgr.on_policy_selector_update(pol_id_b, None, None, async=True)
        self.mgr.on_policy_selector_update(pol_id_b, None, None, async=True)
        self.step_actor(self.mgr)
        tiers = OrderedDict()
        tiers["a"] = [pol_id_a]
        self.assertEqual(
            m_endpoint.on_tiered_policy_update.mock_calls,
            [mock.call(tiers, async=True)] * 2  # One for policy, one for tier.
        )
        m_endpoint.on_tiered_policy_update.reset_mock()

        # Check lexicographic tie-breaker.
        self.mgr.on_tier_data_update("c1", {"order": 0}, async=True)
        self.mgr.on_tier_data_update("c2", {"order": 0}, async=True)
        self.mgr.on_tier_data_update("c3", {"order": 0}, async=True)
        self.step_actor(self.mgr)
        tiers = OrderedDict()
        # All 'c's should sort before 'a' due to explicit ordering but 'c's
        # should sort in lexicographic order.
        tiers["c1"] = [pol_id_c1]
        tiers["c2"] = [pol_id_c2]
        tiers["c3"] = [pol_id_c3]
        tiers["a"] = [pol_id_a]
        actual_call = m_endpoint.on_tiered_policy_update.mock_calls[-1]
        expected_call = mock.call(tiers, async=True)
        self.assertEqual(actual_call, expected_call,
                         msg="\nExpected: %s\n Got:     %s" %
                             (expected_call, actual_call))
        m_endpoint.on_tiered_policy_update.reset_mock()

    def test_label_inheritance(self):
        # Make sure we have an endpoint so that we can check that it gets
        # put in the dirty set.  These have no labels at all so we test
        # that no labels gets translated to an empty dict.
        self.mgr.on_endpoint_update(ENDPOINT_ID, {"name": "tap12345",
                                                  "profile_ids": ["prof1"]},
                                    async=True)
        self.mgr.on_endpoint_update(ENDPOINT_ID_2, {"name": "tap23456",
                                                    "profile_ids": ["prof2"]},
                                    async=True)
        # And we need a selector to pick out one of the endpoints by the labels
        # attached to its parent.
        self.mgr.on_policy_selector_update(TieredPolicyId("a", "b"),
                                           parse_selector('a == "b"'),
                                           10,
                                           async=True)
        self.step_actor(self.mgr)

        with mock.patch.object(self.mgr, "_update_dirty_policy") as m_update:
            self.mgr.on_prof_labels_set("prof1", {"a": "b"}, async=True)
            self.step_actor(self.mgr)
            # Only the first endpoint should end up matching the selector.
            self.assertEqual(self.mgr.endpoints_with_dirty_policy,
                             set([ENDPOINT_ID]))
            # And an update should be triggered.
            self.assertEqual(m_update.mock_calls, [mock.call()])

    def test_endpoint_update_not_our_host(self):
        ep = {"name": "tap1234"}
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            self.mgr.on_endpoint_update(EndpointId("notus", "b", "c", "d"),
                                        ep,
                                        async=True)
            self.step_actor(self.mgr)
        self.assertFalse(m_sol.called)

    def test_endpoint_live_obj(self):
        ep = {"name": "tap1234"}
        # First send in an update to trigger creation.
        self.mgr.on_endpoint_update(ENDPOINT_ID, ep, async=True)
        self.step_actor(self.mgr)
        self.assertEqual(self.mgr.get_and_incref.mock_calls,
                         [mock.call(ENDPOINT_ID)])
        m_endpoint = Mock(spec=LocalEndpoint)
        self.mgr.objects_by_id[ENDPOINT_ID] = m_endpoint
        # Then send a second update to check that it gets passed on to the
        # LocalEndpoint.
        with mock.patch.object(self.mgr, "_is_starting_or_live") as m_sol:
            m_sol.return_value = True
            self.mgr.on_endpoint_update(ENDPOINT_ID, ep, async=True)
            self.step_actor(self.mgr)
        self.assertEqual(m_sol.mock_calls, [mock.call(ENDPOINT_ID)])
        self.assertEqual(m_endpoint.on_endpoint_update.mock_calls,
                         [mock.call(ep, force_reprogram=False,
                                    async=True)])