Skip to content

Commit 34b483d

Browse files
committed
test(tui): cover deferred restored remote dispatch
1 parent 528df13 commit 34b483d

4 files changed

Lines changed: 199 additions & 30 deletions

File tree

crates/jcode-tui/src/tui/app/tests/remote_events_reload_04.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,18 @@ fn test_remote_error_with_retryable_pending_schedules_retry() {
132132
assert_eq!(pending.retry_attempts, 1);
133133
assert!(pending.retry_at.is_some());
134134
assert!(app.rate_limit_reset.is_some());
135-
assert!(
136-
app.display_messages()
137-
.iter()
138-
.any(|m| m.role == "system" && m.content.contains("Auto-retrying"))
139-
);
135+
let retry_notice = app
136+
.display_messages()
137+
.iter()
138+
.find(|message| message.title.as_deref() == Some("Connection"))
139+
.expect("retry should surface a connection status message");
140+
assert_eq!(retry_notice.role, "system");
141+
assert!(retry_notice.content.contains("Connection lost - retrying"));
142+
assert!(retry_notice.content.contains(&format!(
143+
"attempt 1/{}",
144+
App::AUTO_RETRY_MAX_ATTEMPTS
145+
)));
146+
assert!(retry_notice.content.contains("Remote request failed"));
140147
}
141148

142149
#[test]

crates/jcode-tui/src/tui/app/tests/remote_startup_input_01/part_01.rs

Lines changed: 86 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -337,16 +337,22 @@ fn test_new_for_remote_restores_spawn_startup_hints_and_dispatch_state() {
337337
super::commands::build_autojudge_startup_message("session_parent_123"),
338338
);
339339

340-
let app = App::new_for_remote(Some(session_id.to_string()));
340+
let mut app = App::new_for_remote(Some(session_id.to_string()));
341+
let rt = tokio::runtime::Runtime::new().unwrap();
342+
let _guard = rt.enter();
343+
let mut remote = crate::tui::backend::RemoteConnection::dummy();
341344

342-
assert!(app.pending_queued_dispatch);
343-
assert!(app.is_processing());
344-
assert!(app.processing_started.is_some());
345+
assert!(!app.pending_queued_dispatch);
346+
assert!(!app.is_processing());
347+
assert!(app.processing_started.is_none());
345348
assert!(matches!(
346349
crate::tui::TuiState::status(&app),
347-
ProcessingStatus::Sending
350+
ProcessingStatus::Idle
348351
));
349-
assert_eq!(app.status_notice(), Some("Autojudge starting".to_string()));
352+
assert_eq!(
353+
app.status_notice(),
354+
Some("Restored queued follow-up after reload".to_string())
355+
);
350356
assert_eq!(app.hidden_queued_system_messages.len(), 1);
351357

352358
let startup_banner = app
@@ -363,6 +369,27 @@ fn test_new_for_remote_restores_spawn_startup_hints_and_dispatch_state() {
363369
);
364370
assert!(startup_banner.content.contains("user-visible mirror"));
365371
assert!(startup_banner.content.contains("session_parent_123"));
372+
373+
rt.block_on(super::remote::process_remote_followups(
374+
&mut app,
375+
&mut remote,
376+
));
377+
assert_eq!(app.hidden_queued_system_messages.len(), 1);
378+
assert!(!app.is_processing());
379+
380+
remote.mark_history_loaded();
381+
rt.block_on(super::remote::process_remote_followups(
382+
&mut app,
383+
&mut remote,
384+
));
385+
386+
assert!(app.hidden_queued_system_messages.is_empty());
387+
assert!(app.is_processing());
388+
assert!(matches!(
389+
crate::tui::TuiState::status(&app),
390+
ProcessingStatus::Sending
391+
));
392+
assert!(app.current_message_id.is_some());
366393
});
367394
}
368395

@@ -383,23 +410,39 @@ fn test_remote_startup_done_event_does_not_cancel_pending_judge_launch() {
383410
);
384411

385412
let mut app = App::new_for_remote(Some(session_id.to_string()));
413+
let rt = tokio::runtime::Runtime::new().unwrap();
414+
let _guard = rt.enter();
386415
let mut remote = crate::tui::backend::RemoteConnection::dummy();
387416

388-
assert!(app.pending_queued_dispatch);
389-
assert!(app.is_processing());
417+
assert!(!app.pending_queued_dispatch);
418+
assert!(!app.is_processing());
390419
assert_eq!(app.current_message_id, None);
391420
assert_eq!(app.hidden_queued_system_messages.len(), 1);
392421

393422
app.handle_server_event(crate::protocol::ServerEvent::Done { id: 1 }, &mut remote);
394423

395-
assert!(app.pending_queued_dispatch);
396-
assert!(app.is_processing());
424+
assert!(!app.pending_queued_dispatch);
425+
assert!(!app.is_processing());
397426
assert!(matches!(
398427
crate::tui::TuiState::status(&app),
399-
ProcessingStatus::Sending
428+
ProcessingStatus::Idle
400429
));
401430
assert_eq!(app.current_message_id, None);
402431
assert_eq!(app.hidden_queued_system_messages.len(), 1);
432+
433+
remote.mark_history_loaded();
434+
rt.block_on(super::remote::process_remote_followups(
435+
&mut app,
436+
&mut remote,
437+
));
438+
439+
assert!(app.hidden_queued_system_messages.is_empty());
440+
assert!(app.is_processing());
441+
assert!(matches!(
442+
crate::tui::TuiState::status(&app),
443+
ProcessingStatus::Sending
444+
));
445+
assert!(app.current_message_id.is_some());
403446
});
404447
}
405448

@@ -423,13 +466,19 @@ fn test_remote_startup_judge_hidden_prompt_dispatches_once_history_is_loaded() {
423466
let rt = tokio::runtime::Runtime::new().unwrap();
424467
let _guard = rt.enter();
425468
let mut remote = crate::tui::backend::RemoteConnection::dummy();
426-
remote.mark_history_loaded();
427469

428-
assert!(app.pending_queued_dispatch);
429-
assert!(app.is_processing());
470+
assert!(!app.pending_queued_dispatch);
471+
assert!(!app.is_processing());
430472
assert_eq!(app.current_message_id, None);
431473

432-
app.pending_queued_dispatch = false;
474+
rt.block_on(super::remote::process_remote_followups(
475+
&mut app,
476+
&mut remote,
477+
));
478+
assert_eq!(app.hidden_queued_system_messages.len(), 1);
479+
assert!(!app.is_processing());
480+
481+
remote.mark_history_loaded();
433482
rt.block_on(super::remote::process_remote_followups(
434483
&mut app,
435484
&mut remote,
@@ -474,10 +523,11 @@ fn test_new_for_remote_fresh_spawn_restores_local_transcript() {
474523
super::commands::build_autojudge_startup_message("session_parent_123"),
475524
);
476525

477-
let app = App::new_for_remote_with_options(Some(session_id.to_string()), true);
526+
let mut app = App::new_for_remote_with_options(Some(session_id.to_string()), true);
478527

479528
assert_eq!(crate::tui::TuiState::provider_model(&app), "gpt-5.4");
480-
assert!(app.pending_queued_dispatch);
529+
assert!(!app.pending_queued_dispatch);
530+
assert!(!app.is_processing());
481531
assert_eq!(app.hidden_queued_system_messages.len(), 1);
482532
assert_eq!(app.display_messages().len(), 2);
483533
assert!(
@@ -489,6 +539,25 @@ fn test_new_for_remote_fresh_spawn_restores_local_transcript() {
489539
let startup_banner = app.display_messages().last().expect("startup banner");
490540
assert_eq!(startup_banner.role, "system");
491541
assert_eq!(startup_banner.title.as_deref(), Some("Autojudge"));
542+
543+
let rt = tokio::runtime::Runtime::new().unwrap();
544+
let _guard = rt.enter();
545+
let mut remote = crate::tui::backend::RemoteConnection::dummy();
546+
rt.block_on(super::remote::process_remote_followups(
547+
&mut app,
548+
&mut remote,
549+
));
550+
assert_eq!(app.hidden_queued_system_messages.len(), 1);
551+
assert!(!app.is_processing());
552+
553+
remote.mark_history_loaded();
554+
rt.block_on(super::remote::process_remote_followups(
555+
&mut app,
556+
&mut remote,
557+
));
558+
assert!(app.hidden_queued_system_messages.is_empty());
559+
assert!(app.is_processing());
560+
assert!(app.current_message_id.is_some());
492561
});
493562
}
494563

crates/jcode-tui/src/tui/app/tests/remote_startup_input_03/part_01.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,10 +1122,36 @@ fn test_new_for_remote_restored_interleave_triggers_dispatch_state() {
11221122
app.interleave_message = Some("interrupt after reload".to_string());
11231123
app.save_input_for_reload(&session_id);
11241124

1125-
let restored = App::new_for_remote(Some(session_id));
1125+
let mut restored = App::new_for_remote(Some(session_id));
11261126
assert!(restored.interleave_message.is_none());
11271127
assert_eq!(restored.queued_messages(), &["interrupt after reload"]);
1128-
assert!(restored.pending_queued_dispatch);
1128+
assert!(!restored.pending_queued_dispatch);
1129+
assert!(!restored.is_processing);
1130+
assert!(matches!(restored.status, ProcessingStatus::Idle));
1131+
1132+
let rt = tokio::runtime::Runtime::new().unwrap();
1133+
let _guard = rt.enter();
1134+
let mut remote = crate::tui::backend::RemoteConnection::dummy();
1135+
rt.block_on(super::remote::process_remote_followups(
1136+
&mut restored,
1137+
&mut remote,
1138+
));
1139+
assert_eq!(restored.queued_messages(), &["interrupt after reload"]);
1140+
assert!(!restored.is_processing);
1141+
1142+
remote.mark_history_loaded();
1143+
rt.block_on(super::remote::process_remote_followups(
1144+
&mut restored,
1145+
&mut remote,
1146+
));
1147+
1148+
assert!(restored.queued_messages().is_empty());
11291149
assert!(restored.is_processing);
11301150
assert!(matches!(restored.status, ProcessingStatus::Sending));
1151+
assert!(
1152+
restored
1153+
.display_messages()
1154+
.iter()
1155+
.any(|message| message.role == "user" && message.content == "interrupt after reload")
1156+
);
11311157
}

crates/jcode-tui/src/tui/app/tests/remote_startup_input_03/part_02.rs

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,38 @@ fn test_new_for_remote_restored_soft_interrupt_resend_triggers_dispatch_state()
77
app.pending_soft_interrupt_requests = vec![(55, "sent interrupt".to_string())];
88
app.save_input_for_reload(&session_id);
99

10-
let restored = App::new_for_remote(Some(session_id));
10+
let mut restored = App::new_for_remote(Some(session_id));
1111
assert!(restored.interleave_message.is_none());
1212
assert_eq!(restored.queued_messages(), &["sent interrupt"]);
13-
assert!(restored.pending_queued_dispatch);
13+
assert!(!restored.pending_queued_dispatch);
14+
assert!(!restored.is_processing);
15+
assert!(matches!(restored.status, ProcessingStatus::Idle));
16+
17+
let rt = tokio::runtime::Runtime::new().unwrap();
18+
let _guard = rt.enter();
19+
let mut remote = crate::tui::backend::RemoteConnection::dummy();
20+
rt.block_on(super::remote::process_remote_followups(
21+
&mut restored,
22+
&mut remote,
23+
));
24+
assert_eq!(restored.queued_messages(), &["sent interrupt"]);
25+
assert!(!restored.is_processing);
26+
27+
remote.mark_history_loaded();
28+
rt.block_on(super::remote::process_remote_followups(
29+
&mut restored,
30+
&mut remote,
31+
));
32+
33+
assert!(restored.queued_messages().is_empty());
1434
assert!(restored.is_processing);
1535
assert!(matches!(restored.status, ProcessingStatus::Sending));
36+
assert!(
37+
restored
38+
.display_messages()
39+
.iter()
40+
.any(|message| message.role == "user" && message.content == "sent interrupt")
41+
);
1642
}
1743

1844
#[test]
@@ -25,12 +51,53 @@ fn test_new_for_remote_does_not_requeue_acked_pending_soft_interrupts() {
2551
app.queued_messages.push("queued later".to_string());
2652
app.save_input_for_reload(&session_id);
2753

28-
let restored = App::new_for_remote(Some(session_id));
54+
let mut restored = App::new_for_remote(Some(session_id));
55+
assert!(restored.interleave_message.is_none());
2956
assert_eq!(
30-
restored.interleave_message.as_deref(),
31-
Some("local interleave")
57+
restored.queued_messages(),
58+
&["local interleave", "queued later"]
59+
);
60+
assert!(
61+
!restored
62+
.queued_messages()
63+
.iter()
64+
.any(|message| message == "already queued on server")
65+
);
66+
assert!(!restored.pending_queued_dispatch);
67+
assert!(!restored.is_processing);
68+
69+
let rt = tokio::runtime::Runtime::new().unwrap();
70+
let _guard = rt.enter();
71+
let mut remote = crate::tui::backend::RemoteConnection::dummy();
72+
rt.block_on(super::remote::process_remote_followups(
73+
&mut restored,
74+
&mut remote,
75+
));
76+
assert_eq!(
77+
restored.queued_messages(),
78+
&["local interleave", "queued later"]
79+
);
80+
81+
remote.mark_history_loaded();
82+
rt.block_on(super::remote::process_remote_followups(
83+
&mut restored,
84+
&mut remote,
85+
));
86+
87+
assert!(restored.queued_messages().is_empty());
88+
assert!(restored.is_processing);
89+
assert!(
90+
restored
91+
.display_messages()
92+
.iter()
93+
.any(|message| message.role == "user" && message.content == "local interleave")
94+
);
95+
assert!(
96+
restored
97+
.display_messages()
98+
.iter()
99+
.all(|message| message.content != "already queued on server")
32100
);
33-
assert_eq!(restored.queued_messages(), &["queued later"]);
34101
}
35102

36103
#[test]

0 commit comments

Comments
 (0)