From f4e54795580843d751d4a61905b9ace12b51318d Mon Sep 17 00:00:00 2001 From: PJ Date: Sat, 6 Jun 2026 23:45:13 +0530 Subject: [PATCH] test(folio): add gate-analyzer fixtures for G1-G5 --- .../g1-nonzero-exit/exit_status | 1 + .../gates-testdata/g1-nonzero-exit/output.log | 1 + .../g1-nonzero-exit/trace.jsonl | 4 + .../gates-testdata/g2-benign-only/exit_status | 1 + .../gates-testdata/g2-benign-only/output.log | 4 + .../gates-testdata/g2-benign-only/trace.jsonl | 4 + .../gates-testdata/g2-real-error/exit_status | 1 + .../gates-testdata/g2-real-error/output.log | 4 + .../gates-testdata/g2-real-error/trace.jsonl | 4 + .../gates-testdata/g3-dirty-field/exit_status | 1 + .../gates-testdata/g3-dirty-field/output.log | 1 + .../gates-testdata/g3-dirty-field/trace.jsonl | 2 + .../g4-doubled-text/exit_status | 1 + .../gates-testdata/g4-doubled-text/output.log | 1 + .../g4-doubled-text/trace.jsonl | 2 + .../gates-testdata/g5-slow-p95/exit_status | 1 + .../gates-testdata/g5-slow-p95/output.log | 1 + .../gates-testdata/g5-slow-p95/trace.jsonl | 4 + examples/folio/gates-testdata/generate.py | 118 ++++++++++++++++++ .../folio/gates-testdata/pass/exit_status | 1 + examples/folio/gates-testdata/pass/output.log | 1 + .../folio/gates-testdata/pass/trace.jsonl | 4 + 22 files changed, 162 insertions(+) create mode 100644 examples/folio/gates-testdata/g1-nonzero-exit/exit_status create mode 100644 examples/folio/gates-testdata/g1-nonzero-exit/output.log create mode 100644 examples/folio/gates-testdata/g1-nonzero-exit/trace.jsonl create mode 100644 examples/folio/gates-testdata/g2-benign-only/exit_status create mode 100644 examples/folio/gates-testdata/g2-benign-only/output.log create mode 100644 examples/folio/gates-testdata/g2-benign-only/trace.jsonl create mode 100644 examples/folio/gates-testdata/g2-real-error/exit_status create mode 100644 examples/folio/gates-testdata/g2-real-error/output.log create mode 100644 examples/folio/gates-testdata/g2-real-error/trace.jsonl create mode 100644 examples/folio/gates-testdata/g3-dirty-field/exit_status create mode 100644 examples/folio/gates-testdata/g3-dirty-field/output.log create mode 100644 examples/folio/gates-testdata/g3-dirty-field/trace.jsonl create mode 100644 examples/folio/gates-testdata/g4-doubled-text/exit_status create mode 100644 examples/folio/gates-testdata/g4-doubled-text/output.log create mode 100644 examples/folio/gates-testdata/g4-doubled-text/trace.jsonl create mode 100644 examples/folio/gates-testdata/g5-slow-p95/exit_status create mode 100644 examples/folio/gates-testdata/g5-slow-p95/output.log create mode 100644 examples/folio/gates-testdata/g5-slow-p95/trace.jsonl create mode 100644 examples/folio/gates-testdata/generate.py create mode 100644 examples/folio/gates-testdata/pass/exit_status create mode 100644 examples/folio/gates-testdata/pass/output.log create mode 100644 examples/folio/gates-testdata/pass/trace.jsonl diff --git a/examples/folio/gates-testdata/g1-nonzero-exit/exit_status b/examples/folio/gates-testdata/g1-nonzero-exit/exit_status new file mode 100644 index 0000000..56a6051 --- /dev/null +++ b/examples/folio/gates-testdata/g1-nonzero-exit/exit_status @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/examples/folio/gates-testdata/g1-nonzero-exit/output.log b/examples/folio/gates-testdata/g1-nonzero-exit/output.log new file mode 100644 index 0000000..ca891a9 --- /dev/null +++ b/examples/folio/gates-testdata/g1-nonzero-exit/output.log @@ -0,0 +1 @@ +run complete diff --git a/examples/folio/gates-testdata/g1-nonzero-exit/trace.jsonl b/examples/folio/gates-testdata/g1-nonzero-exit/trace.jsonl new file mode 100644 index 0000000..f40d3b2 --- /dev/null +++ b/examples/folio/gates-testdata/g1-nonzero-exit/trace.jsonl @@ -0,0 +1,4 @@ +{"step": 1, "timestamp": "2026-06-06T12:00:00.600000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}, "next_action": {"kind": "InputText", "text": "demo@folio.app", "selector": "testTag:LoginScreen > testTag:LoginEmail"}} +{"step": 2, "timestamp": "2026-06-06T12:00:01.200000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}, "next_action": {"kind": "InputText", "text": "ledger123", "selector": "testTag:LoginScreen > testTag:LoginPassword"}} +{"step": 3, "timestamp": "2026-06-06T12:00:01.800000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": "ledger123"}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}} +{"step": 4, "timestamp": "2026-06-06T12:00:02.400000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": "ledger123"}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}} diff --git a/examples/folio/gates-testdata/g2-benign-only/exit_status b/examples/folio/gates-testdata/g2-benign-only/exit_status new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/examples/folio/gates-testdata/g2-benign-only/exit_status @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/examples/folio/gates-testdata/g2-benign-only/output.log b/examples/folio/gates-testdata/g2-benign-only/output.log new file mode 100644 index 0000000..e628145 --- /dev/null +++ b/examples/folio/gates-testdata/g2-benign-only/output.log @@ -0,0 +1,4 @@ +companion pid=4242 listening on 127.0.0.1:51000 +objc[4242]: Class FBSDKError is implemented in both /a (0x1) and /b (0x2). One of the two will be used. Which one is undefined. +WARNING: All log messages before absl::InitializeLog() is called are written to STDERR +run complete diff --git a/examples/folio/gates-testdata/g2-benign-only/trace.jsonl b/examples/folio/gates-testdata/g2-benign-only/trace.jsonl new file mode 100644 index 0000000..f40d3b2 --- /dev/null +++ b/examples/folio/gates-testdata/g2-benign-only/trace.jsonl @@ -0,0 +1,4 @@ +{"step": 1, "timestamp": "2026-06-06T12:00:00.600000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}, "next_action": {"kind": "InputText", "text": "demo@folio.app", "selector": "testTag:LoginScreen > testTag:LoginEmail"}} +{"step": 2, "timestamp": "2026-06-06T12:00:01.200000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}, "next_action": {"kind": "InputText", "text": "ledger123", "selector": "testTag:LoginScreen > testTag:LoginPassword"}} +{"step": 3, "timestamp": "2026-06-06T12:00:01.800000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": "ledger123"}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}} +{"step": 4, "timestamp": "2026-06-06T12:00:02.400000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": "ledger123"}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}} diff --git a/examples/folio/gates-testdata/g2-real-error/exit_status b/examples/folio/gates-testdata/g2-real-error/exit_status new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/examples/folio/gates-testdata/g2-real-error/exit_status @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/examples/folio/gates-testdata/g2-real-error/output.log b/examples/folio/gates-testdata/g2-real-error/output.log new file mode 100644 index 0000000..b8c34fa --- /dev/null +++ b/examples/folio/gates-testdata/g2-real-error/output.log @@ -0,0 +1,4 @@ +companion pid=4242 listening on 127.0.0.1:51000 +objc[4242]: Class FBSDKError is implemented in both /a (0x1) and /b (0x2). One of the two will be used. Which one is undefined. +WARNING: All log messages before absl::InitializeLog() is called are written to STDERR +error: hierarchy fetch failed: companion connection lost diff --git a/examples/folio/gates-testdata/g2-real-error/trace.jsonl b/examples/folio/gates-testdata/g2-real-error/trace.jsonl new file mode 100644 index 0000000..f40d3b2 --- /dev/null +++ b/examples/folio/gates-testdata/g2-real-error/trace.jsonl @@ -0,0 +1,4 @@ +{"step": 1, "timestamp": "2026-06-06T12:00:00.600000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}, "next_action": {"kind": "InputText", "text": "demo@folio.app", "selector": "testTag:LoginScreen > testTag:LoginEmail"}} +{"step": 2, "timestamp": "2026-06-06T12:00:01.200000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}, "next_action": {"kind": "InputText", "text": "ledger123", "selector": "testTag:LoginScreen > testTag:LoginPassword"}} +{"step": 3, "timestamp": "2026-06-06T12:00:01.800000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": "ledger123"}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}} +{"step": 4, "timestamp": "2026-06-06T12:00:02.400000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": "ledger123"}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}} diff --git a/examples/folio/gates-testdata/g3-dirty-field/exit_status b/examples/folio/gates-testdata/g3-dirty-field/exit_status new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/examples/folio/gates-testdata/g3-dirty-field/exit_status @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/examples/folio/gates-testdata/g3-dirty-field/output.log b/examples/folio/gates-testdata/g3-dirty-field/output.log new file mode 100644 index 0000000..ca891a9 --- /dev/null +++ b/examples/folio/gates-testdata/g3-dirty-field/output.log @@ -0,0 +1 @@ +run complete diff --git a/examples/folio/gates-testdata/g3-dirty-field/trace.jsonl b/examples/folio/gates-testdata/g3-dirty-field/trace.jsonl new file mode 100644 index 0000000..5319d91 --- /dev/null +++ b/examples/folio/gates-testdata/g3-dirty-field/trace.jsonl @@ -0,0 +1,2 @@ +{"step": 1, "timestamp": "2026-06-06T12:00:00.600000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "stale@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": "leftover"}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}, "next_action": {"kind": "InputText", "text": "demo@folio.app", "selector": "testTag:LoginScreen > testTag:LoginEmail"}} +{"step": 2, "timestamp": "2026-06-06T12:00:01.200000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": "leftover"}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}} diff --git a/examples/folio/gates-testdata/g4-doubled-text/exit_status b/examples/folio/gates-testdata/g4-doubled-text/exit_status new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/examples/folio/gates-testdata/g4-doubled-text/exit_status @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/examples/folio/gates-testdata/g4-doubled-text/output.log b/examples/folio/gates-testdata/g4-doubled-text/output.log new file mode 100644 index 0000000..ca891a9 --- /dev/null +++ b/examples/folio/gates-testdata/g4-doubled-text/output.log @@ -0,0 +1 @@ +run complete diff --git a/examples/folio/gates-testdata/g4-doubled-text/trace.jsonl b/examples/folio/gates-testdata/g4-doubled-text/trace.jsonl new file mode 100644 index 0000000..7108273 --- /dev/null +++ b/examples/folio/gates-testdata/g4-doubled-text/trace.jsonl @@ -0,0 +1,2 @@ +{"step": 1, "timestamp": "2026-06-06T12:00:00.600000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}, "next_action": {"kind": "InputText", "text": "demo@folio.app", "selector": "testTag:LoginScreen > testTag:LoginEmail"}} +{"step": 2, "timestamp": "2026-06-06T12:00:01.200000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.appdemo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}} diff --git a/examples/folio/gates-testdata/g5-slow-p95/exit_status b/examples/folio/gates-testdata/g5-slow-p95/exit_status new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/examples/folio/gates-testdata/g5-slow-p95/exit_status @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/examples/folio/gates-testdata/g5-slow-p95/output.log b/examples/folio/gates-testdata/g5-slow-p95/output.log new file mode 100644 index 0000000..ca891a9 --- /dev/null +++ b/examples/folio/gates-testdata/g5-slow-p95/output.log @@ -0,0 +1 @@ +run complete diff --git a/examples/folio/gates-testdata/g5-slow-p95/trace.jsonl b/examples/folio/gates-testdata/g5-slow-p95/trace.jsonl new file mode 100644 index 0000000..ae4d996 --- /dev/null +++ b/examples/folio/gates-testdata/g5-slow-p95/trace.jsonl @@ -0,0 +1,4 @@ +{"step": 1, "timestamp": "2026-06-06T12:00:04+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}, "next_action": {"kind": "InputText", "text": "demo@folio.app", "selector": "testTag:LoginScreen > testTag:LoginEmail"}} +{"step": 2, "timestamp": "2026-06-06T12:00:08+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}, "next_action": {"kind": "InputText", "text": "ledger123", "selector": "testTag:LoginScreen > testTag:LoginPassword"}} +{"step": 3, "timestamp": "2026-06-06T12:00:12+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": "ledger123"}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}} +{"step": 4, "timestamp": "2026-06-06T12:00:16+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": "ledger123"}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}} diff --git a/examples/folio/gates-testdata/generate.py b/examples/folio/gates-testdata/generate.py new file mode 100644 index 0000000..826fe01 --- /dev/null +++ b/examples/folio/gates-testdata/generate.py @@ -0,0 +1,118 @@ +#!/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", "demo@folio.app")), + step(2, gap_ms, login_screen("demo@folio.app", ""), input_action("LoginPassword", "ledger123")), + step(3, gap_ms, login_screen("demo@folio.app", "ledger123")), + step(4, gap_ms, login_screen("demo@folio.app", "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", +] + +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("stale@folio.app", "leftover"), input_action("LoginEmail", "demo@folio.app")), + step(2, 600, login_screen("demo@folio.app", "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", "demo@folio.app")), + step(2, 600, login_screen("demo@folio.appdemo@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") diff --git a/examples/folio/gates-testdata/pass/exit_status b/examples/folio/gates-testdata/pass/exit_status new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/examples/folio/gates-testdata/pass/exit_status @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/examples/folio/gates-testdata/pass/output.log b/examples/folio/gates-testdata/pass/output.log new file mode 100644 index 0000000..ca891a9 --- /dev/null +++ b/examples/folio/gates-testdata/pass/output.log @@ -0,0 +1 @@ +run complete diff --git a/examples/folio/gates-testdata/pass/trace.jsonl b/examples/folio/gates-testdata/pass/trace.jsonl new file mode 100644 index 0000000..f40d3b2 --- /dev/null +++ b/examples/folio/gates-testdata/pass/trace.jsonl @@ -0,0 +1,4 @@ +{"step": 1, "timestamp": "2026-06-06T12:00:00.600000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}, "next_action": {"kind": "InputText", "text": "demo@folio.app", "selector": "testTag:LoginScreen > testTag:LoginEmail"}} +{"step": 2, "timestamp": "2026-06-06T12:00:01.200000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}, "next_action": {"kind": "InputText", "text": "ledger123", "selector": "testTag:LoginScreen > testTag:LoginPassword"}} +{"step": 3, "timestamp": "2026-06-06T12:00:01.800000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": "ledger123"}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}} +{"step": 4, "timestamp": "2026-06-06T12:00:02.400000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": "ledger123"}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}}