mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-22 00:02:23 +00:00
test(remote,scm): hold both halves of the backlog and completeness rules
Two compound conditions where one half decided every existing fixture, so the other was never asked anything. `remote.rs` exempts a frame larger than the whole backlog bound — a paste is whatever the clipboard holds — but only onto an *empty* queue: a second one arriving before the first has moved a byte is a link that has stopped reading, and letting it through too trades the bound for a heap that grows five megabytes at a time. The existing paste test drains the peer, so the bound is never reached and the empty-queue half never matters. Dropping it left a stalled link accepting oversize frames forever, and nothing failed. `log.rs::load_page` calls a page complete only when git answered with fewer commits than asked for *and* the parse read everything git answered with. The truncation half had a test — of `parse_log`, whose doc comment promises `load_page` turns the flag into `complete: false` while asserting only the flag. Nothing checked the promise. A graph cut at MAX_RECORD would have read as the end of history and frozen paging there, the commits below it unreachable with nothing on screen to say why. Both tests fail against the mutation and pass against the code as written. No production change: the conditions were right, only unheld.
This commit is contained in:
@@ -2112,6 +2112,53 @@ mod tests {
|
||||
assert!(run(host, repo, &["commit", "--quiet", "-m", message]));
|
||||
}
|
||||
|
||||
/// The other half of `a_stream_the_parse_cannot_finish_is_never_called_complete`,
|
||||
/// which asserted only that the *parse* raises the flag. What the flag is
|
||||
/// for is `load_page`, and both halves of its test are needed: git answered
|
||||
/// with fewer commits than asked for, which on its own reads as the end of
|
||||
/// history, *and* a record the parse had to drop. Taking the count alone
|
||||
/// would call a graph missing its middle complete, and paging would stop
|
||||
/// there for good — the history below it unreachable, with nothing on
|
||||
/// screen to say so.
|
||||
#[test]
|
||||
fn a_page_the_parse_had_to_cut_is_not_the_end_of_history() {
|
||||
let host = crate::host::local::LocalHost::new();
|
||||
let Some(scratch) = scratch("cut-page") else {
|
||||
return;
|
||||
};
|
||||
let repo = scratch.0.as_path();
|
||||
if !init_repo(&*host, repo) {
|
||||
return;
|
||||
}
|
||||
commit_file(&*host, repo, "a.txt", "1\n", "first");
|
||||
|
||||
// A commit message past MAX_RECORD, which the splitter drops whole.
|
||||
// Written through a file: an argument this size is over the exec limit
|
||||
// on macOS, and would fail as a bad command rather than a big commit.
|
||||
let huge = repo.join("msg.txt");
|
||||
std::fs::write(&huge, "z".repeat(super::super::MAX_RECORD + 1)).unwrap();
|
||||
std::fs::write(repo.join("b.txt"), "2\n").unwrap();
|
||||
assert!(run(&*host, repo, &["add", "--", "b.txt"]));
|
||||
assert!(run(
|
||||
&*host,
|
||||
repo,
|
||||
&["commit", "--quiet", "-F", huge.to_str().unwrap()]
|
||||
));
|
||||
|
||||
// Thirty asked for and two exist, so the count alone says complete.
|
||||
let page =
|
||||
load_page(&*host, repo, &GraphScope::Head, 30).expect("a repository was just created");
|
||||
assert_eq!(
|
||||
page.commits.len(),
|
||||
1,
|
||||
"the record over the bound is dropped, the readable one survives"
|
||||
);
|
||||
assert!(
|
||||
!page.complete,
|
||||
"a page the parse had to cut is not the end of history, however few commits came back"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_real_repository_answers_for_one_commit_and_its_files() {
|
||||
let host = crate::host::local::LocalHost::new();
|
||||
|
||||
@@ -3802,6 +3802,43 @@ mod tests {
|
||||
draining.join().unwrap();
|
||||
}
|
||||
|
||||
/// The exemption a huge frame gets is for *one* of them. A paste larger
|
||||
/// than the whole bound goes onto an empty queue and lifts the bound by its
|
||||
/// own size while it is outstanding — but a second one arriving before the
|
||||
/// first has moved a byte is not a paste, it is a link that has stopped
|
||||
/// taking input, and letting it through too would trade the bound for a
|
||||
/// heap that grows by five megabytes a go for as long as the peer is gone.
|
||||
///
|
||||
/// The empty-queue half of that rule is the whole of it: without it every
|
||||
/// oversize frame is exempt, and a stalled link accepts them forever.
|
||||
#[test]
|
||||
fn a_second_oversize_frame_onto_a_stalled_link_is_still_a_backlog() {
|
||||
crate::core::config::pin_test_config_dir();
|
||||
let (client_side, daemon_side) = UnixStream::pair().unwrap();
|
||||
let term = RemoteTerminal::from_stream(client_side, TermSize::new(80, 24)).unwrap();
|
||||
|
||||
// Held open and never read from: the peer is parked, not gone. A closed
|
||||
// peer would fail the write outright and report the link lost for a
|
||||
// different reason than the one under test.
|
||||
let frame = MAX_BACKLOG + (1 << 20);
|
||||
term.write(vec![b'x'; frame]);
|
||||
assert!(
|
||||
!term.exited_flag.load(Ordering::SeqCst),
|
||||
"the first oversize frame is a paste and goes through"
|
||||
);
|
||||
|
||||
// Nothing has drained, so the first frame is still charged in full —
|
||||
// the sender parks inside `write_all` and discounts a frame only once
|
||||
// it is out. The bound stands at MAX_BACKLOG + this frame, and a second
|
||||
// frame of the same size is over it.
|
||||
term.write(vec![b'x'; frame]);
|
||||
assert!(
|
||||
term.exited_flag.load(Ordering::SeqCst),
|
||||
"a second oversize frame with the first still outstanding is a link nothing is reading"
|
||||
);
|
||||
drop(daemon_side);
|
||||
}
|
||||
|
||||
/// Input the link refuses used to vanish: `write` threw the error away, so a
|
||||
/// pane whose daemon had stopped reading kept taking keystrokes into
|
||||
/// nothing. The refusal now marks the pane exited by the reader's own signal
|
||||
|
||||
Reference in New Issue
Block a user