#!/usr/bin/env python3 """Exercise editable local drafts while creation is slow and its first reply is lost.""" import base64 import http.server import json import os from pathlib import Path import socket import subprocess import threading import time import urllib.parse root = Path(__file__).resolve().parents[2] class Handler(http.server.BaseHTTPRequestHandler): documents = {} updates = [] creations = 0 title = "" renames = 0 metadata = 0 streams = 0 def reply(self, status, data=b"", **headers): self.send_response(status) self.send_header("Content-Length", str(len(data))) for key, value in headers.items(): self.send_header(key, value) self.end_headers() try: self.wfile.write(data) except (BrokenPipeError, ConnectionResetError): pass def do_POST(self): cls = type(self) data = self.rfile.read(int(self.headers.get("Content-Length", "0"))) form = urllib.parse.parse_qs(data.decode()) if self.path == "/documents" or self.path.endswith("/title") else {} if self.path == "/documents": cls.creations += 1 number = cls.creations token = form["creation_token"][0] cls.documents.setdefault(token, str(len(cls.documents) + 1)) time.sleep(1) if number == 1: self.connection.shutdown(socket.SHUT_RDWR) self.connection.close() return self.reply(201, json.dumps(dict(sqid=cls.documents[token], title="Untitled document")).encode()) elif self.path.endswith("/title"): cls.renames += 1 time.sleep(0.3) if cls.renames == 1: self.reply(503) else: cls.title = form["title"][0] self.reply(204) else: cls.updates.append(base64.b64encode(data).decode()) self.reply(204) def do_GET(self): cls = type(self) if self.path == "/stats": self.reply(200, json.dumps(dict(documents=len(cls.documents), updates=cls.updates, title=cls.title, creations=cls.creations, metadata=cls.metadata)).encode()) elif self.path.endswith("/stream"): cls.streams += 1 if cls.streams == 1: self.reply(503) return self.send_response(200); self.send_header("Content-Type", "text/event-stream"); self.end_headers() self.wfile.write(b"data: 0\n\n"); self.wfile.flush(); time.sleep(5) elif "/updates" in self.path: self.reply(200, **{"Docs-Seq": "0"}) else: cls.metadata += 1 title = cls.title or "Untitled document" if cls.metadata == 2: time.sleep(0.9) # Old title arrives after rename acknowledgement. self.reply(200, json.dumps(dict(sqid=self.path.split("/")[-1], title=title, guid="server-guid", can_write=True, can_share=True)).encode()) def log_message(self, *_): pass with http.server.ThreadingHTTPServer(("127.0.0.1", 0), Handler) as server: threading.Thread(target=server.serve_forever, daemon=True).start() result = subprocess.run(["swift", "test", "--package-path", str(root / "native/apple"), "--filter", "DocumentDraftTests"], env=dict(os.environ, DOCS_DRAFT_TEST_ORIGIN=f"http://127.0.0.1:{server.server_port}"), timeout=180) server.shutdown() raise SystemExit(result.returncode)