Files
wehub-resource-sync 2cab53bc94
Docker Publish / Build and Push Docker Images (map[description:Skill Seekers CLI - Convert documentation to AI skills dockerfile:Dockerfile name:skill-seekers]) (push) Waiting to run
Docker Publish / Build and Push Docker Images (map[description:Skill Seekers MCP Server - 25 tools for AI assistants dockerfile:Dockerfile.mcp name:skill-seekers-mcp]) (push) Waiting to run
Docker Publish / Test Docker Images (push) Blocked by required conditions
Test Vector Database Adaptors / Test chroma Adaptor (push) Waiting to run
Test Vector Database Adaptors / Test faiss Adaptor (push) Waiting to run
Test Vector Database Adaptors / Test qdrant Adaptor (push) Waiting to run
Test Vector Database Adaptors / Test weaviate Adaptor (push) Waiting to run
Test Vector Database Adaptors / Test MCP Vector DB Tools (push) Waiting to run
Tests / Code Quality (Ruff & Mypy) (push) Waiting to run
Tests / Fast Unit Tests (parallel) (macos-latest, 3.11) (push) Waiting to run
Tests / Fast Unit Tests (parallel) (macos-latest, 3.12) (push) Waiting to run
Tests / Fast Unit Tests (parallel) (ubuntu-latest, 3.10) (push) Waiting to run
Tests / Fast Unit Tests (parallel) (ubuntu-latest, 3.11) (push) Waiting to run
Tests / Fast Unit Tests (parallel) (ubuntu-latest, 3.12) (push) Waiting to run
Tests / Tests (push) Blocked by required conditions
Tests / Serial / Integration / E2E Tests (push) Blocked by required conditions
Tests / MCP Server Tests (push) Blocked by required conditions
chore: import upstream snapshot with attribution
2026-07-13 12:46:28 +08:00

146 lines
5.6 KiB
Python

"""Tests for sync notifier (notifier.py)."""
import pytest
from unittest.mock import patch, MagicMock
from skill_seekers.sync.notifier import Notifier
from skill_seekers.sync.models import WebhookPayload, ChangeReport, PageChange, ChangeType
@pytest.fixture
def sample_payload():
return WebhookPayload(
event="change_detected",
skill_name="test-skill",
metadata={"source": "test"},
)
@pytest.fixture
def changed_payload():
report = ChangeReport(
skill_name="test-skill",
total_pages=5,
added=[PageChange(url="https://new.page", change_type=ChangeType.ADDED)],
modified=[
PageChange(
url="https://mod.page", change_type=ChangeType.MODIFIED, old_hash="a", new_hash="b"
)
],
deleted=[PageChange(url="https://del.page", change_type=ChangeType.DELETED)],
)
return WebhookPayload(event="change_detected", skill_name="test-skill", changes=report)
class TestNotifier:
def test_init_defaults(self):
n = Notifier()
assert n.console is True
assert n.webhook_url is None
assert n.slack_webhook is None
assert n.email_recipients == []
def test_init_with_urls(self):
n = Notifier(
webhook_url="https://hooks.example.com", slack_webhook="https://hooks.slack.com/xxx"
)
assert n.webhook_url == "https://hooks.example.com"
assert n.slack_webhook == "https://hooks.slack.com/xxx"
def test_init_with_email(self):
n = Notifier(email_recipients=["a@b.com", "c@d.com"])
assert len(n.email_recipients) == 2
def test_init_console_disabled(self):
n = Notifier(console=False)
assert n.console is False
def test_send_console_routes(self, sample_payload, capsys):
n = Notifier(webhook_url=None, slack_webhook=None, console=True)
n._send_console(sample_payload)
captured = capsys.readouterr()
assert "CHANGE_DETECTED" in captured.out
assert "test-skill" in captured.out
def test_send_console_with_changes(self, changed_payload, capsys):
n = Notifier()
n._send_console(changed_payload)
captured = capsys.readouterr()
assert "Added: 1" in captured.out
assert "Modified: 1" in captured.out
assert "Deleted: 1" in captured.out
def test_send_console_no_changes(self, capsys):
report = ChangeReport(skill_name="test-skill", total_pages=5, unchanged=5)
payload = WebhookPayload(event="change_detected", skill_name="test-skill", changes=report)
n = Notifier()
n._send_console(payload)
captured = capsys.readouterr()
assert "No changes detected" in captured.out
@patch("skill_seekers.sync.notifier.requests.post")
def test_send_webhook(self, mock_post, sample_payload):
mock_post.return_value.raise_for_status = MagicMock()
n = Notifier(webhook_url="https://hooks.example.com/webhook")
n._send_webhook(sample_payload)
mock_post.assert_called_once()
args, kwargs = mock_post.call_args
assert args[0] == "https://hooks.example.com/webhook"
assert kwargs["json"]["event"] == "change_detected"
@patch("skill_seekers.sync.notifier.requests.post")
def test_send_webhook_http_error(self, mock_post, sample_payload):
mock_post.side_effect = Exception("Connection refused")
n = Notifier(webhook_url="https://hooks.example.com/webhook")
n._send_webhook(sample_payload)
@patch("skill_seekers.sync.notifier.requests.post")
def test_send_slack(self, mock_post, changed_payload):
mock_post.return_value.raise_for_status = MagicMock()
n = Notifier(slack_webhook="https://hooks.slack.com/xxx")
n._send_slack(changed_payload)
mock_post.assert_called_once()
args, kwargs = mock_post.call_args
assert args[0] == "https://hooks.slack.com/xxx"
assert "text" in kwargs["json"]
@patch("skill_seekers.sync.notifier.requests.post")
def test_send_slack_many_modified(self, mock_post, capsys):
modified = [
PageChange(
url=f"https://page{i}.com",
change_type=ChangeType.MODIFIED,
old_hash="a",
new_hash="b",
)
for i in range(10)
]
report = ChangeReport(skill_name="test-skill", total_pages=10, modified=modified)
payload = WebhookPayload(event="change_detected", skill_name="test-skill", changes=report)
n = Notifier(slack_webhook="https://hooks.slack.com/xxx")
n._send_slack(payload)
call_arg = mock_post.call_args[1]["json"]["text"]
assert "...and 5 more" in call_arg
def test_send_skips_disabled_channels(self, sample_payload, capsys):
n = Notifier(webhook_url=None, slack_webhook=None, email_recipients=[], console=False)
n.send(sample_payload)
captured = capsys.readouterr()
assert captured.out == ""
def test_send_uses_all_channels(self, sample_payload, capsys):
with (
patch.object(Notifier, "_send_webhook") as mock_webhook,
patch.object(Notifier, "_send_slack") as mock_slack,
patch.object(Notifier, "_send_email") as mock_email,
):
n = Notifier(
webhook_url="https://hooks.example.com",
slack_webhook="https://hooks.slack.com/xxx",
email_recipients=["dev@example.com"],
console=True,
)
n.send(sample_payload)
mock_webhook.assert_called_once()
mock_slack.assert_called_once()
mock_email.assert_called_once()