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, [])
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, [])
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)])
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)])