294 lines
27 KiB
Plaintext
294 lines
27 KiB
Plaintext
============================= test session starts =============================
|
|
platform win32 -- Python 3.11.6, pytest-9.0.2, pluggy-1.6.0
|
|
rootdir: C:\projects\manual_slop
|
|
configfile: pyproject.toml
|
|
plugins: anyio-4.12.1
|
|
collected 113 items
|
|
|
|
tests\conductor\test_infrastructure.py .... [ 3%]
|
|
tests\test_agent_capabilities.py . [ 4%]
|
|
tests\test_agent_tools_wiring.py .. [ 6%]
|
|
tests\test_ai_client_cli.py . [ 7%]
|
|
tests\test_ai_context_history.py . [ 7%]
|
|
tests\test_api_events.py .... [ 11%]
|
|
tests\test_api_hook_client.py ...... [ 16%]
|
|
tests\test_api_hook_extensions.py ..... [ 21%]
|
|
tests\test_cli_tool_bridge.py .FF [ 23%]
|
|
tests\test_conductor_api_hook_integration.py ... [ 26%]
|
|
tests\test_extended_sims.py .... [ 30%]
|
|
tests\test_gemini_cli_adapter.py .... [ 33%]
|
|
tests\test_gemini_cli_integration.py FF [ 35%]
|
|
tests\test_gemini_metrics.py . [ 36%]
|
|
tests\test_gui2_events.py . [ 37%]
|
|
tests\test_gui2_layout.py .. [ 38%]
|
|
tests\test_gui2_mcp.py . [ 39%]
|
|
tests\test_gui2_parity.py ... [ 42%]
|
|
tests\test_gui2_performance.py .s [ 44%]
|
|
tests\test_gui_diagnostics.py .. [ 46%]
|
|
tests\test_gui_events.py . [ 46%]
|
|
tests\test_gui_performance_requirements.py . [ 47%]
|
|
tests\test_gui_stress_performance.py . [ 48%]
|
|
tests\test_gui_updates.py .. [ 50%]
|
|
tests\test_headless_api.py ......... [ 58%]
|
|
tests\test_headless_dependencies.py .. [ 60%]
|
|
tests\test_headless_startup.py .. [ 61%]
|
|
tests\test_history_blacklist.py .. [ 63%]
|
|
tests\test_history_bleed.py F
|
|
|
|
================================== FAILURES ===================================
|
|
____________________ TestCliToolBridge.test_deny_decision _____________________
|
|
|
|
self = <test_cli_tool_bridge.TestCliToolBridge testMethod=test_deny_decision>
|
|
mock_request = <MagicMock name='request_confirmation' id='2685850806608'>
|
|
mock_stdout = <_io.StringIO object at 0x00000271259C3B50>
|
|
mock_stdin = <_io.StringIO object at 0x0000027158FFF2E0>
|
|
|
|
@patch('sys.stdin', new_callable=io.StringIO)
|
|
@patch('sys.stdout', new_callable=io.StringIO)
|
|
@patch('api_hook_client.ApiHookClient.request_confirmation')
|
|
def test_deny_decision(self, mock_request, mock_stdout, mock_stdin):
|
|
# Mock stdin
|
|
mock_stdin.write(json.dumps(self.tool_call))
|
|
mock_stdin.seek(0)
|
|
|
|
# 4. Mock ApiHookClient to return denied
|
|
mock_request.return_value = {'approved': False}
|
|
|
|
main()
|
|
|
|
# Assert deny
|
|
output = json.loads(mock_stdout.getvalue().strip())
|
|
> self.assertEqual(output.get('decision'), 'deny')
|
|
E AssertionError: 'allow' != 'deny'
|
|
E - allow
|
|
E + deny
|
|
|
|
tests\test_cli_tool_bridge.py:54: AssertionError
|
|
_______________ TestCliToolBridge.test_unreachable_hook_server ________________
|
|
|
|
self = <test_cli_tool_bridge.TestCliToolBridge testMethod=test_unreachable_hook_server>
|
|
mock_request = <MagicMock name='request_confirmation' id='2685851588240'>
|
|
mock_stdout = <_io.StringIO object at 0x0000027158FFF1C0>
|
|
mock_stdin = <_io.StringIO object at 0x00000271593A0A60>
|
|
|
|
@patch('sys.stdin', new_callable=io.StringIO)
|
|
@patch('sys.stdout', new_callable=io.StringIO)
|
|
@patch('api_hook_client.ApiHookClient.request_confirmation')
|
|
def test_unreachable_hook_server(self, mock_request, mock_stdout, mock_stdin):
|
|
# Mock stdin
|
|
mock_stdin.write(json.dumps(self.tool_call))
|
|
mock_stdin.seek(0)
|
|
|
|
# 5. Test case where hook server is unreachable (exception)
|
|
mock_request.side_effect = Exception("Connection refused")
|
|
|
|
main()
|
|
|
|
# Assert deny on error
|
|
output = json.loads(mock_stdout.getvalue().strip())
|
|
> self.assertEqual(output.get('decision'), 'deny')
|
|
E AssertionError: 'allow' != 'deny'
|
|
E - allow
|
|
E + deny
|
|
|
|
tests\test_cli_tool_bridge.py:71: AssertionError
|
|
______________________ test_gemini_cli_full_integration _______________________
|
|
|
|
live_gui = (<Popen: returncode: None args: ['uv', 'run', 'python', '-u', 'gui_2.py', '--...>, 'gui_2.py')
|
|
|
|
def test_gemini_cli_full_integration(live_gui):
|
|
"""
|
|
Integration test for the Gemini CLI provider and tool bridge.
|
|
"""
|
|
client = ApiHookClient("http://127.0.0.1:8999")
|
|
|
|
# 1. Setup paths and configure the GUI
|
|
mock_script = os.path.abspath("tests/mock_gemini_cli.py")
|
|
# Wrap in quotes for shell execution if path has spaces
|
|
cli_cmd = f'"{sys.executable}" "{mock_script}"'
|
|
|
|
# Set provider and binary path via GUI hooks
|
|
# Note: Using set_value which now triggers the property setter in gui_2.py
|
|
print(f"[TEST] Setting current_provider to gemini_cli")
|
|
client.set_value("current_provider", "gemini_cli")
|
|
print(f"[TEST] Setting gcli_path to {cli_cmd}")
|
|
client.set_value("gcli_path", cli_cmd)
|
|
|
|
# Verify settings were applied
|
|
assert client.get_value("current_provider") == "gemini_cli"
|
|
assert client.get_value("gcli_path") == cli_cmd
|
|
|
|
# Clear events
|
|
client.get_events()
|
|
|
|
# 2. Trigger a message in the GUI
|
|
print("[TEST] Sending user message...")
|
|
client.set_value("ai_input", "Please read test.txt")
|
|
client.click("btn_gen_send")
|
|
|
|
# 3. Monitor for the 'ask_received' event
|
|
print("[TEST] Waiting for ask_received event...")
|
|
request_id = None
|
|
timeout = 30
|
|
start_time = time.time()
|
|
while time.time() - start_time < timeout:
|
|
events = client.get_events()
|
|
if events:
|
|
print(f"[TEST] Received {len(events)} events: {[e.get('type') for e in events]}")
|
|
for ev in events:
|
|
if ev.get("type") == "ask_received":
|
|
request_id = ev.get("request_id")
|
|
print(f"[TEST] Found request_id: {request_id}")
|
|
break
|
|
if request_id:
|
|
break
|
|
time.sleep(0.5)
|
|
|
|
assert request_id is not None, "Timed out waiting for 'ask_received' event from the bridge"
|
|
|
|
# 4. Respond to the permission request
|
|
print("[TEST] Responding to ask with approval")
|
|
resp = requests.post(
|
|
"http://127.0.0.1:8999/api/ask/respond",
|
|
json={
|
|
"request_id": request_id,
|
|
"response": {"approved": True}
|
|
}
|
|
)
|
|
assert resp.status_code == 200
|
|
|
|
# 5. Verify that the final response is displayed in the GUI
|
|
print("[TEST] Waiting for final message in history...")
|
|
final_message_received = False
|
|
start_time = time.time()
|
|
while time.time() - start_time < timeout:
|
|
session = client.get_session()
|
|
entries = session.get("session", {}).get("entries", [])
|
|
for entry in entries:
|
|
content = entry.get("content", "")
|
|
if "Hello from mock!" in content:
|
|
print(f"[TEST] Success! Found message: {content[:50]}...")
|
|
final_message_received = True
|
|
break
|
|
if final_message_received:
|
|
break
|
|
time.sleep(1.0)
|
|
|
|
> assert final_message_received, "Final message from mock CLI was not found in the GUI history"
|
|
E AssertionError: Final message from mock CLI was not found in the GUI history
|
|
E assert False
|
|
|
|
tests\test_gemini_cli_integration.py:86: AssertionError
|
|
---------------------------- Captured stdout call -----------------------------
|
|
[TEST] Setting current_provider to gemini_cli
|
|
[TEST] Setting gcli_path to "C:\projects\manual_slop\.venv\Scripts\python.exe" "C:\projects\manual_slop\tests\mock_gemini_cli.py"
|
|
[TEST] Sending user message...
|
|
[TEST] Waiting for ask_received event...
|
|
[TEST] Received 1 events: ['ask_received']
|
|
[TEST] Found request_id: e24686e7-274a-4cd0-a8a4-dc026d322dc9
|
|
[TEST] Responding to ask with approval
|
|
[TEST] Waiting for final message in history...
|
|
____________________ test_gemini_cli_rejection_and_history ____________________
|
|
|
|
live_gui = (<Popen: returncode: None args: ['uv', 'run', 'python', '-u', 'gui_2.py', '--...>, 'gui_2.py')
|
|
|
|
def test_gemini_cli_rejection_and_history(live_gui):
|
|
"""
|
|
Integration test for the Gemini CLI provider: Rejection flow and history.
|
|
"""
|
|
client = ApiHookClient("http://127.0.0.1:8999")
|
|
|
|
# 1. Setup paths and configure the GUI
|
|
mock_script = os.path.abspath("tests/mock_gemini_cli.py")
|
|
cli_cmd = f'"{sys.executable}" "{mock_script}"'
|
|
|
|
client.set_value("current_provider", "gemini_cli")
|
|
client.set_value("gcli_path", cli_cmd)
|
|
|
|
# 2. Trigger a message that will be denied
|
|
print("[TEST] Sending user message (to be denied)...")
|
|
client.set_value("ai_input", "Deny me")
|
|
client.click("btn_gen_send")
|
|
|
|
# 3. Wait for 'ask_received' and respond with rejection
|
|
request_id = None
|
|
timeout = 15
|
|
start_time = time.time()
|
|
while time.time() - start_time < timeout:
|
|
for ev in client.get_events():
|
|
if ev.get("type") == "ask_received":
|
|
request_id = ev.get("request_id")
|
|
break
|
|
if request_id: break
|
|
time.sleep(0.5)
|
|
|
|
assert request_id is not None
|
|
|
|
print("[TEST] Responding to ask with REJECTION")
|
|
requests.post("http://127.0.0.1:8999/api/ask/respond",
|
|
json={"request_id": request_id, "response": {"approved": False}})
|
|
|
|
# 4. Verify rejection message in history
|
|
print("[TEST] Waiting for rejection message in history...")
|
|
rejection_found = False
|
|
start_time = time.time()
|
|
while time.time() - start_time < timeout:
|
|
session = client.get_session()
|
|
entries = session.get("session", {}).get("entries", [])
|
|
for entry in entries:
|
|
if "Tool execution was denied. Decision: deny" in entry.get("content", ""):
|
|
rejection_found = True
|
|
break
|
|
if rejection_found: break
|
|
time.sleep(1.0)
|
|
|
|
> assert rejection_found, "Rejection message not found in history"
|
|
E AssertionError: Rejection message not found in history
|
|
E assert False
|
|
|
|
tests\test_gemini_cli_integration.py:138: AssertionError
|
|
---------------------------- Captured stdout call -----------------------------
|
|
[TEST] Sending user message (to be denied)...
|
|
[TEST] Responding to ask with REJECTION
|
|
[TEST] Waiting for rejection message in history...
|
|
_____________________ test_get_history_bleed_stats_basic ______________________
|
|
|
|
def test_get_history_bleed_stats_basic():
|
|
# Reset state
|
|
ai_client.reset_session()
|
|
|
|
# Mock some history
|
|
ai_client.history_trunc_limit = 1000
|
|
# Simulate 500 tokens used
|
|
with MagicMock() as mock_stats:
|
|
# This would usually involve patching the encoder or session logic
|
|
pass
|
|
|
|
stats = ai_client.get_history_bleed_stats()
|
|
assert 'current' in stats
|
|
assert 'limit' in stats
|
|
# ai_client.py hardcodes Gemini limit to 900_000
|
|
> assert stats['limit'] == 900000
|
|
E assert 0 == 900000
|
|
|
|
tests\test_history_bleed.py:26: AssertionError
|
|
-------------------------- Captured stdout teardown ---------------------------
|
|
|
|
[Fixture] Finally block triggered: Shutting down gui_2.py...
|
|
[Fixture] Attempting to kill process tree for PID 5788...
|
|
[Fixture] Process tree 5788 killed.
|
|
=========================== short test summary info ===========================
|
|
FAILED tests/test_cli_tool_bridge.py::TestCliToolBridge::test_deny_decision - AssertionError: 'allow' != 'deny'
|
|
- allow
|
|
+ deny
|
|
FAILED tests/test_cli_tool_bridge.py::TestCliToolBridge::test_unreachable_hook_server - AssertionError: 'allow' != 'deny'
|
|
- allow
|
|
+ deny
|
|
FAILED tests/test_gemini_cli_integration.py::test_gemini_cli_full_integration - AssertionError: Final message from mock CLI was not found in the GUI history
|
|
assert False
|
|
FAILED tests/test_gemini_cli_integration.py::test_gemini_cli_rejection_and_history - AssertionError: Rejection message not found in history
|
|
assert False
|
|
FAILED tests/test_history_bleed.py::test_get_history_bleed_stats_basic - assert 0 == 900000
|
|
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 5 failures !!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
============= 5 failed, 67 passed, 1 skipped in 163.79s (0:02:43) =============
|