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:
parent
da9d300cf8
commit
f60b3919be
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue