Skip to content

refactor(core) #357, #358: remove dead leader code and add missing test coverage - #359

Merged
JoshuaChi merged 1 commit into
mainfrom
refactor/357-358-leader-state-cleanup
Apr 13, 2026
Merged

JoshuaChi merged 1 commit into
mainfrom
refactor/357-358-leader-state-cleanup

Conversation

@JoshuaChi

@JoshuaChi JoshuaChi commented Apr 12, 2026 •

Copy link
Copy Markdown
Contributor

What Does This PR Do?

Removes two dead functions (batch_promote_learners, if_update_commit_index) from LeaderState and adds tests for four previously uncovered code paths.

Type:

  • Test/Coverage

Why Is This Needed?

#358: batch_promote_learners was superseded by process_pending_promotions but left behind with #[allow(dead_code)]. if_update_commit_index had no callers. Both add maintenance burden and the dead_code suppression masks future regressions.

#357: Four code paths in leader_state.rs had no test coverage, causing Codecov patch failures in adjacent PRs:

  • RaftEvent::StepDownSelfRemoved handler
  • conditionally_purge_zombie_nodes BatchRemove path
  • BackpressureMetrics::record_rejection / record_buffer_utilization (enabled branch)

Checklist

Required:

  • make test passes
  • Added tests for new code
  • Commits squashed to 1-2 logical units

Testing

How tested:

  • Unit tests: test_step_down_self_removed_sends_become_follower verifies BecomeFollower event on self-removal; zombie_purge_tests (3 cases: no candidates, non-Active nodes removed, Active nodes skipped); 5 BackpressureMetrics tests covering enabled/disabled × write/read × sampling rate
  • All 209 leader_state_test tests pass

Does This Follow d-engine's Principles?

  • Solves a real problem for most users (not just my edge case)
  • Keeps implementation simple
  • Doesn't bloat the API surface

Reviewer Notes

conditionally_purge_zombie_nodes visibility changed from private to pub(super) to enable direct unit testing — no public API change.

Estimated review complexity:

  • Medium (< 300 lines)

Summary by CodeRabbit

  • Refactor

    • Refactored internal leader state APIs to improve code organization and maintainability.
  • Tests

    • Added comprehensive unit tests for backpressure metrics validation under different configurations and sampling rates.
    • Expanded test coverage for zombie node purging behavior with multiple membership scenarios.
    • Added test coverage for leader step-down event handling and role transitions.

@coderabbitai

coderabbitai Bot commented Apr 12, 2026 •

Copy link
Copy Markdown

Warning

Rate limit exceeded

@JoshuaChi has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 50 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 5 minutes and 50 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8e119f26-3b46-432e-83f5-05826ef89271

📥 Commits

Reviewing files that changed from the base of the PR and between 2e40d92 and 0723aa7.

📒 Files selected for processing (4)
  • d-engine-core/src/raft_role/leader_state.rs
  • d-engine-core/src/raft_role/leader_state_test/backpressure_test.rs
  • d-engine-core/src/raft_role/leader_state_test/event_handling_test.rs
  • d-engine-core/src/raft_role/leader_state_test/membership_change_test.rs
📝 Walkthrough

Walkthrough

This PR removes two unused methods (batch_promote_learners and if_update_commit_index) from LeaderState, exposes conditionally_purge_zombie_nodes as pub(super), and reorganizes tests. It removes batch promotion tests while adding tests for backpressure metrics, zombie node purging, and leader step-down event handling.

Changes

Cohort / File(s) Summary
Leader State Core
d-engine-core/src/raft_role/leader_state.rs
Removed batch_promote_learners method (with ensure_safe_join logic), removed unused if_update_commit_index helper, changed conditionally_purge_zombie_nodes visibility from private to pub(super).
Backpressure Tests
d-engine-core/src/raft_role/leader_state_test/backpressure_test.rs
Added synchronous unit tests for BackpressureMetrics covering initialization, rejection recording, buffer utilization tracking, and sampling behavior under enabled/disabled configurations.
Event Handling Tests
d-engine-core/src/raft_role/leader_state_test/event_handling_test.rs
Added async test test_step_down_self_removed_sends_become_follower validating that RaftEvent::StepDownSelfRemoved triggers a RoleEvent::BecomeFollower(None) message.
Membership Change Tests
d-engine-core/src/raft_role/leader_state_test/membership_change_test.rs
Removed batch_promote_learners_test module (four tests); added zombie_purge_tests module with three tests for conditionally_purge_zombie_nodes covering empty candidates, non-active status removal, and active status skipping scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related issues

Possibly related PRs

  • Feature/245 refactor server ut #247: Modifies LeaderState membership-change behavior and associated tests; this PR removes batch-promotion logic while that PR may have introduced related membership-change patterns.

Poem

🐰 The Raft hops lighter, cleaner too,
Old batch-promote paths we bid adieu.
Zombie nodes purged with purpose true,
Tests bloom bright where once code grew. 🌿

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main changes: removing dead code (batch_promote_learners, if_update_commit_index) and adding test coverage, with issue references (#357, #358).
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/357-358-leader-state-cleanup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (2)
d-engine-core/src/raft_role/leader_state_test/backpressure_test.rs (1)

363-413: Strengthen these metrics tests with behavioral assertions.

These tests currently only verify “no panic,” so they can still pass if enabled/sampling logic regresses. Please assert observable outcomes (e.g., recorded counter/gauge events and sampling cadence) so the tests actually fail on logic breaks.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@d-engine-core/src/raft_role/leader_state_test/backpressure_test.rs` around
lines 363 - 413, Tests only check for absence of panics but not behavior; update
the BackpressureMetrics tests to assert actual metric changes by reading the
observable state after calls: for BackpressureMetrics::record_rejection call
record_rejection(true/false) and assert the corresponding rejection
counter/gauge has incremented (or remains unchanged when enabled=false); for
record_buffer_utilization call record_buffer_utilization(...) and assert the
buffer utilization gauge was updated with the expected value and label (write vs
read); for sampling-rate tests (BackpressureMetrics::new(..., sample_rate)) call
record_buffer_utilization repeatedly and assert only the expected fraction of
samples produced metric updates (e.g., check an internal sample counter or
exported metric count increments every N calls). Use existing accessors or add
small test-only getters on BackpressureMetrics (e.g.,
get_rejection_count(label), get_last_buffer_utilization(label),
get_sample_counter()) to make these assertions deterministic.
d-engine-core/src/raft_role/leader_state_test/membership_change_test.rs (1)

1906-1909: Optionally tighten get_node_status call expectations for stronger regression signals.

For the two-candidate case, consider asserting exact invocation count to ensure per-candidate status checks remain intact.

Optional test hardening
-        membership.expect_get_node_status().returning(|_| Some(NodeStatus::Promotable));
+        membership
+            .expect_get_node_status()
+            .times(2)
+            .returning(|_| Some(NodeStatus::Promotable));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@d-engine-core/src/raft_role/leader_state_test/membership_change_test.rs`
around lines 1906 - 1909, The test currently stubs
membership.expect_get_node_status() with a generic returning closure; tighten it
to assert it is called once per candidate by setting an exact call count (e.g.,
times(2)) and keep returning Some(NodeStatus::Promotable) so the two zombie
candidates from membership.expect_get_zombie_candidates() are each checked;
update the mock setup for get_node_status to use the expect_* call-count
assertion (referencing membership.expect_get_node_status and
NodeStatus::Promotable) to catch regressions where per-candidate status checks
might be skipped.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@d-engine-core/src/raft_role/leader_state_test/backpressure_test.rs`:
- Around line 363-413: Tests only check for absence of panics but not behavior;
update the BackpressureMetrics tests to assert actual metric changes by reading
the observable state after calls: for BackpressureMetrics::record_rejection call
record_rejection(true/false) and assert the corresponding rejection
counter/gauge has incremented (or remains unchanged when enabled=false); for
record_buffer_utilization call record_buffer_utilization(...) and assert the
buffer utilization gauge was updated with the expected value and label (write vs
read); for sampling-rate tests (BackpressureMetrics::new(..., sample_rate)) call
record_buffer_utilization repeatedly and assert only the expected fraction of
samples produced metric updates (e.g., check an internal sample counter or
exported metric count increments every N calls). Use existing accessors or add
small test-only getters on BackpressureMetrics (e.g.,
get_rejection_count(label), get_last_buffer_utilization(label),
get_sample_counter()) to make these assertions deterministic.

In `@d-engine-core/src/raft_role/leader_state_test/membership_change_test.rs`:
- Around line 1906-1909: The test currently stubs
membership.expect_get_node_status() with a generic returning closure; tighten it
to assert it is called once per candidate by setting an exact call count (e.g.,
times(2)) and keep returning Some(NodeStatus::Promotable) so the two zombie
candidates from membership.expect_get_zombie_candidates() are each checked;
update the mock setup for get_node_status to use the expect_* call-count
assertion (referencing membership.expect_get_node_status and
NodeStatus::Promotable) to catch regressions where per-candidate status checks
might be skipped.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c35a988b-5b69-496b-8cd8-e4cd923f1d33

📥 Commits

Reviewing files that changed from the base of the PR and between 8db9bb1 and 2e40d92.

📒 Files selected for processing (4)
  • d-engine-core/src/raft_role/leader_state.rs
  • d-engine-core/src/raft_role/leader_state_test/backpressure_test.rs
  • d-engine-core/src/raft_role/leader_state_test/event_handling_test.rs
  • d-engine-core/src/raft_role/leader_state_test/membership_change_test.rs

…st coverage

#358: Delete batch_promote_learners (superseded by process_pending_promotions),
if_update_commit_index (no callers), and their associated tests.
Remove now-unused ensure_safe_join import.

#357: Add tests for StepDownSelfRemoved event handling, conditionally_purge_zombie_nodes
BatchRemove path (no_candidates / submits_batch_remove / skips_active_nodes),
and BackpressureMetrics record_rejection/record_buffer_utilization branches.
@JoshuaChi
JoshuaChi force-pushed the refactor/357-358-leader-state-cleanup branch from 2e40d92 to 0723aa7 Compare April 12, 2026 14:50
@codecov

codecov Bot commented Apr 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.07317% with 13 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...t_role/leader_state_test/membership_change_test.rs 89.07% 13 Missing ⚠️

📢 Thoughts on this report? Let us know!

@JoshuaChi
JoshuaChi merged commit 773cd9c into main Apr 13, 2026
9 checks passed
@JoshuaChi
JoshuaChi deleted the refactor/357-358-leader-state-cleanup branch April 13, 2026 01:34
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.

1 participant