import unittest
from typing import List
from olc.control.handler_chain.box_handler import AbsBoxHandler
from olc.control.handler_chain.box_handler_chain_builder import OlcHandlerChain, DefaultBoxHandlerChain
from olc.control.context.context import OlcContext
from olc.bean.tag_group import TagGroup
from olc.bean.olc_control_request import OlcControlRequest
class MockHandler(AbsBoxHandler):
"""覆盖 do_in_coming / do_out_coming(业务),不再管链路推进"""
def __init__(self, name, next_handler=None, private_handler=None):
super().__init__(next_handler, private_handler)
self.name = name
self.in_coming_called = False
self.out_coming_called = False
self.in_coming_context = None
self.in_coming_groups = None
self.out_coming_context = None
def do_in_coming(self, context: OlcContext, groups: List[TagGroup]):
self.in_coming_called = True
self.in_coming_context = context
self.in_coming_groups = groups
return None
def do_out_coming(self, context: OlcContext):
self.out_coming_called = True
self.out_coming_context = context
class ExceptionHandler(AbsBoxHandler):
def do_in_coming(self, context: OlcContext, groups: List[TagGroup]):
raise Exception("Test exception in in_coming")
def do_out_coming(self, context: OlcContext):
raise Exception("Test exception in out_coming")
class TestHandlerChain(unittest.TestCase):
def setUp(self):
OlcHandlerChain.chain = DefaultBoxHandlerChain()
def test_add_handler(self):
"""测试添加处理器到调用链"""
handler1 = MockHandler("handler1")
handler2 = MockHandler("handler2")
handler3 = MockHandler("handler3")
OlcHandlerChain.add_last(handler1)
OlcHandlerChain.add_last(handler2)
OlcHandlerChain.add_last(handler3)
chain = OlcHandlerChain.get_chain()
self.assertIsNotNone(chain.first_box)
def test_in_coming_execution_order(self):
handler1 = MockHandler("handler1")
handler2 = MockHandler("handler2")
handler3 = MockHandler("handler3")
OlcHandlerChain.add_last(handler1)
OlcHandlerChain.add_last(handler2)
OlcHandlerChain.add_last(handler3)
context = OlcContext(OlcControlRequest())
groups = [TagGroup(domain="test", name="group1")]
chain = OlcHandlerChain.get_chain()
chain.in_coming(context, groups)
self.assertTrue(handler1.in_coming_called)
self.assertTrue(handler2.in_coming_called)
self.assertTrue(handler3.in_coming_called)
self.assertEqual(handler1.in_coming_context, context)
self.assertEqual(handler2.in_coming_context, context)
self.assertEqual(handler3.in_coming_context, context)
self.assertEqual(handler1.in_coming_groups, groups)
self.assertEqual(handler2.in_coming_groups, groups)
self.assertEqual(handler3.in_coming_groups, groups)
def test_out_coming_execution_order(self):
handler1 = MockHandler("handler1")
handler2 = MockHandler("handler2")
handler3 = MockHandler("handler3")
OlcHandlerChain.add_last(handler1)
OlcHandlerChain.add_last(handler2)
OlcHandlerChain.add_last(handler3)
context = OlcContext(OlcControlRequest())
chain = OlcHandlerChain.get_chain()
chain.out_coming(context)
self.assertTrue(handler1.out_coming_called)
self.assertTrue(handler2.out_coming_called)
self.assertTrue(handler3.out_coming_called)
self.assertEqual(handler1.out_coming_context, context)
self.assertEqual(handler2.out_coming_context, context)
self.assertEqual(handler3.out_coming_context, context)
def test_empty_chain(self):
"""测试空调用链"""
context = OlcContext(OlcControlRequest())
groups = [TagGroup(domain="test", name="group1")]
chain = OlcHandlerChain.get_chain()
chain.in_coming(context, groups)
chain.out_coming(context)
def test_exception_handling_in_coming(self):
"""测试 do_in_coming 方法的异常会向上传播"""
exception_handler = ExceptionHandler()
OlcHandlerChain.add_last(exception_handler)
context = OlcContext(OlcControlRequest())
groups = [TagGroup(domain="test", name="group1")]
chain = OlcHandlerChain.get_chain()
with self.assertRaises(Exception):
chain.in_coming(context, groups)
def test_exception_handling_out_coming(self):
"""测试 do_out_coming 方法的异常会向上传播"""
exception_handler = ExceptionHandler()
OlcHandlerChain.add_last(exception_handler)
context = OlcContext(OlcControlRequest())
chain = OlcHandlerChain.get_chain()
with self.assertRaises(Exception):
chain.out_coming(context)
def test_stop_flag(self):
"""v3 stop 语义:
- 默认 stop_aware=True:context.stop=True 时跳过下游 do_in_coming(业务)
- 但链路推进仍然继续:handler 节点本身仍被访问
- 如果下游 handler 设置 stop_aware=False,则即便 stop=True 也执行业务
"""
class StopHandler(AbsBoxHandler):
def do_in_coming(self, context: OlcContext, groups: List[TagGroup]):
context.stop = True
return None
def do_out_coming(self, context: OlcContext):
pass
stop_handler = StopHandler()
handler_after_stop = MockHandler("handler_after_stop")
OlcHandlerChain.add_last(stop_handler)
OlcHandlerChain.add_last(handler_after_stop)
context = OlcContext(OlcControlRequest())
groups = [TagGroup(domain="test", name="group1")]
chain = OlcHandlerChain.get_chain()
chain.in_coming(context, groups)
self.assertFalse(handler_after_stop.in_coming_called)
def test_stop_flag_with_stop_unaware_handler(self):
"""stop_aware=False 的 handler 即便 stop=True 也照常执行业务(如 StatisticHandler)"""
class StopHandler(AbsBoxHandler):
def do_in_coming(self, context: OlcContext, groups: List[TagGroup]):
context.stop = True
return None
def do_out_coming(self, context: OlcContext):
pass
class StopUnawareHandler(MockHandler):
stop_aware = False
stop_handler = StopHandler()
stop_unaware = StopUnawareHandler("unaware")
OlcHandlerChain.add_last(stop_handler)
OlcHandlerChain.add_last(stop_unaware)
context = OlcContext(OlcControlRequest())
groups = [TagGroup(domain="test", name="group1")]
chain = OlcHandlerChain.get_chain()
chain.in_coming(context, groups)
self.assertTrue(stop_unaware.in_coming_called)
if __name__ == '__main__':
unittest.main()