feat(MAT-174): Add cron job scheduler and executors

Cron package that syncs jobs from matrixhost portal API, schedules execution
with timezone-aware timing, and posts results to Matrix rooms. Includes
Brave Search, reminder, and browser scrape (placeholder) executors with
formatter. 31 pytest tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Christian Gick
2026-03-16 09:31:19 +02:00
parent 21b8a4efb1
commit 4d8ea44b3d
15 changed files with 1009 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
"""Tests for the browser scrape executor."""
from unittest.mock import AsyncMock
import pytest
from cron.browser_executor import execute_browser_scrape
class TestBrowserScrapeExecutor:
@pytest.mark.asyncio
async def test_returns_error_without_profile(self):
job = {
"id": "j1",
"name": "FB Scan",
"config": {"url": "https://facebook.com/marketplace"},
"targetRoom": "!room:test",
"browserProfile": None,
}
send_text = AsyncMock()
result = await execute_browser_scrape(job=job, send_text=send_text)
assert result["status"] == "error"
assert "browser profile" in result["error"].lower()
send_text.assert_called_once()
msg = send_text.call_args[0][1]
assert "matrixhost.eu/settings/automations" in msg
@pytest.mark.asyncio
async def test_returns_error_with_expired_profile(self):
job = {
"id": "j1",
"name": "FB Scan",
"config": {"url": "https://facebook.com/marketplace"},
"targetRoom": "!room:test",
"browserProfile": {"id": "b1", "status": "expired", "name": "facebook"},
}
send_text = AsyncMock()
result = await execute_browser_scrape(job=job, send_text=send_text)
assert result["status"] == "error"
assert "expired" in result["error"].lower()
send_text.assert_called_once()
msg = send_text.call_args[0][1]
assert "re-record" in msg.lower()
@pytest.mark.asyncio
async def test_placeholder_with_active_profile(self):
job = {
"id": "j1",
"name": "FB Scan",
"config": {"url": "https://facebook.com/marketplace"},
"targetRoom": "!room:test",
"browserProfile": {"id": "b1", "status": "active", "name": "facebook"},
}
send_text = AsyncMock()
result = await execute_browser_scrape(job=job, send_text=send_text)
# Currently a placeholder, should indicate not yet implemented
assert result["status"] == "error"
assert "not yet implemented" in result["error"].lower()