diff --git a/tests/cases/reattach.py b/tests/cases/reattach.py index e054675..c340aa1 100644 --- a/tests/cases/reattach.py +++ b/tests/cases/reattach.py @@ -50,7 +50,7 @@ def run(t): results = [{} for _ in range(n)] def one(r): - got = t.http(f"http://127.0.0.1:{origin}/data?size=2000000&block=65536&delay=60", + got = t.http(f"http://127.0.0.1:{origin}/data?size=400000&block=8192&delay=40", proxy=f"127.0.0.1:{proxy}") r["length"] = got.length @@ -66,8 +66,8 @@ def run(t): threads, results = downloads(2) reload(config(f"proxy -p{proxy}", maxconn=2)) for th in threads: - th.join(20) - whole = sum(1 for r in results if r.get("length") == 2000000) + th.join(60) + whole = sum(1 for r in results if r.get("length") == 400000) t.eq(1, whole, "with one slot free in the new service one download goes on") t.contains(server.output(), " 00027 ", "the other is cut for want of a slot (27)") @@ -77,11 +77,11 @@ def run(t): threads, results = downloads(1) reload(config(f"socks -p{proxy}")) for th in threads: - th.join(20) + th.join(60) t.ok("a proxy download is cut when a socks service takes the port") \ - if results[0].get("length", 0) < 2000000 else \ + if results[0].get("length", 0) < 400000 else \ t.fail("a proxy download is cut when a socks service takes the port", - "less than 2000000 bytes", results[0].get("length")) + "less than 400000 bytes", results[0].get("length")) t.contains(server.output(), " 00026 ", "as its service is another one now (26)") # --- services of one configuration on one address share its socket, so @@ -129,10 +129,10 @@ def run(t): client once it has sent C.""" try: c, _ = peer.accept() - c.settimeout(20) + c.settimeout(30) c.sendall(b"C") auth = base64.b64encode(b"alice:one").decode() - c.sendall((f"GET http://127.0.0.1:{origin}/data?size=2000000&block=65536&delay=60 HTTP/1.1\r\n" + c.sendall((f"GET http://127.0.0.1:{origin}/data?size=400000&block=8192&delay=40 HTTP/1.1\r\n" f"Host: 127.0.0.1:{origin}\r\nProxy-Authorization: Basic {auth}\r\n" "Connection: close\r\n\r\n").encode()) got = b"" @@ -154,8 +154,8 @@ def run(t): th.start() time.sleep(0.5) reload(cbconfig(users)) - th.join(25) - whole = result.get("body") == 2000000 + th.join(60) + whole = result.get("body") == 400000 name = f"a download through a connect-back service {want} when alice is " + \ ("kept" if keep else "removed") t.ok(name) if whole == keep else t.fail(name, "whole" if keep else "cut", result) diff --git a/tests/cases/reload.py b/tests/cases/reload.py index 05ded98..6620fc3 100644 --- a/tests/cases/reload.py +++ b/tests/cases/reload.py @@ -69,8 +69,9 @@ def run(t): # --- a good file: the new configuration takes over, and the connections # of the old services go by its rules from then on --------------------- def download(result): - # about two seconds: 2 MB in 64 KB blocks, 60 ms apart - r = t.http(f"http://127.0.0.1:{origin}/data?size=2000000&block=65536&delay=60", + # about two seconds: 400 KB in 8 KB blocks (httpsrv's largest), + # 40 ms apart + r = t.http(f"http://127.0.0.1:{origin}/data?size=400000&block=8192&delay=40", proxy=proxy, proxy_auth=("alice", "one")) result["status"], result["length"] = r.status, r.length @@ -86,8 +87,8 @@ def run(t): # alice stays: her download goes on under the new service th, kept = during_reload("alice:CL:one bob:CL:two", first) t.eq(200, as_user("bob", "two"), "the new configuration lets bob in") - th.join(20) - t.eq(2000000, kept.get("length"), + th.join(60) + t.eq(400000, kept.get("length"), "a download of a user the new configuration keeps finishes whole") # a connection kept alive: each request is authorized by the rules in @@ -105,11 +106,11 @@ def run(t): # alice is removed: her download is cut, being re-authenticated th, cut = during_reload("bob:CL:two", first) - th.join(20) + th.join(60) t.ok("a download of a user the new configuration removes is cut") \ - if cut.get("length", 0) < 2000000 else \ + if cut.get("length", 0) < 400000 else \ t.fail("a download of a user the new configuration removes is cut", - "less than 2000000 bytes", cut.get("length")) + "less than 400000 bytes", cut.get("length")) t.ne(200, as_user("alice", "one"), "and alice cannot come back") # the service moves to another port: the old one closes diff --git a/tests/cases/takeover.py b/tests/cases/takeover.py index 2da8ec1..fe4e40b 100644 --- a/tests/cases/takeover.py +++ b/tests/cases/takeover.py @@ -115,7 +115,25 @@ def run(t): uconf = conf + f"\n udppm {udp} 127.0.0.1 {echo_port}\n" t.write_config("takeover", uconf) t.http(f"http://127.0.0.1:{adm}/R") - time.sleep(1.5) + # a UDP service has no listening socket to wait for, so ask until it + # answers rather than racing it + def udp_answers(deadline): + probe = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + probe.settimeout(0.3) + try: + while time.time() < deadline: + try: + probe.sendto(b"ping", ("127.0.0.1", udp)) + probe.recvfrom(2048) + return True + except OSError: + pass + return False + finally: + probe.close() + + t.ok("the UDP service added by a reload answers") if udp_answers(time.time() + 10) else \ + t.fail("the UDP service added by a reload answers", "a reply", "none in 10 seconds") client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) client.settimeout(1) @@ -141,8 +159,9 @@ def run(t): time.sleep(0.02) client.close() echo.close() - t.ok(f"a UDP session sends through three reloads ({sent} datagrams)") if sent > 100 else \ - t.fail("a UDP session sends through three reloads", "more than 100", sent) + # how many depends on the runner's speed; that none is lost is the point + t.ok(f"a UDP session sends through three reloads ({sent} datagrams)") if sent > 20 else \ + t.fail("a UDP session sends through three reloads", "more than 20", sent) t.eq(0, lost, "and every datagram comes back, the socket handed over") t.contains(server.output(), f"{udp} 0.0.0.0:0 0 0 0 Accepting connections, taken over", "the UDP service takes the socket over") diff --git a/tests/run.py b/tests/run.py index 5b6cf09..9501072 100644 --- a/tests/run.py +++ b/tests/run.py @@ -13,6 +13,7 @@ positive and negative scenarios expected from them. import argparse import importlib.util import os +import re import shutil import sys import tempfile @@ -119,6 +120,14 @@ def main(): if not lines: continue print(f" --- {name} said ---") + # why connections ended: the lines with a result code, + # wherever they are, then the last few + ended = [line for line in lines + if re.match(r"\d+\.\d+ \S+ (?!00000 )\d{5} ", line)] + for line in ended[-20:]: + print(f" {line}") + if ended: + print(" ...") for line in lines[-12:]: print(f" {line}")