import copy
import json
import unittest
from unittest.mock import patch, MagicMock
import threading
from olc.bean.constant import NORMAL, GLOBAL, EQUAL, DEFAULT, REGEX, TAGS_SIZE_MAX
from olc.bean.olc_config_rule import (
OlcConfigRule,
OlcRule,
Group,
OlcMultiTag,
FlowPolicy,
AdmissionPolicy,
AlgInstance,
)
from olc.bean.tag_group import TagGroup, OlcTag
from olc.rule.olc_rule_convert import OlcRuleConvert, RuleRefreshTask
def _make_multi_tag(tag="ServiceName", match="equal", values=None, share=None):
if values is None:
values = ["svc1"]
return OlcMultiTag(tag=tag, match=match, values=values, share=share)
def _make_group(
name="test_group",
group_type="normal",
enabled=True,
tags=None,
priority=500,
):
if tags is None:
tags = [_make_multi_tag()]
return Group(
priority=priority,
enabled=enabled,
name=name,
type=group_type,
tags=tags,
)
def _make_flow_policy(
name="flow1",
enabled=True,
rate_limit=100,
time_unit="second",
time_interval=1,
):
return FlowPolicy(
name=name,
category="test",
enabled=enabled,
block_msg="",
policy_type="NODE",
time_unit=time_unit,
time_interval=time_interval,
rate_limit=rate_limit,
burst_limit=0,
flow_control_mode="qps",
max_wait_time_ms=0,
calculate_alg=None,
assign_alg=None,
)
def _make_admission_policy(name="admission1", enabled=True):
return AdmissionPolicy(
name=name,
category="test",
enabled=enabled,
block_msg="",
type="test_type",
calculate_alg=None,
)
def _make_olc_rule(group=None, flow=None, admission=None):
if group is None:
group = _make_group()
if flow is None:
flow = _make_flow_policy()
return OlcRule(group=group, flow=flow, admission=admission)
def _make_config_rule(domain="test_domain", rules=None):
if rules is None:
rules = [_make_olc_rule()]
return OlcConfigRule(domain=domain, rules=rules)
class TestOlcRuleConvertInit(unittest.TestCase):
def setUp(self):
OlcRuleConvert._instance = None
def tearDown(self):
OlcRuleConvert._instance = None
@patch("olc.rule.olc_rule_convert.OlcConfigManager")
def test_get_instance_creates_singleton(self, mock_config_mgr):
mock_sdk = MagicMock()
mock_sdk.policy_update_period = 10
mock_config_mgr.get_instance.return_value.get_sdk_config.return_value = mock_sdk
instance1 = OlcRuleConvert.get_instance()
instance2 = OlcRuleConvert.get_instance()
self.assertIs(instance1, instance2)
self.assertEqual(instance1.interval_seconds, 10)
@patch("olc.rule.olc_rule_convert.OlcConfigManager")
def test_get_instance_uses_config_period(self, mock_config_mgr):
mock_sdk = MagicMock()
mock_sdk.policy_update_period = 30
mock_config_mgr.get_instance.return_value.get_sdk_config.return_value = mock_sdk
instance = OlcRuleConvert.get_instance()
self.assertEqual(instance.interval_seconds, 30)
def test_init_default_interval(self):
converter = OlcRuleConvert()
self.assertEqual(converter.interval_seconds, 6)
self.assertIsNone(converter.stub)
self.assertIsNone(converter._old_olc_rule)
def test_init_custom_interval(self):
converter = OlcRuleConvert(interval_seconds=60)
self.assertEqual(converter.interval_seconds, 60)
@patch("olc.rule.olc_rule_convert.OlcConfigManager")
def test_singleton_double_checked_locking(self, mock_config_mgr):
mock_sdk = MagicMock()
mock_sdk.policy_update_period = 6
mock_config_mgr.get_instance.return_value.get_sdk_config.return_value = mock_sdk
instances = []
barrier = threading.Barrier(5)
def get_instance():
barrier.wait()
instances.append(OlcRuleConvert.get_instance())
threads = [threading.Thread(target=get_instance) for _ in range(5)]
for t in threads:
t.start()
for t in threads:
t.join()
first = instances[0]
for inst in instances[1:]:
self.assertIs(inst, first)
class TestOlcRuleConvertInitMethod(unittest.TestCase):
def setUp(self):
OlcRuleConvert._instance = None
def tearDown(self):
OlcRuleConvert._instance = None
@patch("olc.rule.olc_rule_convert.OlcConfigPluginManager")
@patch("olc.rule.olc_rule_convert.OlcConfigManager")
def test_init_with_valid_plugin(self, mock_config_mgr, mock_plugin_mgr):
mock_sdk = MagicMock()
mock_sdk.config_stub = "jsonfile"
mock_config_mgr.get_instance.return_value.get_sdk_config.return_value = mock_sdk
mock_stub_instance = MagicMock()
mock_stub_instance.get_olc_config_rules.return_value = None
mock_plugin_class = MagicMock(return_value=mock_stub_instance)
mock_plugin_mgr.get_instance.return_value.get_stub_plugin.return_value = (
mock_plugin_class
)
converter = OlcRuleConvert()
with patch.object(converter, "convert_rules_task"), patch.object(
converter, "start_task"
):
converter.init()
self.assertEqual(converter.stub, mock_stub_instance)
@patch("olc.rule.olc_rule_convert.OlcConfigPluginManager")
@patch("olc.rule.olc_rule_convert.OlcConfigManager")
def test_init_plugin_not_found_returns_early(self, mock_config_mgr, mock_plugin_mgr):
mock_sdk = MagicMock()
mock_sdk.config_stub = "nonexistent"
mock_config_mgr.get_instance.return_value.get_sdk_config.return_value = mock_sdk
mock_plugin_mgr.get_instance.return_value.get_stub_plugin.return_value = None
converter = OlcRuleConvert()
converter.init()
self.assertIsNone(converter.stub)
@patch("olc.rule.olc_rule_convert.OlcConfigPluginManager")
@patch("olc.rule.olc_rule_convert.OlcConfigManager")
def test_init_plugin_raises_exception(self, mock_config_mgr, mock_plugin_mgr):
mock_sdk = MagicMock()
mock_sdk.config_stub = "jsonfile"
mock_config_mgr.get_instance.return_value.get_sdk_config.return_value = mock_sdk
mock_plugin_class = MagicMock(side_effect=Exception("plugin init error"))
mock_plugin_mgr.get_instance.return_value.get_stub_plugin.return_value = (
mock_plugin_class
)
converter = OlcRuleConvert()
converter.init()
self.assertIsNone(converter.stub)
class TestConvertRulesTask(unittest.TestCase):
def setUp(self):
OlcRuleConvert._instance = None
def tearDown(self):
OlcRuleConvert._instance = None
def test_convert_rules_task_stub_returns_none(self):
converter = OlcRuleConvert()
converter.stub = MagicMock()
converter.stub.get_olc_config_rules.return_value = None
converter.convert_rules_task()
self.assertIsNone(converter._old_olc_rule)
def test_convert_rules_task_first_time_load(self):
converter = OlcRuleConvert()
converter.stub = MagicMock()
rules_json = '{"domain":"test","rules":[]}'
converter.stub.get_olc_config_rules.return_value = rules_json
with patch.object(converter, "update_rule") as mock_update:
converter.convert_rules_task()
mock_update.assert_called_once()
self.assertEqual(converter._old_olc_rule, rules_json)
def test_convert_rules_task_same_rule_skips(self):
rules_json = '{"domain":"test","rules":[]}'
converter = OlcRuleConvert()
converter.stub = MagicMock()
converter.stub.get_olc_config_rules.return_value = rules_json
converter._old_olc_rule = rules_json
with patch.object(converter, "update_rule") as mock_update:
converter.convert_rules_task()
mock_update.assert_not_called()
def test_convert_rules_task_different_rule_updates(self):
old_rule = '{"domain":"test","rules":[]}'
new_rule = '{"domain":"test2","rules":[]}'
converter = OlcRuleConvert()
converter.stub = MagicMock()
converter.stub.get_olc_config_rules.return_value = new_rule
converter._old_olc_rule = old_rule
with patch.object(converter, "update_rule") as mock_update:
converter.convert_rules_task()
mock_update.assert_called_once()
self.assertEqual(converter._old_olc_rule, new_rule)
def test_convert_rules_task_invalid_json(self):
converter = OlcRuleConvert()
converter.stub = MagicMock()
converter.stub.get_olc_config_rules.return_value = "invalid json"
with patch.object(converter, "update_rule") as mock_update:
converter.convert_rules_task()
mock_update.assert_not_called()
def test_convert_rules_task_exception_handling(self):
converter = OlcRuleConvert()
converter.stub = MagicMock()
converter.stub.get_olc_config_rules.side_effect = Exception("connection error")
converter.convert_rules_task()
def test_convert_rules_task_no_stub_catches_error(self):
converter = OlcRuleConvert()
converter.stub = None
converter.convert_rules_task()
def test_convert_rules_task_old_rule_preserved_on_failure(self):
old_rule = '{"domain":"test","rules":[]}'
converter = OlcRuleConvert()
converter.stub = MagicMock()
converter._old_olc_rule = old_rule
converter.stub.get_olc_config_rules.return_value = "invalid json"
converter.convert_rules_task()
self.assertEqual(converter._old_olc_rule, old_rule)
def test_convert_rules_task_json_key_order_independence(self):
rules_json1 = '{"domain":"test","rules":[]}'
rules_json2 = '{"rules":[],"domain":"test"}'
converter = OlcRuleConvert()
converter.stub = MagicMock()
converter._old_olc_rule = rules_json1
converter.stub.get_olc_config_rules.return_value = rules_json2
with patch.object(converter, "update_rule") as mock_update:
converter.convert_rules_task()
mock_update.assert_called()
class TestUpdateRule(unittest.TestCase):
def setUp(self):
OlcRuleConvert._instance = None
def tearDown(self):
OlcRuleConvert._instance = None
@patch("olc.rule.olc_rule_convert.OlcRuleManager")
@patch("olc.rule.olc_rule_convert.Event")
def test_update_rule_invalid_rule_skips(self, mock_event, mock_rule_mgr):
converter = OlcRuleConvert()
invalid_rule = MagicMock()
invalid_rule.valid.return_value = False
converter.update_rule(invalid_rule)
mock_rule_mgr.get_instance.return_value.config_update.assert_not_called()
@patch("olc.rule.olc_rule_convert.OlcRuleManager")
@patch("olc.rule.olc_rule_convert.Event")
def test_update_rule_valid_rule_updates(self, mock_event, mock_rule_mgr):
converter = OlcRuleConvert()
config_rule = MagicMock()
config_rule.valid.return_value = True
with patch.object(converter, "convert_to_rule_cache") as mock_convert:
mock_cache = MagicMock()
mock_convert.return_value = mock_cache
converter.update_rule(config_rule)
mock_rule_mgr.get_instance.return_value.config_update.assert_called_once_with(
mock_cache
)
mock_event.get_instance.return_value.olc_clean_rule.send.assert_called_once()
@patch("olc.rule.olc_rule_convert.OlcRuleManager")
@patch("olc.rule.olc_rule_convert.Event")
def test_update_rule_sends_clean_event(self, mock_event, mock_rule_mgr):
converter = OlcRuleConvert()
config_rule = MagicMock()
config_rule.valid.return_value = True
with patch.object(converter, "convert_to_rule_cache") as mock_convert:
mock_convert.return_value = MagicMock()
converter.update_rule(config_rule)
mock_event.get_instance.return_value.olc_clean_rule.send.assert_called_once()
class TestConvertToRuleCache(unittest.TestCase):
def setUp(self):
OlcRuleConvert._instance = None
def tearDown(self):
OlcRuleConvert._instance = None
def test_empty_rules(self):
converter = OlcRuleConvert()
config_rule = _make_config_rule(rules=[])
result = converter.convert_to_rule_cache(config_rule)
self.assertEqual(result.domain, "test_domain")
self.assertEqual(len(result.tag_groups), 0)
def test_invalid_group_filtered_out(self):
group_no_name = Group(
priority=500,
enabled=True,
name="",
type="unknown_type",
tags=[_make_multi_tag()],
)
rule = _make_olc_rule(group=group_no_name)
config_rule = _make_config_rule(rules=[rule])
converter = OlcRuleConvert()
result = converter.convert_to_rule_cache(config_rule)
self.assertEqual(len(result.tag_groups), 0)
def test_disabled_group_skipped(self):
group = _make_group(enabled=False)
rule = _make_olc_rule(group=group)
config_rule = _make_config_rule(rules=[rule])
converter = OlcRuleConvert()
result = converter.convert_to_rule_cache(config_rule)
self.assertEqual(len(result.tag_groups), 0)
def test_group_with_too_many_tags_filtered(self):
tags = [
_make_multi_tag(tag=f"tag_{i}", values=[f"val_{i}"])
for i in range(TAGS_SIZE_MAX + 1)
]
group = _make_group(tags=tags)
rule = _make_olc_rule(group=group)
config_rule = _make_config_rule(rules=[rule])
converter = OlcRuleConvert()
result = converter.convert_to_rule_cache(config_rule)
self.assertEqual(len(result.tag_groups), 0)
def test_group_with_empty_tags_filtered(self):
group = _make_group(tags=[])
rule = _make_olc_rule(group=group)
config_rule = _make_config_rule(rules=[rule])
converter = OlcRuleConvert()
result = converter.convert_to_rule_cache(config_rule)
self.assertEqual(len(result.tag_groups), 0)
def test_normal_type_group_converts_correctly(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
group = _make_group(group_type="normal", tags=[tag])
rule = _make_olc_rule(group=group)
config_rule = _make_config_rule(rules=[rule])
converter = OlcRuleConvert()
result = converter.convert_to_rule_cache(config_rule)
self.assertGreater(len(result.tag_groups), 0)
first_tg = list(result.tag_groups.values())[0]
self.assertEqual(first_tg.tags[0].tag, "ServiceName")
self.assertEqual(first_tg.tags[0].value, "svc1")
def test_global_type_group_converts_correctly(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
group = _make_group(group_type="global", tags=[tag])
flow = _make_flow_policy(enabled=False)
rule = _make_olc_rule(group=group, flow=flow)
config_rule = _make_config_rule(rules=[rule])
converter = OlcRuleConvert()
result = converter.convert_to_rule_cache(config_rule)
self.assertGreater(len(result.tag_groups), 0)
first_tg = list(result.tag_groups.values())[0]
self.assertEqual(first_tg.domain, "test_domain")
def test_global_type_direct_call_to_global_handler(self):
converter = OlcRuleConvert()
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
group = _make_group(group_type="global", tags=[tag])
result = converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].domain, "test_domain")
def test_global_type_direct_multiple_tags(self):
converter = OlcRuleConvert()
tags = [
_make_multi_tag(tag="ServiceName", match="equal", values=["svc1", "svc2"]),
_make_multi_tag(tag="InterfaceName", match="equal", values=["if1"]),
]
group = _make_group(group_type="global", tags=tags)
result = converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 3)
@patch("olc.rule.olc_rule_convert.OlcAlgManager")
def test_disabled_policy_not_added(self, mock_alg_mgr):
mock_alg_mgr.get_instance.return_value.get_flow_alg.return_value = None
converter = OlcRuleConvert()
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
group = _make_group(group_type="global", tags=[tag])
flow = _make_flow_policy(enabled=False)
admission = _make_admission_policy(enabled=False)
rule = _make_olc_rule(group=group, flow=flow, admission=admission)
config_rule = _make_config_rule(rules=[rule])
result = converter.convert_to_rule_cache(config_rule)
self.assertEqual(len(result.bind_flow_relation), 0)
self.assertEqual(len(result.bind_admission_relation), 0)
@patch("olc.rule.olc_rule_convert.OlcAlgManager")
def test_enabled_policy_added(self, mock_alg_mgr):
mock_alg_mgr.get_instance.return_value.get_flow_alg.return_value = None
converter = OlcRuleConvert()
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
group = _make_group(group_type="global", tags=[tag])
flow = _make_flow_policy(enabled=True, rate_limit=100)
rule = _make_olc_rule(group=group, flow=flow)
config_rule = _make_config_rule(rules=[rule])
result = converter.convert_to_rule_cache(config_rule)
self.assertEqual(len(result.bind_flow_relation), 1)
def test_domain_passed_correctly_to_tag_groups(self):
converter = OlcRuleConvert()
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
group = _make_group(group_type="global", tags=[tag])
flow = _make_flow_policy(enabled=False)
rule = _make_olc_rule(group=group, flow=flow)
config_rule = _make_config_rule(domain="my_domain", rules=[rule])
result = converter.convert_to_rule_cache(config_rule)
self.assertGreater(len(result.tag_groups), 0)
for tg in result.tag_groups.values():
self.assertEqual(tg.domain, "my_domain")
def test_set_default_value_called_on_copied_group(self):
converter = OlcRuleConvert()
tag = _make_multi_tag(tag="ServiceName", match="", values=["svc1"])
group = _make_group(group_type="normal", tags=tag if isinstance(tag, list) else [tag], priority=0)
rule = _make_olc_rule(group=group)
config_rule = _make_config_rule(rules=[rule])
original_tag_match = tag.match
original_group_priority = group.priority
result = converter.convert_to_rule_cache(config_rule)
self.assertEqual(tag.match, original_tag_match)
self.assertEqual(group.priority, original_group_priority)
self.assertIsNotNone(result)
@patch("olc.rule.olc_rule_convert.OlcAlgManager")
def test_policy_check_failure_skips_policy(self, mock_alg_mgr):
mock_alg_mgr.get_instance.return_value.get_flow_alg.return_value = None
converter = OlcRuleConvert()
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
group = _make_group(group_type="global", tags=[tag])
flow = _make_flow_policy(enabled=True, rate_limit=-1, time_unit="invalid")
rule = _make_olc_rule(group=group, flow=flow)
config_rule = _make_config_rule(rules=[rule])
result = converter.convert_to_rule_cache(config_rule)
self.assertEqual(len(result.bind_flow_relation), 0)
def test_multiple_rules_combined(self):
converter = OlcRuleConvert()
tag1 = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
tag2 = _make_multi_tag(tag="InterfaceName", match="equal", values=["if1"])
group1 = _make_group(name="group1", group_type="global", tags=[tag1])
group2 = _make_group(name="group2", group_type="global", tags=[tag2])
flow1 = _make_flow_policy(name="flow1", enabled=False)
flow2 = _make_flow_policy(name="flow2", enabled=False)
rule1 = _make_olc_rule(group=group1, flow=flow1)
rule2 = _make_olc_rule(group=group2, flow=flow2)
config_rule = _make_config_rule(rules=[rule1, rule2])
result = converter.convert_to_rule_cache(config_rule)
self.assertEqual(len(result.tag_groups), 2)
def test_valid_but_disabled_group_not_added_to_tag_groups(self):
group = _make_group(enabled=False)
rule = _make_olc_rule(group=group)
config_rule = _make_config_rule(rules=[rule])
converter = OlcRuleConvert()
result = converter.convert_to_rule_cache(config_rule)
self.assertEqual(len(result.tag_groups), 0)
class TestGroupToTagGroup(unittest.TestCase):
def setUp(self):
self.converter = OlcRuleConvert()
def test_disabled_group_returns_none(self):
group = _make_group(enabled=False)
result = self.converter._OlcRuleConvert__group_to_tag_group(group, "domain")
self.assertIsNone(result)
def test_normal_type_calls_normal_handler(self):
group = _make_group(group_type="normal")
result = self.converter._OlcRuleConvert__group_to_tag_group(group, "domain")
self.assertIsNotNone(result)
def test_global_type_matches_correctly(self):
group = _make_group(group_type="global", tags=[_make_multi_tag()])
result = self.converter._OlcRuleConvert__group_to_tag_group(group, "domain")
self.assertIsNotNone(result)
def test_unsupported_type_returns_none(self):
group = _make_group(group_type="unknown_type")
result = self.converter._OlcRuleConvert__group_to_tag_group(group, "domain")
self.assertIsNone(result)
def test_global_constant_is_string(self):
self.assertIsInstance(GLOBAL, str)
self.assertEqual(GLOBAL, "global")
def test_normal_constant_is_string(self):
self.assertIsInstance(NORMAL, str)
self.assertEqual(NORMAL, "normal")
def test_normal_type_case_insensitive(self):
group = _make_group(group_type="NORMAL")
result = self.converter._OlcRuleConvert__group_to_tag_group(group, "domain")
self.assertIsNotNone(result)
def test_global_type_case_insensitive(self):
group = _make_group(group_type="GLOBAL")
result = self.converter._OlcRuleConvert__group_to_tag_group(group, "domain")
self.assertIsNotNone(result)
def test_normal_handler_returns_none_not_falls_through(self):
group = _make_group(group_type="normal", tags=[])
result = self.converter._OlcRuleConvert__group_to_tag_group(group, "domain")
self.assertIsNone(result)
class TestNormalToTagGroup(unittest.TestCase):
def setUp(self):
self.converter = OlcRuleConvert()
def test_empty_tag_values_returns_none(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=[])
group = _make_group(group_type="normal", tags=[tag])
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNone(result)
def test_empty_tag_name_returns_none(self):
tag = _make_multi_tag(tag="", match="equal", values=["val1"])
group = _make_group(group_type="normal", tags=[tag])
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNone(result)
def test_single_dimension_single_value(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
group = _make_group(group_type="normal", tags=[tag])
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].tags[0].tag, "ServiceName")
self.assertEqual(result[0].tags[0].value, "svc1")
def test_single_dimension_multiple_values(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1", "svc2"])
group = _make_group(group_type="normal", tags=[tag])
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 2)
def test_multiple_dimensions_cartesian_product(self):
tags = [
_make_multi_tag(tag="ServiceName", match="equal", values=["svc1", "svc2"]),
_make_multi_tag(tag="InterfaceName", match="equal", values=["if1"]),
]
group = _make_group(group_type="normal", tags=tags)
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 2)
def test_wildcard_value_handling(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["*"])
group = _make_group(group_type="normal", tags=[tag])
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].tags[0].value, "*")
def test_tag_group_properties_set(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"], share=True)
group = _make_group(
group_type="normal",
tags=[tag],
priority=100,
)
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "my_domain")
self.assertIsNotNone(result)
self.assertEqual(result[0].domain, "my_domain")
self.assertEqual(result[0].priority, 100)
self.assertTrue(result[0].tags[0].share)
def test_default_match_when_empty_is_equal(self):
tag = _make_multi_tag(tag="ServiceName", match="", values=["svc1"])
group = _make_group(group_type="normal", tags=[tag])
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNotNone(result)
self.assertEqual(result[0].tags[0].match, EQUAL)
def test_none_tag_values_returns_none(self):
tag = OlcMultiTag(tag="ServiceName", match="equal", values=None, share=None)
group = _make_group(group_type="normal", tags=[tag])
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNone(result)
def test_none_tag_name_returns_none(self):
tag = OlcMultiTag(tag=None, match="equal", values=["svc1"], share=None)
group = _make_group(group_type="normal", tags=[tag])
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNone(result)
def test_three_dimensions_cartesian_product(self):
tags = [
_make_multi_tag(tag="ServiceName", match="equal", values=["svc1", "svc2"]),
_make_multi_tag(tag="InterfaceName", match="equal", values=["if1", "if2"]),
_make_multi_tag(tag="IP", match="equal", values=["test1", "test2"]),
]
group = _make_group(group_type="normal", tags=tags)
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 8)
def test_mixed_empty_and_valid_tags(self):
tags = [
_make_multi_tag(tag="", match="equal", values=["val1"]),
_make_multi_tag(tag="ServiceName", match="equal", values=["svc1"]),
]
group = _make_group(group_type="normal", tags=tags)
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].tags[0].tag, "ServiceName")
class TestMergeGroupDimension(unittest.TestCase):
def setUp(self):
self.converter = OlcRuleConvert()
def test_single_dimension_returns_tag_groups(self):
group = _make_group()
dimension_and_value = {"ServiceName": ["svc1"]}
middle_tag = {"ServiceName": _make_multi_tag()}
result = self.converter._OlcRuleConvert__merge_group_dimension(
group, "domain", dimension_and_value, middle_tag
)
self.assertIsNotNone(result)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].tags[0].tag, "ServiceName")
self.assertEqual(result[0].tags[0].value, "svc1")
def test_multiple_dimensions_with_consistent_tags(self):
tags = [
_make_multi_tag(tag="ServiceName", match="equal", values=["svc1", "svc2"]),
_make_multi_tag(tag="InterfaceName", match="equal", values=["if1"]),
]
group = _make_group(group_type="normal", tags=tags)
dimension_and_value = {
"InterfaceName": ["if1"],
"ServiceName": ["svc1", "svc2"],
}
middle_tag = {
"ServiceName": _make_multi_tag(values=["svc1", "svc2"]),
"InterfaceName": _make_multi_tag(tag="InterfaceName", values=["if1"]),
}
result = self.converter._OlcRuleConvert__merge_group_dimension(
group, "domain", dimension_and_value, middle_tag
)
self.assertIsNotNone(result)
self.assertEqual(len(result), 2)
def test_empty_dimension_and_value_returns_none(self):
group = _make_group()
result = self.converter._OlcRuleConvert__merge_group_dimension(
group, "domain", {}, {}
)
self.assertIsNone(result)
def test_tag_group_domain_set(self):
group = _make_group()
dimension_and_value = {"ServiceName": ["svc1"]}
middle_tag = {"ServiceName": _make_multi_tag()}
result = self.converter._OlcRuleConvert__merge_group_dimension(
group, "my_domain", dimension_and_value, middle_tag
)
self.assertIsNotNone(result)
self.assertEqual(result[0].domain, "my_domain")
def test_tag_group_name_set(self):
group = _make_group(name="test_group")
dimension_and_value = {"ServiceName": ["svc1"]}
middle_tag = {"ServiceName": _make_multi_tag()}
result = self.converter._OlcRuleConvert__merge_group_dimension(
group, "domain", dimension_and_value, middle_tag
)
self.assertIsNotNone(result)
self.assertEqual(result[0].name, "test_group")
class TestToDimensionEntry(unittest.TestCase):
def setUp(self):
self.converter = OlcRuleConvert()
def test_single_dimension_single_value(self):
dimension_and_value = {"ServiceName": ["svc1"]}
result = self.converter._OlcRuleConvert__to_dimension_entry(dimension_and_value)
self.assertEqual(len(result), 1)
self.assertEqual(len(result[0]), 1)
self.assertEqual(result[0][0], {"ServiceName": "svc1"})
def test_single_dimension_multiple_values(self):
dimension_and_value = {"ServiceName": ["svc1", "svc2"]}
result = self.converter._OlcRuleConvert__to_dimension_entry(dimension_and_value)
self.assertEqual(len(result), 1)
self.assertEqual(len(result[0]), 2)
def test_multiple_dimensions(self):
dimension_and_value = {
"ServiceName": ["svc1"],
"InterfaceName": ["if1"],
}
result = self.converter._OlcRuleConvert__to_dimension_entry(dimension_and_value)
self.assertEqual(len(result), 2)
def test_wildcard_value(self):
dimension_and_value = {"ServiceName": ["*"]}
result = self.converter._OlcRuleConvert__to_dimension_entry(dimension_and_value)
self.assertEqual(len(result), 1)
self.assertEqual(len(result[0]), 1)
self.assertEqual(result[0][0], {"ServiceName": "*"})
def test_empty_values_skipped_for_non_dimension(self):
dimension_and_value = {"UnknownDim": []}
result = self.converter._OlcRuleConvert__to_dimension_entry(dimension_and_value)
self.assertEqual(len(result), 0)
def test_registered_dimension_with_empty_values_skipped(self):
dimension_and_value = {"ServiceName": []}
result = self.converter._OlcRuleConvert__to_dimension_entry(dimension_and_value)
self.assertEqual(len(result), 0)
def test_sorted_dimensions(self):
dimension_and_value = {
"InterfaceName": ["if1"],
"ServiceName": ["svc1"],
}
result = self.converter._OlcRuleConvert__to_dimension_entry(dimension_and_value)
self.assertEqual(len(result), 2)
first_dim = list(result[0][0].keys())[0]
second_dim = list(result[1][0].keys())[0]
self.assertEqual(first_dim, "InterfaceName")
self.assertEqual(second_dim, "ServiceName")
def test_empty_input(self):
result = self.converter._OlcRuleConvert__to_dimension_entry({})
self.assertEqual(len(result), 0)
def test_wildcard_case_insensitive(self):
dimension_and_value = {"ServiceName": ["*"]}
result = self.converter._OlcRuleConvert__to_dimension_entry(dimension_and_value)
self.assertEqual(result[0][0]["ServiceName"], "*")
def test_values_sorted(self):
dimension_and_value = {"ServiceName": ["svc3", "svc1", "svc2"]}
result = self.converter._OlcRuleConvert__to_dimension_entry(dimension_and_value)
values = [list(entry.values())[0] for entry in result[0]]
self.assertEqual(values, ["svc1", "svc2", "svc3"])
def test_wildcard_with_other_values_only_wildcard_used(self):
dimension_and_value = {"ServiceName": ["svc1", "*", "svc2"]}
result = self.converter._OlcRuleConvert__to_dimension_entry(dimension_and_value)
self.assertEqual(len(result), 1)
self.assertEqual(len(result[0]), 1)
self.assertEqual(result[0][0]["ServiceName"], "*")
def test_mixed_registered_and_unregistered_empty_skipped(self):
dimension_and_value = {
"ServiceName": [],
"UnknownDim": [],
}
result = self.converter._OlcRuleConvert__to_dimension_entry(dimension_and_value)
self.assertEqual(len(result), 0)
class TestAppendDimValueEntry(unittest.TestCase):
def test_cartesian_product(self):
current = [{"country": "US"}]
next_entries = [{"language": "en"}, {"language": "zh"}]
result = OlcRuleConvert._OlcRuleConvert__append_dim_value_entry(
current, next_entries
)
self.assertEqual(len(result), 2)
self.assertEqual(result[0], {"country": "US", "language": "en"})
self.assertEqual(result[1], {"country": "US", "language": "zh"})
def test_multiple_current_multiple_next(self):
current = [{"country": "US"}, {"country": "CN"}]
next_entries = [{"language": "en"}, {"language": "zh"}]
result = OlcRuleConvert._OlcRuleConvert__append_dim_value_entry(
current, next_entries
)
self.assertEqual(len(result), 4)
def test_empty_current(self):
result = OlcRuleConvert._OlcRuleConvert__append_dim_value_entry(
[], [{"language": "en"}]
)
self.assertEqual(len(result), 0)
def test_empty_next(self):
result = OlcRuleConvert._OlcRuleConvert__append_dim_value_entry(
[{"country": "US"}], []
)
self.assertEqual(len(result), 0)
def test_later_key_overwrites_earlier_key(self):
current = [{"key": "val1"}]
next_entries = [{"key": "val2"}]
result = OlcRuleConvert._OlcRuleConvert__append_dim_value_entry(
current, next_entries
)
self.assertEqual(len(result), 1)
self.assertEqual(result[0]["key"], "val2")
def test_both_empty(self):
result = OlcRuleConvert._OlcRuleConvert__append_dim_value_entry([], [])
self.assertEqual(len(result), 0)
def test_single_entry_each(self):
current = [{"a": "1"}]
next_entries = [{"b": "2"}]
result = OlcRuleConvert._OlcRuleConvert__append_dim_value_entry(
current, next_entries
)
self.assertEqual(len(result), 1)
self.assertEqual(result[0], {"a": "1", "b": "2"})
def test_does_not_modify_original(self):
current = [{"a": "1"}]
next_entries = [{"b": "2"}]
original_current = copy.deepcopy(current)
original_next = copy.deepcopy(next_entries)
OlcRuleConvert._OlcRuleConvert__append_dim_value_entry(current, next_entries)
self.assertEqual(current, original_current)
self.assertEqual(next_entries, original_next)
class TestGlobalToTagGroup(unittest.TestCase):
def setUp(self):
self.converter = OlcRuleConvert()
def test_single_tag_single_value(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
group = _make_group(group_type="global", tags=[tag])
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].domain, "test_domain")
self.assertEqual(result[0].tags[0].tag, "ServiceName")
self.assertEqual(result[0].tags[0].value, "svc1")
def test_single_tag_multiple_values(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1", "svc2"])
group = _make_group(group_type="global", tags=[tag])
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 2)
def test_multiple_tags_multiple_values(self):
tags = [
_make_multi_tag(tag="ServiceName", match="equal", values=["svc1", "svc2"]),
_make_multi_tag(tag="InterfaceName", match="equal", values=["if1"]),
]
group = _make_group(group_type="global", tags=tags)
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 3)
def test_empty_tag_name_skipped(self):
tag = _make_multi_tag(tag="", match="equal", values=["val1"])
group = _make_group(group_type="global", tags=[tag])
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertEqual(len(result), 0)
def test_empty_tag_values_skipped(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=[])
group = _make_group(group_type="global", tags=[tag])
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertEqual(len(result), 0)
def test_default_match_when_empty(self):
tag = _make_multi_tag(tag="ServiceName", match="", values=["svc1"])
group = _make_group(group_type="global", tags=[tag])
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertEqual(result[0].tags[0].match, EQUAL)
def test_custom_match_preserved(self):
tag = _make_multi_tag(tag="ServiceName", match="regex", values=["svc1"])
group = _make_group(group_type="global", tags=[tag])
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertEqual(result[0].tags[0].match, "regex")
def test_only_one_tag_naming(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
group = _make_group(name="mygroup", group_type="global", tags=[tag])
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertEqual(result[0].name, "mygroup")
def test_multiple_values_indexed_naming(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1", "svc2"])
group = _make_group(name="mygroup", group_type="global", tags=[tag])
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertEqual(result[0].name, "mygroup_1")
self.assertEqual(result[1].name, "mygroup_2")
def test_duplicate_name_generates_unique_names(self):
tags = [
_make_multi_tag(tag="ServiceName", match="equal", values=["svc1"]),
_make_multi_tag(tag="ServiceName", match="equal", values=["svc1"]),
]
group = _make_group(name="mygroup", group_type="global", tags=tags)
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertEqual(len(result), 1)
def test_tag_group_properties_set(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"], share=True)
group = _make_group(
name="mygroup",
group_type="global",
tags=[tag],
priority=100,
)
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertEqual(result[0].priority, 100)
self.assertTrue(result[0].tags[0].share)
def test_domain_set_correctly(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
group = _make_group(group_type="global", tags=[tag])
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "my_domain")
self.assertEqual(result[0].domain, "my_domain")
def test_none_tag_name_returns_empty_list(self):
tag = OlcMultiTag(tag=None, match="equal", values=["svc1"], share=None)
group = _make_group(group_type="global", tags=[tag])
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertEqual(len(result), 0)
def test_none_tag_values_returns_empty_list(self):
tag = OlcMultiTag(tag="ServiceName", match="equal", values=None, share=None)
group = _make_group(group_type="global", tags=[tag])
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertEqual(len(result), 0)
def test_index_resets_per_tag(self):
tags = [
_make_multi_tag(tag="ServiceName", match="equal", values=["svc1", "svc2"]),
_make_multi_tag(tag="InterfaceName", match="equal", values=["if1"]),
]
group = _make_group(name="mygroup", group_type="global", tags=tags)
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 3)
self.assertEqual(result[0].name, "mygroup_1")
self.assertEqual(result[1].name, "mygroup_2")
self.assertEqual(result[2].name, "mygroup_3")
def test_share_property_preserved(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"], share=True)
group = _make_group(group_type="global", tags=[tag])
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertTrue(result[0].tags[0].share)
def test_share_none_preserved(self):
tag = OlcMultiTag(tag="ServiceName", match="regex", values=["svc1"], share=None)
group = _make_group(group_type="global", tags=[tag])
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertIsNone(result[0].tags[0].share)
def test_enabled_property_from_group(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
group = _make_group(group_type="global", tags=[tag], enabled=True)
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "test_domain")
self.assertTrue(result[0].enabled)
class TestIsOnlyOneTag(unittest.TestCase):
def test_single_tag_single_value(self):
tag = _make_multi_tag(values=["val1"])
group = _make_group(tags=[tag])
result = OlcRuleConvert._OlcRuleConvert__is_onlyone_tag(group)
self.assertTrue(result)
def test_single_tag_multiple_values(self):
tag = _make_multi_tag(values=["val1", "val2"])
group = _make_group(tags=[tag])
result = OlcRuleConvert._OlcRuleConvert__is_onlyone_tag(group)
self.assertFalse(result)
def test_multiple_tags_all_single_value(self):
tags = [
_make_multi_tag(tag="tag1", values=["val1"]),
_make_multi_tag(tag="tag2", values=["val2"]),
]
group = _make_group(tags=tags)
result = OlcRuleConvert._OlcRuleConvert__is_onlyone_tag(group)
self.assertTrue(result)
def test_multiple_tags_mixed_values(self):
tags = [
_make_multi_tag(tag="tag1", values=["val1"]),
_make_multi_tag(tag="tag2", values=["val1", "val2"]),
]
group = _make_group(tags=tags)
result = OlcRuleConvert._OlcRuleConvert__is_onlyone_tag(group)
self.assertFalse(result)
def test_empty_tags(self):
group = _make_group(tags=[])
result = OlcRuleConvert._OlcRuleConvert__is_onlyone_tag(group)
self.assertFalse(result)
class TestGroupToTagGroups(unittest.TestCase):
def setUp(self):
self.converter = OlcRuleConvert()
def test_empty_current_entries_returns_none(self):
group = _make_group()
result = self.converter._OlcRuleConvert__group_to_tag_groups(
group, "domain", [], {}, {}
)
self.assertIsNone(result)
def test_single_entry(self):
group = _make_group(name="g1")
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
result = self.converter._OlcRuleConvert__group_to_tag_groups(
group,
"domain",
[{"ServiceName": "svc1"}],
{"ServiceName": ["svc1"]},
{"ServiceName": tag},
)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].tags[0].tag, "ServiceName")
self.assertEqual(result[0].tags[0].value, "svc1")
def test_duplicate_names_generate_unique_names(self):
group = _make_group(name="g1")
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
result = self.converter._OlcRuleConvert__group_to_tag_groups(
group,
"domain",
[{"ServiceName": "svc1"}, {"ServiceName": "svc1"}],
{"ServiceName": ["svc1"]},
{"ServiceName": tag},
)
self.assertEqual(len(result), 1)
def test_match_default_when_empty_is_equal(self):
group = _make_group(name="g1")
tag = OlcMultiTag(tag="ServiceName", match="", values=["svc1"], share=None)
result = self.converter._OlcRuleConvert__group_to_tag_groups(
group,
"domain",
[{"ServiceName": "svc1"}],
{"ServiceName": ["svc1"]},
{"ServiceName": tag},
)
self.assertEqual(result[0].tags[0].match, EQUAL)
def test_match_preserved_when_not_empty(self):
group = _make_group(name="g1")
tag = _make_multi_tag(tag="ServiceName", match="regex", values=["svc1"])
result = self.converter._OlcRuleConvert__group_to_tag_groups(
group,
"domain",
[{"ServiceName": "svc1"}],
{"ServiceName": ["svc1"]},
{"ServiceName": tag},
)
self.assertEqual(result[0].tags[0].match, "regex")
def test_domain_set_correctly(self):
group = _make_group(name="g1")
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
result = self.converter._OlcRuleConvert__group_to_tag_groups(
group,
"my_domain",
[{"ServiceName": "svc1"}],
{"ServiceName": ["svc1"]},
{"ServiceName": tag},
)
self.assertEqual(result[0].domain, "my_domain")
def test_multiple_entries_different_values(self):
tags = [
_make_multi_tag(tag="ServiceName", match="equal", values=["svc1", "svc2"]),
]
group = _make_group(name="g1", tags=tags)
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1", "svc2"])
result = self.converter._OlcRuleConvert__group_to_tag_groups(
group,
"domain",
[{"ServiceName": "svc1"}, {"ServiceName": "svc2"}],
{"ServiceName": ["svc1", "svc2"]},
{"ServiceName": tag},
)
self.assertEqual(len(result), 2)
def test_missing_middle_tags_key_causes_error(self):
group = _make_group(name="g1")
with self.assertRaises(AttributeError):
self.converter._OlcRuleConvert__group_to_tag_groups(
group,
"domain",
[{"UnknownDim": "val1"}],
{"UnknownDim": ["val1"]},
{},
)
class TestToTagGroup(unittest.TestCase):
def setUp(self):
self.converter = OlcRuleConvert()
def test_single_tag_single_value_uses_group_name(self):
group = _make_group(name="mygroup", tags=[_make_multi_tag(values=["v1"])])
tags = [OlcTag(match="equal", tag="ServiceName", value="svc1", share=True)]
result = self.converter.to_tag_group(group, "domain", tags, "0_")
self.assertEqual(result.name, "mygroup")
def test_multiple_values_uses_append_name(self):
group = _make_group(name="mygroup", tags=[_make_multi_tag(values=["v1", "v2"])])
tags = [OlcTag(match="equal", tag="ServiceName", value="svc1", share=True)]
result = self.converter.to_tag_group(group, "domain", tags, "0_")
self.assertEqual(result.name, "mygroup_0")
def test_append_name_without_trailing_underscore(self):
group = _make_group(name="mygroup", tags=[_make_multi_tag(values=["v1", "v2"])])
tags = [OlcTag(match="equal", tag="ServiceName", value="svc1", share=True)]
result = self.converter.to_tag_group(group, "domain", tags, "noscore")
self.assertEqual(result.name, "mygroup")
def test_empty_append_name(self):
group = _make_group(name="mygroup", tags=[_make_multi_tag(values=["v1", "v2"])])
tags = [OlcTag(match="equal", tag="ServiceName", value="svc1", share=True)]
result = self.converter.to_tag_group(group, "domain", tags, "")
self.assertEqual(result.name, "mygroup")
def test_tags_deep_copied(self):
group = _make_group(name="mygroup", tags=[_make_multi_tag(values=["v1"])])
tags = [OlcTag(match="equal", tag="ServiceName", value="svc1", share=True)]
result = self.converter.to_tag_group(group, "domain", tags, "0_")
tags[0].value = "modified"
self.assertEqual(result.tags[0].value, "svc1")
def test_domain_set(self):
group = _make_group(name="mygroup")
tags = [OlcTag(match="equal", tag="ServiceName", value="svc1", share=True)]
result = self.converter.to_tag_group(group, "my_domain", tags, "0_")
self.assertEqual(result.domain, "my_domain")
def test_priority_set(self):
group = _make_group(name="mygroup", priority=100)
tags = [OlcTag(match="equal", tag="ServiceName", value="svc1", share=True)]
result = self.converter.to_tag_group(group, "domain", tags, "0_")
self.assertEqual(result.priority, 100)
class TestCheckAlgInstance(unittest.TestCase):
@patch("olc.rule.olc_rule_convert.OlcAlgManager")
def test_no_flow(self, mock_alg_mgr):
rule = _make_olc_rule()
rule.flow = None
OlcRuleConvert.check_alg_instance(rule)
mock_alg_mgr.get_instance.return_value.get_flow_alg.assert_not_called()
@patch("olc.rule.olc_rule_convert.OlcAlgManager")
def test_no_calculate_alg(self, mock_alg_mgr):
rule = _make_olc_rule()
rule.flow.calculate_alg = None
OlcRuleConvert.check_alg_instance(rule)
mock_alg_mgr.get_instance.return_value.get_flow_alg.assert_not_called()
@patch("olc.rule.olc_rule_convert.OlcAlgManager")
def test_alg_not_found_disables_flow(self, mock_alg_mgr):
mock_alg_mgr.get_instance.return_value.get_flow_alg.return_value = None
rule = _make_olc_rule()
alg_instance = AlgInstance(alg_name="nonexistent", alg_param={})
rule.flow.calculate_alg = alg_instance
OlcRuleConvert.check_alg_instance(rule)
self.assertFalse(rule.flow.enabled)
@patch("olc.rule.olc_rule_convert.OlcAlgManager")
def test_alg_found_keeps_flow_enabled(self, mock_alg_mgr):
mock_flow_alg = MagicMock()
mock_flow_alg.check.return_value = True
mock_flow_alg.get_dynamic_param_key.return_value = []
mock_flow_alg.para_names = {}
mock_alg_mgr.get_instance.return_value.get_flow_alg.return_value = mock_flow_alg
rule = _make_olc_rule()
alg_instance = AlgInstance(alg_name="test_alg", alg_param={"minWal": 0.5})
rule.flow.calculate_alg = alg_instance
OlcRuleConvert.check_alg_instance(rule)
self.assertTrue(rule.flow.enabled)
@patch("olc.rule.olc_rule_convert.OlcAlgManager")
@patch("olc.rule.olc_rule_convert.OlcCollectorManager")
def test_alg_check_fails_disables_flow(self, mock_collector_mgr, mock_alg_mgr):
mock_flow_alg = MagicMock()
mock_flow_alg.check.return_value = False
mock_flow_alg.para_names = {}
mock_alg_mgr.get_instance.return_value.get_flow_alg.return_value = mock_flow_alg
rule = _make_olc_rule()
alg_instance = AlgInstance(alg_name="test_alg", alg_param={})
rule.flow.calculate_alg = alg_instance
OlcRuleConvert.check_alg_instance(rule)
self.assertFalse(rule.flow.enabled)
@patch("olc.rule.olc_rule_convert.OlcAlgManager")
@patch("olc.rule.olc_rule_convert.OlcCollectorManager")
def test_dynamic_param_invalid_disables_flow(
self, mock_collector_mgr, mock_alg_mgr
):
mock_flow_alg = MagicMock()
mock_flow_alg.check.return_value = True
mock_flow_alg.get_dynamic_param_key.return_value = ["currentUsage"]
mock_flow_alg.para_names = {}
mock_alg_mgr.get_instance.return_value.get_flow_alg.return_value = mock_flow_alg
mock_collector_mgr.get_instance.return_value.valid.return_value = False
rule = _make_olc_rule()
alg_instance = AlgInstance(alg_name="test_alg", alg_param={"currentUsage": "cpu.usage"})
rule.flow.calculate_alg = alg_instance
OlcRuleConvert.check_alg_instance(rule)
self.assertFalse(rule.flow.enabled)
@patch("olc.rule.olc_rule_convert.OlcAlgManager")
def test_check_alg_instance_side_effect_on_rule(self, mock_alg_mgr):
mock_alg_mgr.get_instance.return_value.get_flow_alg.return_value = None
rule = _make_olc_rule()
self.assertTrue(rule.flow.enabled)
alg_instance = AlgInstance(alg_name="nonexistent", alg_param={})
rule.flow.calculate_alg = alg_instance
OlcRuleConvert.check_alg_instance(rule)
self.assertFalse(rule.flow.enabled)
OlcRuleConvert.check_alg_instance(rule)
self.assertFalse(rule.flow.enabled)
class TestSetAlgDefaultValue(unittest.TestCase):
def test_missing_params_filled_with_defaults(self):
mock_alg = MagicMock()
param1 = MagicMock()
param1.key = "minWal"
param1.default_value = 0.5
param2 = MagicMock()
param2.key = "maxWal"
param2.default_value = 2.0
mock_alg.para_names = {"minWal": param1, "maxWal": param2}
alg_instance = AlgInstance(alg_name="test", alg_param={"minWal": 0.8})
OlcRuleConvert.set_alg_default_value(alg_instance, mock_alg)
self.assertEqual(alg_instance.alg_param["minWal"], 0.8)
self.assertEqual(alg_instance.alg_param["maxWal"], 2.0)
def test_all_params_present_no_override(self):
mock_alg = MagicMock()
param1 = MagicMock()
param1.key = "minWal"
param1.default_value = 0.5
mock_alg.para_names = {"minWal": param1}
alg_instance = AlgInstance(alg_name="test", alg_param={"minWal": 0.8})
OlcRuleConvert.set_alg_default_value(alg_instance, mock_alg)
self.assertEqual(alg_instance.alg_param["minWal"], 0.8)
def test_empty_alg_params(self):
mock_alg = MagicMock()
param1 = MagicMock()
param1.key = "minWal"
param1.default_value = 0.5
mock_alg.para_names = {"minWal": param1}
alg_instance = AlgInstance(alg_name="test", alg_param={})
OlcRuleConvert.set_alg_default_value(alg_instance, mock_alg)
self.assertEqual(alg_instance.alg_param["minWal"], 0.5)
def test_none_default_value_filled(self):
mock_alg = MagicMock()
param1 = MagicMock()
param1.key = "key1"
param1.default_value = None
mock_alg.para_names = {"key1": param1}
alg_instance = AlgInstance(alg_name="test", alg_param={})
OlcRuleConvert.set_alg_default_value(alg_instance, mock_alg)
self.assertIsNone(alg_instance.alg_param["key1"])
def test_empty_para_names(self):
mock_alg = MagicMock()
mock_alg.para_names = {}
alg_instance = AlgInstance(alg_name="test", alg_param={"existing": 1})
OlcRuleConvert.set_alg_default_value(alg_instance, mock_alg)
self.assertEqual(alg_instance.alg_param, {"existing": 1})
class TestCheckCalculateAlg(unittest.TestCase):
@patch("olc.rule.olc_rule_convert.OlcCollectorManager")
def test_alg_check_fails(self, mock_collector_mgr):
mock_alg = MagicMock()
mock_alg.check.return_value = False
mock_alg.alg_name = "test_alg"
alg_instance = AlgInstance(alg_name="test_alg", alg_param={})
result = OlcRuleConvert._check_calculate_alg(alg_instance, mock_alg)
self.assertFalse(result)
@patch("olc.rule.olc_rule_convert.OlcCollectorManager")
def test_alg_check_passes_no_dynamic_params(self, mock_collector_mgr):
mock_alg = MagicMock()
mock_alg.check.return_value = True
mock_alg.get_dynamic_param_key.return_value = []
mock_alg.alg_name = "test_alg"
alg_instance = AlgInstance(alg_name="test_alg", alg_param={})
result = OlcRuleConvert._check_calculate_alg(alg_instance, mock_alg)
self.assertTrue(result)
@patch("olc.rule.olc_rule_convert.OlcCollectorManager")
def test_dynamic_param_valid(self, mock_collector_mgr):
mock_alg = MagicMock()
mock_alg.check.return_value = True
mock_alg.get_dynamic_param_key.return_value = ["currentUsage"]
mock_alg.alg_name = "test_alg"
mock_collector_mgr.get_instance.return_value.valid.return_value = True
alg_instance = AlgInstance(
alg_name="test_alg", alg_param={"currentUsage": "cpu.usage"}
)
result = OlcRuleConvert._check_calculate_alg(alg_instance, mock_alg)
self.assertTrue(result)
@patch("olc.rule.olc_rule_convert.OlcCollectorManager")
def test_dynamic_param_invalid(self, mock_collector_mgr):
mock_alg = MagicMock()
mock_alg.check.return_value = True
mock_alg.get_dynamic_param_key.return_value = ["currentUsage"]
mock_alg.alg_name = "test_alg"
mock_collector_mgr.get_instance.return_value.valid.return_value = False
alg_instance = AlgInstance(
alg_name="test_alg", alg_param={"currentUsage": "invalid.param"}
)
result = OlcRuleConvert._check_calculate_alg(alg_instance, mock_alg)
self.assertFalse(result)
@patch("olc.rule.olc_rule_convert.OlcCollectorManager")
def test_dynamic_param_key_missing_from_alg_params_returns_none(self, mock_collector_mgr):
mock_alg = MagicMock()
mock_alg.check.return_value = True
mock_alg.get_dynamic_param_key.return_value = ["missingKey"]
mock_alg.alg_name = "test_alg"
mock_collector_mgr.get_instance.return_value.valid.return_value = True
alg_instance = AlgInstance(alg_name="test_alg", alg_param={})
result = OlcRuleConvert._check_calculate_alg(alg_instance, mock_alg)
self.assertTrue(result)
mock_collector_mgr.get_instance.return_value.valid.assert_called_with(None)
@patch("olc.rule.olc_rule_convert.OlcCollectorManager")
def test_multiple_dynamic_params_all_valid(self, mock_collector_mgr):
mock_alg = MagicMock()
mock_alg.check.return_value = True
mock_alg.get_dynamic_param_key.return_value = ["key1", "key2"]
mock_alg.alg_name = "test_alg"
mock_collector_mgr.get_instance.return_value.valid.return_value = True
alg_instance = AlgInstance(
alg_name="test_alg", alg_param={"key1": "val1", "key2": "val2"}
)
result = OlcRuleConvert._check_calculate_alg(alg_instance, mock_alg)
self.assertTrue(result)
@patch("olc.rule.olc_rule_convert.OlcCollectorManager")
def test_multiple_dynamic_params_one_invalid(self, mock_collector_mgr):
mock_alg = MagicMock()
mock_alg.check.return_value = True
mock_alg.get_dynamic_param_key.return_value = ["key1", "key2"]
mock_alg.alg_name = "test_alg"
def side_effect(value):
return value != "invalid"
mock_collector_mgr.get_instance.return_value.valid.side_effect = side_effect
alg_instance = AlgInstance(
alg_name="test_alg", alg_param={"key1": "valid", "key2": "invalid"}
)
result = OlcRuleConvert._check_calculate_alg(alg_instance, mock_alg)
self.assertFalse(result)
class TestRuleRefreshTask(unittest.TestCase):
@patch("olc.rule.olc_rule_convert.OlcRuleConvert")
def test_run_calls_convert_rules_task(self, mock_converter):
task = RuleRefreshTask()
task.run()
mock_converter.get_instance.return_value.convert_rules_task.assert_called_once()
class TestGroupValidation(unittest.TestCase):
def test_unsupported_group_type_returns_false(self):
tag = _make_multi_tag()
group = _make_group(group_type="unknown_type", tags=[tag])
result = group.valid()
self.assertFalse(result)
def test_normal_type_valid(self):
group = _make_group(group_type="normal")
result = group.valid()
self.assertTrue(result)
def test_global_type_valid(self):
group = _make_group(group_type="global", tags=[_make_multi_tag()])
result = group.valid()
self.assertTrue(result)
def test_set_default_value_empty_match_sets_equal(self):
tag = _make_multi_tag(tag="ServiceName", match="", values=["val1"])
group = _make_group(tags=[tag])
group.set_default_value()
self.assertEqual(tag.match, EQUAL)
def test_set_default_value_existing_match_preserved(self):
tag = _make_multi_tag(tag="ServiceName", match="regex", values=["val1"])
group = _make_group(tags=[tag])
group.set_default_value()
self.assertEqual(tag.match, "regex")
class TestFlowPolicyCheck(unittest.TestCase):
def test_invalid_time_unit_returns_false(self):
policy = _make_flow_policy(time_unit="invalid_unit")
result = policy.check()
self.assertFalse(result)
def test_valid_time_unit_returns_true(self):
policy = _make_flow_policy(time_unit="second")
result = policy.check()
self.assertTrue(result)
def test_negative_rate_limit_returns_false(self):
policy = _make_flow_policy(rate_limit=-1)
result = policy.check()
self.assertFalse(result)
def test_negative_time_interval_returns_false(self):
policy = _make_flow_policy(time_interval=-1)
result = policy.check()
self.assertFalse(result)
def test_zero_rate_limit_returns_true(self):
policy = _make_flow_policy(rate_limit=0)
result = policy.check()
self.assertTrue(result)
def test_all_valid_time_units(self):
for unit in ["second", "minute", "hour", "day"]:
policy = _make_flow_policy(time_unit=unit)
result = policy.check()
self.assertTrue(result, f"Time unit '{unit}' should be valid")
class TestAdmissionPolicyPrefix(unittest.TestCase):
def test_set_default_value_uses_admission_prefix(self):
policy = _make_admission_policy(name="")
policy.set_default_value("mygroup")
self.assertNotIn("_flow_", policy.name)
class TestStartTask(unittest.TestCase):
@patch("olc.rule.olc_rule_convert.OlcScheduleManager")
def test_start_task_creates_and_starts_task(self, mock_schedule_mgr):
converter = OlcRuleConvert(interval_seconds=6)
converter.start_task()
mock_schedule_mgr.get_instance.return_value.create_task.assert_called_once()
call_kwargs = mock_schedule_mgr.get_instance.return_value.create_task.call_args
self.assertEqual(call_kwargs[1]["name"], "olc-rule-refresh")
self.assertEqual(call_kwargs[1]["interval"], 6)
@patch("olc.rule.olc_rule_convert.OlcScheduleManager")
def test_start_task_with_custom_interval(self, mock_schedule_mgr):
converter = OlcRuleConvert(interval_seconds=30)
converter.start_task()
call_kwargs = mock_schedule_mgr.get_instance.return_value.create_task.call_args
self.assertEqual(call_kwargs[1]["interval"], 30)
def test_start_task_is_instance_method(self):
self.assertFalse(isinstance(OlcRuleConvert.__dict__["start_task"], staticmethod))
class TestStop(unittest.TestCase):
@patch("olc.rule.olc_rule_convert.OlcScheduleManager")
def test_stop_calls_stop_task(self, mock_schedule_mgr):
OlcRuleConvert.stop()
mock_schedule_mgr.get_instance.return_value.stop_task.assert_called_once_with(
"olc-rule-refresh"
)
class TestInconsistentDefaultMatch(unittest.TestCase):
def test_global_handler_empty_match_becomes_equal(self):
converter = OlcRuleConvert()
tag = _make_multi_tag(tag="ServiceName", match="", values=["svc1"])
group = _make_group(group_type="global", tags=[tag])
result = converter._OlcRuleConvert__global_to_tag_group(group, "domain")
self.assertEqual(result[0].tags[0].match, EQUAL)
def test_normal_handler_empty_match_becomes_equal(self):
converter = OlcRuleConvert()
tag = _make_multi_tag(tag="ServiceName", match="", values=["svc1"])
group = _make_group(group_type="normal", tags=[tag])
result = converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertEqual(result[0].tags[0].match, EQUAL)
def test_set_default_value_then_normal_handler_match_is_equal(self):
converter = OlcRuleConvert()
tag = _make_multi_tag(tag="ServiceName", match="", values=["svc1"])
group = _make_group(group_type="normal", tags=[tag])
group.set_default_value()
self.assertEqual(tag.match, EQUAL)
result = converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertEqual(result[0].tags[0].match, EQUAL)
class TestSideEffectsInConvertToRuleCache(unittest.TestCase):
def test_set_default_value_does_not_mutate_input(self):
converter = OlcRuleConvert()
tag = _make_multi_tag(tag="ServiceName", match="", values=["svc1"])
group = _make_group(group_type="normal", tags=[tag], priority=0)
rule = _make_olc_rule(group=group)
config_rule = _make_config_rule(rules=[rule])
original_tag_match = tag.match
original_group_priority = group.priority
converter.convert_to_rule_cache(config_rule)
self.assertEqual(tag.match, original_tag_match)
self.assertEqual(group.priority, original_group_priority)
@patch("olc.rule.olc_rule_convert.OlcAlgManager")
def test_check_alg_instance_does_not_disable_flow_as_side_effect(self, mock_alg_mgr):
mock_alg_mgr.get_instance.return_value.get_flow_alg.return_value = None
converter = OlcRuleConvert()
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc1"])
group = _make_group(group_type="global", tags=[tag])
flow = _make_flow_policy(enabled=True)
alg_instance = AlgInstance(alg_name="nonexistent", alg_param={})
flow.calculate_alg = alg_instance
rule = _make_olc_rule(group=group, flow=flow)
config_rule = _make_config_rule(rules=[rule])
original_flow_enabled = rule.flow.enabled
converter.convert_to_rule_cache(config_rule)
self.assertEqual(rule.flow.enabled, original_flow_enabled)
class TestStartTaskIntervalInconsistency(unittest.TestCase):
def test_instance_interval_used_by_start_task(self):
converter = OlcRuleConvert(interval_seconds=30)
self.assertEqual(converter.interval_seconds, 30)
with patch("olc.rule.olc_rule_convert.OlcScheduleManager") as mock_schedule_mgr:
converter.start_task()
call_kwargs = mock_schedule_mgr.get_instance.return_value.create_task.call_args
self.assertEqual(call_kwargs[1]["interval"], 30)
class TestEdgeCases(unittest.TestCase):
def setUp(self):
self.converter = OlcRuleConvert()
def test_tag_with_special_characters_in_value(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["svc/1", "svc-2"])
group = _make_group(group_type="normal", tags=[tag])
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 2)
def test_tag_with_unicode_value(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=["\u670d\u52a1"])
group = _make_group(group_type="normal", tags=[tag])
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 1)
def test_tag_with_whitespace_value(self):
tag = _make_multi_tag(tag="ServiceName", match="equal", values=[" "])
group = _make_group(group_type="normal", tags=[tag])
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 1)
def test_wildcard_uppercase(self):
dimension_and_value = {"ServiceName": ["SVC1", "*"]}
result = self.converter._OlcRuleConvert__to_dimension_entry(dimension_and_value)
self.assertEqual(len(result), 1)
self.assertEqual(result[0][0]["ServiceName"], "*")
def test_not_supported_dimension_name(self):
long_name = "A"
tag = _make_multi_tag(tag=long_name, match="equal", values=["val1"])
group = _make_group(group_type="normal", tags=[tag])
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNone(result)
def test_very_long_value(self):
long_value = "V" * 1000
tag = _make_multi_tag(tag="ServiceName", match="equal", values=[long_value])
group = _make_group(group_type="normal", tags=[tag])
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNotNone(result)
self.assertEqual(result[0].tags[0].value, long_value)
def test_duplicate_dimension_names_in_tags_last_wins(self):
tags = [
_make_multi_tag(tag="ServiceName", match="equal", values=["svc1"]),
_make_multi_tag(tag="ServiceName", match="equal", values=["svc2"]),
]
group = _make_group(group_type="normal", tags=tags)
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNotNone(result)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].tags[0].value, "svc2")
def test_global_empty_tags_list(self):
group = _make_group(group_type="global", tags=[])
result = self.converter._OlcRuleConvert__global_to_tag_group(group, "domain")
self.assertEqual(len(result), 0)
def test_normal_all_tags_filtered_returns_none(self):
tags = [
_make_multi_tag(tag="", match="equal", values=["val1"]),
_make_multi_tag(tag="ServiceName", match="equal", values=[]),
]
group = _make_group(group_type="normal", tags=tags)
result = self.converter._OlcRuleConvert__normal_to_tag_group(group, "domain")
self.assertIsNone(result)
class TestTypeAnnotationTypo(unittest.TestCase):
def test_dict_str_bool_typo_fixed(self):
import inspect
source = inspect.getsource(OlcRuleConvert._OlcRuleConvert__group_to_tag_groups)
self.assertIn("str, bool", source)
self.assertNotIn("str. bool", source)
class TestRegisteredDimensionEmptyValuesBug(unittest.TestCase):
def setUp(self):
self.converter = OlcRuleConvert()
def test_registered_dimension_empty_values_skipped(self):
dimension_and_value = {"ServiceName": []}
result = self.converter._OlcRuleConvert__to_dimension_entry(dimension_and_value)
self.assertEqual(len(result), 0)
def test_registered_dimension_empty_values_does_not_cause_empty_cartesian(self):
dimension_and_value = {
"ServiceName": [],
"InterfaceName": ["if1"],
}
middle_tag = {
"ServiceName": _make_multi_tag(values=[]),
"InterfaceName": _make_multi_tag(tag="InterfaceName", values=["if1"]),
}
group = _make_group()
result = self.converter._OlcRuleConvert__merge_group_dimension(
group, "domain", dimension_and_value, middle_tag
)
self.assertIsNotNone(result)
self.assertEqual(len(result), 1)
def test_unregistered_dimension_empty_values_skipped(self):
dimension_and_value = {"UnknownDim": []}
result = self.converter._OlcRuleConvert__to_dimension_entry(dimension_and_value)
self.assertEqual(len(result), 0)
if __name__ == "__main__":
unittest.main()