fix flaky tests against time
## Motivation
fix flaky tests
tested with
```
go clean -testcache && go test ./activation/ -v -run "^TestBuilder_waitForFirstATX" -count 2000
go clean -testcache && go test ./timesync/ -v -run "^TestClock_" -count 1000
```
MODIFY
activation/activation.go
activation/activation.go
@@ -321,16 +321,16 @@ func (b *Builder) generateProof() error {
return nil
}
-func (b *Builder) waitForFirstATX(ctx context.Context) {
+func (b *Builder) waitForFirstATX(ctx context.Context) bool {
currentLayer := b.layerClock.GetCurrentLayer()
currEpoch := currentLayer.GetEpoch()
if currEpoch == 0 { // genesis miner
- return
+ return false
}
if prev, err := b.cdb.GetPrevAtx(b.nodeID); err == nil {
if prev.PubLayerID.GetEpoch() == currEpoch {
// miner has ATX in previous epoch
- return
+ return false
}
}
@@ -349,7 +349,7 @@ func (b *Builder) waitForFirstATX(ctx context.Context) {
log.Stringer("wait_till_epoch", waitTill.GetEpoch()))
select {
case <-ctx.Done():
- return
+ return false
case <-b.layerClock.AwaitLayer(waitTill):
wait = window
}
@@ -360,12 +360,13 @@ func (b *Builder) waitForFirstATX(ctx context.Context) {
defer timer.Stop()
select {
case <-ctx.Done():
- return
+ return false
case <-timer.C:
}
b.log.WithContext(ctx).With().Info("ready to build first atx",
log.Stringer("current_layer", b.layerClock.GetCurrentLayer()),
log.Stringer("current_epoch", b.layerClock.GetCurrentLayer().GetEpoch()))
+ return true
}
// loop is the main loop that tries to create an atx per tick received from the global clock.

MODIFY
activation/activation_test.go
activation/activation_test.go
@@ -329,23 +329,13 @@ func TestBuilder_waitForFirstATX(t *testing.T) {
WithPoetConfig(poetCfg))
b.initialPost = initialPost
- layerStart := time.Now().Add(-1 * time.Millisecond)
- poetWindwow := poetCfg.PhaseShift - poetCfg.CycleGap + poetCfg.GracePeriod
- expectedWait := poetWindwow - time.Millisecond
ch := make(chan struct{}, 1)
close(ch)
- current := types.NewLayerID(layersPerEpoch * 2)
+ current := types.NewLayerID(layersPerEpoch * 2) // first layer of epoch 2
addPrevAtx(t, cdb, current.GetEpoch()-1)
mClock.EXPECT().GetCurrentLayer().Return(current).AnyTimes()
- start := time.Time{}
- mClock.EXPECT().LayerToTime(current).DoAndReturn(
- func(_ types.LayerID) time.Time {
- start = time.Now()
- return layerStart
- })
- b.waitForFirstATX(context.TODO())
- elapsed := time.Since(start)
- require.GreaterOrEqual(t, elapsed, expectedWait)
+ mClock.EXPECT().LayerToTime(current).Return(time.Now().Add(100 * time.Millisecond))
+ require.True(t, b.waitForFirstATX(context.TODO()))
}
func TestBuilder_waitForFirstATX_nextEpoch(t *testing.T) {
@@ -369,23 +359,15 @@ func TestBuilder_waitForFirstATX_nextEpoch(t *testing.T) {
WithPoetConfig(poetCfg))
b.initialPost = initialPost
- poetWindwow := poetCfg.PhaseShift - poetCfg.CycleGap + poetCfg.GracePeriod
ch := make(chan struct{}, 1)
close(ch)
- current := types.NewLayerID(layersPerEpoch * 2)
+ current := types.NewLayerID(layersPerEpoch * 2) // first layer of epoch 2
addPrevAtx(t, cdb, current.GetEpoch()-1)
mClock.EXPECT().GetCurrentLayer().Return(current)
mClock.EXPECT().LayerToTime(current).Return(time.Now().Add(-5 * time.Millisecond))
- start := time.Time{}
- mClock.EXPECT().AwaitLayer(current.Add(layersPerEpoch)).DoAndReturn(
- func(_ types.LayerID) chan struct{} {
- start = time.Now()
- return ch
- })
+ mClock.EXPECT().AwaitLayer(current.Add(layersPerEpoch)).Return(ch)
mClock.EXPECT().GetCurrentLayer().Return(current.Add(layersPerEpoch)).AnyTimes()
- b.waitForFirstATX(context.TODO())
- elapsed := time.Since(start)
- require.GreaterOrEqual(t, elapsed, poetWindwow)
+ require.True(t, b.waitForFirstATX(context.TODO()))
}
func TestBuilder_waitForFirstATX_Genesis(t *testing.T) {
@@ -397,7 +379,7 @@ func TestBuilder_waitForFirstATX_Genesis(t *testing.T) {
current := types.NewLayerID(0)
mClock.EXPECT().GetCurrentLayer().Return(current)
- b.waitForFirstATX(context.TODO())
+ require.False(t, b.waitForFirstATX(context.TODO()))
}
func TestBuilder_waitForFirstATX_NoWait(t *testing.T) {
@@ -410,7 +392,7 @@ func TestBuilder_waitForFirstATX_NoWait(t *testing.T) {
current := types.NewLayerID(layersPerEpoch)
addPrevAtx(t, cdb, current.GetEpoch())
mClock.EXPECT().GetCurrentLayer().Return(current)
- b.waitForFirstATX(context.TODO())
+ require.False(t, b.waitForFirstATX(context.TODO()))
}
func TestBuilder_StartSmeshingCoinbase(t *testing.T) {

MODIFY
timesync/clock.go
timesync/clock.go
@@ -58,8 +58,6 @@ func NewClock(c Clock, tickInterval time.Duration, genesisTime time.Time, logger
func (t *TimeClock) startClock() error {
t.log.Info("starting global clock now=%v genesis=%v %p", t.clock.Now(), t.genesis, t)
- tmr := time.NewTimer(0)
- defer tmr.Stop()
for {
currLayer := t.Ticker.TimeToLayer(t.clock.Now()) // get current layer
nextLayer := currLayer.Add(1)
@@ -68,13 +66,14 @@ func (t *TimeClock) startClock() error {
}
nextTickTime := t.Ticker.LayerToTime(nextLayer) // get next tick time for the next layer
diff := nextTickTime.Sub(t.clock.Now())
- tmr.Reset(diff)
t.log.With().Info("global clock going to sleep before next layer",
log.String("diff", diff.String()),
log.FieldNamed("curr_layer", currLayer),
log.FieldNamed("next_layer", nextLayer))
+ tmr := time.NewTimer(diff)
select {
case <-tmr.C:
+ tmr.Stop()
t.mu.Lock()
subscriberCount := len(t.subscribers)
t.mu.Unlock()
@@ -90,6 +89,7 @@ func (t *TimeClock) startClock() error {
log.Int("missed", missed))
}
case <-t.stop:
+ tmr.Stop()
t.log.Info("stopping global clock %p", t)
return nil
}

fix flaky tests against time (#3521)

## Motivation
fix flaky tests

tested with 
```
go clean -testcache && go test ./activation/ -v -run "^TestBuilder_waitForFirstATX" -count 2000
go clean -testcache && go test ./timesync/ -v -run "^TestClock_" -count 1000
```