# Copyright (c) Huawei Technologies Co., Ltd. 2026-2026. All rights reserved.
# OpenOLC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         `http://license.coscl.org.cn/MulanPSL2`
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.

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()