1
- use std:: hash:: { DefaultHasher , Hash } ;
1
+ use std:: hash:: { DefaultHasher , Hash , Hasher } ;
2
2
3
3
use rstest:: { fixture, rstest} ;
4
4
use torrust_tracker_primitives:: announce_event:: AnnounceEvent ;
5
5
use torrust_tracker_primitives:: info_hash:: InfoHash ;
6
- use torrust_tracker_primitives:: NumberOfBytes ;
6
+ use torrust_tracker_primitives:: { NumberOfBytes , PersistentTorrents } ;
7
7
use torrust_tracker_torrent_repository:: entry:: Entry as _;
8
8
use torrust_tracker_torrent_repository:: repository:: { RwLockStd , RwLockTokio } ;
9
9
use torrust_tracker_torrent_repository:: EntrySingle ;
@@ -104,6 +104,37 @@ fn three() -> Entries {
104
104
]
105
105
}
106
106
107
+ #[ fixture]
108
+ fn persistent_empty ( ) -> PersistentTorrents {
109
+ PersistentTorrents :: default ( )
110
+ }
111
+
112
+ #[ fixture]
113
+ fn persistent_single ( ) -> PersistentTorrents {
114
+ let hash = & mut DefaultHasher :: default ( ) ;
115
+
116
+ hash. write_u8 ( 1 ) ;
117
+ let t = [ ( InfoHash :: from ( & hash. clone ( ) ) , 0_u32 ) ] ;
118
+
119
+ t. iter ( ) . copied ( ) . collect ( )
120
+ }
121
+
122
+ #[ fixture]
123
+ fn persistent_three ( ) -> PersistentTorrents {
124
+ let hash = & mut DefaultHasher :: default ( ) ;
125
+
126
+ hash. write_u8 ( 1 ) ;
127
+ let info_1 = InfoHash :: from ( & hash. clone ( ) ) ;
128
+ hash. write_u8 ( 2 ) ;
129
+ let info_2 = InfoHash :: from ( & hash. clone ( ) ) ;
130
+ hash. write_u8 ( 3 ) ;
131
+ let info_3 = InfoHash :: from ( & hash. clone ( ) ) ;
132
+
133
+ let t = [ ( info_1, 1_u32 ) , ( info_2, 2_u32 ) , ( info_3, 3_u32 ) ] ;
134
+
135
+ t. iter ( ) . copied ( ) . collect ( )
136
+ }
137
+
107
138
async fn make ( repo : & Repo , entries : & Entries ) {
108
139
for ( info_hash, entry) in entries {
109
140
repo. insert ( info_hash, entry. clone ( ) ) . await ;
@@ -116,7 +147,7 @@ async fn make(repo: &Repo, entries: &Entries) {
116
147
#[ case:: started( started( ) ) ]
117
148
#[ case:: completed( completed( ) ) ]
118
149
#[ case:: downloaded( downloaded( ) ) ]
119
- #[ case:: four ( three( ) ) ]
150
+ #[ case:: three ( three( ) ) ]
120
151
#[ tokio:: test]
121
152
async fn it_should_get_a_torrent_entry (
122
153
#[ values( standard( ) , standard_mutex( ) , standard_tokio( ) , tokio_std( ) , tokio_mutex( ) , tokio_tokio( ) ) ] repo : Repo ,
@@ -137,7 +168,7 @@ async fn it_should_get_a_torrent_entry(
137
168
#[ case:: started( started( ) ) ]
138
169
#[ case:: completed( completed( ) ) ]
139
170
#[ case:: downloaded( downloaded( ) ) ]
140
- #[ case:: four ( three( ) ) ]
171
+ #[ case:: three ( three( ) ) ]
141
172
#[ tokio:: test]
142
173
async fn it_should_get_entries (
143
174
#[ values( standard( ) , standard_mutex( ) , standard_tokio( ) , tokio_std( ) , tokio_mutex( ) , tokio_tokio( ) ) ] repo : Repo ,
@@ -158,7 +189,7 @@ async fn it_should_get_entries(
158
189
#[ case:: started( started( ) ) ]
159
190
#[ case:: completed( completed( ) ) ]
160
191
#[ case:: downloaded( downloaded( ) ) ]
161
- #[ case:: four ( three( ) ) ]
192
+ #[ case:: three ( three( ) ) ]
162
193
#[ tokio:: test]
163
194
async fn it_should_get_metrics (
164
195
#[ values( standard( ) , standard_mutex( ) , standard_tokio( ) , tokio_std( ) , tokio_mutex( ) , tokio_tokio( ) ) ] repo : Repo ,
@@ -181,3 +212,126 @@ async fn it_should_get_metrics(
181
212
182
213
assert_eq ! ( repo. get_metrics( ) . await , metrics) ;
183
214
}
215
+
216
+ #[ rstest]
217
+ #[ case:: empty( empty( ) ) ]
218
+ #[ case:: default( default ( ) ) ]
219
+ #[ case:: started( started( ) ) ]
220
+ #[ case:: completed( completed( ) ) ]
221
+ #[ case:: downloaded( downloaded( ) ) ]
222
+ #[ case:: three( three( ) ) ]
223
+ #[ tokio:: test]
224
+ async fn it_should_import_persistent_torrents (
225
+ #[ values( standard( ) , standard_mutex( ) , standard_tokio( ) , tokio_std( ) , tokio_mutex( ) , tokio_tokio( ) ) ] repo : Repo ,
226
+ #[ case] entries : Entries ,
227
+ #[ values( persistent_empty( ) , persistent_single( ) , persistent_three( ) ) ] persistent_torrents : PersistentTorrents ,
228
+ ) {
229
+ make ( & repo, & entries) . await ;
230
+
231
+ let mut downloaded = repo. get_metrics ( ) . await . downloaded ;
232
+ persistent_torrents. iter ( ) . for_each ( |( _, d) | downloaded += u64:: from ( * d) ) ;
233
+
234
+ repo. import_persistent ( & persistent_torrents) . await ;
235
+
236
+ assert_eq ! ( repo. get_metrics( ) . await . downloaded, downloaded) ;
237
+
238
+ for ( entry, _) in persistent_torrents {
239
+ assert ! ( repo. get( & entry) . await . is_some( ) ) ;
240
+ }
241
+ }
242
+
243
+ #[ rstest]
244
+ #[ case:: empty( empty( ) ) ]
245
+ #[ case:: default( default ( ) ) ]
246
+ #[ case:: started( started( ) ) ]
247
+ #[ case:: completed( completed( ) ) ]
248
+ #[ case:: downloaded( downloaded( ) ) ]
249
+ #[ case:: three( three( ) ) ]
250
+ #[ tokio:: test]
251
+ async fn it_should_remove_an_entry (
252
+ #[ values( standard( ) , standard_mutex( ) , standard_tokio( ) , tokio_std( ) , tokio_mutex( ) , tokio_tokio( ) ) ] repo : Repo ,
253
+ #[ case] entries : Entries ,
254
+ ) {
255
+ make ( & repo, & entries) . await ;
256
+
257
+ for ( info_hash, torrent) in entries {
258
+ assert_eq ! ( repo. get( & info_hash) . await , Some ( torrent. clone( ) ) ) ;
259
+ assert_eq ! ( repo. remove( & info_hash) . await , Some ( torrent) ) ;
260
+
261
+ assert_eq ! ( repo. get( & info_hash) . await , None ) ;
262
+ assert_eq ! ( repo. remove( & info_hash) . await , None ) ;
263
+ }
264
+
265
+ assert_eq ! ( repo. get_metrics( ) . await . torrents, 0 ) ;
266
+ }
267
+
268
+ #[ rstest]
269
+ #[ case:: empty( empty( ) ) ]
270
+ #[ case:: default( default ( ) ) ]
271
+ #[ case:: started( started( ) ) ]
272
+ #[ case:: completed( completed( ) ) ]
273
+ #[ case:: downloaded( downloaded( ) ) ]
274
+ #[ case:: three( three( ) ) ]
275
+ #[ tokio:: test]
276
+ async fn it_should_remove_inactive_peers (
277
+ #[ values( standard( ) , standard_mutex( ) , standard_tokio( ) , tokio_std( ) , tokio_mutex( ) , tokio_tokio( ) ) ] repo : Repo ,
278
+ #[ case] entries : Entries ,
279
+ ) {
280
+ use std:: ops:: Sub as _;
281
+ use std:: time:: Duration ;
282
+
283
+ use torrust_tracker_clock:: clock:: stopped:: Stopped as _;
284
+ use torrust_tracker_clock:: clock:: { self , Time as _} ;
285
+ use torrust_tracker_primitives:: peer;
286
+
287
+ use crate :: CurrentClock ;
288
+
289
+ const TIMEOUT : Duration = Duration :: from_secs ( 120 ) ;
290
+ const EXPIRE : Duration = Duration :: from_secs ( 121 ) ;
291
+
292
+ make ( & repo, & entries) . await ;
293
+
294
+ let info_hash: InfoHash ;
295
+ let mut peer: peer:: Peer ;
296
+
297
+ // Generate a new infohash and peer.
298
+ {
299
+ let hash = & mut DefaultHasher :: default ( ) ;
300
+ hash. write_u8 ( 255 ) ;
301
+ info_hash = InfoHash :: from ( & hash. clone ( ) ) ;
302
+ peer = a_completed_peer ( -1 ) ;
303
+ }
304
+
305
+ // Set the last updated time of the peer to be 121 seconds ago.
306
+ {
307
+ let now = clock:: Working :: now ( ) ;
308
+ clock:: Stopped :: local_set ( & now) ;
309
+
310
+ peer. updated = now. sub ( EXPIRE ) ;
311
+ }
312
+
313
+ // Insert the infohash and peer into the repository
314
+ // and verify there is an extra torrent entry.
315
+ {
316
+ repo. update_torrent_with_peer_and_get_stats ( & info_hash, & peer) . await ;
317
+ assert_eq ! ( repo. get_metrics( ) . await . torrents, entries. len( ) as u64 + 1 ) ;
318
+ }
319
+
320
+ // Verify that this new peer was inserted into the repository.
321
+ {
322
+ let entry = repo. get ( & info_hash) . await . expect ( "it_should_get_some" ) ;
323
+ assert ! ( entry. get_peers( None ) . contains( & peer. into( ) ) ) ;
324
+ }
325
+
326
+ // Remove peers that have not been updated since the timeout (120 seconds ago).
327
+ {
328
+ repo. remove_inactive_peers ( CurrentClock :: now_sub ( & TIMEOUT ) . expect ( "it should get a time passed" ) )
329
+ . await ;
330
+ }
331
+
332
+ // Verify that the this peer was removed from the repository.
333
+ {
334
+ let entry = repo. get ( & info_hash) . await . expect ( "it_should_get_some" ) ;
335
+ assert ! ( !entry. get_peers( None ) . contains( & peer. into( ) ) ) ;
336
+ }
337
+ }
0 commit comments