@@ -236,3 +236,153 @@ fn handle_error(e: ServerError, transaction_id: TransactionId) -> Response {
236236        message :  message. into ( ) , 
237237    } ) 
238238} 
239+ 
240+ #[ cfg( test) ]  
241+ mod  tests { 
242+     use  std:: { 
243+         net:: { IpAddr ,  Ipv4Addr ,  Ipv6Addr ,  SocketAddr } , 
244+         sync:: Arc , 
245+     } ; 
246+ 
247+     use  tokio:: sync:: { mpsc:: error:: SendError ,  RwLock ,  RwLockReadGuard } ; 
248+ 
249+     use  crate :: { 
250+         protocol:: utils:: get_connection_id, 
251+         statistics:: { 
252+             StatsTracker ,  TrackerStatistics ,  TrackerStatisticsEvent ,  TrackerStatisticsEventSender ,  TrackerStatisticsRepository , 
253+             TrackerStatsService , 
254+         } , 
255+         tracker:: tracker:: TorrentTracker , 
256+         udp:: handle_connect, 
257+         Configuration , 
258+     } ; 
259+     use  aquatic_udp_protocol:: { ConnectRequest ,  ConnectResponse ,  Response ,  TransactionId } ; 
260+     use  async_trait:: async_trait; 
261+ 
262+     fn  default_tracker_config ( )  -> Arc < Configuration >  { 
263+         Arc :: new ( Configuration :: default ( ) ) 
264+     } 
265+ 
266+     fn  initialized_tracker ( )  -> Arc < TorrentTracker >  { 
267+         Arc :: new ( TorrentTracker :: new ( default_tracker_config ( ) ,  Box :: new ( StatsTracker :: new_running_instance ( ) ) ) . unwrap ( ) ) 
268+     } 
269+ 
270+     fn  sample_remote_addr ( )  -> SocketAddr  { 
271+         SocketAddr :: new ( IpAddr :: V4 ( Ipv4Addr :: new ( 127 ,  0 ,  0 ,  1 ) ) ,  8080 ) 
272+     } 
273+ 
274+     fn  sample_connect_request ( )  -> ConnectRequest  { 
275+         ConnectRequest  { 
276+             transaction_id :  TransactionId ( 0i32 ) , 
277+         } 
278+     } 
279+ 
280+     fn  sample_ipv4_socket_address ( )  -> SocketAddr  { 
281+         SocketAddr :: new ( IpAddr :: V4 ( Ipv4Addr :: new ( 127 ,  0 ,  0 ,  1 ) ) ,  8080 ) 
282+     } 
283+ 
284+     fn  sample_ipv6_socket_address ( )  -> SocketAddr  { 
285+         SocketAddr :: new ( IpAddr :: V6 ( Ipv6Addr :: new ( 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  1 ) ) ,  8080 ) 
286+     } 
287+ 
288+     #[ tokio:: test]  
289+     async  fn  a_connect_response_should_contain_the_same_transaction_id_as_the_connect_request ( )  { 
290+         let  request = ConnectRequest  { 
291+             transaction_id :  TransactionId ( 0i32 ) , 
292+         } ; 
293+ 
294+         let  response = handle_connect ( sample_remote_addr ( ) ,  & request,  initialized_tracker ( ) ) 
295+             . await 
296+             . unwrap ( ) ; 
297+ 
298+         assert_eq ! ( 
299+             response, 
300+             Response :: Connect ( ConnectResponse  { 
301+                 connection_id:  get_connection_id( & sample_remote_addr( ) ) , 
302+                 transaction_id:  request. transaction_id
303+             } ) 
304+         ) ; 
305+     } 
306+ 
307+     #[ tokio:: test]  
308+     async  fn  a_connect_response_should_contain_a_new_connection_id ( )  { 
309+         let  request = ConnectRequest  { 
310+             transaction_id :  TransactionId ( 0i32 ) , 
311+         } ; 
312+ 
313+         let  response = handle_connect ( sample_remote_addr ( ) ,  & request,  initialized_tracker ( ) ) 
314+             . await 
315+             . unwrap ( ) ; 
316+ 
317+         assert_eq ! ( 
318+             response, 
319+             Response :: Connect ( ConnectResponse  { 
320+                 connection_id:  get_connection_id( & sample_remote_addr( ) ) , 
321+                 transaction_id:  request. transaction_id
322+             } ) 
323+         ) ; 
324+     } 
325+ 
326+     struct  TrackerStatsServiceMock  { 
327+         stats :  Arc < RwLock < TrackerStatistics > > , 
328+         expected_event :  Option < TrackerStatisticsEvent > , 
329+     } 
330+ 
331+     impl  TrackerStatsServiceMock  { 
332+         fn  new ( )  -> Self  { 
333+             Self  { 
334+                 stats :  Arc :: new ( RwLock :: new ( TrackerStatistics :: new ( ) ) ) , 
335+                 expected_event :  None , 
336+             } 
337+         } 
338+ 
339+         fn  should_throw_event ( & mut  self ,  expected_event :  TrackerStatisticsEvent )  { 
340+             self . expected_event  = Some ( expected_event) ; 
341+         } 
342+     } 
343+ 
344+     #[ async_trait]  
345+     impl  TrackerStatisticsEventSender  for  TrackerStatsServiceMock  { 
346+         async  fn  send_event ( & self ,  _event :  TrackerStatisticsEvent )  -> Option < Result < ( ) ,  SendError < TrackerStatisticsEvent > > >  { 
347+             if  self . expected_event . is_some ( )  { 
348+                 assert_eq ! ( _event,  * self . expected_event. as_ref( ) . unwrap( ) ) ; 
349+             } 
350+             None 
351+         } 
352+     } 
353+ 
354+     #[ async_trait]  
355+     impl  TrackerStatisticsRepository  for  TrackerStatsServiceMock  { 
356+         async  fn  get_stats ( & self )  -> RwLockReadGuard < ' _ ,  TrackerStatistics >  { 
357+             self . stats . read ( ) . await 
358+         } 
359+     } 
360+ 
361+     impl  TrackerStatsService  for  TrackerStatsServiceMock  { } 
362+ 
363+     #[ tokio:: test]  
364+     async  fn  it_should_send_the_upd4_connect_event_when_a_client_tries_to_connect_using_a_ip4_socket_address ( )  { 
365+         let  mut  tracker_stats_service = Box :: new ( TrackerStatsServiceMock :: new ( ) ) ; 
366+ 
367+         let  client_socket_address = sample_ipv4_socket_address ( ) ; 
368+         tracker_stats_service. should_throw_event ( TrackerStatisticsEvent :: Udp4Connect ) ; 
369+ 
370+         let  torrent_tracker = Arc :: new ( TorrentTracker :: new ( default_tracker_config ( ) ,  tracker_stats_service) . unwrap ( ) ) ; 
371+         handle_connect ( client_socket_address,  & sample_connect_request ( ) ,  torrent_tracker) 
372+             . await 
373+             . unwrap ( ) ; 
374+     } 
375+ 
376+     #[ tokio:: test]  
377+     async  fn  it_should_send_the_upd6_connect_event_when_a_client_tries_to_connect_using_a_ip6_socket_address ( )  { 
378+         let  mut  tracker_stats_service = Box :: new ( TrackerStatsServiceMock :: new ( ) ) ; 
379+ 
380+         let  client_socket_address = sample_ipv6_socket_address ( ) ; 
381+         tracker_stats_service. should_throw_event ( TrackerStatisticsEvent :: Udp6Connect ) ; 
382+ 
383+         let  torrent_tracker = Arc :: new ( TorrentTracker :: new ( default_tracker_config ( ) ,  tracker_stats_service) . unwrap ( ) ) ; 
384+         handle_connect ( client_socket_address,  & sample_connect_request ( ) ,  torrent_tracker) 
385+             . await 
386+             . unwrap ( ) ; 
387+     } 
388+ } 
0 commit comments