Files
vpd-permission-poc/poc4_active_source_20260714/tests/test_scenarios.py
2026-07-23 09:40:09 +09:00

185 lines
6.8 KiB
Python

from __future__ import annotations
import json
from pathlib import Path
import tempfile
import unittest
from unittest.mock import patch
from src.poc4.scenarios import ScenarioConfigError, load_demo_scenarios
from src.agent_console.profile import load_app_profile
from src.mcp_tool_router import McpTool, build_mcp_tool_arguments
from src.mcp_result import (
has_actionable_text_result,
status_result_evidence,
status_result_summary,
)
def _load_poc4_query_helpers():
"""Load the Streamlit entrypoint only when its optional runtime is installed."""
try:
from apps.poc4.mcp_discovery_ui import _prepare_hmm_hr_tool_query
except ModuleNotFoundError:
return None
return _prepare_hmm_hr_tool_query
class DemoScenarioConfigTest(unittest.TestCase):
def test_profile_environment_overrides_json_defaults(self) -> None:
path = Path(__file__).parents[1] / "config" / "app_profile.json"
with patch.dict(
"os.environ",
{
"AGENT_CONSOLE_SHORT_NAME": "HMM",
"AGENT_CONSOLE_PAGE_TITLE": "HMM AI 업무 에이전트",
"AGENT_CONSOLE_PRIMARY_COLOR": "#003b70",
},
clear=False,
):
profile = load_app_profile(path)
self.assertEqual(profile.short_name, "HMM")
self.assertEqual(profile.page_title, "HMM AI 업무 에이전트")
self.assertEqual(profile.primary_color, "#003b70")
def test_profile_reads_dotenv_values(self) -> None:
path = Path(__file__).parents[1] / "config" / "app_profile.json"
with tempfile.TemporaryDirectory() as temp_dir:
env_file = Path(temp_dir) / ".env"
env_file.write_text("AGENT_CONSOLE_SHORT_NAME=HMM\n", encoding="utf-8")
profile = load_app_profile(path, env_file)
self.assertEqual(profile.short_name, "HMM")
def test_common_theme_covers_lists_expanders_and_secondary_buttons(self) -> None:
path = Path(__file__).parents[1] / "src" / "agent_console" / "presentation.py"
source = path.read_text(encoding="utf-8")
self.assertIn('[data-testid="stAppViewContainer"] li', source)
self.assertIn('[data-testid="stExpander"] summary', source)
self.assertIn('div[data-testid="stButton"] > button', source)
def test_hmm_scenarios_are_enabled_and_unique(self) -> None:
path = Path(__file__).parents[1] / "config" / "hmm_demo_scenarios.json"
scenarios = load_demo_scenarios(path)
self.assertGreaterEqual(len(scenarios), 3)
self.assertEqual(len(scenarios), len({item.scenario_id for item in scenarios}))
self.assertTrue(all(item.question.strip() for item in scenarios))
def test_hmm_demo_user_presets_reference_runtime_token_only(self) -> None:
path = Path(__file__).parents[1] / "config" / "vpd_token_presets.json"
payload = json.loads(path.read_text(encoding="utf-8"))
presets = payload["presets"]
self.assertEqual(payload["version"], 2)
self.assertEqual({item["user_id"] for item in presets}, {
"E1001", "E1002", "E1003", "E1005", "E1007"
})
self.assertTrue(all(item["mcp_token_env"] == "HMM_MCP_BEARER_TOKEN" for item in presets))
self.assertTrue(all("token" not in item for item in presets))
def test_duplicate_id_is_rejected(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir:
path = Path(temp_dir) / "scenarios.json"
path.write_text(
json.dumps(
{
"scenarios": [
{"id": "HR-01", "title": "one", "question": "q1"},
{"id": "HR-01", "title": "two", "question": "q2"},
]
}
),
encoding="utf-8",
)
with self.assertRaises(ScenarioConfigError):
load_demo_scenarios(path)
def test_default_mcp_tool_arguments_follow_discovered_query_schema(self) -> None:
tool = McpTool(
name="search_hr_data",
description="",
schema={
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"],
},
read_only=True,
)
arguments = build_mcp_tool_arguments(
tool, "직원 E1005의 휴가 신청 내역", 50, preferred_tool="search_hr_data"
)
self.assertEqual(arguments, {"query": "직원 E1005의 휴가 신청 내역"})
def test_term_tool_arguments_follow_discovered_term_schema(self) -> None:
tool = McpTool(
name="resolve_hr_term",
description="",
schema={
"type": "object",
"properties": {"term": {"type": "string"}},
"required": ["term"],
},
read_only=True,
)
arguments = build_mcp_tool_arguments(
tool, "반차", 50, preferred_tool="search_hr_data"
)
self.assertEqual(arguments, {"term": "반차"})
def test_status_result_policy_text_is_preserved_as_answer_evidence(self) -> None:
result = {
"status": "success",
"result": (
"HR_POLICY_SEARCH_RESULT\n"
"EVIDENCE|file=KR_Leave_Policy.pdf|chunk=13|text=이월 기준"
),
}
summary = status_result_summary(result, excerpt_chars=40)
evidence = status_result_evidence(result)
self.assertEqual(summary["status"], "success")
self.assertGreater(summary["result_chars"], 40)
self.assertIn("KR_Leave_Policy.pdf", evidence["result"])
self.assertTrue(has_actionable_text_result(result))
def test_no_data_text_is_not_actionable(self) -> None:
self.assertFalse(
has_actionable_text_result({"status": "success", "result": "No data found"})
)
@unittest.skipIf(_load_poc4_query_helpers() is None, "Streamlit runtime is optional")
def test_policy_query_does_not_include_demo_user_context(self) -> None:
prepare = _load_poc4_query_helpers()
assert prepare is not None
tool = McpTool(
name="search_hr_policy",
description="Search policy documents",
schema={"properties": {"query": {"type": "string"}}},
read_only=True,
)
query = prepare(
question="연차 휴가 이월 기준과 제한을 알려줘",
tool=tool,
model_profile_key="gpt54_mini_oci",
selected_user_id="E1001",
selected_user_role="HR Team Manager",
selected_user_team="HMM HR Demo Team",
selected_user_scope="팀원 6명 관리",
)
self.assertEqual(query, "연차 휴가 이월 기준과 제한을 알려줘")
if __name__ == "__main__":
unittest.main()