services: update ingestion collector, paced publisher, and deduplication
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
"""Auto-routing must queue to subscribed targets WITHOUT replacing the admin review card."""
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, "/app")
|
||||
|
||||
from db.database import init_db, close_db_pool
|
||||
from db.repository import Repository
|
||||
from services.admin_bot import AdminBotService
|
||||
|
||||
SRC_A = -1009999000020
|
||||
SRC_B = -1009999000021
|
||||
TRG = -1009999000022
|
||||
|
||||
|
||||
class FakeQueue:
|
||||
def __init__(self):
|
||||
self.pushed = []
|
||||
|
||||
async def push_target_post(self, target_id, payload):
|
||||
self.pushed.append((target_id, payload))
|
||||
|
||||
async def get_target_queue_size(self, target_id):
|
||||
return 0
|
||||
|
||||
|
||||
class FakeAI:
|
||||
async def rewrite_for_target(self, raw_text, target, has_media=False, *args, **kwargs):
|
||||
return f"[{target.title}] {raw_text}"
|
||||
|
||||
|
||||
|
||||
async def _cleanup(repo):
|
||||
pool = await repo._get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
for cid in (SRC_A, SRC_B):
|
||||
await conn.execute("DELETE FROM posts WHERE source_channel_id = $1;", cid)
|
||||
await conn.execute("DELETE FROM sources WHERE channel_id = $1;", cid)
|
||||
await conn.execute("DELETE FROM targets WHERE channel_id = $1;", TRG)
|
||||
|
||||
|
||||
async def run_tests():
|
||||
await init_db()
|
||||
repo = Repository()
|
||||
await _cleanup(repo)
|
||||
|
||||
await repo.add_source(SRC_A, "Source A", None)
|
||||
await repo.add_source(SRC_B, "Source B", None)
|
||||
target_id = await repo.add_target(TRG, "Auto Target", None)
|
||||
|
||||
# A brand new target routes nothing.
|
||||
assert await repo.get_targets_auto_routed_from(SRC_A) == []
|
||||
|
||||
# Toggle is a switch, not a one-way door.
|
||||
assert await repo.toggle_target_auto_source(target_id, SRC_A) is True
|
||||
routed = await repo.get_targets_auto_routed_from(SRC_A)
|
||||
assert len(routed) == 1 and routed[0].id == target_id
|
||||
assert routed[0].auto_source_ids == [SRC_A]
|
||||
assert await repo.toggle_target_auto_source(target_id, SRC_A) is False
|
||||
assert await repo.get_targets_auto_routed_from(SRC_A) == []
|
||||
|
||||
# Subscribe to A only; B must stay manual.
|
||||
await repo.set_target_auto_sources(target_id, [SRC_A])
|
||||
|
||||
queue = FakeQueue()
|
||||
bot = AdminBotService(repo=repo, ai_processor=FakeAI(), queue=queue,
|
||||
review_channel_id=0, admin_user_ids=[1])
|
||||
|
||||
post_a = await repo.create_raw_post(SRC_A, 1, "post from A", content_hash="auto_a")
|
||||
post_b = await repo.create_raw_post(SRC_B, 2, "post from B", content_hash="auto_b")
|
||||
|
||||
assert await bot.auto_route_post(post_a) == 1, "subscribed source must route"
|
||||
assert await bot.auto_route_post(post_b) == 0, "unsubscribed source must not route"
|
||||
|
||||
assert len(queue.pushed) == 1, f"expected 1 enqueue, got {queue.pushed}"
|
||||
tid, payload = queue.pushed[0]
|
||||
assert tid == target_id
|
||||
assert payload["text"] == "[Auto Target] post from A", f"AI rewrite not applied: {payload['text']}"
|
||||
assert payload["post_id"] == post_a
|
||||
|
||||
# The post is recorded against the target but must NOT be marked published yet.
|
||||
stored = await repo.get_post_by_id(post_a)
|
||||
assert stored.status == "pending_review", f"auto-routing must not publish, got {stored.status}"
|
||||
assert len(stored.published_to) == 1
|
||||
assert stored.published_to[0]["target_id"] == target_id
|
||||
assert stored.published_to[0]["published_at"] is None
|
||||
|
||||
# A soft-deleted post is never auto-routed.
|
||||
await repo.soft_delete_post(post_b)
|
||||
await repo.set_target_auto_sources(target_id, [SRC_A, SRC_B])
|
||||
assert await bot.auto_route_post(post_b) == 0, "deleted posts must not route"
|
||||
|
||||
await _cleanup(repo)
|
||||
await close_db_pool()
|
||||
print("All auto-routing tests passed successfully!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(run_tests())
|
||||
Reference in New Issue
Block a user