feat(test): add Phase 5b integration and E2E tests

Add comprehensive integration and end-to-end test suites:
- Integration tests for API flows (authorization, token, verification)
- Integration tests for middleware chain and security headers
- Integration tests for domain verification services
- E2E tests for complete authentication flows
- E2E tests for error scenarios and edge cases
- Shared test fixtures and utilities in conftest.py
- Rename Dockerfile to Containerfile for Podman compatibility

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-21 22:22:04 -07:00
parent 01dcaba86b
commit e1f79af347
19 changed files with 4387 additions and 0 deletions

View File

@@ -0,0 +1,190 @@
"""
Integration tests for domain verification service.
Tests the complete domain verification flow with mocked external services.
"""
import pytest
from unittest.mock import Mock
class TestDomainVerificationIntegration:
"""Integration tests for DomainVerificationService."""
def test_complete_verification_flow(self, verification_service, mock_email_service):
"""Test complete DNS + email verification flow."""
# Start verification
result = verification_service.start_verification(
domain="example.com",
me_url="https://example.com/"
)
assert result["success"] is True
assert "email" in result
assert result["verification_method"] == "email"
# Email should have been sent
assert len(mock_email_service.messages_sent) == 1
sent = mock_email_service.messages_sent[0]
assert sent["email"] == "test@example.com"
assert sent["domain"] == "example.com"
assert len(sent["code"]) == 6
def test_dns_failure_blocks_verification(self, verification_service_dns_failure):
"""Test that DNS verification failure stops the process."""
result = verification_service_dns_failure.start_verification(
domain="example.com",
me_url="https://example.com/"
)
assert result["success"] is False
assert result["error"] == "dns_verification_failed"
def test_email_discovery_failure(self, mock_dns_service, mock_email_service, mock_html_fetcher, test_code_storage):
"""Test verification fails when no email is discovered."""
from gondulf.services.domain_verification import DomainVerificationService
from gondulf.services.relme_parser import RelMeParser
# HTML fetcher returns page without email
mock_html_fetcher.fetch = Mock(return_value="<html><body>No email here</body></html>")
service = DomainVerificationService(
dns_service=mock_dns_service,
email_service=mock_email_service,
code_storage=test_code_storage,
html_fetcher=mock_html_fetcher,
relme_parser=RelMeParser()
)
result = service.start_verification(
domain="example.com",
me_url="https://example.com/"
)
assert result["success"] is False
assert result["error"] == "email_discovery_failed"
def test_code_verification_success(self, verification_service, test_code_storage):
"""Test successful code verification."""
# Start verification to generate code
verification_service.start_verification(
domain="example.com",
me_url="https://example.com/"
)
# Get the stored code
stored_code = test_code_storage.get("email_verify:example.com")
assert stored_code is not None
# Verify the code
result = verification_service.verify_email_code(
domain="example.com",
code=stored_code
)
assert result["success"] is True
assert result["email"] == "test@example.com"
def test_code_verification_invalid_code(self, verification_service, test_code_storage):
"""Test code verification fails with wrong code."""
# Start verification
verification_service.start_verification(
domain="example.com",
me_url="https://example.com/"
)
# Try to verify with wrong code
result = verification_service.verify_email_code(
domain="example.com",
code="000000"
)
assert result["success"] is False
assert result["error"] == "invalid_code"
def test_code_single_use(self, verification_service, test_code_storage):
"""Test verification code can only be used once."""
# Start verification
verification_service.start_verification(
domain="example.com",
me_url="https://example.com/"
)
# Get the stored code
stored_code = test_code_storage.get("email_verify:example.com")
# First verification should succeed
result1 = verification_service.verify_email_code(
domain="example.com",
code=stored_code
)
assert result1["success"] is True
# Second verification should fail
result2 = verification_service.verify_email_code(
domain="example.com",
code=stored_code
)
assert result2["success"] is False
class TestAuthorizationCodeGeneration:
"""Integration tests for authorization code generation."""
def test_create_authorization_code(self, verification_service):
"""Test authorization code creation stores metadata."""
code = verification_service.create_authorization_code(
client_id="https://app.example.com",
redirect_uri="https://app.example.com/callback",
state="test123",
code_challenge="abc123",
code_challenge_method="S256",
scope="",
me="https://user.example.com"
)
assert code is not None
assert len(code) > 20 # Should be a substantial code
def test_authorization_code_unique(self, verification_service):
"""Test each authorization code is unique."""
codes = set()
for _ in range(100):
code = verification_service.create_authorization_code(
client_id="https://app.example.com",
redirect_uri="https://app.example.com/callback",
state="test123",
code_challenge="abc123",
code_challenge_method="S256",
scope="",
me="https://user.example.com"
)
codes.add(code)
# All 100 codes should be unique
assert len(codes) == 100
def test_authorization_code_stored_with_metadata(self, verification_service, test_code_storage):
"""Test authorization code metadata is stored correctly."""
code = verification_service.create_authorization_code(
client_id="https://app.example.com",
redirect_uri="https://app.example.com/callback",
state="test123",
code_challenge="abc123",
code_challenge_method="S256",
scope="profile",
me="https://user.example.com"
)
# Retrieve stored metadata
metadata = test_code_storage.get(f"authz:{code}")
assert metadata is not None
assert metadata["client_id"] == "https://app.example.com"
assert metadata["redirect_uri"] == "https://app.example.com/callback"
assert metadata["state"] == "test123"
assert metadata["code_challenge"] == "abc123"
assert metadata["code_challenge_method"] == "S256"
assert metadata["scope"] == "profile"
assert metadata["me"] == "https://user.example.com"
assert metadata["used"] is False