@@ -106,3 +106,96 @@ impl MessagePublisher for RetryPublisher {
106106 self
107107 }
108108}
109+
110+ #[ cfg( test) ]
111+ mod tests {
112+ use super :: * ;
113+ use crate :: traits:: MessagePublisher ;
114+ use crate :: CanonicalMessage ;
115+ use anyhow:: anyhow;
116+ use async_trait:: async_trait;
117+ use std:: any:: Any ;
118+ use std:: sync:: { Arc , Mutex } ;
119+
120+ #[ derive( Clone ) ]
121+ struct MockPublisher {
122+ attempts : Arc < Mutex < usize > > ,
123+ succeed_after : usize ,
124+ }
125+
126+ #[ async_trait]
127+ impl MessagePublisher for MockPublisher {
128+ async fn send ( & self , _msg : CanonicalMessage ) -> anyhow:: Result < Option < CanonicalMessage > > {
129+ let mut attempts = self . attempts . lock ( ) . unwrap ( ) ;
130+ * attempts += 1 ;
131+ if * attempts > self . succeed_after {
132+ Ok ( None )
133+ } else {
134+ Err ( anyhow ! ( "Simulated error" ) )
135+ }
136+ }
137+
138+ async fn send_batch (
139+ & self ,
140+ _messages : Vec < CanonicalMessage > ,
141+ ) -> anyhow:: Result < ( Option < Vec < CanonicalMessage > > , Vec < CanonicalMessage > ) > {
142+ let mut attempts = self . attempts . lock ( ) . unwrap ( ) ;
143+ * attempts += 1 ;
144+ if * attempts > self . succeed_after {
145+ Ok ( ( None , Vec :: new ( ) ) )
146+ } else {
147+ Err ( anyhow ! ( "Simulated batch error" ) )
148+ }
149+ }
150+
151+ fn as_any ( & self ) -> & dyn Any {
152+ self
153+ }
154+ }
155+
156+ #[ tokio:: test]
157+ async fn test_retry_success ( ) {
158+ let attempts = Arc :: new ( Mutex :: new ( 0 ) ) ;
159+ let mock = MockPublisher {
160+ attempts : attempts. clone ( ) ,
161+ succeed_after : 2 , // Fails 2 times, succeeds on 3rd
162+ } ;
163+
164+ let config = RetryMiddleware {
165+ max_attempts : 5 ,
166+ initial_interval_ms : 1 ,
167+ max_interval_ms : 10 ,
168+ multiplier : 1.0 ,
169+ } ;
170+
171+ let retry_publisher = RetryPublisher :: new ( Box :: new ( mock) , config) ;
172+ let msg = CanonicalMessage :: new ( vec ! [ ] , None ) ;
173+
174+ let result = retry_publisher. send ( msg) . await ;
175+ assert ! ( result. is_ok( ) ) ;
176+ assert_eq ! ( * attempts. lock( ) . unwrap( ) , 3 ) ;
177+ }
178+
179+ #[ tokio:: test]
180+ async fn test_retry_exhaustion ( ) {
181+ let attempts = Arc :: new ( Mutex :: new ( 0 ) ) ;
182+ let mock = MockPublisher {
183+ attempts : attempts. clone ( ) ,
184+ succeed_after : 10 ,
185+ } ;
186+
187+ let config = RetryMiddleware {
188+ max_attempts : 3 ,
189+ initial_interval_ms : 1 ,
190+ max_interval_ms : 10 ,
191+ multiplier : 1.0 ,
192+ } ;
193+
194+ let retry_publisher = RetryPublisher :: new ( Box :: new ( mock) , config) ;
195+ let msg = CanonicalMessage :: new ( vec ! [ ] , None ) ;
196+
197+ let result = retry_publisher. send ( msg) . await ;
198+ assert ! ( result. is_err( ) ) ;
199+ assert_eq ! ( * attempts. lock( ) . unwrap( ) , 3 ) ;
200+ }
201+ }
0 commit comments