blob: 526d58d75e7a478781bf6e78cbf77ad134b31a48 [file] [log] [blame]
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package time_test
import (
"errors"
"fmt"
"runtime"
"sort"
"sync/atomic"
"testing"
. "time"
)
func TestSleep(t *testing.T) {
const delay = 100 * Millisecond
go func() {
Sleep(delay / 2)
Interrupt()
}()
start := Now()
Sleep(delay)
duration := Now().Sub(start)
if duration < delay {
t.Fatalf("Sleep(%s) slept for only %s", delay, duration)
}
}
// Test the basic function calling behavior. Correct queueing
// behavior is tested elsewhere, since After and AfterFunc share
// the same code.
func TestAfterFunc(t *testing.T) {
i := 10
c := make(chan bool)
var f func()
f = func() {
i--
if i >= 0 {
AfterFunc(0, f)
Sleep(1 * Second)
} else {
c <- true
}
}
AfterFunc(0, f)
<-c
}
func TestAfterStress(t *testing.T) {
stop := uint32(0)
go func() {
for atomic.LoadUint32(&stop) == 0 {
runtime.GC()
// Need to yield, because otherwise
// the main goroutine will never set the stop flag.
runtime.Gosched()
}
}()
c := Tick(1)
for i := 0; i < 100; i++ {
<-c
}
atomic.StoreUint32(&stop, 1)
}
func BenchmarkAfterFunc(b *testing.B) {
i := b.N
c := make(chan bool)
var f func()
f = func() {
i--
if i >= 0 {
AfterFunc(0, f)
} else {
c <- true
}
}
AfterFunc(0, f)
<-c
}
func BenchmarkAfter(b *testing.B) {
for i := 0; i < b.N; i++ {
<-After(1)
}
}
func BenchmarkStop(b *testing.B) {
for i := 0; i < b.N; i++ {
NewTimer(1 * Second).Stop()
}
}
func TestAfter(t *testing.T) {
const delay = 100 * Millisecond
start := Now()
end := <-After(delay)
if duration := Now().Sub(start); duration < delay {
t.Fatalf("After(%s) slept for only %d ns", delay, duration)
}
if min := start.Add(delay); end.Before(min) {
t.Fatalf("After(%s) expect >= %s, got %s", delay, min, end)
}
}
func TestAfterTick(t *testing.T) {
const Count = 10
Delta := 100 * Millisecond
if testing.Short() {
Delta = 10 * Millisecond
}
t0 := Now()
for i := 0; i < Count; i++ {
<-After(Delta)
}
t1 := Now()
d := t1.Sub(t0)
target := Delta * Count
if d < target*9/10 {
t.Fatalf("%d ticks of %s too fast: took %s, expected %s", Count, Delta, d, target)
}
if !testing.Short() && d > target*30/10 {
t.Fatalf("%d ticks of %s too slow: took %s, expected %s", Count, Delta, d, target)
}
}
func TestAfterStop(t *testing.T) {
AfterFunc(100*Millisecond, func() {})
t0 := NewTimer(50 * Millisecond)
c1 := make(chan bool, 1)
t1 := AfterFunc(150*Millisecond, func() { c1 <- true })
c2 := After(200 * Millisecond)
if !t0.Stop() {
t.Fatalf("failed to stop event 0")
}
if !t1.Stop() {
t.Fatalf("failed to stop event 1")
}
<-c2
select {
case <-t0.C:
t.Fatalf("event 0 was not stopped")
case <-c1:
t.Fatalf("event 1 was not stopped")
default:
}
if t1.Stop() {
t.Fatalf("Stop returned true twice")
}
}
func TestAfterQueuing(t *testing.T) {
// This test flakes out on some systems,
// so we'll try it a few times before declaring it a failure.
const attempts = 3
err := errors.New("!=nil")
for i := 0; i < attempts && err != nil; i++ {
if err = testAfterQueuing(t); err != nil {
t.Logf("attempt %v failed: %v", i, err)
}
}
if err != nil {
t.Fatal(err)
}
}
var slots = []int{5, 3, 6, 6, 6, 1, 1, 2, 7, 9, 4, 8, 0}
type afterResult struct {
slot int
t Time
}
func await(slot int, result chan<- afterResult, ac <-chan Time) {
result <- afterResult{slot, <-ac}
}
func testAfterQueuing(t *testing.T) error {
Delta := 100 * Millisecond
if testing.Short() {
Delta = 20 * Millisecond
}
// make the result channel buffered because we don't want
// to depend on channel queueing semantics that might
// possibly change in the future.
result := make(chan afterResult, len(slots))
t0 := Now()
for _, slot := range slots {
go await(slot, result, After(Duration(slot)*Delta))
}
sort.Ints(slots)
for _, slot := range slots {
r := <-result
if r.slot != slot {
return fmt.Errorf("after slot %d, expected %d", r.slot, slot)
}
dt := r.t.Sub(t0)
target := Duration(slot) * Delta
if dt < target-Delta/2 || dt > target+Delta*10 {
return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-Delta/2, target+Delta*10)
}
}
return nil
}
func TestTimerStopStress(t *testing.T) {
if testing.Short() {
return
}
for i := 0; i < 100; i++ {
go func(i int) {
timer := AfterFunc(2*Second, func() {
t.Fatalf("timer %d was not stopped", i)
})
Sleep(1 * Second)
timer.Stop()
}(i)
}
Sleep(3 * Second)
}