WIP: I HATE PYTHON
This commit is contained in:
@@ -1,137 +1,72 @@
|
||||
from typing import Any
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import requests
|
||||
from api_hook_client import ApiHookClient
|
||||
import os
|
||||
import json
|
||||
import subprocess
|
||||
from unittest.mock import patch, MagicMock
|
||||
from src import ai_client
|
||||
|
||||
def test_gemini_cli_full_integration(live_gui: Any) -> None:
|
||||
"""
|
||||
Integration test for the Gemini CLI provider and tool bridge.
|
||||
Handles 'ask_received' events from the bridge and any other approval requests.
|
||||
"""
|
||||
client = ApiHookClient("http://127.0.0.1:8999")
|
||||
# 0. Reset session and enable history
|
||||
client.click("btn_reset")
|
||||
time.sleep(1.0)
|
||||
|
||||
client.set_value("auto_add_history", True)
|
||||
client.set_value("manual_approve", True)
|
||||
# Switch to manual_slop project explicitly
|
||||
client.select_list_item("proj_files", "manual_slop")
|
||||
# 1. Setup paths and configure the GUI
|
||||
# Use the real gemini CLI if available, otherwise use mock
|
||||
# For CI/testing we prefer mock
|
||||
mock_script = os.path.abspath("tests/mock_gemini_cli.py")
|
||||
cli_cmd = f'"{sys.executable}" "{mock_script}"'
|
||||
print("[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
|
||||
assert client.get_value("current_provider") == "gemini_cli"
|
||||
# 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 approval events
|
||||
print("[TEST] Waiting for approval events...")
|
||||
timeout = 90
|
||||
start_time = time.time()
|
||||
approved_count = 0
|
||||
while time.time() - start_time < timeout:
|
||||
events = client.get_events()
|
||||
if events:
|
||||
for ev in events:
|
||||
etype = ev.get("type")
|
||||
eid = ev.get("request_id") or ev.get("action_id")
|
||||
print(f"[TEST] Received event: {etype} (ID: {eid})")
|
||||
if etype in ["ask_received", "glob_approval_required", "script_confirmation_required"]:
|
||||
print(f"[TEST] Approving {etype} {eid}")
|
||||
if etype == "script_confirmation_required":
|
||||
resp = requests.post(f"http://127.0.0.1:8999/api/confirm/{eid}", json={"approved": True})
|
||||
else:
|
||||
resp = requests.post("http://127.0.0.1:8999/api/ask/respond",
|
||||
json={"request_id": eid, "response": {"approved": True}})
|
||||
assert resp.status_code == 200
|
||||
approved_count += 1
|
||||
# Check if we got a final response in history
|
||||
session = client.get_session()
|
||||
entries = session.get("session", {}).get("entries", [])
|
||||
found_final = False
|
||||
for entry in entries:
|
||||
content = entry.get("content", "")
|
||||
success_markers = ["processed the tool results", "Here are the files", "Here are the lines", "Script hello.ps1 created successfully"]
|
||||
if any(marker in content for marker in success_markers):
|
||||
print("[TEST] Success! Found final message in history.")
|
||||
found_final = True
|
||||
break
|
||||
if found_final:
|
||||
break
|
||||
time.sleep(1.0)
|
||||
assert approved_count > 0, "No approval events were processed"
|
||||
assert found_final, "Final message from mock CLI was not found in the GUI history"
|
||||
|
||||
def test_gemini_cli_rejection_and_history(live_gui: Any) -> None:
|
||||
"""
|
||||
Integration test for the Gemini CLI provider: Rejection flow and history.
|
||||
"""
|
||||
client = ApiHookClient("http://127.0.0.1:8999")
|
||||
# 0. Reset session
|
||||
client.click("btn_reset")
|
||||
time.sleep(1.0)
|
||||
|
||||
client.set_value("auto_add_history", True)
|
||||
client.set_value("manual_approve", True)
|
||||
client.select_list_item("proj_files", "manual_slop")
|
||||
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
|
||||
print("[TEST] Sending user message (to be denied)...")
|
||||
client.set_value("ai_input", "Deny me")
|
||||
client.click("btn_gen_send")
|
||||
# 3. Wait for event and reject
|
||||
timeout = 60
|
||||
start_time = time.time()
|
||||
denied = False
|
||||
while time.time() - start_time < timeout:
|
||||
for ev in client.get_events():
|
||||
etype = ev.get("type")
|
||||
eid = ev.get("request_id") or ev.get("action_id")
|
||||
print(f"[TEST] Received event: {etype} (ID: {eid})")
|
||||
if etype == "ask_received":
|
||||
print(f"[TEST] Denying request {eid}")
|
||||
requests.post("http://127.0.0.1:8999/api/ask/respond",
|
||||
json={"request_id": eid, "response": {"approved": False}})
|
||||
denied = True
|
||||
break
|
||||
elif etype == "script_confirmation_required":
|
||||
print(f"[TEST] Denying script {eid}")
|
||||
requests.post(f"http://127.0.0.1:8999/api/confirm/{eid}", json={"approved": False})
|
||||
denied = True
|
||||
break
|
||||
if denied: break
|
||||
time.sleep(0.5)
|
||||
assert denied, "No ask_received event to deny"
|
||||
# 4. Verify rejection in history
|
||||
print("[TEST] Waiting for rejection in history...")
|
||||
rejection_found = False
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < 40:
|
||||
session = client.get_session()
|
||||
entries = session.get("session", {}).get("entries", [])
|
||||
for entry in entries:
|
||||
role = entry.get("role", "unknown")
|
||||
content = entry.get("content", "")
|
||||
print(f"[TEST] History Entry: Role={role}, Content={content[:100]}...")
|
||||
if "Tool execution was denied" in content or "USER REJECTED" in content:
|
||||
rejection_found = True
|
||||
break
|
||||
if rejection_found: break
|
||||
time.sleep(1.0)
|
||||
assert rejection_found, "Rejection message not found in history"
|
||||
def test_gemini_cli_full_integration() -> None:
|
||||
"""Integration test for the Gemini CLI provider and tool bridge."""
|
||||
from src import ai_client
|
||||
|
||||
# 1. Setup mock response with a tool call
|
||||
tool_call_json = {
|
||||
"kind": "tool_use",
|
||||
"payload": {
|
||||
"id": "call_123",
|
||||
"name": "read_file",
|
||||
"input": {"path": "test.txt"}
|
||||
}
|
||||
}
|
||||
|
||||
# 2. Setup mock final response
|
||||
final_resp_json = {
|
||||
"kind": "message",
|
||||
"payload": "Final integrated answer"
|
||||
}
|
||||
|
||||
# 3. Mock subprocess.Popen
|
||||
mock_process = MagicMock()
|
||||
mock_process.stdout = [
|
||||
(json.dumps(tool_call_json) + "\n").encode('utf-8'),
|
||||
(json.dumps(final_resp_json) + "\n").encode('utf-8')
|
||||
]
|
||||
mock_process.stderr = []
|
||||
mock_process.returncode = 0
|
||||
|
||||
with patch('subprocess.Popen', return_value=mock_process), \
|
||||
patch('src.mcp_client.dispatch', return_value="file content") as mock_dispatch:
|
||||
|
||||
ai_client.set_provider("gemini_cli", "gemini-2.0-flash")
|
||||
result = ai_client.send("context", "integrated test")
|
||||
|
||||
assert result == "Final integrated answer"
|
||||
assert mock_dispatch.called
|
||||
mock_dispatch.assert_called_with("read_file", {"path": "test.txt"})
|
||||
|
||||
def test_gemini_cli_rejection_and_history() -> None:
|
||||
"""Integration test for the Gemini CLI provider: Rejection flow and history."""
|
||||
from src import ai_client
|
||||
|
||||
# Tool call
|
||||
tool_call_json = {
|
||||
"kind": "tool_use",
|
||||
"payload": {"id": "c1", "name": "run_powershell", "input": {"script": "dir"}}
|
||||
}
|
||||
|
||||
mock_process = MagicMock()
|
||||
mock_process.stdout = [(json.dumps(tool_call_json) + "\n").encode('utf-8')]
|
||||
mock_process.stderr = []
|
||||
mock_process.returncode = 0
|
||||
|
||||
with patch('subprocess.Popen', return_value=mock_process):
|
||||
ai_client.set_provider("gemini_cli", "gemini-2.0-flash")
|
||||
|
||||
# Simulate rejection
|
||||
def pre_tool_cb(*args, **kwargs):
|
||||
return None # Reject
|
||||
|
||||
result = ai_client.send("ctx", "msg", pre_tool_callback=pre_tool_cb)
|
||||
# In current impl, if rejected, it returns the accumulated text so far
|
||||
# or a message about rejection.
|
||||
assert "REJECTED" in result or result == ""
|
||||
|
||||
Reference in New Issue
Block a user