Skip to content

B2: fix the remaining test_main failures - #1182

Merged
trissim merged 8 commits into
mainfrom
fix/B2-test-main-failures
Oct 10, 2026
Merged

trissim merged 8 commits into
mainfrom
fix/B2-test-main-failures

Conversation

@trissim

@trissim trissim commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes the tests/integration/test_main.py failures left after B1 (#1181). Depends on OpenHCSDev/PolyStore#34; the submodule points at that branch.

Causes and fixes

0. Test isolation (cross-talk). test_main hard-coded its ports: 7777 for the execution server, 5555/5556/5557/5559 for viewers, and Fiji's default 5565. On Linux the transport is IPC, so these ports name sockets in ~/.openhcs/ipc, which every checkout shares. Concurrent runs talked to each other's servers and viewers. During this work a viewer from another worktree rejected this checkout's metadata (Undeclared viewer metadata fields: ['source_channel_axis']).

  • A new free_port_pair fixture in tests/integration/conftest.py allocates pairs through DataControlPortPairAuthority, the transport owner that binds them. It starts the search from an OS-assigned port, not the default port every run would pick first. At teardown it shuts down whatever still listens on those pairs.
  • A new autouse reap_spawned_processes fixture marks each test's environment. Children inherit the marker, so at teardown it can kill the process group of every marked process still alive, pass or fail. This includes setsid-detached viewer and execution servers, which ViewerStateManager never stopped. The coordinator reported 38 leaked Fiji servers from an earlier run; after this fixture, ps -eo ppid,args | awk '$1==1 && /os.setsid/' is empty after every run.
  • All parametrizations of one microscope used to share one tests_data plate directory. A zarr run converts its input plate in place (adding a second main subdirectory) and leaves outputs behind, so the next parametrization failed with Multiple OpenHCS metadata subdirectories are marked main. Each test now gets a fresh plate under its own tmp_path.
  • Deleted the disabled _test_main_with_code_serialization and the ignored sequential_config parameter of create_test_pipeline.

1. zarr-OpenHCS: Zarr conversion output has no declared source projection. Broken by ccfef5f. update_metadata_for_zarr_conversion looked up store-relative paths (A01_….tif), but source projections are keyed by plate-relative virtual paths (TimePoint_1/A01_….tif). It now prefixes the original subdirectory. The existing unit test used "." as the subdirectory, where the two paths are the same. New regression test: tests/unit/test_zarr_input_conversion_subdirectory.py.

2. Other zarr cases: the results entry was missing required fields. Broken by 1f15250, on top of #134 (8224363). Step-time publication admits a result directory when exists() sees its saved files. The zarr backend answers that through disk passthrough. Completion writes the header fields only when is_dir()/list_files() find outputs, and zarr did not list passthrough files. The result was a results entry with projection fields only. Fixed in PolyStore: zarr list_files/is_dir now report passthrough saves. PolyStore#34 also fixes zarr delete(), which kept its own .json/.csv/.txt list, so replacing a saved .roi.zip on a re-run failed. New regression tests are in PolyStore and in tests/unit/test_persisted_roi_only_publication.py.

3. napari cases: ack timeouts and Saved images lack typed produced addresses. Broken by 7bc7816. It called Layer._make_slice_input, which the installed napari 0.9.2 does not have; slicing moved to Layer._slicing_state. Every scheduled layer update raised inside the viewer, so it never acked and producers timed out after 30 s. The "lack typed produced addresses" error is a knock-on effect: the failed steps left saved images without produced records. Fixed with a one-line change in napari_viewer_server.py. Regression test against a real ViewerModel: tests/unit/test_napari_native_frame_applied.py.

Coordination

  • G6 (G6: domain-blind viewers #1178): one line in openhcs/runtime/napari_viewer_server.py (native_frame_applied). The G6 branch still has _make_slice_input. Separately, test_napari_reset_transitions.py fails 26 cases on _indices_view, another napari API that 0.9.2 removed. Those tests hang on main's viewer server. I did not fix them; they belong to G6.
  • G3 (G3: tensor payload with declared axes #1180): no payload modules touched.
  • Out of scope: detached viewers rewrite QT_QPA_PLATFORM=offscreen to xcb by design (QtPlatformName.OFFSCREEN is non-interactive). Running viewer modes with a display therefore opens real windows.

Results (serial, nice -n 19, worktree --basetemp, QT_QPA_PLATFORM=offscreen, DISPLAY/WAYLAND_DISPLAY unset)

  • Non-viewer modes, 12/12 pass: disk and zarr × ImageXpress, OperaPhenix and OpenHCS × direct and zmq.
  • Viewer modes, 36/36 fail from environment limits. These are the napari, fiji and napari+fiji modes. With no display, napari's viewer process dies at startup (no Qt platform plugin can start). Fiji runs headless and fails settlement with an InvocationTargetException. This machine has no Xvfb.
  • Earlier runs with the display set, before the coordinator asked for headless runs: these passed after the fixes: disk-ImageXpress direct-napari, disk-ImageXpress zmq-none and zmq-napari, disk-OpenHCS zmq-napari, zarr-OpenHCS direct-napari, and zarr-ImageXpress direct-fiji.
  • Official30 parity (CI command and env): 29/30. The failure is the known baseline cp_tutorial_3d_monolayer (.pkl serialization).
  • Unit tests: PolyStore suite 594 passed. The touched OpenHCS unit files pass except the 26 G6 napari failures above.

B2 · PR #1182 · guards n/a · production −6 +9 (PolyStore −3 +32) · tests −219 +337 (PolyStore +38)

🤖 Generated with Claude Code

trissim and others added 7 commits October 10, 2026 08:13
test_main hard-coded the execution server (7777) and viewer ports
(5555/5556/5557/5559, plus Fiji's default 5565). On Linux these name IPC
sockets under ~/.openhcs/ipc, shared by every checkout, so concurrent runs
and agents connected to each other's servers and viewers: an ImageXpress
run reported an OperaPhenix plate, and a viewer from another checkout
rejected this checkout's metadata.

A free_port_pair fixture in the integration conftest now allocates pairs
through DataControlPortPairAuthority, starting from an OS-assigned port
rather than the configured default every run would pick first, and shuts
down whatever still listens on those pairs at teardown (viewers kept alive
by a spawned execution server). test_main takes all its ports from it.

Also delete the disabled _test_main_with_code_serialization reference
function and create_test_pipeline's ignored sequential_config parameter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
update_metadata_for_zarr_conversion looked up each converted store file by
its path relative to the zarr store ("A01_....tif"), but source projections
are keyed by plate-relative virtual paths ("TimePoint_1/A01_....tif").
Conversion mirrors the source subdirectory's layout inside the store, so the
lookup now prefixes the original subdirectory. Any prepared workspace whose
images live in a subdirectory failed step 0 with "Zarr conversion output has
no declared source projection" since ccfef5f; the existing unit test used
the plate root (".") as the subdirectory, where both keys coincide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bump PolyStore so the zarr backend lists and reports the CSV, JSON and ROI
archive files it saves through disk passthrough. Since 1f15250 the
step-time publication admits a result directory when exists() finds its
saved files, which zarr answers through passthrough, while completion
writes the entry's header fields only when is_dir()/list_files() find
outputs, which zarr did not. Zarr runs therefore left a "results" entry
with projection fields only and no image_files, available_backends or
microscope_handler_name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7bc7816 called Layer._make_slice_input, which the installed napari
(0.9.2, slicing moved to Layer._slicing_state) does not have. Every scheduled
layer update raised AttributeError inside the viewer, so it never acked and
producers timed out after 30 s. The failed steps then left saved images
without produced records, which surfaced as "Saved images lack typed
produced addresses". Use _slicing_state.make_slice_input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bump PolyStore: the zarr backend's delete() used its own .json/.csv/.txt
list instead of the declared passthrough extensions, so replacing a
.roi.zip saved through disk passthrough failed in Cell Counting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
All parametrizations of one microscope regenerated their plate into the same
tests/integration/tests_data directory. A zarr run converts its input plate
in place (a second subdirectory marked main) and leaves saved outputs, so the
next parametrization started from the previous one's state and failed with
"Multiple OpenHCS metadata subdirectories are marked main". Plates now live
under the test's own tmp_path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Execution and viewer servers start their own sessions (setsid) and outlive
the test process tree; ViewerStateManager only stops viewers the test
process itself launched. With per-test ports each zmq or Fiji run left new
viewer servers (and Fiji windows) behind. An autouse fixture now marks each
test's environment, which every descendant inherits, and at teardown kills
the process group of every marked process still alive, pass or fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 10, 2026 14:29

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

trissim added a commit that referenced this pull request Oct 10, 2026
…ies; absorb napari 0.9.2 slicing API

- zmqruntime 0.5.0 (079a1c41d), PolyStore 0.4.0 (f6af43a9b), python-introspect
  0.2.5 (4bb7d132d); minimum versions raised.
- Axis keeps G6's label beside G4's metadata declarations; the installed demo
  takes main's typed viewer payload check.
- napari 0.9.2 removed Layer._make_slice_input and _indices_view: native frame
  completion uses _slicing_state.make_slice_input (B2's fix, #1182) and the
  displayed-subject projection reads _view_indices.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Take main's PolyStore pin (0.4.0 includes the zarr passthrough fixes) and
G6's napari_viewer_server.py, which already carries the slicing-state fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@trissim
trissim merged commit 66a0b30 into main Oct 10, 2026
3 of 37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants