""" Minimal fake flow smoke tests for LangBot. These tests verify basic component interactions using fake providers and platforms. Not a full pipeline integration test - tests individual factory components. For full pipeline tests, see tests/integration/ (planned). """ from __future__ import annotations import pytest from tests.factories import ( FakeApp, FakeProvider, FakePlatform, text_query, fake_provider_pong, fake_model, mock_platform_adapter, ) class TestFakeMessageFlow: """Smoke tests for fake message flow through pipeline.""" @pytest.mark.asyncio async def test_fake_app_creation(self): """Test FakeApp can be created with all dependencies.""" app = FakeApp() assert app.logger is not None assert app.sess_mgr is not None assert app.model_mgr is not None assert app.tool_mgr is not None assert app.persistence_mgr is not None assert app.query_pool is not None assert app.instance_config is not None # Verify default config assert app.instance_config.data['command']['prefix'] == ['/', '!'] assert app.instance_config.data['command']['enable'] is True @pytest.mark.asyncio async def test_fake_provider_returns_text(self): """Test FakeProvider returns configured response.""" provider = FakeProvider(default_response='test response') # Create mock model with provider model = fake_model(provider=provider) # Create a simple query query = text_query('hello') # Simulate invoke result = await provider.invoke_llm( query=query, model=model, messages=[], funcs=[], extra_args={}, ) assert result is not None assert result.role == 'assistant' assert result.content == 'test response' @pytest.mark.asyncio async def test_fake_provider_pong(self): """Test FakeProvider returns LANGBOT_FAKE_PONG marker.""" provider = fake_provider_pong() model = fake_model(provider=provider) query = text_query('ping') result = await provider.invoke_llm( query=query, model=model, messages=[], funcs=[], extra_args={}, ) assert result.content == FakeProvider.PONG_RESPONSE @pytest.mark.asyncio async def test_fake_provider_streaming(self): """Test FakeProvider streaming response.""" provider = FakeProvider().returns_streaming(['Hello', ' World']) model = fake_model(provider=provider) query = text_query('hello') chunks = [] # invoke_llm_stream returns an async generator, don't await it async for chunk in provider.invoke_llm_stream( query=query, model=model, messages=[], funcs=[], extra_args={}, ): chunks.append(chunk) assert len(chunks) == 2 assert chunks[0].content == 'Hello' assert chunks[1].content == ' World' assert chunks[1].is_final is True @pytest.mark.asyncio async def test_fake_provider_timeout(self): """Test FakeProvider simulates timeout error.""" provider = FakeProvider().timeout() model = fake_model(provider=provider) query = text_query('hello') with pytest.raises(TimeoutError, match='Provider timeout'): await provider.invoke_llm( query=query, model=model, messages=[], funcs=[], extra_args={}, ) @pytest.mark.asyncio async def test_fake_provider_rate_limit(self): """Test FakeProvider simulates rate limit error.""" provider = FakeProvider().rate_limit() model = fake_model(provider=provider) query = text_query('hello') with pytest.raises(Exception, match='Rate limit exceeded'): await provider.invoke_llm( query=query, model=model, messages=[], funcs=[], extra_args={}, ) @pytest.mark.asyncio async def test_fake_provider_captures_requests(self): """Test FakeProvider captures request arguments.""" provider = FakeProvider() model = fake_model(name='gpt-4', provider=provider) query = text_query('hello') await provider.invoke_llm( query=query, model=model, messages=[{'role': 'user', 'content': 'hello'}], funcs=[{'name': 'test_func'}], extra_args={'temperature': 0.7}, ) captured = provider.get_captured_requests() assert len(captured) == 1 assert captured[0]['model'] == 'gpt-4' assert captured[0]['messages'] == [{'role': 'user', 'content': 'hello'}] assert captured[0]['funcs'] == [{'name': 'test_func'}] assert captured[0]['extra_args'] == {'temperature': 0.7} @pytest.mark.asyncio async def test_fake_platform_capture_outbound(self): """Test FakePlatform captures outbound messages.""" platform = FakePlatform(bot_account_id='test-bot') query = text_query('hello') # Simulate sending reply from tests.factories.message import text_chain reply_chain = text_chain('response text') event = query.message_event await platform.reply_message(event, reply_chain, quote_origin=False) # Verify captured outbound = platform.get_outbound_messages() assert len(outbound) == 1 assert outbound[0]['type'] == 'reply' assert outbound[0]['message'] == reply_chain @pytest.mark.asyncio async def test_fake_platform_friend_message(self): """Test FakePlatform creates friend message events.""" platform = FakePlatform(bot_account_id='test-bot') event = platform.create_friend_message( text='hello bot', sender_id=12345, nickname='TestUser', ) assert event.type == 'FriendMessage' assert event.sender.id == 12345 assert event.sender.nickname == 'TestUser' assert str(event.message_chain) == 'hello bot' @pytest.mark.asyncio async def test_fake_platform_group_message_with_mention(self): """Test FakePlatform creates group message with @mention.""" platform = FakePlatform(bot_account_id='test-bot') event = platform.create_group_message( text='hello everyone', sender_id=12345, group_id=99999, mention_bot=True, ) assert event.type == 'GroupMessage' assert event.sender.id == 12345 assert event.group.id == 99999 # Check message chain has @mention chain = event.message_chain assert len(chain) >= 2 # At + Plain @pytest.mark.asyncio async def test_query_factories_basic(self): """Test basic query factory functions.""" # Text query q1 = text_query('hello world') assert q1.launcher_type.value == 'person' assert str(q1.message_chain) == 'hello world' # Group query from tests.factories import group_text_query q2 = group_text_query('hello group', group_id=88888) assert q2.launcher_type.value == 'group' assert q2.launcher_id == 88888 # Command query from tests.factories import command_query q3 = command_query('help', prefix='/') assert str(q3.message_chain) == '/help' # Mention query from tests.factories import mention_query q4 = mention_query('hi', target='test-bot', group_id=77777) assert q4.launcher_type.value == 'group' @pytest.mark.asyncio async def test_fake_platform_send_failure(self): """Test FakePlatform simulates send failure.""" platform = FakePlatform().send_failure() query = text_query('hello') from tests.factories.message import text_chain with pytest.raises(Exception, match='Platform send failure'): await platform.reply_message( query.message_event, text_chain('response'), ) @pytest.mark.asyncio async def test_mock_platform_adapter(self): """Test mock_platform_adapter helper.""" platform = FakePlatform(bot_account_id='bot-123') adapter = mock_platform_adapter(platform) assert adapter.bot_account_id == 'bot-123' assert adapter._fake_platform is platform # Test reply_message is wired from tests.factories.message import text_chain query = text_query('test') await adapter.reply_message(query.message_event, text_chain('response')) # Verify platform captured it assert len(platform.get_outbound_messages()) == 1 class TestMessageFlowIntegration: """Minimal fake flow integration tests. These tests verify component interactions but do NOT run full LangBot pipeline. For real pipeline tests, integration tests are needed (planned). """ @pytest.mark.asyncio async def test_minimal_message_flow(self): """Minimal fake flow test: fake query -> fake provider -> fake platform. This test verifies: 1. Fake text query is created 2. Fake provider returns LANGBOT_FAKE_PONG 3. Fake platform captures outbound response 4. No unexpected exception Note: This does NOT run actual LangBot pipeline stages. """ # Setup platform = FakePlatform(bot_account_id='test-bot') provider = fake_provider_pong() model = fake_model(provider=provider) # Create inbound message query = text_query('ping') # Simulate provider processing response = await provider.invoke_llm( query=query, model=model, messages=[{'role': 'user', 'content': 'ping'}], funcs=[], extra_args={}, ) # Verify provider returned pong assert response.content == FakeProvider.PONG_RESPONSE # Simulate platform sending response from tests.factories.message import text_chain reply_chain = text_chain(response.content) await platform.reply_message(query.message_event, reply_chain) # Verify platform captured outbound outbound = platform.get_outbound_messages() assert len(outbound) == 1 assert outbound[0]['type'] == 'reply' assert str(outbound[0]['message']) == FakeProvider.PONG_RESPONSE @pytest.mark.asyncio async def test_streaming_message_flow(self): """Smoke test: streaming message flow.""" platform = FakePlatform().supports_streaming() provider = FakeProvider().returns_streaming(['Hello', ' there']) model = fake_model(provider=provider) query = text_query('hi') chunks = [] async for chunk in provider.invoke_llm_stream( query=query, model=model, messages=[], funcs=[], extra_args={}, ): chunks.append(chunk) # Verify streaming worked assert len(chunks) == 2 full_content = ''.join(c.content for c in chunks) assert full_content == 'Hello there' # Verify platform supports streaming assert await platform.is_stream_output_supported() is True