ci / test (push) Successful in 45m25s
- Vendor codex-ui-stack host/ as cloud/codex-ui-host/ (original/ not vendored, 650MB) - Bridge emulates 7 methods missing in codex 0.164.0-alpha.9, exposes 29 experimental-protocol methods (150 -> 179), Linux binary candidates, read-only POST /__codex_git - GET /console 302s to the UI host (:8095) when reachable, else falls back to the classic React console; GET /console-classic always serves it - Alignment tables: docs/codex-native-ui-alignment.md - Tests: test_console 7, new test_codex_ui_host 4, handler method pin 247 -> 249
81 lines
3.0 KiB
Python
81 lines
3.0 KiB
Python
"""Codex 原生 UI host 入仓清单单测(见 docs/codex-native-ui-alignment.md §4 第 4 项)。
|
||
|
||
只做静态断言,不起服务、不调网络、不读密钥:
|
||
- appserver-methods.json 是合法 JSON、179 个方法、无重复;
|
||
- app-server-bridge.mjs 里 7 个仿真方法都在(读文件文本断言方法名出现);
|
||
- 仓内无 cloud/codex-ui-host/original/ 目录(650MB 原版栈不入仓);
|
||
- scripts/run-codex-ui.sh 存在且可执行。
|
||
|
||
路径一律以仓库根(本文件向上两级)为基准,不写死绝对路径。
|
||
"""
|
||
|
||
import json
|
||
import os
|
||
import unittest
|
||
|
||
REPO_ROOT = os.path.dirname(os.path.dirname(
|
||
os.path.dirname(os.path.abspath(__file__))))
|
||
|
||
# §4 适配 A5:150 个 UI 清单方法 + 29 个实验协议方法 = 179。
|
||
EXPECTED_METHOD_COUNT = 179
|
||
|
||
# §4 适配 A1–A4:桥接层仿真的 7 个缺失方法。
|
||
SIMULATED_METHODS = [
|
||
"thread/stop",
|
||
"thread/rollback",
|
||
"thread/startAeon",
|
||
"interactive/liveSessions/list",
|
||
"interactive/session/upload",
|
||
"interactive/sessionSandbox/list",
|
||
"interactive/sessionSandbox/read",
|
||
]
|
||
|
||
|
||
class TestAppserverMethodsJson(unittest.TestCase):
|
||
def test_valid_json_179_methods_no_duplicates(self):
|
||
path = os.path.join(
|
||
REPO_ROOT, "cloud", "codex-ui-host", "host",
|
||
"appserver-methods.json")
|
||
with open(path, encoding="utf-8") as f:
|
||
methods = json.load(f)
|
||
self.assertIsInstance(methods, list)
|
||
self.assertEqual(len(methods), EXPECTED_METHOD_COUNT)
|
||
self.assertTrue(all(isinstance(m, str) for m in methods))
|
||
self.assertEqual(len(set(methods)), len(methods),
|
||
"appserver-methods.json must not list a method twice")
|
||
|
||
|
||
class TestAppServerBridgeSimulations(unittest.TestCase):
|
||
def test_seven_simulated_methods_present(self):
|
||
path = os.path.join(
|
||
REPO_ROOT, "cloud", "codex-ui-host", "host",
|
||
"app-server-bridge.mjs")
|
||
with open(path, encoding="utf-8") as f:
|
||
text = f.read()
|
||
for name in SIMULATED_METHODS:
|
||
self.assertIn(name, text,
|
||
"%s must be simulated in app-server-bridge.mjs"
|
||
% name)
|
||
|
||
|
||
class TestOriginalNotVendored(unittest.TestCase):
|
||
def test_no_original_directory_in_repo(self):
|
||
self.assertFalse(
|
||
os.path.exists(os.path.join(
|
||
REPO_ROOT, "cloud", "codex-ui-host", "original")),
|
||
"cloud/codex-ui-host/original/ must not be vendored "
|
||
"(650MB original stack stays out of the repo)")
|
||
|
||
|
||
class TestRunScript(unittest.TestCase):
|
||
def test_run_script_exists_and_is_executable(self):
|
||
path = os.path.join(REPO_ROOT, "scripts", "run-codex-ui.sh")
|
||
self.assertTrue(os.path.isfile(path),
|
||
"scripts/run-codex-ui.sh must exist")
|
||
self.assertTrue(os.access(path, os.X_OK),
|
||
"scripts/run-codex-ui.sh must be executable")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
unittest.main()
|