test: cover graceful-leave instant-evict and rejoin-after-eviction edges
Two reconnect-eviction edges were logically handled but had no explicit assertion: - A graceful ConnEvent::Left must emit PeerLeft *immediately* (not wait on the grace timer). New graceful_leave_evicts_immediately asserts the leave lands well inside the grace window. - After a grace-timer eviction scrubs the peer from seen_connected, a later rejoin's initial dial must be a fresh first-dial, not a reconnect that arms a new eviction. New rejoin_after_grace_eviction_dials_cleanly covers this (distinct from the existing graceful-leave scrub path). Also reorder the eviction task to scrub timers/seen_connected before emitting PeerConnectionFailed, so an observer (or a redial racing the eviction) always sees clean internal state — this also makes the new rejoin-after-eviction test deterministic. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+5
-1
@@ -100,9 +100,13 @@ fn arm_grace_timer(
|
||||
crate::log_msg(&format!("Reconnect grace expired; evicting peer {:?}", peer_id));
|
||||
transport_evict.disconnect_peer(peer_id).await;
|
||||
jitter_evict.lock().await.remove(&peer_id);
|
||||
let _ = ui_evict.send(UiEvent::PeerConnectionFailed { id: peer_id }).await;
|
||||
// Scrub our internal state *before* announcing the eviction, so anything
|
||||
// that observes `PeerConnectionFailed` (or a rejoin racing it) sees a clean
|
||||
// slate — a later dial for this identity is then a fresh first-dial, not a
|
||||
// reconnect.
|
||||
timers_evict.lock().unwrap().remove(&peer_id);
|
||||
seen_evict.lock().unwrap().remove(&peer_id);
|
||||
let _ = ui_evict.send(UiEvent::PeerConnectionFailed { id: peer_id }).await;
|
||||
});
|
||||
timers_guard.insert(peer_id, handle);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user