-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtest_host.py
More file actions
153 lines (113 loc) · 5.7 KB
/
Copy pathtest_host.py
File metadata and controls
153 lines (113 loc) · 5.7 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
148
149
150
151
152
153
# SPDX-License-Identifier: BSD-3-Clause
"""Smoke tests for the host-extra bindings: OsFileSystem, SimpleThreadPool,
HttpHandler subclassable trampoline, and SimpleHttpHandler.
Run from the repo root:
python -m pytest tests/python/test_host.py -q
Pre-requisite: build the extension with `scripts\\build-python.ps1`.
"""
from __future__ import annotations
import sys
import threading
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / 'packages' / 'python'))
import whiteout as w
# ── OsFileSystem ──────────────────────────────────────────────────────────
def test_os_file_system_round_trip(tmp_path: Path) -> None:
payload = b"\x01\x02\x03\x04\x05"
(tmp_path / "hello.bin").write_bytes(payload)
fs = w.OsFileSystem(str(tmp_path))
assert fs.file_exists("hello.bin")
assert not fs.file_exists("missing.bin")
assert fs.read_file("hello.bin") == payload
def test_os_file_system_write(tmp_path: Path) -> None:
fs = w.OsFileSystem(str(tmp_path))
payload = b"hello, world"
# write_file is codegen-produced — its `data` arg takes the opaque
# VectorU8 (PYBIND11_MAKE_OPAQUE precludes auto py::bytes conversion).
# Construct one from the buffer-protocol-friendly bytes object.
vec = w.VectorU8()
vec.extend(payload)
assert fs.write_file("out.bin", vec)
assert (tmp_path / "out.bin").read_bytes() == payload
# ── SimpleThreadPool ──────────────────────────────────────────────────────
def test_simple_thread_pool_reports_thread_count() -> None:
pool = w.SimpleThreadPool(4)
assert pool.thread_count() == 4
pool.wait_idle()
def test_simple_thread_pool_subclass_chain() -> None:
# Just constructing a pool and passing it through the WorkerPool base
# is enough to validate the class hierarchy is right (we can't yet pass
# the pool to any pybind11-bound parser — the Texture/Storage call
# sites still take the plain default — but the binding hierarchy
# itself must be correct for that future wiring).
pool = w.SimpleThreadPool(2)
assert isinstance(pool, w.WorkerPool)
pool.wait_idle()
# ── HttpHandler trampoline ────────────────────────────────────────────────
def test_http_handler_subclass_round_trips_response() -> None:
"""A Python subclass receives `(url, complete)` and invokes complete
with an HttpResponse. We capture the response on the C++ side by
invoking get_async ourselves (the only available `dispatch` path
without an actual CDN consumer in this build)."""
captured: list[w.HttpResponse] = []
class FakeHandler(w.HttpHandler):
def capabilities(self) -> int:
return w.HTTP_CAPABILITY_HTTP2_MULTIPLEXING
def get_async(self, url, complete):
complete(w.HttpResponse(
status_code=200,
body=b"payload-for-" + url.encode(),
))
def get_range_async(self, url, start, end, complete):
complete(w.HttpResponse(
status_code=206,
body=f"{start}-{end}".encode(),
))
h = FakeHandler()
assert h.capabilities() == w.HTTP_CAPABILITY_HTTP2_MULTIPLEXING
h.get_async("https://example/foo", lambda r: captured.append(r))
assert len(captured) == 1
assert captured[0].status_code == 200
assert captured[0].body == b"payload-for-https://example/foo"
h.get_range_async("https://example/foo", 0, 511,
lambda r: captured.append(r))
assert len(captured) == 2
assert captured[1].status_code == 206
assert captured[1].body == b"0-511"
def test_http_handler_default_capabilities() -> None:
class MinimalHandler(w.HttpHandler):
def get_async(self, url, complete):
complete(w.HttpResponse(status_code=204))
def get_range_async(self, url, start, end, complete):
complete(w.HttpResponse(status_code=204))
# No `capabilities` override — default is HTTP_CAPABILITY_NONE.
h = MinimalHandler()
assert h.capabilities() == w.HTTP_CAPABILITY_NONE
# ── SimpleHttpHandler ────────────────────────────────────────────────────
def test_simple_http_handler_constructs() -> None:
# We don't fire a real request (would hit the network and be flaky in
# CI). Just verify the binding exists and constructs cleanly — and
# that its capabilities() resolves through the C++ vtable, not the
# Python trampoline.
h = w.SimpleHttpHandler(n_threads=2)
caps = h.capabilities()
# Should be either NONE or HTTP2_MULTIPLEXING depending on backend.
assert caps in (w.HTTP_CAPABILITY_NONE,
w.HTTP_CAPABILITY_HTTP2_MULTIPLEXING)
# ── HttpResponse value type ──────────────────────────────────────────────
def test_http_response_defaults() -> None:
r = w.HttpResponse()
assert r.status_code == 0
assert r.body == b""
assert r.error == ""
def test_http_response_field_round_trip() -> None:
r = w.HttpResponse(status_code=404, body=b"not found", error="missing")
assert r.status_code == 404
assert r.body == b"not found"
assert r.error == "missing"
r.status_code = 200
r.body = b"ok"
r.error = ""
assert r.status_code == 200
assert r.body == b"ok"
assert r.error == ""