""" 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