test: add unit tests for plugin registry and event bus
This commit is contained in:
parent
f34c805b84
commit
a1659531c7
139
tests/unit/test_plugin_registry.py
Normal file
139
tests/unit/test_plugin_registry.py
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from proxy_pool.plugins.protocols import CheckContext, CheckResult, DiscoveredProxy, Event
|
||||||
|
from proxy_pool.plugins.registry import PluginConflictError, PluginNotFoundError, PluginRegistry, PluginValidationError
|
||||||
|
|
||||||
|
|
||||||
|
class FakeParser:
|
||||||
|
name = "fake"
|
||||||
|
|
||||||
|
def supports(self, url: str) -> bool:
|
||||||
|
return "fake" in url
|
||||||
|
|
||||||
|
async def parse(self, raw, source_url, source_id, default_protocol):
|
||||||
|
return [DiscoveredProxy(ip="1.2.3.4", port=8080, protocol="http")]
|
||||||
|
|
||||||
|
def default_schedule(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class FakeChecker:
|
||||||
|
name = "fake_check"
|
||||||
|
stage = 1
|
||||||
|
priority = 0
|
||||||
|
timeout = 5.0
|
||||||
|
|
||||||
|
async def check(self, proxy_ip, proxy_port, proxy_protocol, context):
|
||||||
|
return CheckResult(passed=True, detail="ok")
|
||||||
|
|
||||||
|
def should_skip(self, proxy_protocol):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class FakeNotifier:
|
||||||
|
name = "fake_notify"
|
||||||
|
subscribes_to = ["test.*"]
|
||||||
|
notified_events: list[Event]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.notified_events = []
|
||||||
|
|
||||||
|
async def notify(self, event):
|
||||||
|
self.notified_events.append(event)
|
||||||
|
|
||||||
|
async def health_check(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class TestParserRegistration:
|
||||||
|
def test_register_and_retrieve(self):
|
||||||
|
registry = PluginRegistry()
|
||||||
|
parser = FakeParser()
|
||||||
|
registry.register_parser(parser)
|
||||||
|
|
||||||
|
assert registry.get_parser("fake") is parser
|
||||||
|
|
||||||
|
def test_duplicate_name_raises_conflict(self):
|
||||||
|
registry = PluginRegistry()
|
||||||
|
registry.register_parser(FakeParser())
|
||||||
|
|
||||||
|
with pytest.raises(PluginConflictError):
|
||||||
|
registry.register_parser(FakeParser())
|
||||||
|
|
||||||
|
def test_get_missing_parser_raises(self):
|
||||||
|
registry = PluginRegistry()
|
||||||
|
|
||||||
|
with pytest.raises(PluginNotFoundError):
|
||||||
|
registry.get_parser("nonexistent")
|
||||||
|
|
||||||
|
def test_get_parser_for_url(self):
|
||||||
|
registry = PluginRegistry()
|
||||||
|
parser = FakeParser()
|
||||||
|
registry.register_parser(parser)
|
||||||
|
|
||||||
|
assert registry.get_parser_for_url("http://fake.com/list") is parser
|
||||||
|
assert registry.get_parser_for_url("http://other.com/list") is None
|
||||||
|
|
||||||
|
def test_invalid_plugin_raises_validation_error(self):
|
||||||
|
registry = PluginRegistry()
|
||||||
|
|
||||||
|
with pytest.raises(PluginValidationError):
|
||||||
|
registry.register_parser("not a plugin")
|
||||||
|
|
||||||
|
|
||||||
|
class TestCheckerRegistration:
|
||||||
|
def test_checkers_sorted_by_stage_and_priority(self):
|
||||||
|
registry = PluginRegistry()
|
||||||
|
|
||||||
|
class Late(FakeChecker):
|
||||||
|
name = "late"
|
||||||
|
stage = 2
|
||||||
|
priority = 0
|
||||||
|
|
||||||
|
class Early(FakeChecker):
|
||||||
|
name = "early"
|
||||||
|
stage = 1
|
||||||
|
priority = 0
|
||||||
|
|
||||||
|
class EarlyLow(FakeChecker):
|
||||||
|
name = "early_low"
|
||||||
|
stage = 1
|
||||||
|
priority = 10
|
||||||
|
|
||||||
|
registry.register_checker(Late())
|
||||||
|
registry.register_checker(EarlyLow())
|
||||||
|
registry.register_checker(Early())
|
||||||
|
|
||||||
|
pipeline = registry.get_checker_pipeline()
|
||||||
|
names = [c.name for c in pipeline]
|
||||||
|
assert names == ["early", "early_low", "late"]
|
||||||
|
|
||||||
|
|
||||||
|
class TestEventBus:
|
||||||
|
async def test_emit_notifies_matching_subscribers(self):
|
||||||
|
registry = PluginRegistry()
|
||||||
|
notifier = FakeNotifier()
|
||||||
|
registry.register_notifier(notifier)
|
||||||
|
|
||||||
|
event = Event(type="test.something", payload={"key": "value"})
|
||||||
|
await registry.emit(event)
|
||||||
|
|
||||||
|
# Give the fire-and-forget task a moment to run
|
||||||
|
import asyncio
|
||||||
|
await asyncio.sleep(0.05)
|
||||||
|
|
||||||
|
assert len(notifier.notified_events) == 1
|
||||||
|
assert notifier.notified_events[0].type == "test.something"
|
||||||
|
|
||||||
|
async def test_emit_skips_non_matching(self):
|
||||||
|
registry = PluginRegistry()
|
||||||
|
notifier = FakeNotifier()
|
||||||
|
notifier.subscribes_to = ["other.*"]
|
||||||
|
registry.register_notifier(notifier)
|
||||||
|
|
||||||
|
await registry.emit(Event(type="test.something", payload={}))
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
await asyncio.sleep(0.05)
|
||||||
|
|
||||||
|
assert len(notifier.notified_events) == 0
|
||||||
Loading…
x
Reference in New Issue
Block a user