""" Integration tests for h-app parser service. Tests client metadata fetching with mocked HTTP responses. """ import pytest from unittest.mock import MagicMock, Mock, patch class TestHAppParserIntegration: """Integration tests for h-app metadata parsing.""" @pytest.fixture def happ_parser_with_mock_fetcher(self): """Create h-app parser with mocked HTML fetcher.""" from gondulf.services.happ_parser import HAppParser html = ''' Test App

Example Application

Home
''' mock_fetcher = Mock() mock_fetcher.fetch = Mock(return_value=html) return HAppParser(html_fetcher=mock_fetcher) def test_fetch_and_parse_happ_metadata(self, happ_parser_with_mock_fetcher): """Test fetching and parsing h-app microformat.""" import asyncio result = asyncio.get_event_loop().run_until_complete( happ_parser_with_mock_fetcher.fetch_and_parse("https://app.example.com") ) assert result is not None assert result.name == "Example Application" assert result.logo == "https://app.example.com/logo.png" def test_parse_page_without_happ(self, mock_urlopen): """Test parsing page without h-app returns fallback.""" from gondulf.services.happ_parser import HAppParser from gondulf.services.html_fetcher import HTMLFetcherService # Setup mock to return page without h-app html = b'Plain PageNo h-app' mock_response = MagicMock() mock_response.read.return_value = html mock_response.status = 200 mock_response.__enter__ = Mock(return_value=mock_response) mock_response.__exit__ = Mock(return_value=False) mock_urlopen.return_value = mock_response fetcher = HTMLFetcherService() parser = HAppParser(html_fetcher=fetcher) import asyncio result = asyncio.get_event_loop().run_until_complete( parser.fetch_and_parse("https://app.example.com") ) # Should return fallback metadata using domain assert result is not None assert "example.com" in result.name.lower() or result.name == "Plain Page" def test_fetch_timeout_returns_fallback(self, mock_urlopen_timeout): """Test HTTP timeout returns fallback metadata.""" from gondulf.services.happ_parser import HAppParser from gondulf.services.html_fetcher import HTMLFetcherService fetcher = HTMLFetcherService() parser = HAppParser(html_fetcher=fetcher) import asyncio result = asyncio.get_event_loop().run_until_complete( parser.fetch_and_parse("https://slow-app.example.com") ) # Should return fallback metadata assert result is not None # Should use domain as fallback name assert "slow-app.example.com" in result.name or result.url == "https://slow-app.example.com" class TestClientMetadataCaching: """Tests for client metadata caching behavior.""" def test_metadata_fetched_from_url(self, mock_urlopen_with_happ): """Test metadata is actually fetched from URL.""" from gondulf.services.happ_parser import HAppParser from gondulf.services.html_fetcher import HTMLFetcherService fetcher = HTMLFetcherService() parser = HAppParser(html_fetcher=fetcher) import asyncio result = asyncio.get_event_loop().run_until_complete( parser.fetch_and_parse("https://app.example.com") ) # urlopen should have been called mock_urlopen_with_happ.assert_called() class TestHAppMicroformatVariants: """Tests for various h-app microformat formats.""" @pytest.fixture def create_parser_with_html(self): """Factory to create parser with specific HTML content.""" def _create(html_content): from gondulf.services.happ_parser import HAppParser mock_fetcher = Mock() mock_fetcher.fetch = Mock(return_value=html_content) return HAppParser(html_fetcher=mock_fetcher) return _create def test_parse_happ_with_minimal_data(self, create_parser_with_html): """Test parsing h-app with only name.""" html = '''
Minimal App
''' parser = create_parser_with_html(html) import asyncio result = asyncio.get_event_loop().run_until_complete( parser.fetch_and_parse("https://minimal.example.com") ) assert result.name == "Minimal App" def test_parse_happ_with_logo_relative_url(self, create_parser_with_html): """Test parsing h-app with relative logo URL.""" html = '''
Relative Logo App
''' parser = create_parser_with_html(html) import asyncio result = asyncio.get_event_loop().run_until_complete( parser.fetch_and_parse("https://relative.example.com") ) assert result.name == "Relative Logo App" # Logo should be resolved to absolute URL assert result.logo is not None