ooni-probe-cli/internal/testingx/time.go
Simone Basso 5ebdeb56ca
feat: tlsping and tcpping using step-by-step (#815)
## Checklist

- [x] I have read the [contribution guidelines](https://github.com/ooni/probe-cli/blob/master/CONTRIBUTING.md)
- [x] reference issue for this pull request: https://github.com/ooni/probe/issues/2158
- [x] if you changed anything related how experiments work and you need to reflect these changes in the ooni/spec repository, please link to the related ooni/spec pull request: https://github.com/ooni/spec/pull/250

## Description

This diff refactors the codebase to reimplement tlsping and tcpping
to use the step-by-step measurements style.

See docs/design/dd-003-step-by-step.md for more information on the
step-by-step measurement style.
2022-07-01 12:22:22 +02:00

49 lines
1.4 KiB
Go

package testingx
import (
"sync"
"time"
)
// TimeDeterministic implements time.Now in a deterministic fashion
// such that every time.Time call returns a moment in time that occurs
// one second after the configured zeroTime.
//
// It's safe to use this struct from multiple goroutine contexts.
type TimeDeterministic struct {
// counter counts the number of "ticks" passed since the zero time: each
// call to Now increments this counter by one second.
counter time.Duration
// mu protects fields in this structure from concurrent access.
mu sync.Mutex
// zeroTime is the lazy-initialized zero time. The first call to Now
// will initialize this field with the current time.
zeroTime time.Time
}
// NewTimeDeterministic creates a new instance using the given zeroTime value.
func NewTimeDeterministic(zeroTime time.Time) *TimeDeterministic {
return &TimeDeterministic{
counter: 0,
mu: sync.Mutex{},
zeroTime: zeroTime,
}
}
// Now is like time.Now but more deterministic. The first call returns the
// configured zeroTime and subsequent calls return moments in time that occur
// exactly one second after the time returned by the previous call.
func (td *TimeDeterministic) Now() time.Time {
td.mu.Lock()
if td.zeroTime.IsZero() {
td.zeroTime = time.Now()
}
offset := td.counter
td.counter += time.Second
res := td.zeroTime.Add(offset)
td.mu.Unlock()
return res
}