Skip to content

test(pyamber): add test coverage for AsyncRPCHandlerInitializer - #7749

Open
eugenegujing wants to merge 1 commit into
apache:mainfrom
eugenegujing:test/async-rpc-handler-initializer-spec
Open

test(pyamber): add test coverage for AsyncRPCHandlerInitializer#7749
eugenegujing wants to merge 1 commit into
apache:mainfrom
eugenegujing:test/async-rpc-handler-initializer-spec

Conversation

@eugenegujing

Copy link
Copy Markdown
Contributor

What changes were proposed in this PR?

Adds test_async_rpc_handler_initializer.py (50 tests) for core/architecture/rpc/async_rpc_handler_initializer.py — the class whose body is pass and whose mixin list is the entire wiring between the generated WorkerService and the Python worker's control handlers. Nothing covered it before: test_async_rpc_server.py deliberately substitutes a stub initializer, so a proto RPC added without a Python handler was only discovered at runtime.

Expectations are derived from the generated code rather than hand-listed, so a newly generated RPC joins the parametrization on its own and fails until a handler exists. The spec pins:

  • every declared RPC resolves to an async coroutine on a ControlHandler mixin, taking exactly the request type and returning exactly the reply type the generated mapping declares;
  • the deliberately-unimplemented set is exactly prepare_checkpoint, finalize_checkpoint, retrieve_state and flush_network_buffer, as a set equality in both directions — implementing one without updating the set fails too. (One correction to the issue text: flush_network_buffer is a Scala-side network concern, not checkpoint-related, so the set is four RPCs rather than "the checkpoint-related ones".)
  • no RPC is defined by more than one mixin — an MRO-shadowed duplicate is dead code invisible to every other check;
  • every ControlHandler subclass on disk is wired into the initializer's bases — the one check not derived from the MRO, so a handler that was written but never wired is reported by name;
  • every request type is registered in ControlRequest's oneof, and the reply types missing from ControlReturn's oneof are exactly evaluate_python_expression. That last one is a real, currently-broken shape: the worker service declares EvaluatedValue as its reply but the oneof only registers the coordinator-side wrapper, so set_one_of packs an empty ControlReturn and the answer is silently dropped. The fix is a .proto change and out of scope here; pinning the current shape forces whoever fixes it to clean up the exception set in the same change.
  • the real AsyncRPCServer registers one collision-free lowercased lookup key per RPC, each bound to the real initializer, NoOperation round-trips end to end through the unmodified production wiring, and each unimplemented RPC replies with an UNIMPLEMENTED ControlError instead of taking the worker down.

Not redundant with test_async_rpc_server.py: that spec pins the server's dispatch and packing mechanics against a stub (including set_one_of swallowing a wrong-typed reply, exercised with a synthetic type); this one pins the real wiring and names which actual RPC hits that mechanism. The Scala twin of this file gained its spec in #7729; this is the Python side.

Any related issues, documentation, discussions?

Closes #7747.

How was this PR tested?

50 new tests, all green locally:

cd amber
pytest src/test/python/core/architecture/rpc/test_async_rpc_handler_initializer.py -q   # 50 passed
pytest src/test/python/core/architecture/ -q                                            # 341 passed
pytest -m "not integration" -q                                                          # 1106 passed
ruff check src/main/python src/test/python && ruff format --check src/main/python src/test/python

The only full-suite failures are the pre-existing core/storage/iceberg/test_iceberg_document.py items that need a local catalog stack; they fail identically without this PR.

The tests were also mutation-checked: removing a mixin from the bases, renaming a handler method away from the proto name, turning a handler async def into a plain def, adding a new RPC to the generated base without a handler, implementing one of the acknowledged-unimplemented RPCs, duplicating an RPC on a second mixin, hiding an unwired handler in a subpackage, and deleting a oneof registration each turn the expected tests red.

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

Generated-by: Claude Code (Claude Opus 5)

Add test_async_rpc_handler_initializer.py with 50 tests: RPC-to-handler wiring and signatures, the unimplemented-RPC set, duplicate-mixin and unwired-on-disk guards, ControlRequest/ControlReturn oneof membership (with the known EvaluatedValue gap pinned as an exception set), and end-to-end dispatch through the real AsyncRPCServer.
@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

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.03%. Comparing base (e80add4) to head (ec22984).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##               main    #7749   +/-   ##
=========================================
  Coverage     91.03%   91.03%           
  Complexity     4459     4459           
=========================================
  Files          1174     1174           
  Lines         47139    47139           
  Branches       5284     5284           
=========================================
  Hits          42915    42915           
  Misses         2549     2549           
  Partials       1675     1675           
Flag Coverage Δ *Carryforward flag
access-control-service 81.00% <ø> (ø) Carriedforward from e80add4
agent-service 98.62% <ø> (ø) Carriedforward from e80add4
amber 87.49% <ø> (ø) Carriedforward from e80add4
computing-unit-managing-service 73.67% <ø> (ø) Carriedforward from e80add4
config-service 86.73% <ø> (ø) Carriedforward from e80add4
file-service 68.90% <ø> (ø) Carriedforward from e80add4
frontend 92.58% <ø> (ø) Carriedforward from e80add4
notebook-migration-service 83.74% <ø> (ø) Carriedforward from e80add4
pyamber 97.57% <ø> (ø)
workflow-compiling-service 77.19% <ø> (ø) Carriedforward from e80add4

*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

Copy link
Copy Markdown
Contributor

⚠️ Benchmark changes need a look

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

Compared against main 60300e3 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 384 0.235 26,700/33,700/33,700 us 🔴 +5.3% / 🔴 +110.8%
🔴 bs=100 sw=10 sl=64 909 0.555 109,487/137,105/137,105 us 🔴 +9.3% / 🔴 +27.8%
🔴 bs=1000 sw=10 sl=64 1,080 0.659 924,291/1,026,642/1,026,642 us 🔴 +5.9% / 🟢 -5.5%
Baseline details

Latest main 60300e3 from same runner

config metric PR latest main 7d avg Δ latest Δ 7d
bs=10 sw=10 sl=64 throughput 384 tuples/sec 404 tuples/sec 779.07 tuples/sec -5.0% -50.7%
bs=10 sw=10 sl=64 MB/s 0.235 MB/s 0.247 MB/s 0.476 MB/s -4.9% -50.6%
bs=10 sw=10 sl=64 p50 26,700 us 25,359 us 12,818 us +5.3% +108.3%
bs=10 sw=10 sl=64 p95 33,700 us 35,580 us 15,986 us -5.3% +110.8%
bs=10 sw=10 sl=64 p99 33,700 us 35,580 us 19,339 us -5.3% +74.3%
bs=100 sw=10 sl=64 throughput 909 tuples/sec 932 tuples/sec 1,011 tuples/sec -2.5% -10.1%
bs=100 sw=10 sl=64 MB/s 0.555 MB/s 0.569 MB/s 0.617 MB/s -2.5% -10.1%
bs=100 sw=10 sl=64 p50 109,487 us 108,549 us 100,965 us +0.9% +8.4%
bs=100 sw=10 sl=64 p95 137,105 us 125,457 us 107,295 us +9.3% +27.8%
bs=100 sw=10 sl=64 p99 137,105 us 125,457 us 115,531 us +9.3% +18.7%
bs=1000 sw=10 sl=64 throughput 1,080 tuples/sec 1,079 tuples/sec 1,049 tuples/sec +0.1% +3.0%
bs=1000 sw=10 sl=64 MB/s 0.659 MB/s 0.659 MB/s 0.64 MB/s 0.0% +2.9%
bs=1000 sw=10 sl=64 p50 924,291 us 929,816 us 978,248 us -0.6% -5.5%
bs=1000 sw=10 sl=64 p95 1,026,642 us 969,801 us 1,021,881 us +5.9% +0.5%
bs=1000 sw=10 sl=64 p99 1,026,642 us 969,801 us 1,050,075 us +5.9% -2.2%
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,520.38,200,128000,384,0.235,26699.83,33700.09,33700.09
1,100,10,64,20,2201.21,2000,1280000,909,0.555,109486.78,137105.29,137105.29
2,1000,10,64,20,18520.61,20000,12800000,1080,0.659,924290.93,1026642.25,1026642.25

@aglinxinyuan
aglinxinyuan added this pull request to the merge queue Aug 18, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Aug 18, 2026
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 Python AsyncRPCHandlerInitializer

3 participants