Skip to content

test(pyamber): cover the main loop's control, console and end-channel paths - #8042

Merged
aglinxinyuan merged 2 commits into
apache:mainfrom
aglinxinyuan:cov/pyamber-main-loop
Aug 28, 2026
Merged

test(pyamber): cover the main loop's control, console and end-channel paths#8042
aglinxinyuan merged 2 commits into
apache:mainfrom
aglinxinyuan:cov/pyamber-main-loop

Conversation

@aglinxinyuan

Copy link
Copy Markdown
Contributor

What changes were proposed in this PR?

test_main_loop.py goes from 34 tests to 44, covering the console-message RPC path, the end-channel completion rules, the per-element exception backstop, and the ECM/loop-counter forwarding paths.

Metric Before After
Codecov fully-covered lines today 270/285 284/285
Codecov fully-covered lines after #8040 259/285 280/285
Branch arms newly taken +11

+14 fully-covered lines move on Codecov today; the full +21 only shows up once #8040 lands. Lines 176, 397, 658, 661, 706, 714 and 837 are line-hit with one arm untaken, so today's branch-less report already scores them covered — closing their second arm is real and mutation-proven but invisible until branch coverage is on. I would rather state both figures than quote the larger one and have it not materialise.

The [tool.coverage.run] branch = true setting is deliberately not added here; it belongs to #8040 and adding it would conflict.

Newly fully covered: 176, 177, 397, 400, 658, 661, 662, 706, 714, 715, 718, 719, 725, 813, 814, 817, 837, 838, 839, 849, 850. Nothing lost. Line 795 remains uncovered and four lines (349, 650, 740, 794) remain branch-partial.

What the reviewers found

Two adversarial reviewers reported eight surviving mutants against the first draft. Every one was reproduced before being fixed — seven gave a clean 43 passed on the delivered spec and one produced no summary at all. Eight of the claimed lines were covered vacuously. The ones worth naming:

  • The console-message test blocked on output_queue.get() instead of failing — a hang, not an assertion failure, which is the worst way for a test to be wrong.
  • The two-input-port end-channel test could not distinguish the port lookup from a constant, so the rule it exists to pin was unconstrained.
  • The no-output-ports test could not see an EndChannel broadcast at all.
  • assert switched == [True] claimed a statement order it cannot observe.
  • A emitted_counter == 0 assertion was a degenerate literal, and a reset_calls == [] assertion was call-graph-guaranteed to hold.

All eight now die. 33 mutations applied one at a time, 32 killed, 1 judged equivalent (a flush/pause order exchange, with the reasoning recorded).

Four of the 32 kills are honest about their conditions: the line-706, line-661, line-837 negations and the 393–394 order swap die only when the run is scoped to a single test, because they make pre-existing thread-driven tests block, and pytest-timeout's Windows thread method then kills the session before the killing test runs. They are stated as scoped kills rather than credited as clean whole-file kills.

One further mutant was discarded rather than reported as surviving: negating line 661 makes the pre-existing test_main_loop_thread_can_process_messages block forever, yielding no per-test signal. The same statement is covered by a returnpass mutant that dies exclusively against a new test, so nothing is left unproven.

A defect found and deliberately not pinned

_process_data_element's per-element backstop (813–814) is except Exception as err: logger.exception(err) — it logs and continues without calling context.report_exception. A runtime failure on one element therefore never reaches the coordinator, and the workflow can report SUCCESS on a short result.

The new test asserts only that iteration continues and that nothing propagates. It does not assert that nothing is reported, because that half is arguably a silent-wrong-results bug and pinning it would cement it. The test carries a comment saying so; anyone strengthening it should keep that boundary.

Verification

Measured with the full CI-shaped suite from amber/, --cov-branch passed explicitly on both sides (this branch is on main and so lacks #8040's config), LOGURU_LEVEL=WARNING, per-line hits and condition-coverage read out of coverage.xml by script rather than from the summary percentage. The before-state was obtained by copying the original spec back from a scratch snapshot — never via git restore — with the production tree verified pristine throughout.

No regression. Full pyamber suite: 5 failed, 1169 passed, 7 errors against a baseline of 5 failed, 1159 passed, 7 errors. The FAILED/ERROR node-id sets were extracted from both runs, sorted and diffed: identical by identity, 12 entries (7 test_iceberg_document errors, 2 iceberg failures, test_tuple::test_hash, 2 test_expression_evaluator repr-formatting failures). +10 passing. The scoped spec passes 44 passed on five consecutive runs.

ruff check and ruff format --check pass on CI's exact scope (src/main/python src/test/python). git diff --numstat shows 666 0 — 666 added, zero deleted.

A flake seen once and reported rather than buried: one no-branch after-run came back 282/285 with lines 324–325 at zero hits; three consecutive re-runs all gave 284/285 with both covered. Those two lines are in _check_and_process_control's while body, reached from a daemon thread, so a scheduling-dependent miss is plausible. The published figure is the reproducible one.

On overlap with open PRs

This file is not untouched work. #7624 (open) and #7388 (draft) both modify main_loop.py and test_main_loop.py. I checked both diffs: none of the 21 lines here falls inside either PR's edited hunks, and the new tests are appended at the end of TestMainLoop, away from the test-file hunks. The collision risk is a routine rebase rather than a semantic conflict — but it is not zero, and the earlier claim that this target was free was wrong.

Deliberately not included

Line 795 and the four remaining partials (349, 650, 740, 794) are left. Reaching 813/814 already required monkeypatching a MainLoop private — established practice in this file but white-box, and flagged as the one such test in the bundle.

No production file is touched; git diff -- 'amber/src/main/*' is empty, checked after every mutation revert and as the final action.

Any related issues, documentation, discussions?

Closes #8041

How was this PR tested?

cd amber && python -m pytest -m "not integration" -q src/test/python/core/runnables/test_main_loop.py
44 passed, 1 warning
cd amber && ruff check src/main/python src/test/python && ruff format --check src/main/python src/test/python

amber/junit.xml, amber/coverage.xml and amber/.coverage are regenerated by every run and are not committed.

Was this PR authored or co-authored using generative AI tooling?

Generated-by: Claude Code (Opus 5)

Copilot AI lite review requested due to automatic review settings August 27, 2026 10:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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.

@github-actions

Copy link
Copy Markdown
Contributor

Automated Reviewer Suggestions

Based on the git blame history of the changed files, we recommend the following reviewers:

  • No candidates found from git blame history.

@codecov-commenter

codecov-commenter commented Aug 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.44%. Comparing base (b01b11f) to head (c1a6edb).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #8042      +/-   ##
============================================
+ Coverage     93.41%   93.44%   +0.02%     
  Complexity     4696     4696              
============================================
  Files          1179     1179              
  Lines         47713    47713              
  Branches       5314     5314              
============================================
+ Hits          44573    44587      +14     
+ Misses         1698     1684      -14     
  Partials       1442     1442              
Flag Coverage Δ *Carryforward flag
access-control-service 81.00% <ø> (ø) Carriedforward from 6c4d209
agent-service 99.32% <ø> (ø) Carriedforward from 6c4d209
amber 89.60% <ø> (ø) Carriedforward from 6c4d209
computing-unit-managing-service 73.67% <ø> (ø) Carriedforward from 6c4d209
config-service 86.73% <ø> (ø) Carriedforward from 6c4d209
file-service 86.70% <ø> (ø) Carriedforward from 6c4d209
frontend 95.89% <ø> (ø) Carriedforward from 6c4d209
notebook-migration-service 79.31% <ø> (ø) Carriedforward from 6c4d209
pyamber 98.09% <ø> (+0.30%) ⬆️
workflow-compiling-service 77.19% <ø> (ø) Carriedforward from 6c4d209

*This pull request uses carry forward flags. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actions Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

⚠️ Benchmark changes need a look

🟢 0 better · 🔴 5 worse · ⚪ 10 noise (<±5%) · 0 without baseline

Compared against main b01b11f benchmarked on this same runner, so the delta is largely free of cross-runner hardware noise. The "7d avg" column still reflects the gh-pages dashboard. Treat <±5% as noise unless repeated.

Dashboard · Run

config throughput MB/s latency max Δ latest / 7d
🔴 bs=10 sw=10 sl=64 419 0.256 22,480/32,614/32,614 us 🔴 +22.1% / 🔴 +132.8%
bs=100 sw=10 sl=64 958 0.584 100,183/139,559/139,559 us ⚪ within ±5% / 🔴 +46.8%
🔴 bs=1000 sw=10 sl=64 1,133 0.691 877,076/969,080/969,080 us 🔴 +6.9% / 🔴 +5.6%
Baseline details

Latest main b01b11f from same runner

config metric PR latest main 7d avg Δ latest Δ 7d
bs=10 sw=10 sl=64 throughput 419 tuples/sec 477 tuples/sec 893.99 tuples/sec -12.2% -53.1%
bs=10 sw=10 sl=64 MB/s 0.256 MB/s 0.291 MB/s 0.546 MB/s -12.0% -53.1%
bs=10 sw=10 sl=64 p50 22,480 us 18,410 us 11,176 us +22.1% +101.1%
bs=10 sw=10 sl=64 p95 32,614 us 31,634 us 14,009 us +3.1% +132.8%
bs=10 sw=10 sl=64 p99 32,614 us 31,634 us 16,898 us +3.1% +93.0%
bs=100 sw=10 sl=64 throughput 958 tuples/sec 973 tuples/sec 1,157 tuples/sec -1.5% -17.2%
bs=100 sw=10 sl=64 MB/s 0.584 MB/s 0.594 MB/s 0.706 MB/s -1.7% -17.3%
bs=100 sw=10 sl=64 p50 100,183 us 99,602 us 88,763 us +0.6% +12.9%
bs=100 sw=10 sl=64 p95 139,559 us 145,900 us 95,096 us -4.3% +46.8%
bs=100 sw=10 sl=64 p99 139,559 us 145,900 us 102,854 us -4.3% +35.7%
bs=1000 sw=10 sl=64 throughput 1,133 tuples/sec 1,157 tuples/sec 1,187 tuples/sec -2.1% -4.5%
bs=1000 sw=10 sl=64 MB/s 0.691 MB/s 0.706 MB/s 0.724 MB/s -2.1% -4.6%
bs=1000 sw=10 sl=64 p50 877,076 us 858,220 us 874,968 us +2.2% +0.2%
bs=1000 sw=10 sl=64 p95 969,080 us 906,790 us 917,815 us +6.9% +5.6%
bs=1000 sw=10 sl=64 p99 969,080 us 906,790 us 949,868 us +6.9% +2.0%
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,477.59,200,128000,419,0.256,22480.41,32614.08,32614.08
1,100,10,64,20,2088.47,2000,1280000,958,0.584,100183.05,139559.15,139559.15
2,1000,10,64,20,17654.14,20000,12800000,1133,0.691,877075.71,969079.63,969079.63

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.

Comment thread amber/src/test/python/core/runnables/test_main_loop.py Outdated
Comment thread amber/src/test/python/core/runnables/test_main_loop.py
Comment thread amber/src/test/python/core/runnables/test_main_loop.py

@mengw15 mengw15 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Xinyuan Lin <xinyual3@uci.edu>
@aglinxinyuan
aglinxinyuan enabled auto-merge August 28, 2026 02:42
@aglinxinyuan
aglinxinyuan added this pull request to the merge queue Aug 28, 2026
Merged via the queue into apache:main with commit e750074 Aug 28, 2026
23 checks passed
@aglinxinyuan
aglinxinyuan deleted the cov/pyamber-main-loop branch August 28, 2026 03:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add unit test coverage for the pyamber main loop's control, console and end-channel paths

4 participants