<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ida-tui.git/tests/test_worker_client.py, branch main</title>
<subtitle>tui for headless ida</subtitle>
<id>https://git.sl0p.foo/ida-tui.git/atom/tests/test_worker_client.py?h=main</id>
<link rel='self' href='https://git.sl0p.foo/ida-tui.git/atom/tests/test_worker_client.py?h=main'/>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/'/>
<updated>2026-08-07T10:40:14Z</updated>
<entry>
<title>Rebase MISTER EXO's ida-codemode port onto the current tree</title>
<updated>2026-08-07T10:40:14Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-08-07T10:39:54Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=c9208de05d8583b677117fe43c9d3567e89eb2ce'/>
<id>urn:sha1:c9208de05d8583b677117fe43c9d3567e89eb2ce</id>
<content type='text'>
Mechanical part of the port: the 27-file patch was cut against a base ~148
commits behind us, so it did not apply. Resolved 11 conflicts (all of them
diff drift, not semantic clashes) and the three file deletions:

- app.py: the patch re-inserted _do_rename/_do_name_addr/_seek_split etc. as
  "theirs" because our tree moved them to edit_ctl.py/trace_ctl.py. Kept ours
  and applied the real intent (WorkerClient-&gt;CodeModeClient, .call-&gt;.invoke,
  _open_worker_client-&gt;_open_database_client) at their current homes.
- domain.py: kept Head as a NamedTuple -- the patch reverted it to a frozen
  dataclass, which the perf work measured at 2.9us vs 1.9us per row on a
  quarter-million-row walk. Dropped _fetch_output (no download_url under Code
  Mode) and its now-dead urllib/json imports.
- pane.py: the patch's deletion swallowed our zellij support along with the
  worker-reaping block it meant to remove. Kept zellij, removed the reaping.
- test_scenarios.py: the idb_save-&gt;save_database teardown hunk belongs to
  tests/_fixtures.py in our tree; applied it there and kept our pc_num_format
  scenario that the drift landed on.

Three defects in the patch itself, fixed here:

- It made "import idatui" hard-require ida_codemode, so every offline suite
  died at import -- including the pure ones (graph/index/trace) that are the
  house rule for "tests/run.py --fast". The import is now deferred and gated
  on the binding, which is also what lets the port's own contract tests
  inject a fake DatabaseHandle.
- project.stage() inlined an ida_codemode.registry import and treated "library
  not installed" as "someone owns this database", which broke IDA-free project
  staging. Ownership lookup moved to codemode_client.database_owner().
- tests/test_codemode_client.py had no NEEDS_IDA marker, which tests/run.py
  rejects outright.

Offline suite: 301 passed, 0 failed. Against master's 344 the whole delta is
accounted for: -40 worker_client (module deleted), -18 launch sweep checks
(behaviour deliberately removed) +3 guarding that it stays removed, +2 pool
(GUI-save semantics), +13 new codemode_client contract tests.

NOT yet done, and the port is not functional without it: the adapter is
missing five operations our tree grew since the patch's base (flowchart,
op_format, pc_nums, pc_num_format, survey_binary) and its "heads" predates
back-walking and digest/expect.
</content>
</entry>
<entry>
<title>worker_client: tests, and stop resurrecting a closed worker</title>
<updated>2026-08-06T22:14:28Z</updated>
<author>
<name>blasty</name>
<email>blasty@local</email>
</author>
<published>2026-08-06T22:14:28Z</published>
<link rel='alternate' type='text/html' href='https://git.sl0p.foo/ida-tui.git/commit/?id=89db0e023d5bafbd1868f22b9b31e5006066cdad'/>
<id>urn:sha1:89db0e023d5bafbd1868f22b9b31e5006066cdad</id>
<content type='text'>
The layer between the app and idalib had no tests, which is awkward: it is
where failures are silent. A worker that dies during startup, a socket that
drops mid-call, two UI threads sharing one socket -- none of those look like
bugs from outside, they look like the TUI hanging or showing stale data.

None of it needs IDA. WorkerClient spawns whatever _WORKER_PY points at, so the
suite points it at a fake speaking the same length-prefixed pickle and tells it
to misbehave on demand: die at startup, never bind, drop the connection, fail a
tool, take its time. 40 checks in the --fast tier.

Two things the tests found:

call() reconnects when _sock is None, which is what makes a dropped socket
recoverable -- but it made an explicitly CLOSED client resurrect too, spawning a
whole new idalib worker to serve one stray call (verified: pid 1066961 -&gt;
1066962). close() runs on teardown and on binary-switch while @work threads are
still in flight, so quitting during a decompile could leave a fresh process
re-opening the .i64 we had just released, which is the wedging hazard. A closed
client now refuses; connect() still revives it, which is all _reconnect needs
(it builds a new client anyway).

connect() polled on a flat 0.2s sleep, so every caller paid a fifth of a second
even when the worker was ready in milliseconds -- a seeded .i64, a small binary.
Backs off from 5ms instead.

786 checks, 144.6s; --fast is 297 in 3.3s.
</content>
</entry>
</feed>
