aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-26 10:46:30 +0100
committereunhhu <[email protected]>2026-09-26 10:46:30 +0100
commit91332801ff2334cd887df3971f944b60bebf729c (patch)
tree03955fd10502e5807b1f2217fdec9d6d37a312ed /tests
parentb14c2a21551b3790e4419340ad862dc2fa904c56 (diff)
downloadaup-91332801ff2334cd887df3971f944b60bebf729c.tar.gz
aup-91332801ff2334cd887df3971f944b60bebf729c.zip
Check that lent answers count against the budget
Two readers that stop reading keep one 1 MiB answer each waiting on their sockets; a third read must get 503 payload_budget until one of them goes.
Diffstat (limited to 'tests')
-rw-r--r--tests/check.py46
1 files changed, 44 insertions, 2 deletions
diff --git a/tests/check.py b/tests/check.py
index 83afac9..c4484c4 100644
--- a/tests/check.py
+++ b/tests/check.py
@@ -17,8 +17,9 @@
9. Server: the HTTP document server running editor.aup answers random
requests exactly as the server running editor.pure, on persistent and
pipelined connections too; a read lends the stored extents and still
- carries its version while the document changes; concurrent edits share
- commits, and every acknowledged edit survives kill -9.
+ carries its version while the document changes, and lent answers count
+ against the payload budget; concurrent edits share commits, and every
+ acknowledged edit survives kill -9.
8. Stored state: the list app and the text editor run on a tree store,
restarting at random points (every other run saving in bursts), and still
match their reference models.
@@ -840,6 +841,46 @@ def server_lent_reads(aup, pure, work):
return len(big)
+def server_lent_budget(aup, pure, work):
+ """Lent extents count against the payload budget while an answer waits
+ on its socket. Two readers pipeline 1 MiB reads without reading: the
+ kernel takes what it can and each reader leaves one answer waiting. A
+ third request finds no room (503 payload_budget) until a reader goes."""
+ import socket
+ import struct
+ import time
+ module = work / 'editor-budget.pmod'
+ compile_module(aup, ROOT / 'examples/editor.aup', module)
+ big = bytes(range(256)) * 4096
+ budget = 2 * len(big) + len(big) // 2
+ host = HttpHost([pure / 'build/pure-serve', '--module', module, '--store', work / 'lent-budget',
+ '--budget', budget])
+ readers = []
+ try:
+ assert host.request('PUT', 'big', struct.pack('<II', 0, 0) + big, 0)[0] == 200
+ for _ in range(2):
+ sock = socket.create_connection(('127.0.0.1', host.port), timeout=30)
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 4096)
+ sock.sendall(b'GET /objects/big HTTP/1.1\r\nHost: x\r\nContent-Length: 0\r\n\r\n' * 32)
+ readers.append(sock)
+ time.sleep(0.3)
+ refused = host.request('GET', 'big')
+ assert refused[0] == 503 and refused[2] == 'payload_budget', refused[:3]
+ readers.pop().close()
+ for _ in range(100):
+ answered = host.request('GET', 'big')
+ if answered[0] == 200:
+ break
+ time.sleep(0.05)
+ assert answered[0] == 200 and answered[3] == big, answered[:3]
+ finally:
+ for sock in readers:
+ sock.close()
+ stats = host.stop()
+ assert stats[0]['active'] == 0 and stats[0]['retained_payload_bytes'] == 0, stats
+ return budget
+
+
def server_bursts(aup, pure, work, clients=8, edits=30, shards=1):
"""Concurrent edits share commits, and every acknowledged edit survives a
kill -9 of the server."""
@@ -1042,6 +1083,7 @@ def main():
threads=threads) for threads in (1, 3))
report['server_pipelined_answers'] = server_pipelining(aup, args.pure.resolve(), work)
report['server_lent_read_bytes'] = server_lent_reads(aup, args.pure.resolve(), work)
+ report['server_lent_budget_bytes'] = server_lent_budget(aup, args.pure.resolve(), work)
report['server_bursts'] = server_bursts(aup, args.pure.resolve(), work)
report['server_bursts_three_threads'] = server_bursts(aup, args.pure.resolve(), work, shards=3)
print(json.dumps(report))