@@ -2,16 +2,21 @@ package network_test
2
2
3
3
import (
4
4
"context"
5
+ "fmt"
5
6
"math/rand"
6
7
"testing"
7
8
"time"
8
9
9
10
basicnode "github.com/ipld/go-ipld-prime/node/basic"
10
11
"github.com/ipld/go-ipld-prime/traversal/selector/builder"
12
+ "github.com/libp2p/go-libp2p-core/host"
13
+ libp2pnet "github.com/libp2p/go-libp2p-core/network"
11
14
"github.com/libp2p/go-libp2p-core/peer"
15
+ "github.com/libp2p/go-libp2p-core/protocol"
12
16
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
13
17
"github.com/stretchr/testify/assert"
14
18
"github.com/stretchr/testify/require"
19
+ "golang.org/x/xerrors"
15
20
16
21
datatransfer "github.com/filecoin-project/go-data-transfer"
17
22
"github.com/filecoin-project/go-data-transfer/message"
@@ -174,3 +179,122 @@ func TestMessageSendAndReceive(t *testing.T) {
174
179
})
175
180
176
181
}
182
+
183
+ // Wrap a host so that we can mock out errors when calling NewStream
184
+ type wrappedHost struct {
185
+ host.Host
186
+ errs chan error
187
+ }
188
+
189
+ func (w wrappedHost ) NewStream (ctx context.Context , p peer.ID , pids ... protocol.ID ) (libp2pnet.Stream , error ) {
190
+ var err error
191
+ select {
192
+ case err = <- w .errs :
193
+ default :
194
+ }
195
+ if err != nil {
196
+ return nil , err
197
+ }
198
+
199
+ return w .Host .NewStream (ctx , p , pids ... )
200
+ }
201
+
202
+ // TestSendMessageRetry verifies that if the number of retry attempts
203
+ // is greater than the number of errors, SendMessage will succeed.
204
+ func TestSendMessageRetry (t * testing.T ) {
205
+ tcases := []struct {
206
+ attempts int
207
+ errors int
208
+ expSuccess bool
209
+ }{{
210
+ attempts : 1 ,
211
+ errors : 0 ,
212
+ expSuccess : true ,
213
+ }, {
214
+ attempts : 1 ,
215
+ errors : 1 ,
216
+ expSuccess : false ,
217
+ }, {
218
+ attempts : 2 ,
219
+ errors : 1 ,
220
+ expSuccess : true ,
221
+ }, {
222
+ attempts : 2 ,
223
+ errors : 2 ,
224
+ expSuccess : false ,
225
+ }}
226
+ for _ , tcase := range tcases {
227
+ name := fmt .Sprintf ("%d attempts, %d errors" , tcase .attempts , tcase .errors )
228
+ t .Run (name , func (t * testing.T ) {
229
+ // create network
230
+ ctx := context .Background ()
231
+ ctx , cancel := context .WithTimeout (ctx , 10 * time .Second )
232
+ defer cancel ()
233
+ mn := mocknet .New (ctx )
234
+
235
+ host1 , err := mn .GenPeer ()
236
+ require .NoError (t , err )
237
+
238
+ // Create a wrapped host that will return tcase.errors errors from
239
+ // NewStream
240
+ mockHost1 := & wrappedHost {
241
+ Host : host1 ,
242
+ errs : make (chan error , tcase .errors ),
243
+ }
244
+ for i := 0 ; i < tcase .errors ; i ++ {
245
+ mockHost1 .errs <- xerrors .Errorf ("network err" )
246
+ }
247
+ host1 = mockHost1
248
+
249
+ host2 , err := mn .GenPeer ()
250
+ require .NoError (t , err )
251
+ err = mn .LinkAll ()
252
+ require .NoError (t , err )
253
+
254
+ retry := network .RetryParameters (
255
+ time .Millisecond ,
256
+ time .Millisecond ,
257
+ float64 (tcase .attempts ),
258
+ 1 )
259
+ dtnet1 := network .NewFromLibp2pHost (host1 , retry )
260
+ dtnet2 := network .NewFromLibp2pHost (host2 )
261
+ r := & receiver {
262
+ messageReceived : make (chan struct {}),
263
+ connectedPeers : make (chan peer.ID , 2 ),
264
+ }
265
+ dtnet1 .SetDelegate (r )
266
+ dtnet2 .SetDelegate (r )
267
+
268
+ err = dtnet1 .ConnectTo (ctx , host2 .ID ())
269
+ require .NoError (t , err )
270
+
271
+ baseCid := testutil .GenerateCids (1 )[0 ]
272
+ selector := builder .NewSelectorSpecBuilder (basicnode .Prototype .Any ).Matcher ().Node ()
273
+ isPull := false
274
+ id := datatransfer .TransferID (rand .Int31 ())
275
+ voucher := testutil .NewFakeDTType ()
276
+ request , err := message .NewRequest (id , false , isPull , voucher .Type (), voucher , baseCid , selector )
277
+ require .NoError (t , err )
278
+
279
+ err = dtnet1 .SendMessage (ctx , host2 .ID (), request )
280
+ if ! tcase .expSuccess {
281
+ require .Error (t , err )
282
+ return
283
+ }
284
+
285
+ require .NoError (t , err )
286
+
287
+ select {
288
+ case <- ctx .Done ():
289
+ t .Fatal ("did not receive message sent" )
290
+ case <- r .messageReceived :
291
+ }
292
+
293
+ sender := r .lastSender
294
+ require .Equal (t , sender , host1 .ID ())
295
+
296
+ receivedRequest := r .lastRequest
297
+ require .NotNil (t , receivedRequest )
298
+ })
299
+ }
300
+ }
0 commit comments