mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-01-23 13:08:59 -06:00
- Normalize line endings from CRLF to LF across all files to match .editorconfig - Standardize quote style from single quotes to double quotes - Normalize whitespace and formatting throughout codebase - Apply consistent code style across 372 files including: * Application code (models, routes, services, utils) * Test files * Configuration files * CI/CD workflows This ensures consistency with the project's .editorconfig settings and improves code maintainability.
191 lines
6.5 KiB
Python
191 lines
6.5 KiB
Python
"""Tests for Webhook models"""
|
|
|
|
import pytest
|
|
from datetime import datetime, timedelta
|
|
from app import db
|
|
from app.models import Webhook, WebhookDelivery, User
|
|
from app.utils.timezone import now_in_app_timezone
|
|
|
|
|
|
@pytest.fixture
|
|
def test_user(db_session):
|
|
"""Create a test user"""
|
|
user = User(username="testuser", role="admin")
|
|
db_session.add(user)
|
|
db_session.commit()
|
|
return user
|
|
|
|
|
|
@pytest.fixture
|
|
def test_webhook(db_session, test_user):
|
|
"""Create a test webhook"""
|
|
webhook = Webhook(
|
|
name="Test Webhook",
|
|
url="https://example.com/webhook",
|
|
events=["project.created", "task.created"],
|
|
user_id=test_user.id,
|
|
is_active=True,
|
|
)
|
|
webhook.set_secret()
|
|
db_session.add(webhook)
|
|
db_session.commit()
|
|
return webhook
|
|
|
|
|
|
class TestWebhook:
|
|
"""Test Webhook model"""
|
|
|
|
def test_create_webhook(self, db_session, test_user):
|
|
"""Test creating a webhook"""
|
|
webhook = Webhook(
|
|
name="My Webhook", url="https://example.com/webhook", events=["project.created"], user_id=test_user.id
|
|
)
|
|
webhook.set_secret()
|
|
|
|
db_session.add(webhook)
|
|
db_session.commit()
|
|
|
|
assert webhook.id is not None
|
|
assert webhook.name == "My Webhook"
|
|
assert webhook.url == "https://example.com/webhook"
|
|
assert webhook.secret is not None
|
|
assert len(webhook.secret) > 0
|
|
|
|
def test_webhook_subscribes_to(self, test_webhook):
|
|
"""Test webhook event subscription"""
|
|
assert test_webhook.subscribes_to("project.created") is True
|
|
assert test_webhook.subscribes_to("task.created") is True
|
|
assert test_webhook.subscribes_to("project.updated") is False
|
|
|
|
def test_webhook_wildcard_subscription(self, db_session, test_user):
|
|
"""Test wildcard subscription"""
|
|
webhook = Webhook(name="All Events", url="https://example.com/webhook", events=["*"], user_id=test_user.id)
|
|
db_session.add(webhook)
|
|
db_session.commit()
|
|
|
|
assert webhook.subscribes_to("project.created") is True
|
|
assert webhook.subscribes_to("any.event") is True
|
|
|
|
def test_webhook_signature_generation(self, test_webhook):
|
|
"""Test signature generation"""
|
|
payload = '{"test": "data"}'
|
|
signature = test_webhook.generate_signature(payload)
|
|
|
|
assert signature is not None
|
|
assert signature.startswith("sha256=")
|
|
assert len(signature) > 10
|
|
|
|
def test_webhook_signature_verification(self, test_webhook):
|
|
"""Test signature verification"""
|
|
payload = '{"test": "data"}'
|
|
signature = test_webhook.generate_signature(payload)
|
|
|
|
assert test_webhook.verify_signature(payload, signature) is True
|
|
assert test_webhook.verify_signature(payload, "invalid") is False
|
|
|
|
def test_webhook_to_dict(self, test_webhook):
|
|
"""Test webhook serialization"""
|
|
data = test_webhook.to_dict()
|
|
|
|
assert "id" in data
|
|
assert "name" in data
|
|
assert "url" in data
|
|
assert "events" in data
|
|
assert "is_active" in data
|
|
assert "secret" not in data # Secret not included by default
|
|
|
|
def test_webhook_to_dict_with_secret(self, test_webhook):
|
|
"""Test webhook serialization with secret"""
|
|
data = test_webhook.to_dict(include_secret=True)
|
|
|
|
assert "secret" in data
|
|
assert data["secret"] == test_webhook.secret
|
|
|
|
|
|
class TestWebhookDelivery:
|
|
"""Test WebhookDelivery model"""
|
|
|
|
def test_create_delivery(self, db_session, test_webhook):
|
|
"""Test creating a delivery record"""
|
|
delivery = WebhookDelivery(
|
|
webhook_id=test_webhook.id, event_type="project.created", payload='{"test": "data"}', status="pending"
|
|
)
|
|
|
|
db_session.add(delivery)
|
|
db_session.commit()
|
|
|
|
assert delivery.id is not None
|
|
assert delivery.webhook_id == test_webhook.id
|
|
assert delivery.status == "pending"
|
|
|
|
def test_delivery_mark_success(self, db_session, test_webhook):
|
|
"""Test marking delivery as successful"""
|
|
delivery = WebhookDelivery(
|
|
webhook_id=test_webhook.id, event_type="project.created", payload='{"test": "data"}', status="pending"
|
|
)
|
|
db_session.add(delivery)
|
|
db_session.commit()
|
|
|
|
delivery.mark_success(status_code=200, response_body="OK", duration_ms=100)
|
|
db_session.commit()
|
|
|
|
assert delivery.status == "success"
|
|
assert delivery.response_status_code == 200
|
|
assert delivery.completed_at is not None
|
|
assert test_webhook.successful_deliveries == 1
|
|
|
|
def test_delivery_mark_failed(self, db_session, test_webhook):
|
|
"""Test marking delivery as failed"""
|
|
delivery = WebhookDelivery(
|
|
webhook_id=test_webhook.id, event_type="project.created", payload='{"test": "data"}', status="pending"
|
|
)
|
|
db_session.add(delivery)
|
|
db_session.commit()
|
|
|
|
delivery.mark_failed(error_message="Connection timeout", error_type="timeout", duration_ms=30000)
|
|
db_session.commit()
|
|
|
|
assert delivery.status == "failed"
|
|
assert delivery.error_message == "Connection timeout"
|
|
assert test_webhook.failed_deliveries == 1
|
|
|
|
def test_delivery_mark_retrying(self, db_session, test_webhook):
|
|
"""Test marking delivery for retry"""
|
|
delivery = WebhookDelivery(
|
|
webhook_id=test_webhook.id, event_type="project.created", payload='{"test": "data"}', status="pending"
|
|
)
|
|
db_session.add(delivery)
|
|
db_session.commit()
|
|
|
|
next_retry = now_in_app_timezone() + timedelta(minutes=5)
|
|
delivery.mark_retrying(next_retry)
|
|
db_session.commit()
|
|
|
|
assert delivery.status == "retrying"
|
|
assert delivery.retry_count == 1
|
|
assert delivery.next_retry_at == next_retry
|
|
|
|
def test_delivery_hash_payload(self):
|
|
"""Test payload hashing"""
|
|
payload = '{"test": "data"}'
|
|
hash1 = WebhookDelivery.hash_payload(payload)
|
|
hash2 = WebhookDelivery.hash_payload(payload)
|
|
|
|
assert hash1 == hash2
|
|
assert len(hash1) == 64 # SHA256 hex length
|
|
|
|
def test_delivery_to_dict(self, db_session, test_webhook):
|
|
"""Test delivery serialization"""
|
|
delivery = WebhookDelivery(
|
|
webhook_id=test_webhook.id, event_type="project.created", payload='{"test": "data"}', status="success"
|
|
)
|
|
db_session.add(delivery)
|
|
db_session.commit()
|
|
|
|
data = delivery.to_dict()
|
|
|
|
assert "id" in data
|
|
assert "webhook_id" in data
|
|
assert "event_type" in data
|
|
assert "status" in data
|