1- use hotfix:: message:: FixMessage ;
1+ use hotfix:: message:: { FixMessage , RawFixMessage } ;
22use hotfix:: session:: SessionRef ;
33use hotfix:: transport:: FixConnection ;
44use hotfix:: transport:: reader:: ReaderRef ;
55use hotfix:: transport:: writer:: { WriterMessage , WriterRef } ;
6+ use hotfix_message:: dict:: Dictionary ;
7+ use hotfix_message:: message:: { Config as MessageConfig , Message } ;
8+ use hotfix_message:: parsed_message:: ParsedMessage ;
69use std:: time:: Duration ;
10+ use tokio:: sync:: mpsc:: Receiver ;
711use tokio:: sync:: { mpsc, oneshot} ;
812
9- const DEFAULT_TIMEOUT : Duration = Duration :: from_secs ( 1 ) ;
13+ const DEFAULT_TIMEOUT : Duration = Duration :: from_millis ( 10 ) ;
1014
1115pub struct MockCounterparty {
12- // Receiver-End of the channel
13- receiver : mpsc:: UnboundedReceiver < WriterMessage > ,
14- // History of Received messages from the client
15- messages : Vec < WriterMessage > ,
16+ receiver : Receiver < WriterMessage > ,
17+ // History of received messages from the session
18+ messages : Vec < Message > ,
19+ dictionary : Dictionary ,
20+ message_config : MessageConfig ,
1621 _connection : FixConnection ,
1722 _dc_sender : oneshot:: Sender < ( ) > ,
1823}
1924
2025impl MockCounterparty {
2126 pub async fn start ( session_ref : SessionRef < impl FixMessage > ) -> Self {
22- let ( writer_ref, receiver) = Self :: spawn_writer ( ) ;
27+ let ( writer_ref, receiver) = Self :: create_writer ( ) ;
2328 let ( reader_ref, dc_sender) = Self :: create_reader ( ) ;
2429 let connection = FixConnection :: new ( writer_ref, reader_ref) ;
2530
@@ -28,65 +33,92 @@ impl MockCounterparty {
2833 Self {
2934 receiver,
3035 messages : vec ! [ ] ,
36+ dictionary : Dictionary :: fix44 ( ) ,
37+ message_config : MessageConfig :: default ( ) ,
3138 _connection : connection,
3239 _dc_sender : dc_sender,
3340 }
3441 }
3542
36- /// Listen to the next message on the channel
37- pub async fn get_next ( & mut self , timeout : Option < Duration > ) -> & WriterMessage {
38- let timeout = timeout. unwrap_or ( DEFAULT_TIMEOUT ) ;
39- let msg = tokio:: time:: timeout ( timeout, self . receiver . recv ( ) )
43+ /// Waits for and returns the next message received from the session.
44+ ///
45+ /// A `None` response indicates we have been disconnected, either through the channel
46+ /// dropping on the session's side, or through an explicit `Disconnect` message.
47+ async fn get_next ( & mut self ) -> Option < & Message > {
48+ self . receiver
49+ . recv ( )
4050 . await
41- . unwrap_or_else ( |_| panic ! ( "Message not received in less than {timeout:?}" ) )
42- . unwrap_or_else ( || panic ! ( "Received message is None" ) ) ;
43- self . messages . push ( msg) ;
44- self . messages . last ( ) . unwrap ( )
51+ . and_then ( |writer_message| match writer_message {
52+ WriterMessage :: SendMessage ( raw_message) => {
53+ let message = self . parse_message ( & raw_message) ;
54+ self . messages . push ( message) ;
55+ self . messages . last ( )
56+ }
57+ WriterMessage :: Disconnect => None ,
58+ } )
4559 }
4660
47- pub async fn assert_next < F > ( & mut self , timeout : Option < Duration > , assertion : F )
61+ fn parse_message ( & self , raw_message : & RawFixMessage ) -> Message {
62+ match Message :: from_bytes (
63+ & self . message_config ,
64+ & self . dictionary ,
65+ raw_message. as_bytes ( ) ,
66+ ) {
67+ ParsedMessage :: Valid ( valid_message) => valid_message,
68+ _ => {
69+ panic ! ( "only valid messages are supported in the mock counterparty" )
70+ }
71+ }
72+ }
73+
74+ pub async fn assert_next < F > ( & mut self , assertion : F )
4875 where
49- F : FnOnce ( & WriterMessage ) -> bool ,
76+ F : FnOnce ( & Message ) -> bool ,
5077 {
51- let msg = self . get_next ( timeout ) . await ;
52- assert ! ( assertion ( msg ) ) ;
78+ self . assert_next_with_timeout ( assertion , DEFAULT_TIMEOUT )
79+ . await ;
5380 }
5481
55- pub async fn assert_disconnected ( & mut self , timeout : Option < Duration > ) {
56- self . assert_next ( timeout, |msg| matches ! ( msg, & WriterMessage :: Disconnect ) )
57- . await ;
58- assert ! ( self . receiver. is_closed( ) ) ;
82+ pub async fn assert_next_with_timeout < F > ( & mut self , assertion : F , timeout : Duration )
83+ where
84+ F : FnOnce ( & Message ) -> bool ,
85+ {
86+ match tokio:: time:: timeout ( timeout, self . get_next ( ) ) . await {
87+ Ok ( Some ( message) ) => {
88+ assertion ( message) ;
89+ }
90+ Ok ( None ) => {
91+ panic ! ( "disconnected before receiving any message" ) ;
92+ }
93+ Err ( _) => {
94+ panic ! ( "timeout expired before receiving any message" ) ;
95+ }
96+ }
97+ }
98+
99+ pub async fn assert_disconnected ( & mut self ) {
100+ self . assert_disconnected_with_timeout ( DEFAULT_TIMEOUT ) . await ;
59101 }
60102
61- fn spawn_writer ( ) -> ( WriterRef , mpsc:: UnboundedReceiver < WriterMessage > ) {
62- // mock implementation to receive messages from the session
63- // and hold on to them for test assertions
64- let ( tx, rx) = mpsc:: unbounded_channel ( ) ;
65- let ( sender, mailbox) = mpsc:: channel ( 10 ) ;
66- tokio:: spawn ( Self :: run_writer ( mailbox, tx) ) ;
103+ pub async fn assert_disconnected_with_timeout ( & mut self , timeout : Duration ) {
104+ if tokio:: time:: timeout ( timeout, async {
105+ // keep consuming messages until a disconnect occurs
106+ while self . get_next ( ) . await . is_some ( ) { }
107+ } )
108+ . await
109+ . is_err ( )
110+ {
111+ panic ! ( "timeout expired before a disconnect occurred" ) ;
112+ }
113+ }
67114
68- ( WriterRef :: new ( sender) , rx)
115+ fn create_writer ( ) -> ( WriterRef , Receiver < WriterMessage > ) {
116+ let ( sender, receiver) = mpsc:: channel ( 10 ) ;
117+ ( WriterRef :: new ( sender) , receiver)
69118 }
70119
71120 fn create_reader ( ) -> ( ReaderRef , oneshot:: Sender < ( ) > ) {
72121 let ( dc_sender, dc_receiver) = oneshot:: channel ( ) ;
73122 ( ReaderRef :: new ( dc_receiver) , dc_sender)
74123 }
75-
76- async fn run_writer (
77- mut mailbox : mpsc:: Receiver < WriterMessage > ,
78- received_messages : mpsc:: UnboundedSender < WriterMessage > ,
79- ) {
80- while let Some ( msg) = mailbox. recv ( ) . await {
81- println ! ( "Received message from session: {msg:?}" ) ;
82- let disconnect = matches ! ( msg, WriterMessage :: Disconnect ) ;
83- if let Err ( e) = received_messages. send ( msg) {
84- panic ! ( "Failed to send message. Error: {e:?}" ) ;
85- }
86- if disconnect {
87- println ! ( "Disconnecting" ) ;
88- break ;
89- }
90- }
91- }
92124}
0 commit comments