| |
| """ |
| Standalone Tests for Browser Tool |
| |
| Coverage Target: 80%+ |
| Priority: P1 (Browser Automation) |
| """ |
| import sys |
| import os |
| sys.path.insert(0, '.') |
| os.environ['ENVIRONMENT'] = 'development' |
|
|
| from tools.browser_tool import ( |
| BrowserSession, |
| BrowserSessionManager, |
| get_browser_manager, |
| BROWSER_HEADLESS, |
| ) |
| from unittest.mock import MagicMock, AsyncMock, patch |
| from datetime import datetime, timedelta |
| import asyncio |
|
|
|
|
| def test_browser_headless_config(): |
| """Test browser headless configuration""" |
| print("Testing browser headless config...") |
| |
| assert isinstance(BROWSER_HEADLESS, bool) |
| print("✓ Browser headless config tests passed") |
|
|
|
|
| def test_browser_session_initialization(): |
| """Test BrowserSession initialization""" |
| print("Testing BrowserSession initialization...") |
| session = BrowserSession( |
| session_id="test-session-001", |
| user_id="user-001", |
| agent_id="agent-001", |
| headless=True, |
| browser_type="chromium" |
| ) |
| |
| assert session.session_id == "test-session-001" |
| assert session.user_id == "user-001" |
| assert session.agent_id == "agent-001" |
| assert session.headless is True |
| assert session.browser_type == "chromium" |
| assert session.playwright is None |
| assert session.browser is None |
| assert session.context is None |
| assert session.page is None |
| assert isinstance(session.created_at, datetime) |
| assert isinstance(session.last_used, datetime) |
| |
| print("✓ BrowserSession initialization tests passed") |
|
|
|
|
| def test_browser_session_different_types(): |
| """Test BrowserSession with different browser types""" |
| print("Testing BrowserSession different types...") |
| |
| |
| session_ff = BrowserSession( |
| session_id="test-ff", |
| user_id="user-001", |
| browser_type="firefox" |
| ) |
| assert session_ff.browser_type == "firefox" |
| |
| |
| session_wk = BrowserSession( |
| session_id="test-wk", |
| user_id="user-001", |
| browser_type="webkit" |
| ) |
| assert session_wk.browser_type == "webkit" |
| |
| |
| session_cr = BrowserSession( |
| session_id="test-cr", |
| user_id="user-001" |
| ) |
| assert session_cr.browser_type == "chromium" |
| |
| print("✓ BrowserSession different types tests passed") |
|
|
|
|
| def test_session_manager_initialization(): |
| """Test BrowserSessionManager initialization""" |
| print("Testing BrowserSessionManager initialization...") |
| manager = BrowserSessionManager(session_timeout_minutes=30) |
| |
| assert manager.session_timeout_minutes == 30 |
| assert hasattr(manager, 'sessions') |
| assert isinstance(manager.sessions, dict) |
| |
| print("✓ BrowserSessionManager initialization tests passed") |
|
|
|
|
| def test_session_manager_custom_timeout(): |
| """Test BrowserSessionManager with custom timeout""" |
| print("Testing BrowserSessionManager custom timeout...") |
| manager = BrowserSessionManager(session_timeout_minutes=60) |
| assert manager.session_timeout_minutes == 60 |
| |
| manager2 = BrowserSessionManager(session_timeout_minutes=15) |
| assert manager2.session_timeout_minutes == 15 |
| |
| print("✓ BrowserSessionManager custom timeout tests passed") |
|
|
|
|
| def test_get_session_empty(): |
| """Test getting session from empty manager""" |
| print("Testing get session (empty)...") |
| manager = BrowserSessionManager() |
| |
| session = manager.get_session("nonexistent") |
| assert session is None |
| |
| print("✓ Get session (empty) tests passed") |
|
|
|
|
| def test_get_session_existing(): |
| """Test getting existing session""" |
| print("Testing get session (existing)...") |
| manager = BrowserSessionManager() |
| |
| |
| mock_session = MagicMock() |
| manager.sessions["test-session"] = mock_session |
| |
| session = manager.get_session("test-session") |
| assert session == mock_session |
| |
| print("✓ Get session (existing) tests passed") |
|
|
|
|
| async def test_create_session(): |
| """Test creating a new browser session""" |
| print("Testing create session...") |
| manager = BrowserSessionManager() |
| |
| |
| with patch('tools.browser_tool.BrowserSession') as MockSession: |
| mock_session = AsyncMock() |
| mock_session.start = AsyncMock(return_value=True) |
| MockSession.return_value = mock_session |
| |
| session = await manager.create_session( |
| user_id="user-001", |
| agent_id="agent-001", |
| headless=True |
| ) |
| |
| assert session is not None |
| |
| assert len(manager.sessions) == 1 |
| mock_session.start.assert_called_once() |
| |
| print("✓ Create session tests passed") |
|
|
|
|
| async def test_close_session(): |
| """Test closing a browser session""" |
| print("Testing close session...") |
| manager = BrowserSessionManager() |
| |
| |
| mock_session = AsyncMock() |
| mock_session.close = AsyncMock() |
| manager.sessions["test-session"] = mock_session |
| |
| |
| result = await manager.close_session("test-session") |
| |
| assert result is True |
| assert "test-session" not in manager.sessions |
| mock_session.close.assert_called_once() |
| |
| print("✓ Close session tests passed") |
|
|
|
|
| async def test_close_nonexistent_session(): |
| """Test closing nonexistent session""" |
| print("Testing close nonexistent session...") |
| manager = BrowserSessionManager() |
| |
| result = await manager.close_session("nonexistent") |
| |
| assert result is False |
| |
| print("✓ Close nonexistent session tests passed") |
|
|
|
|
| async def test_cleanup_expired_sessions(): |
| """Test cleaning up expired sessions""" |
| print("Testing cleanup expired sessions...") |
| manager = BrowserSessionManager(session_timeout_minutes=30) |
| |
| |
| now = datetime.now() |
| |
| |
| recent_session = MagicMock() |
| recent_session.last_used = now - timedelta(minutes=10) |
| recent_session.close = AsyncMock() |
| manager.sessions["recent"] = recent_session |
| |
| |
| expired_session = MagicMock() |
| expired_session.last_used = now - timedelta(minutes=60) |
| expired_session.close = AsyncMock() |
| manager.sessions["expired"] = expired_session |
| |
| |
| await manager.cleanup_expired_sessions() |
| |
| |
| assert "recent" in manager.sessions |
| |
| assert "expired" not in manager.sessions |
| expired_session.close.assert_called_once() |
| |
| print("✓ Cleanup expired sessions tests passed") |
|
|
|
|
| async def test_cleanup_no_expired_sessions(): |
| """Test cleanup when no sessions are expired""" |
| print("Testing cleanup (no expired)...") |
| manager = BrowserSessionManager(session_timeout_minutes=30) |
| |
| |
| now = datetime.now() |
| |
| for i in range(3): |
| session = MagicMock() |
| session.last_used = now - timedelta(minutes=5) |
| session.close = AsyncMock() |
| manager.sessions[f"session-{i}"] = session |
| |
| |
| await manager.cleanup_expired_sessions() |
| |
| |
| assert len(manager.sessions) == 3 |
| |
| print("✓ Cleanup (no expired) tests passed") |
|
|
|
|
| def test_get_browser_manager_singleton(): |
| """Test get_browser_manager returns singleton""" |
| print("Testing get_browser_manager singleton...") |
| |
| manager1 = get_browser_manager() |
| manager2 = get_browser_manager() |
| |
| |
| assert manager1 is manager2 |
| |
| print("✓ get_browser_manager singleton tests passed") |
|
|
|
|
| def test_browser_session_with_optional_agent(): |
| """Test BrowserSession without agent_id""" |
| print("Testing BrowserSession without agent_id...") |
| |
| session = BrowserSession( |
| session_id="test-no-agent", |
| user_id="user-001" |
| ) |
| |
| assert session.agent_id is None |
| assert session.session_id == "test-no-agent" |
| |
| print("✓ BrowserSession without agent_id tests passed") |
|
|
|
|
| async def test_create_session_without_agent(): |
| """Test creating session without agent_id""" |
| print("Testing create session without agent...") |
| manager = BrowserSessionManager() |
| |
| with patch('tools.browser_tool.BrowserSession') as MockSession: |
| mock_session = AsyncMock() |
| mock_session.start = AsyncMock(return_value=True) |
| MockSession.return_value = mock_session |
| |
| session = await manager.create_session( |
| user_id="user-001" |
| |
| ) |
| |
| assert session is not None |
| assert len(manager.sessions) == 1 |
| |
| print("✓ Create session without agent tests passed") |
|
|
|
|
| def test_session_manager_sessions_dict(): |
| """Test that sessions dict works correctly""" |
| print("Testing sessions dict...") |
| manager = BrowserSessionManager() |
| |
| |
| for i in range(5): |
| mock_session = MagicMock() |
| manager.sessions[f"session-{i}"] = mock_session |
| |
| assert len(manager.sessions) == 5 |
| assert f"session-3" in manager.sessions |
| assert f"session-99" not in manager.sessions |
| |
| |
| del manager.sessions["session-2"] |
| assert len(manager.sessions) == 4 |
| |
| print("✓ Sessions dict tests passed") |
|
|
|
|
| async def test_session_lifecycle(): |
| """Test complete session lifecycle""" |
| print("Testing session lifecycle...") |
| manager = BrowserSessionManager() |
| |
| |
| with patch('tools.browser_tool.uuid.uuid4') as mock_uuid: |
| mock_uuid.return_value = "fixed-test-uuid" |
| |
| mock_session = MagicMock() |
| mock_session.session_id = "fixed-test-uuid" |
| mock_session.start = AsyncMock(return_value=True) |
| mock_session.close = AsyncMock() |
| |
| with patch('tools.browser_tool.BrowserSession', return_value=mock_session): |
| session = await manager.create_session(user_id="user-001") |
| assert session is not None |
| assert session.session_id == "fixed-test-uuid" |
| |
| |
| retrieved = manager.get_session("fixed-test-uuid") |
| assert retrieved is not None |
| assert retrieved.session_id == "fixed-test-uuid" |
| |
| |
| result = await manager.close_session("fixed-test-uuid") |
| assert result is True |
| assert "fixed-test-uuid" not in manager.sessions |
| |
| print("✓ Session lifecycle tests passed") |
|
|
|
|
| async def test_session_timeout_threshold(): |
| """Test session timeout threshold edge cases""" |
| print("Testing session timeout threshold...") |
| manager = BrowserSessionManager(session_timeout_minutes=30) |
| |
| now = datetime.now() |
| |
| |
| within_threshold = MagicMock() |
| within_threshold.last_used = now - timedelta(minutes=15) |
| within_threshold.close = AsyncMock() |
| manager.sessions["within-threshold"] = within_threshold |
| |
| |
| over_threshold = MagicMock() |
| over_threshold.last_used = now - timedelta(minutes=31) |
| over_threshold.close = AsyncMock() |
| manager.sessions["over-threshold"] = over_threshold |
| |
| |
| await manager.cleanup_expired_sessions() |
| |
| |
| assert "within-threshold" in manager.sessions |
| |
| assert "over-threshold" not in manager.sessions |
| |
| print("✓ Session timeout threshold tests passed") |
|
|
|
|
| async def main(): |
| """Run all tests""" |
| print("=" * 60) |
| print("Running Browser Tool Tests (Standalone)") |
| print("=" * 60) |
| |
| try: |
| |
| test_browser_headless_config() |
| test_browser_session_initialization() |
| test_browser_session_different_types() |
| test_session_manager_initialization() |
| test_session_manager_custom_timeout() |
| test_get_session_empty() |
| test_get_session_existing() |
| test_get_browser_manager_singleton() |
| test_browser_session_with_optional_agent() |
| test_session_manager_sessions_dict() |
| |
| |
| await test_create_session() |
| await test_close_session() |
| await test_close_nonexistent_session() |
| await test_cleanup_expired_sessions() |
| await test_cleanup_no_expired_sessions() |
| await test_create_session_without_agent() |
| await test_session_lifecycle() |
| await test_session_timeout_threshold() |
| |
| print("=" * 60) |
| print("✓ ALL TESTS PASSED") |
| print("=" * 60) |
| return 0 |
| except AssertionError as e: |
| print(f"✗ TEST FAILED: {e}") |
| import traceback |
| traceback.print_exc() |
| return 1 |
| except Exception as e: |
| print(f"✗ ERROR: {e}") |
| import traceback |
| traceback.print_exc() |
| return 1 |
|
|
|
|
| if __name__ == "__main__": |
| exit_code = asyncio.run(main()) |
| sys.exit(exit_code) |
|
|