From c6558fe615c70390ce4aa69e556676ae4872dcae Mon Sep 17 00:00:00 2001 From: Xiaoyang Han Date: Thu, 8 Oct 2026 02:27:45 +0800 Subject: [PATCH] test(mst2): decode the first streamed CHUNK as a single frame The per-frame revocation regression receives one CHUNK DATA before revoking its lease. Parse that DATA with parse_frame, assert exact consumed length and the real map/content IDs, chunk index and bytes. Keep the original successful DELETE, next DATA error and terminal None assertions. Feed only the actual received bytes to the complete stream parser and require its exact missing END/ERROR rejection. No synthetic END, production change or weakened decoder. This repairs the sole failure in the exact #71 full suite (2396 passed, 1 failed, 2 ignored). The original fixture has no isolated credit observer; existing separate ownership regressions remain unchanged. The corrected source has not yet run natively. --- .../router/snapshot_chunks_bounded_tests.rs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/api/router/snapshot_chunks_bounded_tests.rs b/src/api/router/snapshot_chunks_bounded_tests.rs index bbbd14c4..8d22a68d 100644 --- a/src/api/router/snapshot_chunks_bounded_tests.rs +++ b/src/api/router/snapshot_chunks_bounded_tests.rs @@ -450,10 +450,16 @@ async fn mst2_budgeted_chunk_body_preserves_per_frame_revocation_and_no_end() { assert_eq!(response.status(), 200); let mut data = response.into_body().into_data_stream(); let first = data.next().await.unwrap().unwrap(); - assert!(matches!( - parse_stream(&first).unwrap().as_slice(), - [Frame::Chunk(_)] - )); + let (frame, consumed) = mst2_codec::treeframe::parse_frame(&first).unwrap(); + assert_eq!(consumed, first.len()); + let Frame::Chunk(chunk) = frame else { + panic!("first DATA must contain exactly one CHUNK frame"); + }; + assert_eq!(format!("sha256:{}", hex_of(&chunk.map_id)), map_id); + assert_eq!(chunk.file_content_id, fixture.digest); + assert_eq!(chunk.chunk_index, 0); + assert_eq!(chunk.chunk_bytes, fixture.raw[..CHUNK_SIZE as usize]); + let received = first.to_vec(); let revoked = fixture .app .clone() @@ -470,4 +476,10 @@ async fn mst2_budgeted_chunk_body_preserves_per_frame_revocation_and_no_end() { assert_eq!(revoked.status(), 200); assert!(data.next().await.unwrap().is_err()); assert!(data.next().await.is_none()); + assert!(matches!( + parse_stream(&received), + Err(mst2_codec::CodecError::BadOrdering( + "stream missing END/ERROR frame" + )) + )); }