Files
codex-app-server/cloud/tests/test_v2cov_server_handlers5.py
T
host 488aedbcad code-to10 v6 A14 batch2: test E402/F401 cleanup plus touched-file residual E,F cleanup
(cherry picked from commit 1db02545f74c96b3b92be4fc32954659cec1f814)

Reconcile-conflict: A14b E402 imports referencing cloud.handler_core (does not exist here; core methods live in server.py) — kept HEAD imports with incoming's noqa: E402 markers, dropped the unused core_mod import (verified unused elsewhere in both files).
2026-11-03 02:49:26 +00:00

647 lines
23 KiB
Python

"""Coverage batch v2 (D4b): cloud/server.py small handler clusters,
second half -- costs/relay, task lists, followups, threads, files,
browser helpers, peer messages, reviews, skills/apps/MCP lists.
Same stubbing discipline as D2-D4: the method under test is never
stubbed; host-CLI collaborators (_run_host_cli, _extract_*) are
stubbed only to drive the handler's own error mapping.
"""
import os
import sqlite3
import sys
import tempfile
import time
import unittest
from pathlib import Path
from types import SimpleNamespace
from unittest import mock
REPO_ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(REPO_ROOT))
from cloud.server import ( # noqa: E402
CloudControlPlaneHandler,
_auth_store,
init_db,
)
def _handler(db_path, upload_dir=None, tenants_root=None):
h = CloudControlPlaneHandler.__new__(CloudControlPlaneHandler)
h.server = SimpleNamespace(db_path=db_path, upload_dir=upload_dir,
tenants_root=tenants_root)
sent = []
h._send_json = lambda status, obj, extra_headers=None: sent.append(
(status, obj))
h.sent = sent
return h
def _conn(db_path):
c = sqlite3.connect(db_path)
c.row_factory = sqlite3.Row
return c
class _ProxyConn:
def __init__(self, real, fail_select_substr=None, fail_exc=None):
self._real = real
self._fail_select_substr = fail_select_substr
self._fail_exc = fail_exc
def execute(self, sql, params=()):
text = sql.strip()
if (self._fail_select_substr and text.startswith("SELECT")
and self._fail_select_substr in text):
raise self._fail_exc
return self._real.execute(sql, params)
def __getattr__(self, name):
return getattr(self._real, name)
class _Base(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.db_path = os.path.join(self.tmp.name, "test.db")
init_db(self.db_path)
self.upload_dir = os.path.join(self.tmp.name, "uploads")
os.makedirs(self.upload_dir, exist_ok=True)
def tearDown(self):
self.tmp.cleanup()
def _h(self, body=None, err=None):
h = _handler(self.db_path, upload_dir=self.upload_dir,
tenants_root=self.tmp.name)
h._read_json = lambda: (body, err)
return h
def _project(self, pid="p1", owner="u1", repo_url=None):
c = _conn(self.db_path)
c.execute(
"INSERT INTO projects(id, name, owner_id, created_at,"
" repo_url, auto_pr) VALUES(?, ?, ?, ?, ?, 0)",
(pid, "P", owner, time.time(), repo_url))
c.commit()
c.close()
with _auth_store(self.db_path) as store:
store.create_project(pid, owner)
def _member(self, pid, uid, role):
c = _conn(self.db_path)
c.execute(
"INSERT OR REPLACE INTO project_members(project_id,"
" user_id, role) VALUES(?, ?, ?)", (pid, uid, role))
c.commit()
c.close()
def _task(self, tid="t1", pid="p1", status="completed",
created_by="u1", **extra):
cols = ["id", "project_id", "prompt", "status", "created_by",
"created_at", "updated_at"]
vals = [tid, pid, "do work", status, created_by, time.time(),
time.time()]
for key, val in extra.items():
cols.append(key)
vals.append(val)
c = _conn(self.db_path)
c.execute(
"INSERT INTO tasks(%s) VALUES(%s)"
% (", ".join(cols), ", ".join("?" * len(cols))), vals)
c.commit()
c.close()
def _last(self, h):
self.assertTrue(h.sent, "handler sent no response")
return h.sent[-1]
class _ClosingConn:
def __init__(self):
self.conn = mock.Mock()
self.conn.close.side_effect = RuntimeError("close down")
class CostRelayTestCase(_Base):
def test_kb_search_q_required(self):
h = self._h()
h._kb_search("p1", {})
code, payload = self._last(h)
self.assertEqual(code, 400)
self.assertIn("q required", payload["error"])
def test_kb_search_bad_top_k(self):
h = self._h()
h._kb_search("p1", {"q": ["x"], "top_k": ["abc"]})
self.assertEqual(self._last(h)[0], 400)
def test_kb_search_close_failure_swallowed(self):
class _Store:
def __init__(self, db_path):
self.conn = _ClosingConn().conn
def search(self, project_id, q, top_k=5):
return []
h = self._h()
with mock.patch("cloud.handler_identity.KBStore", _Store):
h._kb_search("p1", {"q": ["x"]})
self.assertEqual(self._last(h)[0], 200)
def test_project_cost_bad_days(self):
h = self._h()
h._project_cost("p1", {"days": ["abc"]})
code, payload = self._last(h)
self.assertEqual(code, 400)
self.assertIn("days must be an integer", payload["error"])
def test_project_cost_close_failure_swallowed(self):
class _Store:
def __init__(self, db_path):
self._conn = mock.Mock()
self._conn.close.side_effect = RuntimeError("down")
def dual_column_report_by_project(self, project_id):
return {}
h = self._h()
with mock.patch("cloud.server.CostStore", _Store):
h._project_cost("p1", {})
self.assertEqual(self._last(h)[0], 200)
def test_task_cost_close_failure_swallowed(self):
self._project()
self._task()
class _Store:
def __init__(self, db_path):
self._conn = mock.Mock()
self._conn.close.side_effect = RuntimeError("down")
def dual_column_report_by_task(self, task_id):
return {}
h = self._h()
with mock.patch("cloud.server.CostStore", _Store):
h._task_cost("u1", "t1")
self.assertEqual(self._last(h)[0], 200)
def test_relay_models_sub2api_generic_error_502(self):
h = self._h()
with mock.patch.dict(os.environ, {"CLOUD_GATEWAY": "sub2api"}), \
mock.patch("cloud.server._validate_sub2api_key",
side_effect=RuntimeError("net down")):
h._relay_models("u1")
self.assertEqual(self._last(h)[0], 502)
def test_relay_models_sub2api_list_error_502(self):
h = self._h()
with mock.patch.dict(os.environ, {"CLOUD_GATEWAY": "sub2api"}), \
mock.patch("cloud.server._validate_sub2api_key",
return_value=("ok", "key", "sub", "kid")), \
mock.patch("cloud.handler_identity._list_sub2api_models",
side_effect=RuntimeError("gw down")):
h._relay_models("u1")
self.assertEqual(self._last(h)[0], 502)
def test_models_overview_no_memberships_200(self):
self._project()
h = self._h()
h._models_overview("u9")
code, payload = self._last(h)
self.assertEqual(code, 200)
self.assertEqual(payload["model_stats"], [])
def test_models_overview_close_failure_swallowed(self):
self._project()
conn = mock.Mock()
conn.execute.return_value.fetchall.return_value = []
conn.close.side_effect = RuntimeError("down")
class _Store:
def __init__(self, db_path):
self._conn = conn
h = self._h()
with mock.patch("cloud.server.CostStore", _Store):
h._models_overview("u1")
self.assertEqual(self._last(h)[0], 200)
class ListsFollowupsTestCase(_Base):
def test_list_tasks_project_required(self):
h = self._h()
h._list_tasks("u1", {})
code, payload = self._last(h)
self.assertEqual(code, 400)
self.assertIn("project_id required", payload["error"])
def test_list_tasks_executor_filter_skips(self):
self._project()
self._task()
h = self._h()
h._list_tasks("u1", {"project_id": ["p1"],
"executor": ["docker"]})
code, payload = self._last(h)
self.assertEqual(code, 200)
self.assertEqual(payload["tasks"], [])
def test_goal_convert_queued_none(self):
self._project()
self._task(status="completed")
h = self._h()
self.assertIsNone(h._goal_convert_queued("t1", "做目标"))
def test_goal_revive_terminal_none(self):
self._project()
self._task(status="completed", resume_message="old")
h = self._h()
self.assertIsNone(h._goal_revive_terminal("t1", "做目标"))
def test_task_agents_remote_host_200(self):
self._project()
self._task(worktree_host="other-host")
h = self._h()
h._task_agents("u1", "t1")
code, payload = self._last(h)
self.assertEqual(code, 200)
self.assertEqual(payload["agents"], [])
def test_create_followup_convert_race_409(self):
self._project()
self._task(status="queued")
h = self._h(body={"body": "/goal 做目标"})
h._goal_convert_queued = lambda tid, target: None
h._create_followup("u1", "t1")
code, payload = self._last(h)
self.assertEqual(code, 409)
self.assertIn("状态已变化", payload["error"])
def test_create_followup_revive_race_409(self):
self._project()
self._task(status="completed")
h = self._h(body={"body": "/goal 做目标"})
h._goal_revive_terminal = lambda tid, target: None
h._create_followup("u1", "t1")
code, payload = self._last(h)
self.assertEqual(code, 409)
self.assertIn("状态已变化", payload["error"])
def test_append_direct_trace_remote_host_returns(self):
h = self._h()
h._append_direct_trace({"id": "t1", "project_id": "p1",
"worktree_host": "other-host"},
"fu1", "hi")
def test_append_direct_trace_tenant_dir(self):
tenant_dir = os.path.join(self.tmp.name, "p1", "work",
"host-traces")
os.makedirs(tenant_dir, exist_ok=True)
open(os.path.join(tenant_dir, "t1.jsonl"), "w").close()
h = self._h()
h._append_direct_trace({"id": "t1", "project_id": "p1"},
"fu1", "hello tenant")
with open(os.path.join(tenant_dir, "t1.jsonl")) as f:
content = f.read()
self.assertIn("followup-direct", content)
def test_append_direct_trace_write_failure_swallowed(self):
h = self._h()
with mock.patch("os.makedirs",
side_effect=OSError("ro fs")):
h._append_direct_trace({"id": "t1", "project_id": "p1"},
"fu1", "hi")
def test_list_followups_missing_404(self):
h = self._h()
h._list_followups("u1", "ghost")
self.assertEqual(self._last(h)[0], 404)
def test_list_followups_forbidden_403(self):
self._project()
self._task()
h = self._h()
h._list_followups("u9", "t1")
self.assertEqual(self._last(h)[0], 403)
def test_task_timeline_forbidden_403(self):
self._project()
self._task()
h = self._h()
h._task_timeline("u9", "t1")
self.assertEqual(self._last(h)[0], 403)
def test_task_files_200_cap(self):
self._project()
self._task()
worktree = os.path.join(self.tmp.name, "p1", "work",
"host-worktrees", "t1")
os.makedirs(worktree, exist_ok=True)
for i in range(201):
with open(os.path.join(worktree, "f%03d.txt" % i), "w") as f:
f.write("x")
h = self._h()
h._task_files("u1", "t1", {})
code, payload = self._last(h)
self.assertEqual(code, 200)
self.assertEqual(len(payload["entries"]), 200)
def test_browser_worktree_for_cloud_409(self):
self._project()
self._task(executor="cloud")
h = self._h()
worktree, err = h._browser_worktree_for("u1", "t1")
self.assertIsNone(worktree)
self.assertEqual(err[0], 409)
def test_browser_body_dict_none_and_bad(self):
h = self._h()
self.assertIsNone(h._browser_body_dict(None))
self.assertIsNone(h._browser_body_dict(b"not json"))
self.assertEqual(h._browser_body_dict({"a": 1}), {"a": 1})
def test_browser_input_worktree_error(self):
h = self._h()
h._browser_worktree_for = lambda *a: (None, (404, "nope"))
h._browser_input("u1", "t1", {})
self.assertEqual(self._last(h)[0], 404)
def test_browser_input_state_error(self):
h = self._h()
h._browser_worktree_for = lambda *a: (self.tmp.name, None)
with mock.patch("cloud.playwright_remote.read_state",
return_value=(None, (502, "no session"))):
h._browser_input("u1", "t1", {})
self.assertEqual(self._last(h)[0], 502)
def test_browser_input_write_os_error_503(self):
h = self._h()
h._browser_worktree_for = lambda *a: (self.tmp.name, None)
with mock.patch("cloud.playwright_remote.read_state",
return_value=({"url": ""}, None)), \
mock.patch("cloud.playwright_remote.effective_holder",
return_value="user"), \
mock.patch("cloud.playwright_remote.append_input",
side_effect=OSError("unreachable")):
h._browser_input("u1", "t1", {"type": "type", "text": "hi"})
code, payload = self._last(h)
self.assertEqual(code, 503)
self.assertIn("browser input unreachable", payload["error"])
def test_chat_history_forbidden_403(self):
self._project()
self._task()
h = self._h()
h._task_chat_history("u9", "t1")
self.assertEqual(self._last(h)[0], 403)
def test_chat_history_legacy_query_failure_none(self):
self._project()
self._task()
h = self._h()
h._trace_snapshot = lambda task: ([], None)
h._db = lambda: _ProxyConn(
_conn(self.db_path),
fail_select_substr="FROM audit_log",
fail_exc=RuntimeError("audit down"))
h._task_chat_history("u1", "t1")
code, payload = self._last(h)
self.assertEqual(code, 200)
self.assertIsNone(payload["legacy_continue_count"])
def test_peer_message_read_error(self):
h = self._h(err="bad json")
h._create_peer_message("u1", "t1")
self.assertEqual(self._last(h)[0], 400)
def test_peer_message_sender_forbidden_403(self):
self._project()
self._project(pid="p2", owner="u2")
self._task(tid="t1", pid="p1")
self._task(tid="t2", pid="p2", created_by="u2")
h = self._h(body={"from_task_id": "t2", "body": "hi"})
h._create_peer_message("u1", "t1")
self.assertEqual(self._last(h)[0], 403)
def test_peer_message_body_too_long(self):
self._project()
self._task(tid="t1", pid="p1")
self._task(tid="t2", pid="p1")
h = self._h(body={"from_task_id": "t2", "body": "x" * 20001})
h._create_peer_message("u1", "t1")
code, payload = self._last(h)
self.assertEqual(code, 400)
self.assertIn("body too long", payload["error"])
def test_list_peer_messages_missing_404(self):
h = self._h()
h._list_peer_messages("u1", "ghost")
self.assertEqual(self._last(h)[0], 404)
def test_create_review_read_error(self):
h = self._h(err="bad json")
h._create_review("u1", "t1")
self.assertEqual(self._last(h)[0], 400)
def test_update_review_findings_read_error(self):
h = self._h(err="bad json")
h._update_review_findings("u1", "t1", "r1")
self.assertEqual(self._last(h)[0], 400)
def test_update_review_findings_missing_404(self):
h = self._h(body={})
h._update_review_findings("u1", "ghost", "r1")
self.assertEqual(self._last(h)[0], 404)
class ThreadListsTestCase(_Base):
def test_thread_guard_docker_409(self):
h = self._h()
code, msg = h._thread_task_guard({"executor": "docker"})
self.assertEqual(code, 409)
def test_thread_guard_remote_host_409(self):
h = self._h()
code, msg = h._thread_task_guard(
{"executor": None, "worktree_host": "other-host"})
self.assertEqual(code, 409)
def test_list_threads_no_tenant_home_502(self):
h = self._h()
threads, home, cwd, err, provider = h._list_task_threads(
{"id": "t1", "project_id": None})
self.assertEqual(err[0], 502)
def test_list_threads_extract_none_502(self):
h = self._h()
with mock.patch("cloud.server._run_host_cli",
return_value=(True, "garbage")), \
mock.patch("cloud.server._extract_thread_list",
return_value=None):
threads, home, cwd, err, provider = h._list_task_threads(
{"id": "t1", "project_id": "p1"})
self.assertEqual(err[0], 502)
self.assertIn("no thread list", err[1])
def test_task_thread_guard_409(self):
self._project()
self._task(executor="docker")
h = self._h()
h._task_thread("u1", "t1", {})
self.assertEqual(self._last(h)[0], 409)
def test_task_thread_cli_failure_502(self):
self._project()
self._task()
h = self._h()
h._resolve_task_thread = lambda task: (
{"id": "th1"}, "/tmp", "/tmp", None, None)
with mock.patch("cloud.server._run_host_cli",
return_value=(False, "host down")):
h._task_thread("u1", "t1", {})
code, payload = self._last(h)
self.assertEqual(code, 502)
self.assertIn("host down", payload["error"])
def test_task_thread_no_thread_502(self):
self._project()
self._task()
h = self._h()
h._resolve_task_thread = lambda task: (
{"id": "th1"}, "/tmp", "/tmp", None, None)
with mock.patch("cloud.server._run_host_cli",
return_value=(True, "garbage")):
h._task_thread("u1", "t1", {})
code, payload = self._last(h)
self.assertEqual(code, 502)
self.assertIn("no thread", payload["error"])
def test_task_thread_mutate_task_error(self):
h = self._h()
h._task_thread_mutate("u1", "ghost", ["archive"],
"thread_archived", "detail")
self.assertEqual(self._last(h)[0], 404)
def test_task_thread_rename_read_error(self):
self._project()
self._task()
h = self._h(err="bad json")
h._task_thread_rename("u1", "t1")
self.assertEqual(self._last(h)[0], 400)
def test_task_thread_rename_name_too_long(self):
self._project()
self._task()
h = self._h(body={"name": "x" * 201})
h._task_thread_rename("u1", "t1")
code, payload = self._last(h)
self.assertEqual(code, 400)
self.assertIn("name too long", payload["error"])
def test_project_host_home_none(self):
h = self._h()
self.assertEqual(h._project_host_home(None), (None, None))
def _list_case(self, method):
h = self._h()
method(h, None)
return h
def test_skills_list_home_none_502(self):
h = self._h()
h._skills_list(None)
self.assertEqual(self._last(h)[0], 502)
def test_skills_list_cli_failure_502(self):
h = self._h()
with mock.patch("cloud.server._run_host_cli",
return_value=(False, "host down")):
h._skills_list("p1")
self.assertEqual(self._last(h)[0], 502)
def test_skills_list_no_list_502(self):
h = self._h()
with mock.patch("cloud.server._run_host_cli",
return_value=(True, "garbage")):
h._skills_list("p1")
self.assertEqual(self._last(h)[0], 502)
def test_apps_list_home_none_502(self):
h = self._h()
h._apps_list(None)
self.assertEqual(self._last(h)[0], 502)
def test_apps_list_cli_failure_502(self):
h = self._h()
with mock.patch("cloud.server._run_host_cli",
return_value=(False, "host down")):
h._apps_list("p1")
self.assertEqual(self._last(h)[0], 502)
def test_apps_list_no_list_502(self):
h = self._h()
with mock.patch("cloud.server._run_host_cli",
return_value=(True, "garbage")):
h._apps_list("p1")
self.assertEqual(self._last(h)[0], 502)
def test_mcp_list_home_none_502(self):
h = self._h()
h._mcp_servers_list(None)
self.assertEqual(self._last(h)[0], 502)
def test_mcp_list_cli_failure_502(self):
h = self._h()
with mock.patch("cloud.server._run_host_cli",
return_value=(False, "host down")):
h._mcp_servers_list("p1")
self.assertEqual(self._last(h)[0], 502)
def test_mcp_list_no_list_502(self):
h = self._h()
with mock.patch("cloud.server._run_host_cli",
return_value=(True, "garbage")):
h._mcp_servers_list("p1")
self.assertEqual(self._last(h)[0], 502)
def test_mcp_list_next_cursor(self):
h = self._h()
with mock.patch("cloud.server._run_host_cli",
return_value=(True, {"servers": [],
"nextCursor": "n1"})):
h._mcp_servers_list("p1")
code, payload = self._last(h)
self.assertEqual(code, 200)
self.assertEqual(payload["nextCursor"], "n1")
def test_mcp_reload_home_none_502(self):
h = self._h()
h._mcp_servers_reload("u1", None)
self.assertEqual(self._last(h)[0], 502)
def test_mcp_reload_cli_failure_502(self):
h = self._h()
with mock.patch("cloud.server._run_host_cli",
return_value=(False, "host down")):
h._mcp_servers_reload("u1", "p1")
self.assertEqual(self._last(h)[0], 502)
def test_mcp_oauth_login_read_error(self):
h = self._h(err="bad json")
h._mcp_server_oauth_login("u1", "p1", "srv")
self.assertEqual(self._last(h)[0], 400)
def test_mcp_oauth_login_timeout_argv(self):
h = self._h(body={"timeoutSecs": 30})
with mock.patch("cloud.server._run_host_cli",
return_value=(True, {"authorizationUrl": "u",
"loginId": "l"})) as cli:
h._mcp_server_oauth_login("u1", "p1", "srv")
argv = cli.call_args[0][0]
self.assertIn("--timeout-secs", argv)
self.assertEqual(self._last(h)[0], 200)
def test_mcp_oauth_login_cli_failure_502(self):
h = self._h(body={})
with mock.patch("cloud.server._run_host_cli",
return_value=(False, "host down")):
h._mcp_server_oauth_login("u1", "p1", "srv")
self.assertEqual(self._last(h)[0], 502)