test_integration.pyβ’15 kB
"""ν΅ν© ν
μ€νΈ"""
import pytest
from unittest.mock import AsyncMock
from datetime import datetime
from src.server import MarketStatsServer
from src.tools.market_tools import MarketOverviewTool
from src.tools.investor_tools import InvestorFlowsTool
from src.tools.market_breadth_tools import MarketBreadthTool
from src.tools.sector_tools import SectorAnalysisTool
class TestMCPServerIntegration:
"""MCP μλ² ν΅ν© ν
μ€νΈ"""
@pytest.fixture
def mock_dependencies(self):
"""Mock μμ‘΄μ±λ€"""
mock_db = AsyncMock()
mock_cache = AsyncMock()
return mock_db, mock_cache
@pytest.fixture
def server(self, mock_dependencies):
"""ν΅ν© ν
μ€νΈμ© μλ² μΈμ€ν΄μ€"""
mock_db, mock_cache = mock_dependencies
# μλ² μ€μ
config = {
"name": "market-stats-server",
"version": "1.0.0",
"database": {"host": "localhost", "port": 5432, "name": "test_db"},
"redis": {"host": "localhost", "port": 6379}
}
# μλ² μμ±
server = MarketStatsServer(config)
# Mock μμ‘΄μ±λ€μ μ§μ μ£Όμ
server.db_manager = mock_db
server.cache_manager = mock_cache
# λͺ¨λ λꡬ λ±λ‘
market_tool = MarketOverviewTool(mock_db, mock_cache)
investor_tool = InvestorFlowsTool(mock_db, mock_cache)
breadth_tool = MarketBreadthTool(mock_db, mock_cache)
sector_tool = SectorAnalysisTool(mock_db, mock_cache)
server.register_tool(market_tool.name, market_tool)
server.register_tool(investor_tool.name, investor_tool)
server.register_tool(breadth_tool.name, breadth_tool)
server.register_tool(sector_tool.name, sector_tool)
return server, mock_db, mock_cache
def test_all_tools_registered(self, server):
"""λͺ¨λ λκ΅¬κ° μ μμ μΌλ‘ λ±λ‘λμλμ§ ν
μ€νΈ"""
server_instance, _, _ = server
available_tools = server_instance.get_available_tools()
tool_names = list(available_tools.keys())
expected_tools = [
"get_market_overview",
"get_investor_flows",
"get_market_breadth",
"get_sector_analysis"
]
for expected in expected_tools:
assert expected in tool_names
assert len(available_tools) == 4
@pytest.mark.asyncio
async def test_market_overview_integration(self, server):
"""μμ₯ κ°μ λꡬ ν΅ν© ν
μ€νΈ"""
server_instance, mock_db, mock_cache = server
# μλ² μμ
await server_instance.startup()
try:
# Mock λ°μ΄ν° μ€μ
mock_cache.get.return_value = None
mock_db.fetch_all.return_value = [
{
"index_code": "KOSPI",
"current_value": 2650.50,
"change": 15.30,
"change_rate": 0.58,
"volume": 450000000,
"market_cap": 1850000000000000,
"timestamp": datetime.now()
}
]
# λꡬ μ€ν
result = await server_instance.execute_tool("get_market_overview", {
"market": "KOSPI"
})
# κ²°κ³Ό κ²μ¦
assert len(result) == 1
assert result[0].type == "text"
# JSON κ²μ¦
import json
data = json.loads(result[0].text)
assert "timestamp" in data
assert "indices" in data
assert len(data["indices"]) == 1
assert data["indices"][0]["index_code"] == "KOSPI"
finally:
await server_instance.shutdown()
@pytest.mark.asyncio
async def test_investor_flows_integration(self, server):
"""ν¬μμ λν₯ λꡬ ν΅ν© ν
μ€νΈ"""
server_instance, mock_db, mock_cache = server
await server_instance.startup()
try:
# Mock λ°μ΄ν° μ€μ
mock_cache.get.return_value = None
mock_db.fetch_all.return_value = [
{
"date": datetime.now().date(),
"investor_type": "κ°μΈ",
"buy_amount": 1500000000000,
"sell_amount": 1200000000000,
"net_amount": 300000000000,
"market": "KOSPI"
}
]
# λꡬ μ€ν
result = await server_instance.execute_tool("get_investor_flows", {
"market": "KOSPI",
"period": "1d"
})
# κ²°κ³Ό κ²μ¦
assert len(result) == 1
import json
data = json.loads(result[0].text)
assert "flows" in data
assert "summary" in data
assert len(data["flows"]) == 1
assert data["flows"][0]["investor_type"] == "κ°μΈ"
finally:
await server_instance.shutdown()
@pytest.mark.asyncio
async def test_market_breadth_integration(self, server):
"""μμ₯ ν μ§ν λꡬ ν΅ν© ν
μ€νΈ"""
server_instance, mock_db, mock_cache = server
await server_instance.startup()
try:
# Mock λ°μ΄ν° μ€μ
mock_cache.get.return_value = None
mock_db.fetch_all.return_value = [
{
"date": datetime.now().date(),
"market": "KOSPI",
"advancing": 850,
"declining": 680,
"unchanged": 120,
"total_issues": 1650,
"advance_decline_ratio": 1.25,
"advance_volume": 2800000000000,
"decline_volume": 1900000000000,
"timestamp": datetime.now()
}
]
# λꡬ μ€ν
result = await server_instance.execute_tool("get_market_breadth", {
"market": "KOSPI",
"period": "1d"
})
# κ²°κ³Ό κ²μ¦
assert len(result) == 1
import json
data = json.loads(result[0].text)
assert "breadth_data" in data
assert "summary" in data
assert len(data["breadth_data"]) == 1
assert data["breadth_data"][0]["advancing"] == 850
finally:
await server_instance.shutdown()
@pytest.mark.asyncio
async def test_sector_analysis_integration(self, server):
"""μΉν° λΆμ λꡬ ν΅ν© ν
μ€νΈ"""
server_instance, mock_db, mock_cache = server
await server_instance.startup()
try:
# Mock λ°μ΄ν° μ€μ
mock_cache.get.return_value = None
mock_db.fetch_all.return_value = [
{
"sector_name": "IT",
"sector_code": "IT001",
"market_cap": 450000000000000,
"total_volume": 280000000000,
"change_rate": 2.35,
"advancing_stocks": 85,
"declining_stocks": 45,
"unchanged_stocks": 12,
"total_stocks": 142,
"top_performer": "μΌμ±μ μ",
"top_performer_change": 3.8,
"worst_performer": "LGμ νλ¬μ€",
"worst_performer_change": -2.1,
"date": datetime.now().date(),
"timestamp": datetime.now()
}
]
# λꡬ μ€ν
result = await server_instance.execute_tool("get_sector_analysis", {
"market": "ALL",
"sector": "ALL"
})
# κ²°κ³Ό κ²μ¦
assert len(result) == 1
import json
data = json.loads(result[0].text)
assert "sector_analysis" in data
assert "market_summary" in data
assert len(data["sector_analysis"]) == 1
assert data["sector_analysis"][0]["sector_name"] == "IT"
finally:
await server_instance.shutdown()
@pytest.mark.asyncio
async def test_sequential_tool_execution(self, server):
"""μ¬λ¬ λꡬ μμ°¨ μ€ν ν
μ€νΈ"""
server_instance, mock_db, mock_cache = server
await server_instance.startup()
try:
# λͺ¨λ λꡬμ λν Mock λ°μ΄ν° μ€μ
mock_cache.get.return_value = None
mock_db.fetch_all.side_effect = [
# μμ₯ κ°μ λ°μ΄ν°
[{"index_code": "KOSPI", "current_value": 2650.50, "change": 15.30, "change_rate": 0.58, "volume": 450000000, "market_cap": 1850000000000000, "timestamp": datetime.now()}],
# ν¬μμ λν₯ λ°μ΄ν°
[{"date": datetime.now().date(), "investor_type": "κ°μΈ", "buy_amount": 1500000000000, "sell_amount": 1200000000000, "net_amount": 300000000000, "market": "KOSPI"}],
# μμ₯ ν λ°μ΄ν°
[{"date": datetime.now().date(), "market": "KOSPI", "advancing": 850, "declining": 680, "unchanged": 120, "total_issues": 1650, "advance_decline_ratio": 1.25, "advance_volume": 2800000000000, "decline_volume": 1900000000000, "timestamp": datetime.now()}],
# μΉν° λΆμ λ°μ΄ν°
[{"sector_name": "IT", "sector_code": "IT001", "market_cap": 450000000000000, "total_volume": 280000000000, "change_rate": 2.35, "advancing_stocks": 85, "declining_stocks": 45, "unchanged_stocks": 12, "total_stocks": 142, "top_performer": "μΌμ±μ μ", "top_performer_change": 3.8, "worst_performer": "LGμ νλ¬μ€", "worst_performer_change": -2.1, "date": datetime.now().date(), "timestamp": datetime.now()}]
]
# μμ°¨μ μΌλ‘ λͺ¨λ λꡬ μ€ν
tools = [
("get_market_overview", {"market": "KOSPI"}),
("get_investor_flows", {"market": "KOSPI", "period": "1d"}),
("get_market_breadth", {"market": "KOSPI", "period": "1d"}),
("get_sector_analysis", {"market": "ALL", "sector": "ALL"})
]
results = []
for tool_name, args in tools:
result = await server_instance.execute_tool(tool_name, args)
results.append(result)
# λͺ¨λ κ²°κ³Ό κ²μ¦
assert len(results) == 4
for result in results:
assert len(result) == 1
assert result[0].type == "text"
# JSON νμ± κ°λ₯νμ§ νμΈ
import json
data = json.loads(result[0].text)
assert "timestamp" in data
finally:
await server_instance.shutdown()
@pytest.mark.asyncio
async def test_error_handling_integration(self, server):
"""μλ¬ μ²λ¦¬ ν΅ν© ν
μ€νΈ"""
server_instance, mock_db, mock_cache = server
await server_instance.startup()
try:
# μ‘΄μ¬νμ§ μλ λꡬ νΈμΆ
with pytest.raises(KeyError):
await server_instance.execute_tool("nonexistent_tool", {})
# λꡬ μ€ν μ€ μλ¬
mock_cache.get.return_value = None
mock_db.fetch_all.side_effect = Exception("Database error")
with pytest.raises(Exception):
await server_instance.execute_tool("get_market_overview", {"market": "KOSPI"})
finally:
await server_instance.shutdown()
@pytest.mark.asyncio
async def test_cache_integration(self, server):
"""μΊμ ν΅ν© ν
μ€νΈ"""
server_instance, mock_db, mock_cache = server
await server_instance.startup()
try:
# μΊμ ννΈ μλ리μ€
cached_data = {
"timestamp": datetime.now().isoformat(),
"market_summary": {"total_market_cap": 2000000000000000},
"indices": [{"index_code": "KOSPI", "current_value": 2650.50}]
}
mock_cache.get.return_value = cached_data
# λꡬ μ€ν
result = await server_instance.execute_tool("get_market_overview", {"market": "KOSPI"})
# μΊμ λ°μ΄ν° λ°ν νμΈ
import json
data = json.loads(result[0].text)
assert data == cached_data
# λ°μ΄ν°λ² μ΄μ€ νΈμΆμ΄ μμλμ§ νμΈ
mock_db.fetch_all.assert_not_called()
finally:
await server_instance.shutdown()
@pytest.mark.asyncio
async def test_health_check_integration(self, server):
"""ν¬μ€μ²΄ν¬ ν΅ν© ν
μ€νΈ"""
server_instance, mock_db, mock_cache = server
await server_instance.startup()
try:
# μ±κ³΅ μλ리μ€
mock_db.health_check.return_value = True
mock_cache.health_check.return_value = True
health_status = await server_instance.health_check()
assert health_status["status"] == "healthy"
assert health_status["database"] == "connected"
assert health_status["cache"] == "connected"
# DB μ€ν¨ μλ리μ€
mock_db.health_check.return_value = False
health_status = await server_instance.health_check()
assert health_status["status"] == "unhealthy"
finally:
await server_instance.shutdown()
@pytest.mark.asyncio
async def test_server_startup_shutdown_integration(self, server):
"""μλ² μμ/μ’
λ£ ν΅ν© ν
μ€νΈ"""
server_instance, mock_db, mock_cache = server
# μ΄κΈ° μν νμΈ
assert server_instance.is_running is False
# μμ
await server_instance.startup()
assert server_instance.is_running is True
# μ’
λ£
await server_instance.shutdown()
assert server_instance.is_running is False
# μ¬μμ ν
μ€νΈ
await server_instance.startup()
assert server_instance.is_running is True
await server_instance.shutdown()
assert server_instance.is_running is False