test: model worker transport outage deterministically
This commit is contained in:
parent
0fc152f623
commit
cf76bc3636
|
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||||
|
from threading import Event
|
||||||
from urllib.parse import parse_qs, urlsplit
|
from urllib.parse import parse_qs, urlsplit
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -51,6 +52,7 @@ class FakeGiteaServer(ThreadingHTTPServer):
|
||||||
super().__init__(address, FakeGiteaHandler)
|
super().__init__(address, FakeGiteaHandler)
|
||||||
self.created_issues: list[dict] = []
|
self.created_issues: list[dict] = []
|
||||||
self.issue_creation_enabled = False
|
self.issue_creation_enabled = False
|
||||||
|
self.issue_creation_ready = Event()
|
||||||
self.assigned_issue_numbers = [issue["number"] for issue in AVAILABLE_ISSUES]
|
self.assigned_issue_numbers = [issue["number"] for issue in AVAILABLE_ISSUES]
|
||||||
self.comments: list[tuple[int, str]] = []
|
self.comments: list[tuple[int, str]] = []
|
||||||
self.requests: list[tuple[str, str]] = []
|
self.requests: list[tuple[str, str]] = []
|
||||||
|
|
@ -147,6 +149,8 @@ class FakeGiteaHandler(BaseHTTPRequestHandler):
|
||||||
if path != "/api/v1/repos/acme/mobile/issues":
|
if path != "/api/v1/repos/acme/mobile/issues":
|
||||||
self._json(404, {"message": "not found"})
|
self._json(404, {"message": "not found"})
|
||||||
return
|
return
|
||||||
|
if not self.server.issue_creation_enabled:
|
||||||
|
self.server.issue_creation_ready.wait(timeout=45)
|
||||||
if not self.server.issue_creation_enabled:
|
if not self.server.issue_creation_enabled:
|
||||||
self._json(503, {"message": "release journey is still offline"})
|
self._json(503, {"message": "release journey is still offline"})
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,10 @@ def test_release_artifact_files_one_mobile_issue_exactly_once_after_offline_relo
|
||||||
page.locator("#create-issue-repository").select_option("acme/mobile")
|
page.locator("#create-issue-repository").select_option("acme/mobile")
|
||||||
expect(page.locator("#submit-new-issue")).to_be_enabled()
|
expect(page.locator("#submit-new-issue")).to_be_enabled()
|
||||||
|
|
||||||
|
# Page offline emulation can leave service-worker requests connected.
|
||||||
|
# Abort the mutation at the browser boundary too, matching a real
|
||||||
|
# transport outage without poisoning server-side idempotency state.
|
||||||
|
context.route("**/api/v1/repos/acme/mobile/issues", lambda route: route.abort())
|
||||||
context.set_offline(True)
|
context.set_offline(True)
|
||||||
page.locator("#submit-new-issue").click()
|
page.locator("#submit-new-issue").click()
|
||||||
expect(page.locator("#issue-filing-review")).to_be_visible()
|
expect(page.locator("#issue-filing-review")).to_be_visible()
|
||||||
|
|
@ -267,6 +271,8 @@ def test_release_artifact_files_one_mobile_issue_exactly_once_after_offline_relo
|
||||||
browser_errors.clear() # Chromium reports expected network errors while the context is offline.
|
browser_errors.clear() # Chromium reports expected network errors while the context is offline.
|
||||||
failed_responses.clear()
|
failed_responses.clear()
|
||||||
fake.issue_creation_enabled = True
|
fake.issue_creation_enabled = True
|
||||||
|
fake.issue_creation_ready.set()
|
||||||
|
context.unroute("**/api/v1/repos/acme/mobile/issues")
|
||||||
context.set_offline(False)
|
context.set_offline(False)
|
||||||
page.evaluate("window.dispatchEvent(new Event('online'))")
|
page.evaluate("window.dispatchEvent(new Event('online'))")
|
||||||
# Containerized Actions runners can take longer than a local browser to wake the
|
# Containerized Actions runners can take longer than a local browser to wake the
|
||||||
|
|
@ -275,12 +281,15 @@ def test_release_artifact_files_one_mobile_issue_exactly_once_after_offline_relo
|
||||||
if fake.created_issues:
|
if fake.created_issues:
|
||||||
break
|
break
|
||||||
page.wait_for_timeout(250)
|
page.wait_for_timeout(250)
|
||||||
|
local_debug = page.evaluate("localStorage.getItem('stackchain.issue-outbox.v1')")
|
||||||
|
durable_debug = indexed_issue_records(page)
|
||||||
assert fake.created_issues == [
|
assert fake.created_issues == [
|
||||||
{"title": TITLE, "body": BODY, "assignee": "timmy"}
|
{"title": TITLE, "body": BODY, "assignee": "timmy"}
|
||||||
], (
|
], (
|
||||||
f"url={page.url} ready={page.evaluate('document.readyState')} "
|
f"url={page.url} ready={page.evaluate('document.readyState')} "
|
||||||
f"status={page.locator('#my-work-action-status').inner_text()!r} "
|
f"status={page.locator('#my-work-action-status').inner_text()!r} "
|
||||||
f"errors={browser_errors[-5:]!r} responses={failed_responses[-10:]!r} "
|
f"errors={browser_errors[-5:]!r} responses={failed_responses[-10:]!r} "
|
||||||
|
f"local={local_debug!r} durable={durable_debug!r} "
|
||||||
f"requests={fake.requests[-20:]!r}"
|
f"requests={fake.requests[-20:]!r}"
|
||||||
)
|
)
|
||||||
# Deferred workspace startup can report its already-issued offline request
|
# Deferred workspace startup can report its already-issued offline request
|
||||||
|
|
@ -310,6 +319,7 @@ def test_release_artifact_files_one_mobile_issue_exactly_once_after_offline_relo
|
||||||
assert page.evaluate("document.documentElement.scrollWidth <= window.innerWidth")
|
assert page.evaluate("document.documentElement.scrollWidth <= window.innerWidth")
|
||||||
browser.close()
|
browser.close()
|
||||||
finally:
|
finally:
|
||||||
|
fake.issue_creation_ready.set()
|
||||||
fake.shutdown()
|
fake.shutdown()
|
||||||
fake.server_close()
|
fake.server_close()
|
||||||
fake_thread.join(timeout=5)
|
fake_thread.join(timeout=5)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user