oscarArismendi opened a new pull request, #3182:
URL: https://github.com/apache/iggy/pull/3182

   ## Which issue does this PR close?
   
   Closes #3128
   
   ## Rationale
   
   The issue reported that `deserializeVoidResponse` had been changed from 
`status === 0 && data.length === 0` to just `status === 0,` removing the 
protocol safety check for void commands. However, when I inspected the current 
code, the `data.length === 0 `check was already present. Tracing further up the 
call chain, I found the real root cause: `handleResponse` was using` 
r.subarray(8)` to slice the payload, ignoring the length field the server 
sends. This meant data could include trailing bytes from the next response in 
the buffer, making the `data.length === 0` check unreliable regardless of 
whether it was there or not. `SendMessages` was a separate problem, it used 
`deserializeVoidResponse` even though the server returns a non-empty payload 
for that command. Instead of weakening the global void check to accommodate it, 
it now has its own `deserializeStatusResponse` that only checks `status === 0`
   
   ## What changed?
   
   `handleResponse` in `client.utils.ts `was using `r.subarray(8)` to slice the 
payload, ignoring the length field the server sends. This meant data could 
include trailing bytes from the next response in the buffer.
   
   `SendMessages` was using `deserializeVoidResponse` which checks `data.length 
=== 0` even though the server returns a non-empty payload for that command. 
Instead of weakening the global void check, it now has its own 
`deserializeStatusResponse` that only checks `status === 0`.
   
   ## Local Execution
   
   Unit (npm run test:unit) — all pass. Two new test suites were added to 
client.utils.test.ts:
   
   `handleResponse`: proves that with` length=0` and trailing bytes, data is 
now empty
   `deserializeStatusResponse`: proves it returns true with non-empty data (key 
difference from `deserializeVoidResponse`)
   A deserialize block was also added to send-messages.command.test.ts proving 
SendMessages accepts non-empty server payloads.
   
   <details><summary>Unit test screenshot</summary>
   <p>
   <img width="1813" height="839" alt="Screenshot 2026-04-26 at 7 47 26 PM" 
src="https://github.com/user-attachments/assets/26a5965d-3a89-4c78-970a-27bfd4c4272e";
 />
   </p>
   </details> 
   
   E2E (npm run test:e2e) — 57/58 pass. The one failure (`getClusterMetadata`) 
is pre-existing and unrelated, it expects a 2-node cluster which requires` 
IGGY_CLUSTER_ENABLED=true` and two running server instances, matching how CI 
runs it. The TLS test is skipped locally for the same infrastructure reason.
   
   <details><summary>E2E test screenshot</summary>
   <p>
   <img width="1842" height="821" alt="Screenshot 2026-04-26 at 9 01 36 PM" 
src="https://github.com/user-attachments/assets/d38ec25a-3671-4842-9d4d-162ef1818c58";
 />
   </p>
   </details> 
   
   BDD (`npm run test:bdd`) the main scenario (`Create stream and send 
messages`) initially failed because stream IDs were hardcoded as `0` in the 
step definitions instead of using the dynamically assigned IDs from the server. 
This was fixed by using `this.stream.id `and` this.topic.id` in the step 
implementations, and making the Given I have no streams in the system step 
delete any existing streams before asserting a clean state. The scenario now 
passes end-to-end, including `SendMessages` against a real server. Four 
cluster/leader redirection scenarios remain undefined, their step definitions 
don't exist yet in any SDK.
   
   <details><summary>BDD test screenshot</summary>
   <p>
   <img width="1827" height="836" alt="Screenshot 2026-04-26 at 9 27 54 PM" 
src="https://github.com/user-attachments/assets/d324e56a-d097-4ec1-9438-a4b1d7f23b54";
 />
   </p>
   </details> 
   
   ## AI Usage
   
   If AI tools were used, please answer:
   1. Which tools? **Claude (claude.ai/code)**
   2. Scope of usage? **Used for codebase exploration, understanding the binary 
protocol and TCP buffer framing, writing unit tests**
   3. How did you verify the generated code works correctly? **Tests were run 
locally against a real iggy server built from source. Unit tests were written 
first to prove the bug, then the fix was applied to make them pass. E2E and BDD 
tests were run against a locally compiled server**
   4. Can you explain every line of the code if asked? **Yes**
   
   ## Notes
   During investigation I initially assumed SendMessages required a dedicated 
deserializer because the server might return a non-empty response payload, the 
[CreateMessage type has a payload 
field](https://github.com/oscarArismendi/iggy/blob/fix%2FdeserializeVoidResponse-now-ignores-payload-length-for-all-void-commands/foreign/node/src/wire/message/message.utils.ts#L40-L47),
 which led to some confusion and the issue description appear to be pointing in 
that direction as well. However, that payload is the outgoing message content 
sent in the request, not the server response.
   
   Both the Rust server source ([send_empty_ok_response() in 
send_messages_handler.rs](https://github.com/oscarArismendi/iggy/blob/fix%2FdeserializeVoidResponse-now-ignores-payload-length-for-all-void-commands/core/server/src/binary/handlers/messages/send_messages_handler.rs#L202-L203))
 and live debug logs (`ONDATA object true 8 false` exactly 8 bytes = 4 status + 
4 length, zero payload) confirm the response is always empty. With 
handleResponse correctly bounding data by length, `SendMessages` would work 
fine with `deserializeVoidResponse`.
   
   `deserializeStatusResponse` was kept as a defensive measure in case server 
behaviour changes in the future, but it is not strictly necessary given the 
current implementation, just let me know if I should removed it.
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to