tai64n: make the test deterministic

In the presence of preemption, the current test may fail transiently.
This uses static test data instead to ensure consistent behavior.

Signed-off-by: Dmytro Shynkevych <dmytro@tailscale.com>
This commit is contained in:
Dmytro Shynkevych 2020-05-05 18:37:54 -04:00 committed by David Crawshaw
parent da9d300cf8
commit f60b3919be
2 changed files with 32 additions and 19 deletions

View file

@ -17,16 +17,19 @@ const whitenerMask = uint32(0x1000000 - 1)
type Timestamp [TimestampSize]byte type Timestamp [TimestampSize]byte
func Now() Timestamp { func stamp(t time.Time) Timestamp {
var tai64n Timestamp var tai64n Timestamp
now := time.Now() secs := base + uint64(t.Unix())
secs := base + uint64(now.Unix()) nano := uint32(t.Nanosecond()) &^ whitenerMask
nano := uint32(now.Nanosecond()) &^ whitenerMask
binary.BigEndian.PutUint64(tai64n[:], secs) binary.BigEndian.PutUint64(tai64n[:], secs)
binary.BigEndian.PutUint32(tai64n[8:], nano) binary.BigEndian.PutUint32(tai64n[8:], nano)
return tai64n return tai64n
} }
func Now() Timestamp {
return stamp(time.Now())
}
func (t1 Timestamp) After(t2 Timestamp) bool { func (t1 Timestamp) After(t2 Timestamp) bool {
return bytes.Compare(t1[:], t2[:]) > 0 return bytes.Compare(t1[:], t2[:]) > 0
} }

View file

@ -10,21 +10,31 @@ import (
"time" "time"
) )
/* Testing the essential property of the timestamp // Test that timestamps are monotonic as required by Wireguard and that
* as used by WireGuard. // nanosecond-level information is whitened to prevent side channel attacks.
*/
func TestMonotonic(t *testing.T) { func TestMonotonic(t *testing.T) {
old := Now() startTime := time.Unix(0, 123456789) // a nontrivial bit pattern
for i := 0; i < 50; i++ { // Whitening should reduce timestamp granularity
next := Now() // to more than 10 but fewer than 20 milliseconds.
if next.After(old) { tests := []struct {
t.Error("Whitening insufficient") name string
t1, t2 time.Time
wantAfter bool
}{
{"after_10_ns", startTime, startTime.Add(10 * time.Nanosecond), false},
{"after_10_us", startTime, startTime.Add(10 * time.Microsecond), false},
{"after_1_ms", startTime, startTime.Add(time.Millisecond), false},
{"after_10_ms", startTime, startTime.Add(10 * time.Millisecond), false},
{"after_20_ms", startTime, startTime.Add(20 * time.Millisecond), true},
} }
time.Sleep(time.Duration(whitenerMask)/time.Nanosecond + 1)
next = Now() for _, tt := range tests {
if !next.After(old) { t.Run(tt.name, func(t *testing.T) {
t.Error("Not monotonically increasing on whitened nano-second scale") ts1, ts2 := stamp(tt.t1), stamp(tt.t2)
got := ts2.After(ts1)
if got != tt.wantAfter {
t.Errorf("after = %v; want %v", got, tt.wantAfter)
} }
old = next })
} }
} }