ab16f2f278
Per Tier 1 investigation (docs/reports/INVESTIGATION_rag_phase4_final_verify_20260627.md), two live_gui tests were leaking temp/relative paths into the shared subprocess's ui_files_base_dir, which survived across @clean_baseline tests and caused RAGEngine.index_file to silently no-op on a dead base_dir. Three fixes: 1. tests/test_rag_visual_sim.py: stop using tempfile.mkdtemp() (which defaults to C:\Users\Ed\AppData\Local\Temp\tmpXXXX) and instead use tempfile.mkdtemp(dir="tests/artifacts", ...). Also restore files_base_dir and rag_enabled in finally so the next live_gui test in the session doesn't inherit the dead path. 2. tests/test_visual_sim_mma_v2.py: stop changing files_base_dir to 'tests/artifacts/temp_workspace' and stop clicking btn_project_save (which persisted the path to manual_slop.toml). The MMA lifecycle does not depend on a specific files_base_dir. 3. src/app_controller.py _handle_reset_session: defensive fix that resets ui_files_base_dir from the default project's base_dir. This makes reset_session() robust to any future polluter (not just the two known ones). Without this, a test that sets files_base_dir via set_value leaves a dead path in the session-scoped subprocess even after reset_session(). Verified: tests/test_rag_visual_sim.py passes 2/2 after the fix.
112 lines
4.0 KiB
Python
112 lines
4.0 KiB
Python
import pytest
|
|
import time
|
|
import sys
|
|
import os
|
|
import shutil
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "src")))
|
|
|
|
from src import api_hook_client
|
|
|
|
@pytest.mark.integration
|
|
def test_rag_full_lifecycle_sim(live_gui):
|
|
client = api_hook_client.ApiHookClient()
|
|
assert client.wait_for_server(timeout=15), "Hook server did not start"
|
|
|
|
# 1. Setup mock project data
|
|
# Per Tier 1 investigation (docs/reports/INVESTIGATION_rag_phase4_final_verify_20260627.md):
|
|
# Use a temp dir under tests/artifacts/ (NOT tempfile.mkdtemp() which defaults
|
|
# to C:\Users\Ed\AppData\Local\Temp\tmpXXXX and pollutes the session-scoped
|
|
# subprocess's ui_files_base_dir with a dead path that persists across
|
|
# live_gui tests). Also restore files_base_dir and rag_enabled in finally
|
|
# to prevent state leakage into subsequent live_gui tests.
|
|
test_dir = tempfile.mkdtemp(dir="tests/artifacts", prefix="rag_visual_sim_")
|
|
previous_files_base_dir = client.get_value('files_base_dir')
|
|
try:
|
|
(Path(test_dir) / "test_file.txt").write_text("This is a test file about RAG integration. It should be indexed.")
|
|
(Path(test_dir) / "other_file.py").write_text("# This is another file\ndef hello():\n print('world')")
|
|
|
|
# 2. Configure project through Hook API
|
|
client.set_value('files_base_dir', str(Path(test_dir).resolve()))
|
|
client.set_value('rag_enabled', True)
|
|
client.set_value('rag_source', 'mock') # Use mock to avoid sentence-transformers dependency in CI
|
|
|
|
# 3. Verify initial status
|
|
status = client.get_value('rag_status')
|
|
assert status in ['idle', 'ready', 'initializing...'], f"Unexpected initial status: {status}"
|
|
|
|
# 4. Trigger Rebuild Index
|
|
print("[SIM] Triggering index rebuild...")
|
|
client.click('btn_rebuild_rag_index')
|
|
|
|
# 5. Wait for status transition
|
|
# Wait for 'indexing...'
|
|
found_indexing = False
|
|
for _ in range(20):
|
|
status = client.get_value('rag_status')
|
|
if status == 'indexing...':
|
|
found_indexing = True
|
|
break
|
|
time.sleep(0.1)
|
|
|
|
print(f"[SIM] Found indexing: {found_indexing}")
|
|
|
|
# Wait for 'ready'
|
|
success = False
|
|
for _ in range(50):
|
|
status = client.get_value('rag_status')
|
|
if status == 'ready':
|
|
success = True
|
|
break
|
|
if "error" in status.lower():
|
|
pytest.fail(f"RAG indexing failed: {status}")
|
|
time.sleep(0.2)
|
|
|
|
assert success, f"RAG indexing timed out. Final status: {status}"
|
|
print("[SIM] RAG indexing SUCCESS.")
|
|
|
|
# 6. Verify retrieval visualization
|
|
# We simulate a response that has RAG context prepended
|
|
# Since we are testing GUI visualization, we'll manually inject a message into the discussion
|
|
# that contains the RAG marker, then verify the GUI state if possible.
|
|
# However, verifying ImGui internal render state via Hook API is limited to exposed fields.
|
|
# We've already verified the wiring of settings and status.
|
|
|
|
# One final check: toggle RAG off and verify
|
|
client.set_value('rag_enabled', False)
|
|
assert client.get_value('rag_enabled') is False
|
|
|
|
finally:
|
|
# Restore state to prevent pollution of session-scoped subprocess.
|
|
# ui_files_base_dir and rag_enabled are sticky; without restoration,
|
|
# the next live_gui test (e.g. test_rag_phase4_final_verify) inherits
|
|
# the dead temp path and its RAG search silently no-ops on missing files.
|
|
try:
|
|
client.set_value('rag_enabled', False)
|
|
except Exception:
|
|
pass
|
|
if previous_files_base_dir is not None:
|
|
try:
|
|
client.set_value('files_base_dir', previous_files_base_dir)
|
|
except Exception:
|
|
pass
|
|
shutil.rmtree(test_dir, ignore_errors=True)
|
|
|
|
@pytest.mark.integration
|
|
def test_rag_settings_persistence_sim(live_gui):
|
|
client = api_hook_client.ApiHookClient()
|
|
assert client.wait_for_server(timeout=15)
|
|
|
|
# Change settings
|
|
client.set_value('rag_chunk_size', 1234)
|
|
client.set_value('rag_chunk_overlap', 56)
|
|
|
|
# Verify they were set in the controller
|
|
assert client.get_value('rag_chunk_size') == 1234
|
|
assert client.get_value('rag_chunk_overlap') == 56
|
|
|
|
print("[SIM] RAG settings persistence simulation PASSED.")
|