1
1
// TODO(shahak): Add tests for multiple connection ids
2
2
3
3
use core:: { panic, time} ;
4
+ use std:: pin:: Pin ;
5
+ use std:: task:: { Context , Poll } ;
6
+ use std:: time:: { Duration , Instant } ;
4
7
5
8
use assert_matches:: assert_matches;
6
- use chrono:: Duration ;
7
9
use futures:: future:: poll_fn;
10
+ use futures:: { FutureExt , Stream , StreamExt } ;
8
11
use libp2p:: swarm:: behaviour:: ConnectionEstablished ;
9
12
use libp2p:: swarm:: { ConnectionId , NetworkBehaviour , ToSwarm } ;
10
13
use libp2p:: { Multiaddr , PeerId } ;
11
14
use mockall:: predicate:: eq;
12
15
use tokio:: time:: sleep;
16
+ use void:: Void ;
13
17
14
18
use super :: behaviour_impl:: ToOtherBehaviourEvent ;
15
19
use crate :: discovery:: identify_impl:: IdentifyToOtherBehaviourEvent ;
@@ -19,6 +23,19 @@ use crate::peer_manager::peer::{MockPeerTrait, Peer, PeerTrait};
19
23
use crate :: peer_manager:: { PeerManager , PeerManagerConfig , ReputationModifier } ;
20
24
use crate :: sqmr:: OutboundSessionId ;
21
25
26
+ impl < P : PeerTrait > Unpin for PeerManager < P > { }
27
+
28
+ impl < P : PeerTrait > Stream for PeerManager < P > {
29
+ type Item = ToSwarm < ToOtherBehaviourEvent , Void > ;
30
+
31
+ fn poll_next ( self : Pin < & mut Self > , cx : & mut Context < ' _ > ) -> Poll < Option < Self :: Item > > {
32
+ match Pin :: into_inner ( self ) . poll ( cx) {
33
+ Poll :: Pending => Poll :: Pending ,
34
+ Poll :: Ready ( event) => Poll :: Ready ( Some ( event) ) ,
35
+ }
36
+ }
37
+ }
38
+
22
39
#[ test]
23
40
fn peer_assignment_round_robin ( ) {
24
41
// Create a new peer manager
@@ -102,8 +119,8 @@ fn peer_assignment_round_robin() {
102
119
}
103
120
}
104
121
105
- #[ test]
106
- fn peer_assignment_no_peers ( ) {
122
+ #[ tokio :: test]
123
+ async fn peer_assignment_no_peers ( ) {
107
124
// Create a new peer manager
108
125
let config = PeerManagerConfig :: default ( ) ;
109
126
let mut peer_manager: PeerManager < MockPeerTrait > = PeerManager :: new ( config. clone ( ) ) ;
@@ -113,25 +130,72 @@ fn peer_assignment_no_peers() {
113
130
114
131
// Assign a peer to the session
115
132
assert_matches ! ( peer_manager. assign_peer_to_session( outbound_session_id) , None ) ;
133
+ assert ! ( peer_manager. next( ) . now_or_never( ) . is_none( ) ) ;
116
134
117
135
// Now the peer manager finds a new peer and can assign the session.
118
136
let connection_id = ConnectionId :: new_unchecked ( 0 ) ;
119
137
let ( mut peer, peer_id) =
120
138
create_mock_peer ( config. blacklist_timeout , false , Some ( connection_id) ) ;
121
139
peer. expect_is_blocked ( ) . times ( 1 ) . return_const ( false ) ;
122
140
peer_manager. add_peer ( peer) ;
123
- assert_eq ! ( peer_manager. pending_events. len( ) , 1 ) ;
124
141
assert_matches ! (
125
- peer_manager. pending_events . first ( ) . unwrap( ) ,
142
+ peer_manager. next ( ) . await . unwrap( ) ,
126
143
ToSwarm :: GenerateEvent ( ToOtherBehaviourEvent :: SessionAssigned {
127
144
outbound_session_id: event_outbound_session_id,
128
145
peer_id: event_peer_id,
129
146
connection_id: event_connection_id,
130
147
}
131
- ) if outbound_session_id == * event_outbound_session_id &&
132
- peer_id == * event_peer_id &&
133
- connection_id == * event_connection_id
148
+ ) if outbound_session_id == event_outbound_session_id &&
149
+ peer_id == event_peer_id &&
150
+ connection_id == event_connection_id
134
151
) ;
152
+ assert ! ( peer_manager. next( ) . now_or_never( ) . is_none( ) ) ;
153
+ }
154
+
155
+ #[ tokio:: test]
156
+ async fn peer_assignment_no_unblocked_peers ( ) {
157
+ const BLOCKED_UNTIL : Duration = Duration :: from_secs ( 5 ) ;
158
+ const TIMEOUT : Duration = Duration :: from_secs ( 1 ) ;
159
+ // Create a new peer manager
160
+ let config = PeerManagerConfig :: default ( ) ;
161
+ let mut peer_manager: PeerManager < MockPeerTrait > = PeerManager :: new ( config. clone ( ) ) ;
162
+
163
+ // Create a session
164
+ let outbound_session_id = OutboundSessionId { value : 1 } ;
165
+
166
+ // Create a peer
167
+ let connection_id = ConnectionId :: new_unchecked ( 0 ) ;
168
+ let ( mut peer, peer_id) = create_mock_peer ( config. blacklist_timeout , true , Some ( connection_id) ) ;
169
+ peer. expect_is_blocked ( ) . times ( 1 ) . return_const ( true ) ;
170
+ peer. expect_is_blocked ( ) . times ( 1 ) . return_const ( false ) ;
171
+ peer. expect_blocked_until ( ) . times ( 1 ) . returning ( || Instant :: now ( ) + BLOCKED_UNTIL ) ;
172
+
173
+ peer_manager. add_peer ( peer) ;
174
+ peer_manager. report_peer ( peer_id, ReputationModifier :: Bad { } ) . unwrap ( ) ;
175
+
176
+ // Try to assign a peer to the session, and check there wasn't any assignment.
177
+ assert_matches ! ( peer_manager. assign_peer_to_session( outbound_session_id) , None ) ;
178
+ assert ! ( peer_manager. next( ) . now_or_never( ) . is_none( ) ) ;
179
+
180
+ // Simulate that BLOCKED_UNTIL has passed.
181
+ tokio:: time:: pause ( ) ;
182
+ tokio:: time:: advance ( BLOCKED_UNTIL ) . await ;
183
+ tokio:: time:: resume ( ) ;
184
+
185
+ // After BLOCKED_UNTIL has passed, the peer manager can assign the session.
186
+ let event = tokio:: time:: timeout ( TIMEOUT , peer_manager. next ( ) ) . await . unwrap ( ) . unwrap ( ) ;
187
+ assert_matches ! (
188
+ event,
189
+ ToSwarm :: GenerateEvent ( ToOtherBehaviourEvent :: SessionAssigned {
190
+ outbound_session_id: event_outbound_session_id,
191
+ peer_id: event_peer_id,
192
+ connection_id: event_connection_id,
193
+ }
194
+ ) if outbound_session_id == event_outbound_session_id &&
195
+ peer_id == event_peer_id &&
196
+ connection_id == event_connection_id
197
+ ) ;
198
+ assert ! ( peer_manager. next( ) . now_or_never( ) . is_none( ) ) ;
135
199
}
136
200
137
201
#[ test]
@@ -155,7 +219,7 @@ fn report_peer_calls_update_reputation() {
155
219
async fn peer_block_realeased_after_timeout ( ) {
156
220
const DURATION_IN_MILLIS : u64 = 50 ;
157
221
let mut peer = Peer :: new ( PeerId :: random ( ) , Multiaddr :: empty ( ) ) ;
158
- peer. set_timeout_duration ( Duration :: milliseconds ( DURATION_IN_MILLIS as i64 ) ) ;
222
+ peer. set_timeout_duration ( Duration :: from_millis ( DURATION_IN_MILLIS ) ) ;
159
223
peer. update_reputation ( ReputationModifier :: Bad { } ) ;
160
224
assert ! ( peer. is_blocked( ) ) ;
161
225
sleep ( time:: Duration :: from_millis ( DURATION_IN_MILLIS ) ) . await ;
@@ -236,15 +300,16 @@ fn more_peers_needed() {
236
300
assert ! ( !peer_manager. more_peers_needed( ) ) ;
237
301
}
238
302
239
- #[ test]
240
- fn timed_out_peer_not_assignable_to_queries ( ) {
303
+ #[ tokio :: test]
304
+ async fn timed_out_peer_not_assignable_to_queries ( ) {
241
305
// Create a new peer manager
242
306
let config = PeerManagerConfig :: default ( ) ;
243
307
let mut peer_manager: PeerManager < MockPeerTrait > = PeerManager :: new ( config. clone ( ) ) ;
244
308
245
309
// Create a mock peer
246
310
let ( mut peer, peer_id) = create_mock_peer ( config. blacklist_timeout , true , None ) ;
247
311
peer. expect_is_blocked ( ) . times ( 1 ) . return_const ( true ) ;
312
+ peer. expect_blocked_until ( ) . times ( 1 ) . returning ( || Instant :: now ( ) + Duration :: from_secs ( 1 ) ) ;
248
313
249
314
// Add the mock peer to the peer manager
250
315
peer_manager. add_peer ( peer) ;
0 commit comments