70 lines
2.7 KiB
Python
70 lines
2.7 KiB
Python
"""Live local protocol, concurrency, deadlines and bulk-output regression tests."""
|
|
import concurrent.futures
|
|
import json
|
|
import struct
|
|
import subprocess
|
|
import time
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
EXE = ROOT / "build/bin/Release/locate.exe"
|
|
MAGIC = 0x31434C57
|
|
checks = []
|
|
|
|
|
|
def run(*args):
|
|
return subprocess.run([str(EXE), *args], capture_output=True, timeout=30)
|
|
|
|
|
|
def exact(pipe, size):
|
|
data = b""
|
|
while len(data) < size:
|
|
chunk = pipe.read(size - len(data))
|
|
assert chunk, "truncated reply"
|
|
data += chunk
|
|
return data
|
|
|
|
|
|
def malformed(**changes):
|
|
fields = dict(magic=MAGIC, size=0, operation=0, flags=0, limit=10,
|
|
offset=0, sort=0, descending=0, timeout=1000, reserved=0)
|
|
fields.update(changes)
|
|
with open(r"\\.\pipe\WLocate.Search.v1", "r+b", buffering=0) as pipe:
|
|
pipe.write(struct.pack("<IIIIQQIIII", *fields.values()))
|
|
reply = struct.unpack("<IIQQQQ", exact(pipe, 40))
|
|
message = exact(pipe, struct.unpack("<I", exact(pipe, 4))[0]).decode()
|
|
assert reply[0] == MAGIC and reply[1] == 1 and message
|
|
pipe.write(struct.pack("<I", MAGIC))
|
|
return message
|
|
|
|
|
|
for fields in ({"magic": 0}, {"size": 65537}, {"flags": 0xFFFFFFFF},
|
|
{"sort": 99}, {"reserved": 1}, {"operation": 99}):
|
|
checks.append({"malformed": fields, "error": malformed(**fields)})
|
|
|
|
baseline = run("python*.exe")
|
|
assert baseline.returncode == 0 and baseline.stdout
|
|
with concurrent.futures.ThreadPoolExecutor(max_workers=20) as pool:
|
|
jobs = list(pool.map(lambda _: run("python*.exe"), range(60)))
|
|
assert all(job.returncode == 0 and set(job.stdout.splitlines()) == set(baseline.stdout.splitlines()) for job in jobs)
|
|
checks.append({"concurrent_queries": 60, "workers": 20, "passed": True})
|
|
|
|
large = run("-i", "-n", "20000", "-0", "*.txt")
|
|
assert large.returncode == 0 and large.stdout.count(b"\0") == 20000
|
|
assert all(path for path in large.stdout[:-1].decode("utf-8").split("\0"))
|
|
checks.append({"bulk_rows": 20000, "bytes": len(large.stdout), "passed": True})
|
|
|
|
start = time.monotonic()
|
|
limited = run("--timeout", "100", "--sort", "path", "-n", "10", "*")
|
|
elapsed = time.monotonic() - start
|
|
assert limited.returncode == 2 and elapsed < 3 and (b"timed out" in limited.stderr or b"cancelled" in limited.stderr)
|
|
assert run("python*.exe").returncode == 0
|
|
checks.append({"deadline_ms": elapsed * 1000, "service_recovers": True})
|
|
|
|
permission = run("--reindex")
|
|
assert permission.returncode == 2 and b"elevated" in permission.stderr
|
|
checks.append({"unelevated_rebuild_denied": True})
|
|
|
|
(ROOT / "test-output/protocol.json").write_text(json.dumps(checks, indent=2), encoding="utf-8")
|
|
print("Protocol, 60 concurrent queries, 20,000-row output, deadline and permission checks passed")
|