From 897315d2d5dfd55f62c01b0c76af1e54ee3782df Mon Sep 17 00:00:00 2001 From: Pedro Henrique Penna Date: Wed, 21 Oct 2026 01:46:22 -0300 Subject: [PATCH] nvx-rs: build the NVXS unit tests' epoch identities with one function The unit tests of the NVXS session, protocol/nvxs/tests.rs and its guest and host modules, spelled out the identity of an epoch of their instance as a struct literal, Identity { epoch: N, ..IDENTITY }, at 13 sites, and as Identity { instance_id: INSTANCE, epoch: 0 } in the two lists of identities that lack an instance or an epoch. rustfmt spreads each literal over four lines, and a record() call that takes one over nine, so the epoch that a case varies hid in its layout. epoch(n), next to IDENTITY in tests.rs, now returns that identity, and all 15 sites call it: the RESET of host_stream; in the host's tests, the RESET out of sequence, the DATA of epochs 2 and 0, the RESET of epoch 0, the attachment at epoch 3 and its stale RESET, and the epoch that a reset starts; and in the guest's tests, the later and earlier RESETs, the DATA of epoch 2, and the epochs that a reset starts in the middle of a message and in a split stream. The two lists take epoch(0) for their second identity. Each record that a case encodes now fits on one line, and the tests lose 71 lines. Behavior is unchanged: epoch(n) returns the value of each literal that it replaces, so every test encodes the same records and expects the same events and errors. Only test code changes; the library, the CLI, and the guest binaries build from unchanged sources. The 32 protocol::nvxs unit tests cover the change, among them the 9 that build these identities, directly or through host_stream. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- nvx-rs/src/protocol/nvxs/tests.rs | 12 +++-- nvx-rs/src/protocol/nvxs/tests/guest.rs | 40 +++------------- nvx-rs/src/protocol/nvxs/tests/host.rs | 61 ++++--------------------- 3 files changed, 21 insertions(+), 92 deletions(-) diff --git a/nvx-rs/src/protocol/nvxs/tests.rs b/nvx-rs/src/protocol/nvxs/tests.rs index a5e6b7198..4fe4be1f0 100644 --- a/nvx-rs/src/protocol/nvxs/tests.rs +++ b/nvx-rs/src/protocol/nvxs/tests.rs @@ -24,6 +24,12 @@ const NONE: Identity = Identity { epoch: 0, }; +/// Returns the identity of `epoch` of the sessions' instance, such as an epoch that a RESET +/// starts, or epoch 0, which no session has. +fn epoch(epoch: u64) -> Identity { + Identity { epoch, ..IDENTITY } +} + fn hex(bytes: &[u8]) -> String { bytes.iter().map(|byte| format!("{byte:02x}")).collect() } @@ -127,17 +133,13 @@ fn feed( /// The broker's records to a host that attaches after waiting, receives three DATA records, and /// is reset: payloads of 1, 21, and 300 bytes, one of them with the magic inside. fn host_stream() -> Vec { - let next = Identity { - epoch: 2, - ..IDENTITY - }; [ record(RecordType::Wait, IDENTITY, 0, &[]), record(RecordType::Ready, IDENTITY, 1, &[]), record(RecordType::Data, IDENTITY, 2, b"x"), record(RecordType::Data, IDENTITY, 3, b"NVXS inside a payload"), record(RecordType::Data, IDENTITY, 4, &[0x5a; 300]), - record(RecordType::Reset, next, 5, &[]), + record(RecordType::Reset, epoch(2), 5, &[]), ] .concat() } diff --git a/nvx-rs/src/protocol/nvxs/tests/guest.rs b/nvx-rs/src/protocol/nvxs/tests/guest.rs index 747a8104c..75a5e3e8d 100644 --- a/nvx-rs/src/protocol/nvxs/tests/guest.rs +++ b/nvx-rs/src/protocol/nvxs/tests/guest.rs @@ -139,10 +139,7 @@ fn the_guest_checks_the_identity_of_each_reset() { instance_id: [0; 16], epoch: 1, }, - Identity { - instance_id: INSTANCE, - epoch: 0, - }, + epoch(0), ] { let mut guest = attaching_guest(); let reset = record(RecordType::Reset, identity, 0, &[]); @@ -163,23 +160,12 @@ fn the_guest_checks_the_identity_of_each_reset() { let reset = record(RecordType::Reset, IDENTITY, 1, &[]); assert_eq!(guest.receive(&reset), Err(expected)); let mut guest = active_guest(OUTER_RECEIVE_WINDOW); - let later = Identity { - epoch: 9, - ..IDENTITY - }; + let later = epoch(9); let reset = record(RecordType::Reset, later, 0, &[]); let event = Some(GuestEvent::Reset(later)); assert_eq!(guest.receive(&reset), Ok((reset.len(), event))); let mut stale = guest.clone(); - let earlier = record( - RecordType::Reset, - Identity { - epoch: 8, - ..IDENTITY - }, - 1, - &[], - ); + let earlier = record(RecordType::Reset, epoch(8), 1, &[]); let expected = SessionError::StaleEpoch { current: 9, actual: 8, @@ -246,15 +232,7 @@ fn the_guest_checks_the_sequence_and_identity_of_data() { }, ), ( - record( - RecordType::Data, - Identity { - epoch: 2, - ..IDENTITY - }, - 1, - b"x", - ), + record(RecordType::Data, epoch(2), 1, b"x"), SessionError::Epoch { expected: 1, actual: 2, @@ -393,10 +371,7 @@ fn a_reset_in_the_middle_of_a_message_abandons_it() { // The broker resets the session before the rest arrives, so the application abandons the // message, and the outstanding bytes of the old epoch need no credit. - let next = Identity { - epoch: 2, - ..IDENTITY - }; + let next = epoch(2); let reset = record(RecordType::Reset, next, 0, &[]); let event = Some(GuestEvent::Reset(next)); assert_eq!(guest.receive(&reset), Ok((reset.len(), event))); @@ -470,10 +445,7 @@ fn the_guest_session_closes_only_at_a_record_boundary() { #[test] fn the_guest_reports_the_same_events_for_every_split_of_its_stream() { - let next = Identity { - epoch: 2, - ..IDENTITY - }; + let next = epoch(2); let stream = [ record(RecordType::Reset, IDENTITY, 0, &[]), record(RecordType::Data, IDENTITY, 1, b"x"), diff --git a/nvx-rs/src/protocol/nvxs/tests/host.rs b/nvx-rs/src/protocol/nvxs/tests/host.rs index e7cc1da09..839f805a1 100644 --- a/nvx-rs/src/protocol/nvxs/tests/host.rs +++ b/nvx-rs/src/protocol/nvxs/tests/host.rs @@ -180,15 +180,11 @@ fn the_host_checks_the_brokers_sequence_numbers() { ); // DATA and RESET out of sequence after READY at 0. - let next = Identity { - epoch: 2, - ..IDENTITY - }; for (encoded, actual) in [ (record(RecordType::Data, IDENTITY, 0, b"x"), 0), (record(RecordType::Data, IDENTITY, 2, b"x"), 2), (record(RecordType::Data, IDENTITY, u64::MAX, b"x"), u64::MAX), - (record(RecordType::Reset, next, 0, &[]), 0), + (record(RecordType::Reset, epoch(2), 0, &[]), 0), ] { let mut host = attached_host(); let expected = SessionError::Sequence { @@ -217,10 +213,7 @@ fn the_host_checks_the_sessions_identity() { instance_id: [0; 16], epoch: 1, }, - Identity { - instance_id: INSTANCE, - epoch: 0, - }, + epoch(0), ] { let mut host = attaching_host(); let ready = record(RecordType::Ready, identity, 0, &[]); @@ -244,30 +237,14 @@ fn the_host_checks_the_sessions_identity() { instance_error.clone(), ), ( - record( - RecordType::Data, - Identity { - epoch: 2, - ..IDENTITY - }, - 1, - b"x", - ), + record(RecordType::Data, epoch(2), 1, b"x"), SessionError::Epoch { expected: 1, actual: 2, }, ), ( - record( - RecordType::Data, - Identity { - epoch: 0, - ..IDENTITY - }, - 1, - b"x", - ), + record(RecordType::Data, epoch(0), 1, b"x"), SessionError::Epoch { expected: 1, actual: 0, @@ -285,15 +262,7 @@ fn the_host_checks_the_sessions_identity() { }, ), ( - record( - RecordType::Reset, - Identity { - epoch: 0, - ..IDENTITY - }, - 1, - &[], - ), + record(RecordType::Reset, epoch(0), 1, &[]), SessionError::MissingIdentity(RecordType::Reset), ), ]; @@ -304,19 +273,8 @@ fn the_host_checks_the_sessions_identity() { } // A reset never moves an instance's epoch back. - let mut host = attached_host_at(Identity { - epoch: 3, - ..IDENTITY - }); - let reset = record( - RecordType::Reset, - Identity { - epoch: 2, - ..IDENTITY - }, - 1, - &[], - ); + let mut host = attached_host_at(epoch(3)); + let reset = record(RecordType::Reset, epoch(2), 1, &[]); let expected = SessionError::StaleEpoch { current: 3, actual: 2, @@ -327,10 +285,7 @@ fn the_host_checks_the_sessions_identity() { #[test] fn a_reset_ends_the_hosts_attachment() { let mut host = attached_host(); - let next = Identity { - epoch: 2, - ..IDENTITY - }; + let next = epoch(2); let stream = [ record(RecordType::Data, IDENTITY, 1, b"x"), record(RecordType::Reset, next, 2, &[]),