fix(cli): stop continuous groups on peer closure

Record a continuous peer-closed TargetFinished event as the reason for requesting group shutdown and stop each CLI/TUI group at most once. Drain the managed subscription and join before applying exit policy so queued output and target failures are preserved.

Give peer closure precedence over the cancellation caused by that internal stop while keeping explicit interruption and finite-run behavior distinct. Add bounded process regressions for partial closure, mixed failures, queued rows, and interruption plus focused TUI policy coverage.
This commit is contained in:
Nils Andreas Svee committed 2026-07-28 14:29:15 +07:00
1 parent 83fb98dbfd
commit 080d45ca67
4 files changed
+387 -26

No files matched your search

+47 -1
View File
@@ -4,7 +4,9 @@ use std::{
time::{Duration, Instant},
};
use irtt_client::{Client, ClientConfig, ClientEvent, OpenOutcome, RecvBudget};
use irtt_client::{
Client, ClientConfig, ClientEvent, ManagedTargetEndReason, OpenOutcome, RecvBudget,
};
pub const RECV_BUDGET: RecvBudget = RecvBudget { max_packets: 16 };
const MAX_FINAL_DRAIN: Duration = Duration::from_secs(30);
@@ -162,6 +164,22 @@ pub fn peer_close_run_error(
))
}
pub fn should_stop_group_on_peer_close(
continuous: bool,
interrupted: bool,
end_reason: &ManagedTargetEndReason,
) -> bool {
continuous && !interrupted && matches!(end_reason, ManagedTargetEndReason::PeerClosed)
}
pub fn request_group_stop_once(stop_requested: &mut bool) -> bool {
if *stop_requested {
return false;
}
*stop_requested = true;
true
}
pub fn final_drain_duration(probe_timeout: Duration) -> Duration {
probe_timeout.min(MAX_FINAL_DRAIN)
}
@@ -239,6 +257,34 @@ mod tests {
);
}
#[test]
fn grouped_peer_close_stop_policy_is_run_mode_and_interruption_aware() {
assert!(should_stop_group_on_peer_close(
true,
false,
&ManagedTargetEndReason::PeerClosed
));
assert!(!should_stop_group_on_peer_close(
false,
false,
&ManagedTargetEndReason::PeerClosed
));
assert!(!should_stop_group_on_peer_close(
true,
true,
&ManagedTargetEndReason::PeerClosed
));
assert!(!should_stop_group_on_peer_close(
true,
false,
&ManagedTargetEndReason::TestComplete
));
let mut stop_requested = false;
assert!(request_group_stop_once(&mut stop_requested));
assert!(!request_group_stop_once(&mut stop_requested));
}
#[test]
fn peer_close_followed_by_session_cleanup_is_successful() {
let params = test_params(None, Duration::from_millis(10));