mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
122 lines
4.3 KiB
Python
122 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
# Regenerates the canned gate-analyzer fixtures. Each fixture is a minimal but
|
|
# format-accurate run directory (trace.jsonl + output.log + exit_status) that
|
|
# isolates one gate's pass or fail condition. Run from this directory:
|
|
# python3 generate.py
|
|
import json
|
|
import os
|
|
from datetime import datetime, timedelta, timezone
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
BASE = datetime(2026, 6, 6, 12, 0, 0, tzinfo=timezone(timedelta(hours=5, minutes=30)))
|
|
|
|
|
|
def element(resource_id, text="", element_class="android.widget.EditText"):
|
|
return {
|
|
"resourceId": resource_id,
|
|
"class": element_class,
|
|
"editable": True,
|
|
"bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135},
|
|
"attrs": {"resource-id": resource_id, "class": element_class, "text": text},
|
|
}
|
|
|
|
|
|
def login_screen(email_text="", password_text=""):
|
|
return {
|
|
"elements": [
|
|
element("LoginScreen", element_class="android.view.View"),
|
|
element("LoginEmail", email_text),
|
|
element("LoginPassword", password_text),
|
|
element("LoginSubmit", element_class="android.view.View"),
|
|
]
|
|
}
|
|
|
|
|
|
def input_action(field, text):
|
|
return {
|
|
"kind": "InputText",
|
|
"text": text,
|
|
"selector": f"testTag:LoginScreen > testTag:{field}",
|
|
}
|
|
|
|
|
|
def step(index, gap_ms, hierarchy, next_action=None):
|
|
timestamp = (BASE + timedelta(milliseconds=index * gap_ms)).isoformat()
|
|
record = {"step": index, "timestamp": timestamp, "hierarchy": hierarchy}
|
|
if next_action is not None:
|
|
record["next_action"] = next_action
|
|
return record
|
|
|
|
|
|
def write_run(name, steps, exit_status="0", output_lines=None):
|
|
directory = os.path.join(HERE, name)
|
|
os.makedirs(directory, exist_ok=True)
|
|
with open(os.path.join(directory, "trace.jsonl"), "w") as handle:
|
|
for record in steps:
|
|
handle.write(json.dumps(record) + "\n")
|
|
with open(os.path.join(directory, "exit_status"), "w") as handle:
|
|
handle.write(exit_status)
|
|
lines = output_lines if output_lines is not None else ["run complete\n"]
|
|
with open(os.path.join(directory, "output.log"), "w") as handle:
|
|
handle.writelines(lines)
|
|
|
|
|
|
# A clean run: empty login fields first, single (not doubled) typed values in
|
|
# the following snapshots, sub-second step gaps.
|
|
def healthy_steps(gap_ms=600):
|
|
return [
|
|
step(1, gap_ms, login_screen("", ""), input_action("LoginEmail", "[email protected]")),
|
|
step(2, gap_ms, login_screen("[email protected]", ""), input_action("LoginPassword", "ledger123")),
|
|
step(3, gap_ms, login_screen("[email protected]", "ledger123")),
|
|
step(4, gap_ms, login_screen("[email protected]", "ledger123")),
|
|
]
|
|
|
|
|
|
BENIGN_NOISE = [
|
|
"companion pid=4242 listening on 127.0.0.1:51000\n",
|
|
"objc[4242]: Class FBSDKError is implemented in both /a (0x1) and /b (0x2). "
|
|
"One of the two will be used. Which one is undefined.\n",
|
|
"WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n",
|
|
# An incidental ERROR substring inside a longer word: the G2 scan is
|
|
# word-bounded, so this must not trip the gate.
|
|
"archived previous runs under runs/ERRORS_archive\n",
|
|
]
|
|
|
|
write_run("pass", healthy_steps())
|
|
|
|
write_run("g1-nonzero-exit", healthy_steps(), exit_status="1")
|
|
|
|
write_run("g2-benign-only", healthy_steps(), output_lines=BENIGN_NOISE + ["run complete\n"])
|
|
|
|
write_run(
|
|
"g2-real-error",
|
|
healthy_steps(),
|
|
output_lines=BENIGN_NOISE
|
|
+ ["error: hierarchy fetch failed: companion connection lost\n"],
|
|
)
|
|
|
|
# G3: first snapshot already carries text in the login fields (clear-state
|
|
# failed to wipe the previous session).
|
|
write_run(
|
|
"g3-dirty-field",
|
|
[
|
|
step(1, 600, login_screen("[email protected]", "leftover"), input_action("LoginEmail", "[email protected]")),
|
|
step(2, 600, login_screen("[email protected]", "leftover")),
|
|
],
|
|
)
|
|
|
|
# G4: after typing into LoginEmail the next snapshot shows the value appended to
|
|
# itself (append-vs-replace / double-paste regression).
|
|
write_run(
|
|
"g4-doubled-text",
|
|
[
|
|
step(1, 600, login_screen("", ""), input_action("LoginEmail", "[email protected]")),
|
|
step(2, 600, login_screen("[email protected]@folio.app", "")),
|
|
],
|
|
)
|
|
|
|
# G5: step gaps far exceed the 2.5s ceiling, driving p95 over the limit.
|
|
write_run("g5-slow-p95", healthy_steps(gap_ms=4000))
|
|
|
|
print("fixtures written")
|