feat: publish Dever core with project scaffolding and versioned AI skills
This commit is contained in:
1 parent
70fa73cdc2
commit
ac458ffa7f
960 files changed
+221319
-1163
No files matched your search
@@ -0,0 +1,122 @@
|
||||
"""用独立 Python 对端检查 Rust 长连接客户端的正文与生命周期判定。"""
|
||||
|
||||
from contextlib import contextmanager
|
||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||
import json
|
||||
from pathlib import Path
|
||||
import socketserver
|
||||
import subprocess
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from live import parse_progress, phase_sequence, validate_result
|
||||
from settings import configured_peer, stage_peer
|
||||
|
||||
|
||||
@contextmanager
|
||||
def serving(server):
|
||||
with server:
|
||||
thread = threading.Thread(target=server.serve_forever, daemon=True)
|
||||
thread.start()
|
||||
try:
|
||||
yield server.server_address[1]
|
||||
finally:
|
||||
server.shutdown()
|
||||
thread.join(timeout=2)
|
||||
if thread.is_alive():
|
||||
raise RuntimeError("owned test listener did not stop")
|
||||
|
||||
|
||||
class Echo(socketserver.BaseRequestHandler):
|
||||
def handle(self):
|
||||
self.request.settimeout(2)
|
||||
while payload := self.request.recv(4096):
|
||||
response = b"!" * len(payload) if self.server.wrong_body else payload
|
||||
self.request.sendall(response)
|
||||
if self.server.wrong_body:
|
||||
return
|
||||
|
||||
|
||||
class InvalidEvent(BaseHTTPRequestHandler):
|
||||
def log_message(self, *_):
|
||||
pass
|
||||
|
||||
def do_GET(self):
|
||||
body = b"event: live\nid: 1\ndata: wrong\n\n"
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "text/event-stream")
|
||||
self.send_header("Content-Length", str(len(body)))
|
||||
self.end_headers()
|
||||
try:
|
||||
self.wfile.write(body)
|
||||
except (BrokenPipeError, ConnectionResetError):
|
||||
# The client aborts sibling sessions after the first deliberate mismatch.
|
||||
return
|
||||
|
||||
|
||||
class SilentEvent(BaseHTTPRequestHandler):
|
||||
def log_message(self, *_):
|
||||
pass
|
||||
|
||||
def do_GET(self):
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "text/event-stream")
|
||||
self.end_headers()
|
||||
self.wfile.write(b"event: live\nid: 1\ndata: ready\n\n")
|
||||
self.wfile.flush()
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
class LiveClientTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
directory = tempfile.TemporaryDirectory(prefix="dever-live-client-")
|
||||
self.addCleanup(directory.cleanup)
|
||||
self.executable = stage_peer(configured_peer("live_peer"), Path(directory.name), {"workers": 1})
|
||||
|
||||
def execute(self, protocol, port, path):
|
||||
scheme = "http" if protocol == "sse" else protocol
|
||||
return subprocess.run([self.executable, protocol, f"{scheme}://127.0.0.1:{port}{path}", "2", "2", "300", "1000"],
|
||||
capture_output=True, text=True, timeout=8)
|
||||
|
||||
def test_tcp_reconnect_and_exact_echo(self):
|
||||
listener = socketserver.ThreadingTCPServer(("127.0.0.1", 0), Echo)
|
||||
listener.wrong_body = False
|
||||
with serving(listener) as port:
|
||||
result = self.execute("tcp", port, "/")
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
phases, counts = parse_progress(result.stdout, 2)
|
||||
self.assertEqual(phases, phase_sequence(2))
|
||||
validate_result(counts, "tcp", 2, 2)
|
||||
|
||||
def test_tcp_wrong_body_cannot_be_counted_as_held(self):
|
||||
listener = socketserver.ThreadingTCPServer(("127.0.0.1", 0), Echo)
|
||||
listener.wrong_body = True
|
||||
with serving(listener) as port:
|
||||
result = self.execute("tcp", port, "/")
|
||||
self.assert_failure(result)
|
||||
|
||||
def test_sse_wrong_event_cannot_pass_connection_readiness(self):
|
||||
with serving(ThreadingHTTPServer(("127.0.0.1", 0), InvalidEvent)) as port:
|
||||
result = self.execute("sse", port, "/events")
|
||||
self.assert_failure(result)
|
||||
|
||||
def test_sse_silent_hold_cannot_pass_heartbeat_validation(self):
|
||||
with serving(ThreadingHTTPServer(("127.0.0.1", 0), SilentEvent)) as port:
|
||||
result = self.execute("sse", port, "/events")
|
||||
self.assertNotEqual(result.returncode, 0)
|
||||
counts = json.loads(result.stdout.splitlines()[-1])
|
||||
self.assertGreater(counts["errors"], 0)
|
||||
self.assertIn("PHASE|0|connected\n", result.stdout)
|
||||
self.assertNotIn("PHASE|0|closing\n", result.stdout)
|
||||
|
||||
def assert_failure(self, result):
|
||||
self.assertNotEqual(result.returncode, 0)
|
||||
counts = json.loads(result.stdout.splitlines()[-1])
|
||||
self.assertGreater(counts["errors"], 0)
|
||||
self.assertNotIn("PHASE|0|connected\n", result.stdout)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user