"""Tests for domain verification service.""" import pytest from unittest.mock import Mock, MagicMock from gondulf.services.domain_verification import DomainVerificationService from gondulf.dns import DNSService from gondulf.email import EmailService from gondulf.storage import CodeStore from gondulf.services.html_fetcher import HTMLFetcherService from gondulf.services.relme_parser import RelMeParser class TestDomainVerificationService: """Tests for DomainVerificationService.""" @pytest.fixture def mock_dns(self): """Mock DNS service.""" return Mock(spec=DNSService) @pytest.fixture def mock_email(self): """Mock email service.""" return Mock(spec=EmailService) @pytest.fixture def mock_storage(self): """Mock code storage.""" return Mock(spec=CodeStore) @pytest.fixture def mock_fetcher(self): """Mock HTML fetcher.""" return Mock(spec=HTMLFetcherService) @pytest.fixture def mock_parser(self): """Mock rel=me parser.""" return Mock(spec=RelMeParser) @pytest.fixture def service(self, mock_dns, mock_email, mock_storage, mock_fetcher, mock_parser): """Create domain verification service with mocks.""" return DomainVerificationService( dns_service=mock_dns, email_service=mock_email, code_storage=mock_storage, html_fetcher=mock_fetcher, relme_parser=mock_parser ) def test_generate_verification_code(self, service): """Test verification code generation.""" code = service.generate_verification_code() assert isinstance(code, str) assert len(code) == 6 assert code.isdigit() def test_generate_verification_code_unique(self, service): """Test that generated codes are different.""" code1 = service.generate_verification_code() code2 = service.generate_verification_code() # Very unlikely to be the same, but possible # Just check they're both valid assert code1.isdigit() assert code2.isdigit() def test_start_verification_dns_fails(self, service, mock_dns): """Test start_verification when DNS verification fails.""" mock_dns.verify_txt_record.return_value = False result = service.start_verification("example.com", "https://example.com/") assert result["success"] is False assert result["error"] == "dns_verification_failed" def test_start_verification_email_discovery_fails( self, service, mock_dns, mock_fetcher, mock_parser ): """Test start_verification when email discovery fails.""" mock_dns.verify_txt_record.return_value = True mock_fetcher.fetch.return_value = "" mock_parser.find_email.return_value = None result = service.start_verification("example.com", "https://example.com/") assert result["success"] is False assert result["error"] == "email_discovery_failed" def test_start_verification_invalid_email_format( self, service, mock_dns, mock_fetcher, mock_parser ): """Test start_verification with invalid email format.""" mock_dns.verify_txt_record.return_value = True mock_fetcher.fetch.return_value = "" mock_parser.find_email.return_value = "not-an-email" result = service.start_verification("example.com", "https://example.com/") assert result["success"] is False assert result["error"] == "invalid_email_format" def test_start_verification_email_send_fails( self, service, mock_dns, mock_fetcher, mock_parser, mock_email ): """Test start_verification when email sending fails.""" mock_dns.verify_txt_record.return_value = True mock_fetcher.fetch.return_value = "" mock_parser.find_email.return_value = "user@example.com" mock_email.send_verification_code.side_effect = Exception("SMTP error") result = service.start_verification("example.com", "https://example.com/") assert result["success"] is False assert result["error"] == "email_send_failed" def test_start_verification_success( self, service, mock_dns, mock_fetcher, mock_parser, mock_email, mock_storage ): """Test successful verification start.""" mock_dns.verify_txt_record.return_value = True mock_fetcher.fetch.return_value = "" mock_parser.find_email.return_value = "user@example.com" result = service.start_verification("example.com", "https://example.com/") assert result["success"] is True assert result["email"] == "u***@example.com" # Masked assert result["verification_method"] == "email" mock_email.send_verification_code.assert_called_once() assert mock_storage.store.call_count == 2 # Code and email stored def test_verify_email_code_invalid(self, service, mock_storage): """Test verify_email_code with invalid code.""" mock_storage.verify.return_value = False result = service.verify_email_code("example.com", "123456") assert result["success"] is False assert result["error"] == "invalid_code" def test_verify_email_code_email_not_found(self, service, mock_storage): """Test verify_email_code when email not in storage.""" mock_storage.verify.return_value = True mock_storage.get.return_value = None result = service.verify_email_code("example.com", "123456") assert result["success"] is False assert result["error"] == "email_not_found" def test_verify_email_code_success(self, service, mock_storage): """Test successful email code verification.""" mock_storage.verify.return_value = True mock_storage.get.return_value = "user@example.com" result = service.verify_email_code("example.com", "123456") assert result["success"] is True assert result["email"] == "user@example.com" mock_storage.delete.assert_called_once() def test_create_authorization_code(self, service, mock_storage): """Test authorization code creation.""" code = service.create_authorization_code( client_id="https://client.example.com/", redirect_uri="https://client.example.com/callback", state="test_state", code_challenge="challenge", code_challenge_method="S256", scope="profile", me="https://user.example.com/" ) assert isinstance(code, str) assert len(code) > 0 mock_storage.store.assert_called_once() def test_verify_dns_record_success(self, service, mock_dns): """Test DNS record verification success.""" mock_dns.verify_txt_record.return_value = True result = service._verify_dns_record("example.com") assert result is True mock_dns.verify_txt_record.assert_called_with("example.com", "gondulf-verify-domain") def test_verify_dns_record_failure(self, service, mock_dns): """Test DNS record verification failure.""" mock_dns.verify_txt_record.return_value = False result = service._verify_dns_record("example.com") assert result is False def test_verify_dns_record_exception(self, service, mock_dns): """Test DNS record verification handles exceptions.""" mock_dns.verify_txt_record.side_effect = Exception("DNS error") result = service._verify_dns_record("example.com") assert result is False def test_discover_email_success(self, service, mock_fetcher, mock_parser): """Test email discovery success.""" mock_fetcher.fetch.return_value = "" mock_parser.find_email.return_value = "user@example.com" email = service._discover_email("https://example.com/") assert email == "user@example.com" def test_discover_email_fetch_fails(self, service, mock_fetcher): """Test email discovery when fetch fails.""" mock_fetcher.fetch.return_value = None email = service._discover_email("https://example.com/") assert email is None def test_discover_email_no_email_found(self, service, mock_fetcher, mock_parser): """Test email discovery when no email found.""" mock_fetcher.fetch.return_value = "" mock_parser.find_email.return_value = None email = service._discover_email("https://example.com/") assert email is None def test_discover_email_exception(self, service, mock_fetcher): """Test email discovery handles exceptions.""" mock_fetcher.fetch.side_effect = Exception("Fetch error") email = service._discover_email("https://example.com/") assert email is None