11use crate :: common:: actions:: when;
22use crate :: common:: assertions:: then;
33use crate :: common:: setup:: given_an_active_session;
4- use hotfix:: message:: FixMessage ;
4+ use crate :: common:: test_messages:: { TestMessage , replace_field_value} ;
5+ use hotfix:: message:: { FixMessage , generate_message} ;
6+ use hotfix:: session:: Status ;
57use hotfix_message:: dict:: { FieldLocation , FixDatatype } ;
68use hotfix_message:: fix44:: MSG_TYPE ;
79use hotfix_message:: message:: Message ;
810use hotfix_message:: { HardCodedFixFieldDefinition , Part , fix44} ;
911
12+ /// Tests that when a counterparty sends a message containing an invalid/unrecognised field,
13+ /// the session rejects the message by sending a Reject (MsgType=3) message back.
1014#[ tokio:: test]
1115async fn test_message_with_invalid_field_gets_rejected ( ) {
1216 let ( session, mut mock_counterparty) = given_an_active_session ( ) . await ;
@@ -22,6 +26,39 @@ async fn test_message_with_invalid_field_gets_rejected() {
2226 then ( & mut mock_counterparty) . gets_disconnected ( ) . await ;
2327}
2428
29+ /// Tests that when a counterparty sends a garbled message with an invalid body length,
30+ /// the session silently ignores it and detects a sequence gap when the next valid message arrives.
31+ #[ tokio:: test]
32+ async fn test_garbled_message_with_invalid_target_comp_id_gets_ignored ( ) {
33+ let ( session, mut mock_counterparty) = given_an_active_session ( ) . await ;
34+
35+ // counterparty sends a message with invalid body length, which constitutes a garbled message
36+ let garbled_message = build_execution_report_with_incorrect_body_length (
37+ "dummy-acceptor" ,
38+ "dummy-initiator" ,
39+ mock_counterparty. next_target_sequence_number ( ) ,
40+ ) ;
41+ when ( & mut mock_counterparty)
42+ . sends_raw_message ( garbled_message)
43+ . await ;
44+
45+ // they then send a valid message
46+ when ( & mut mock_counterparty)
47+ . sends_message ( TestMessage :: dummy_execution_report ( ) )
48+ . await ;
49+
50+ // we then initiate a resend, having skipped the garbled message
51+ then ( & mut mock_counterparty)
52+ . receives ( |msg| assert_eq ! ( msg. header( ) . get:: <& str >( MSG_TYPE ) . unwrap( ) , "2" ) )
53+ . await ;
54+ then ( & session)
55+ . status_changes_to ( Status :: AwaitingResend )
56+ . await ;
57+
58+ when ( & session) . requests_disconnect ( ) . await ;
59+ then ( & mut mock_counterparty) . gets_disconnected ( ) . await ;
60+ }
61+
2562/// A new order message with an extra, invalid field.
2663#[ derive( Clone , Debug ) ]
2764struct ExecutionReportWithInvalidField {
@@ -83,3 +120,17 @@ pub const CUSTOM_FIELD: &HardCodedFixFieldDefinition = &HardCodedFixFieldDefinit
83120 data_type : FixDatatype :: String ,
84121 location : FieldLocation :: Body ,
85122} ;
123+
124+ fn build_execution_report_with_incorrect_body_length (
125+ sender_comp_id : & str ,
126+ target_comp_id : & str ,
127+ msg_seq_num : usize ,
128+ ) -> Vec < u8 > {
129+ let report = TestMessage :: dummy_execution_report ( ) ;
130+ let mut raw_message =
131+ generate_message ( sender_comp_id, target_comp_id, msg_seq_num, report) . unwrap ( ) ;
132+
133+ replace_field_value ( & mut raw_message, 9 , b"999" ) ;
134+
135+ raw_message
136+ }
0 commit comments