blob: 30a27e2795d04583263ad473f6ae511292eafc18 [file] [log] [blame]
package ctxext
import (
"math/rand"
"testing"
"time"
context "golang.org/x/net/context"
)
func TestWithParentsSingle(t *testing.T) {
ctx1, cancel := context.WithCancel(context.Background())
ctx2 := WithParents(ctx1)
select {
case <-ctx2.Done():
t.Fatal("ended too early")
case <-time.After(time.Millisecond):
}
cancel()
select {
case <-ctx2.Done():
case <-time.After(time.Millisecond):
t.Error("should've cancelled it")
}
if ctx2.Err() != ctx1.Err() {
t.Error("errors should match")
}
}
func TestWithParentsDeadline(t *testing.T) {
ctx1, _ := context.WithCancel(context.Background())
ctx2, _ := context.WithTimeout(context.Background(), time.Second)
ctx3, _ := context.WithTimeout(context.Background(), time.Second*2)
ctx := WithParents(ctx1)
d, ok := ctx.Deadline()
if ok {
t.Error("ctx should have no deadline")
}
ctx = WithParents(ctx1, ctx2, ctx3)
d, ok = ctx.Deadline()
d2, ok2 := ctx2.Deadline()
if !ok {
t.Error("ctx should have deadline")
} else if !ok2 {
t.Error("ctx2 should have deadline")
} else if !d.Equal(d2) {
t.Error("ctx should have ctx2 deadline")
}
}
func SubtestWithParentsMany(t *testing.T, n int) {
ctxs := make([]context.Context, n)
cancels := make([]context.CancelFunc, n)
for i := 0; i < n; i++ {
if i == 0 { // first must be new.
ctxs[i], cancels[i] = context.WithCancel(context.Background())
continue
}
r := rand.Intn(i) // select a previous context
switch rand.Intn(6) {
case 0: // same as old
ctxs[i], cancels[i] = ctxs[r], cancels[r]
case 1: // derive from another
ctxs[i], cancels[i] = context.WithCancel(ctxs[r])
case 2: // deadline
t := (time.Second) * time.Duration(r+2) // +2 so we dont run into 0 or timing bugs
ctxs[i], cancels[i] = context.WithTimeout(ctxs[r], t)
default: // new context
ctxs[i], cancels[i] = context.WithCancel(context.Background())
}
}
ctx := WithParents(ctxs...)
// test deadline is earliest.
d1 := earliestDeadline(ctxs)
d2, ok := ctx.Deadline()
switch {
case d1 == nil && ok:
t.Error("nil, should not have deadline")
case d1 != nil && !ok:
t.Error("not nil, should have deadline")
case d1 != nil && ok && !d1.Equal(d2):
t.Error("should find same deadline")
}
if ok {
t.Logf("deadline - now: %s", d2.Sub(time.Now()))
}
select {
case <-ctx.Done():
t.Fatal("ended too early")
case <-time.After(time.Millisecond):
}
// cancel just one
r := rand.Intn(len(cancels))
cancels[r]()
select {
case <-ctx.Done():
case <-time.After(time.Millisecond):
t.Error("any should've cancelled it")
}
if ctx.Err() != ctxs[r].Err() {
t.Error("errors should match")
}
}
func TestWithParentsMany(t *testing.T) {
n := 100
for i := 1; i < n; i++ {
SubtestWithParentsMany(t, i)
}
}