-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathtest_windows_server_loop.py
More file actions
147 lines (119 loc) · 4.77 KB
/
Copy pathtest_windows_server_loop.py
File metadata and controls
147 lines (119 loc) · 4.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
"""Windows asyncio loop selection for the CodeBuddy HTTP proxy."""
import asyncio
import socket
import subprocess
import sys
import time
from unittest.mock import Mock
import httpx
import pytest
import uvicorn
import codebuddy_proxy.__main__ as proxy
def _capture_run(monkeypatch):
run = Mock()
monkeypatch.setattr(proxy.uvicorn, "run", run)
return run
def test_windows_uses_selector_with_new_uvicorn(monkeypatch):
monkeypatch.setattr(proxy.sys, "platform", "win32")
run = _capture_run(monkeypatch)
proxy.run_http_server(host="0.0.0.0", port=8787)
run.assert_called_once_with(
proxy.app,
host="0.0.0.0",
port=8787,
log_level="warning",
loop=asyncio.SelectorEventLoop,
)
def test_windows_uses_policy_with_old_uvicorn(monkeypatch):
monkeypatch.setattr(proxy.sys, "platform", "win32")
monkeypatch.setattr(proxy.uvicorn, "Config", type("OldConfig", (), {}))
selector_policy = Mock(return_value=object())
monkeypatch.setattr(asyncio, "WindowsSelectorEventLoopPolicy", selector_policy, raising=False)
set_policy = Mock()
monkeypatch.setattr(asyncio, "set_event_loop_policy", set_policy)
run = _capture_run(monkeypatch)
proxy.run_http_server(host="127.0.0.1", port=8787)
selector_policy.assert_called_once_with()
set_policy.assert_called_once_with(selector_policy.return_value)
run.assert_called_once_with(
proxy.app, host="127.0.0.1", port=8787, log_level="warning"
)
def test_windows_proactor_opt_out_preserves_default(monkeypatch):
monkeypatch.setattr(proxy.sys, "platform", "win32")
set_policy = Mock()
monkeypatch.setattr(asyncio, "set_event_loop_policy", set_policy)
run = _capture_run(monkeypatch)
proxy.run_http_server(host="127.0.0.1", port=8787, windows_loop="proactor")
set_policy.assert_not_called()
run.assert_called_once_with(
proxy.app, host="127.0.0.1", port=8787, log_level="warning"
)
def test_other_platforms_use_uvicorn_default(monkeypatch):
monkeypatch.setattr(proxy.sys, "platform", "linux")
run = _capture_run(monkeypatch)
proxy.run_http_server(host="127.0.0.1", port=8787)
run.assert_called_once_with(
proxy.app, host="127.0.0.1", port=8787, log_level="warning"
)
def test_windows_loop_cli_option():
assert proxy.parse_args([]).windows_loop == "selector"
assert proxy.parse_args(["--windows-loop", "proactor"]).windows_loop == "proactor"
@pytest.mark.skipif(sys.platform != "win32", reason="requires Windows asyncio")
def test_installed_uvicorn_creates_windows_selector_loop():
if not hasattr(uvicorn.Config, "get_loop_factory"):
pytest.skip("older Uvicorn uses Windows event-loop policy")
config = uvicorn.Config(proxy.app, loop=asyncio.SelectorEventLoop)
loop = config.get_loop_factory()()
try:
assert isinstance(loop, asyncio.SelectorEventLoop)
finally:
loop.close()
@pytest.mark.skipif(sys.platform != "win32", reason="requires Windows socket server")
def test_windows_proxy_starts_and_accepts_http_requests(tmp_path):
"""Exercise the real Windows Uvicorn startup, without upstream login."""
with socket.socket() as probe:
probe.bind(("127.0.0.1", 0))
port = probe.getsockname()[1]
process = subprocess.Popen(
[
sys.executable,
"-m",
"codebuddy_proxy",
"--host",
"127.0.0.1",
"--port",
str(port),
"--mock-dir",
str(tmp_path),
"--session-file",
str(tmp_path / "session.json"),
"--log-file",
str(tmp_path / "proxy.jsonl"),
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
try:
url = f"http://127.0.0.1:{port}/health"
deadline = time.monotonic() + 10
response = None
with httpx.Client(trust_env=False, timeout=0.5) as client:
while time.monotonic() < deadline and process.poll() is None:
try:
response = client.get(url)
break
except httpx.TransportError:
time.sleep(0.1)
if response is None:
stdout, stderr = process.communicate(timeout=3) if process.poll() is not None else ("", "")
pytest.fail(f"Windows proxy did not start: {stdout}\n{stderr}")
assert response.status_code == 200
assert response.json()["status"] == "ok"
# Separate connections exercise the accept path beyond startup.
for _ in range(5):
assert httpx.get(url, trust_env=False, timeout=1).status_code == 200
finally:
if process.poll() is None:
process.terminate()
process.communicate(timeout=5)