@@ -8,10 +8,12 @@ import (
8
8
"strconv"
9
9
"strings"
10
10
"sync"
11
+ "sync/atomic"
11
12
"testing"
12
13
"time"
13
14
14
15
"github.com/filecoin-project/go-clock"
16
+ "github.com/guillaumemichel/reservedpool"
15
17
logging "github.com/ipfs/go-log/v2"
16
18
"github.com/ipfs/go-test/random"
17
19
"github.com/libp2p/go-libp2p/core/peer"
@@ -546,3 +548,118 @@ func TestIndividualProvideMultiple(t *testing.T) {
546
548
require .True (t , r .reprovideQueue .IsEmpty ())
547
549
require .True (t , r .provideQueue .IsEmpty ())
548
550
}
551
+
552
+ func waitUntil (t * testing.T , condition func () bool , maxDelay time.Duration , args ... any ) {
553
+ step := time .Millisecond
554
+ for range maxDelay / step {
555
+ if condition () {
556
+ return
557
+ }
558
+ time .Sleep (step )
559
+ }
560
+ t .Fatal (args ... )
561
+ }
562
+
563
+ func TestHandleReprovide (t * testing.T ) {
564
+ mockClock := clock .NewMock ()
565
+
566
+ online := atomic.Bool {}
567
+ online .Store (true )
568
+ connectivityCheckInterval := time .Second
569
+ connChecker , err := connectivity .New (
570
+ func () bool { return online .Load () },
571
+ func () {},
572
+ connectivity .WithClock (mockClock ),
573
+ connectivity .WithOfflineCheckInterval (connectivityCheckInterval ),
574
+ connectivity .WithOnlineCheckInterval (connectivityCheckInterval ),
575
+ )
576
+ require .NoError (t , err )
577
+ defer connChecker .Close ()
578
+
579
+ prov := SweepingProvider {
580
+ order : bit256 .ZeroKey (),
581
+
582
+ connectivity : connChecker ,
583
+
584
+ clock : mockClock ,
585
+ cycleStart : mockClock .Now (),
586
+ scheduleTimer : mockClock .Timer (time .Hour ),
587
+ schedule : trie .New [bitstr.Key , time.Duration ](),
588
+
589
+ reprovideQueue : queue .NewReprovideQueue (),
590
+ workerPool : reservedpool .New [workerType ](1 , nil ), // single worker
591
+
592
+ reprovideInterval : time .Minute ,
593
+ maxReprovideDelay : 5 * time .Second ,
594
+
595
+ getSelfAddrs : func () []ma.Multiaddr { return nil },
596
+ }
597
+ prov .scheduleTimer .Stop ()
598
+
599
+ prefixes := []bitstr.Key {
600
+ "00" ,
601
+ "10" ,
602
+ "11" ,
603
+ }
604
+
605
+ // Empty schedule -> early return
606
+ prov .handleReprovide ()
607
+ require .Zero (t , prov .scheduleCursor )
608
+
609
+ // Single prefix in schedule
610
+ prov .schedule .Add (prefixes [0 ], prov .reprovideTimeForPrefix (prefixes [0 ]))
611
+ prov .scheduleCursor = prefixes [0 ]
612
+ prov .handleReprovide ()
613
+ require .Equal (t , prefixes [0 ], prov .scheduleCursor )
614
+
615
+ // Two prefixes in schedule
616
+ mockClock .Add (1 )
617
+ prov .schedule .Add (prefixes [1 ], prov .reprovideTimeForPrefix (prefixes [1 ]))
618
+ prov .handleReprovide () // reprovides prefixes[0], set scheduleCursor to prefixes[1]
619
+ require .Equal (t , prefixes [1 ], prov .scheduleCursor )
620
+
621
+ // Wait more than reprovideInterval to call handleReprovide again.
622
+ // All prefixes should be added to the reprovide queue.
623
+ mockClock .Add (prov .reprovideInterval + 1 )
624
+ require .True (t , prov .reprovideQueue .IsEmpty ())
625
+ prov .handleReprovide ()
626
+ require .Equal (t , prefixes [1 ], prov .scheduleCursor )
627
+
628
+ require .Equal (t , 2 , prov .reprovideQueue .Size ())
629
+ dequeued , ok := prov .reprovideQueue .Dequeue ()
630
+ require .True (t , ok )
631
+ require .Equal (t , prefixes [0 ], dequeued )
632
+ dequeued , ok = prov .reprovideQueue .Dequeue ()
633
+ require .True (t , ok )
634
+ require .Equal (t , prefixes [1 ], dequeued )
635
+ require .True (t , prov .reprovideQueue .IsEmpty ())
636
+
637
+ // Go in time past prefixes[1] and prefixes[2]
638
+ prov .schedule .Add (prefixes [2 ], prov .reprovideTimeForPrefix (prefixes [2 ]))
639
+ mockClock .Add (3 * prov .reprovideInterval / 4 )
640
+ // reprovides prefixes[1], add prefixes[2] to reprovide queue, set
641
+ // scheduleCursor to prefixes[0]
642
+ prov .handleReprovide ()
643
+ require .Equal (t , prefixes [0 ], prov .scheduleCursor )
644
+
645
+ require .Equal (t , 1 , prov .reprovideQueue .Size ())
646
+ dequeued , ok = prov .reprovideQueue .Dequeue ()
647
+ require .True (t , ok )
648
+ require .Equal (t , prefixes [2 ], dequeued )
649
+ require .True (t , prov .reprovideQueue .IsEmpty ())
650
+
651
+ mockClock .Add (prov .reprovideInterval / 4 )
652
+
653
+ // Node goes offline -> prefixes are queued
654
+ online .Store (false )
655
+ prov .connectivity .TriggerCheck ()
656
+ waitUntil (t , func () bool { return ! prov .connectivity .IsOnline () }, 100 * time .Millisecond , "connectivity should be offline" )
657
+ // require.True(t, prov.reprovideQueue.IsEmpty())
658
+ prov .handleReprovide ()
659
+ // require.Equal(t, 1, prov.reprovideQueue.Size())
660
+
661
+ // Node comes back online
662
+ online .Store (true )
663
+ mockClock .Add (connectivityCheckInterval )
664
+ waitUntil (t , func () bool { return prov .connectivity .IsOnline () }, 100 * time .Millisecond , "connectivity should be online" )
665
+ }
0 commit comments