@@ -191,10 +191,20 @@ impl Swarm {
191191 }
192192
193193 /// Returns true if the swarm meets the retention policy, meaning that
194- /// it should be kept in the tracker .
194+ /// it should be kept in the list of swarms .
195195 #[ must_use]
196196 pub fn meets_retaining_policy ( & self , policy : & TrackerPolicy ) -> bool {
197- !( policy. remove_peerless_torrents && self . is_empty ( ) )
197+ !self . should_be_removed ( policy)
198+ }
199+
200+ fn should_be_removed ( & self , policy : & TrackerPolicy ) -> bool {
201+ // If the policy is to remove peerless torrents and the swarm is empty (no peers),
202+ ( policy. remove_peerless_torrents && self . is_empty ( ) )
203+ // but not when the policy is to persist torrent stats and the
204+ // torrent has been downloaded at least once.
205+ // (because the only way to store the counter is to keep the swarm in memory.
206+ // See https://github.com/torrust/torrust-tracker/issues/1502)
207+ && !( policy. persistent_torrent_completed_stat && self . metadata ( ) . downloaded > 0 )
198208 }
199209}
200210
@@ -205,7 +215,6 @@ mod tests {
205215 use std:: sync:: Arc ;
206216
207217 use aquatic_udp_protocol:: PeerId ;
208- use torrust_tracker_configuration:: TrackerPolicy ;
209218 use torrust_tracker_primitives:: peer:: fixture:: PeerBuilder ;
210219 use torrust_tracker_primitives:: swarm_metadata:: SwarmMetadata ;
211220 use torrust_tracker_primitives:: DurationSinceUnixEpoch ;
@@ -376,28 +385,101 @@ mod tests {
376385 assert_eq ! ( swarm. len( ) , 1 ) ;
377386 }
378387
379- #[ test]
380- fn it_should_be_kept_when_empty_if_the_tracker_policy_is_not_to_remove_peerless_torrents ( ) {
381- let empty_swarm = Swarm :: default ( ) ;
388+ mod for_retaining_policy {
382389
383- let policy = TrackerPolicy {
384- remove_peerless_torrents : false ,
385- ..Default :: default ( )
386- } ;
390+ use torrust_tracker_configuration:: TrackerPolicy ;
391+ use torrust_tracker_primitives:: peer:: fixture:: PeerBuilder ;
387392
388- assert ! ( empty_swarm. meets_retaining_policy( & policy) ) ;
389- }
393+ use crate :: Swarm ;
390394
391- # [ test ]
392- fn it_should_be_removed_when_empty_if_the_tracker_policy_is_to_remove_peerless_torrents ( ) {
393- let empty_swarm = Swarm :: default ( ) ;
395+ fn empty_swarm ( ) -> Swarm {
396+ Swarm :: default ( )
397+ }
394398
395- let policy = TrackerPolicy {
396- remove_peerless_torrents : true ,
397- ..Default :: default ( )
398- } ;
399+ fn not_empty_swarm ( ) -> Swarm {
400+ let mut swarm = Swarm :: default ( ) ;
401+ swarm. upsert_peer ( PeerBuilder :: default ( ) . build ( ) . into ( ) , & mut false ) ;
402+ swarm
403+ }
404+
405+ fn not_empty_swarm_with_downloads ( ) -> Swarm {
406+ let mut swarm = Swarm :: default ( ) ;
407+
408+ let mut peer = PeerBuilder :: leecher ( ) . build ( ) ;
409+ let mut downloads_increased = false ;
410+
411+ swarm. upsert_peer ( peer. into ( ) , & mut downloads_increased) ;
412+
413+ peer. event = aquatic_udp_protocol:: AnnounceEvent :: Completed ;
414+
415+ swarm. upsert_peer ( peer. into ( ) , & mut downloads_increased) ;
416+
417+ assert ! ( swarm. metadata( ) . downloads( ) > 0 ) ;
418+
419+ swarm
420+ }
421+
422+ fn remove_peerless_torrents_policy ( ) -> TrackerPolicy {
423+ TrackerPolicy {
424+ remove_peerless_torrents : true ,
425+ ..Default :: default ( )
426+ }
427+ }
428+
429+ fn don_not_remove_peerless_torrents_policy ( ) -> TrackerPolicy {
430+ TrackerPolicy {
431+ remove_peerless_torrents : false ,
432+ ..Default :: default ( )
433+ }
434+ }
399435
400- assert ! ( !empty_swarm. meets_retaining_policy( & policy) ) ;
436+ mod when_removing_peerless_torrents_is_enabled {
437+
438+ use torrust_tracker_configuration:: TrackerPolicy ;
439+
440+ use crate :: swarm:: tests:: for_retaining_policy:: {
441+ empty_swarm, not_empty_swarm, not_empty_swarm_with_downloads, remove_peerless_torrents_policy,
442+ } ;
443+
444+ #[ test]
445+ fn it_should_be_removed_if_the_swarm_is_empty ( ) {
446+ assert ! ( empty_swarm( ) . should_be_removed( & remove_peerless_torrents_policy( ) ) ) ;
447+ }
448+
449+ #[ test]
450+ fn it_should_not_be_removed_is_the_swarm_is_not_empty ( ) {
451+ assert ! ( !not_empty_swarm( ) . should_be_removed( & remove_peerless_torrents_policy( ) ) ) ;
452+ }
453+
454+ #[ test]
455+ fn it_should_not_be_removed_even_if_the_swarm_is_empty_if_we_need_to_track_stats_for_downloads_and_there_has_been_downloads (
456+ ) {
457+ let policy = TrackerPolicy {
458+ remove_peerless_torrents : true ,
459+ persistent_torrent_completed_stat : true ,
460+ ..Default :: default ( )
461+ } ;
462+
463+ assert ! ( !not_empty_swarm_with_downloads( ) . should_be_removed( & policy) ) ;
464+ }
465+ }
466+
467+ mod when_removing_peerless_torrents_is_disabled {
468+
469+ use crate :: swarm:: tests:: for_retaining_policy:: {
470+ don_not_remove_peerless_torrents_policy, empty_swarm, not_empty_swarm,
471+ } ;
472+
473+ #[ test]
474+ fn it_should_not_be_removed_even_if_the_swarm_is_empty ( ) {
475+ assert ! ( !empty_swarm( ) . should_be_removed( & don_not_remove_peerless_torrents_policy( ) ) ) ;
476+ }
477+
478+ #[ test]
479+ fn it_should_not_be_removed_is_the_swarm_is_not_empty ( ) {
480+ assert ! ( !not_empty_swarm( ) . should_be_removed( & don_not_remove_peerless_torrents_policy( ) ) ) ;
481+ }
482+ }
401483 }
402484
403485 #[ test]
0 commit comments