2018-12-06 04:40:46 +00:00
|
|
|
package mrun
|
|
|
|
|
|
|
|
import (
|
2019-02-05 20:18:17 +00:00
|
|
|
"context"
|
2018-12-06 04:40:46 +00:00
|
|
|
"errors"
|
|
|
|
. "testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/mediocregopher/mediocre-go-lib/mctx"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestThreadWait(t *T) {
|
|
|
|
testErr := errors.New("test error")
|
|
|
|
|
|
|
|
cancelCh := func(t time.Duration) <-chan struct{} {
|
2019-02-05 20:18:17 +00:00
|
|
|
tCtx, _ := context.WithTimeout(context.Background(), t*2)
|
2018-12-06 04:40:46 +00:00
|
|
|
return tCtx.Done()
|
|
|
|
}
|
|
|
|
|
2019-02-05 20:18:17 +00:00
|
|
|
wait := func(ctx context.Context, shouldTake time.Duration) error {
|
2018-12-06 04:40:46 +00:00
|
|
|
start := time.Now()
|
|
|
|
err := Wait(ctx, cancelCh(shouldTake*2))
|
|
|
|
if took := time.Since(start); took < shouldTake || took > shouldTake*4/3 {
|
|
|
|
t.Fatalf("wait took %v, should have taken %v", took, shouldTake)
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("noChildren", func(t *T) {
|
|
|
|
t.Run("noBlock", func(t *T) {
|
|
|
|
t.Run("noErr", func(t *T) {
|
2019-02-05 20:18:17 +00:00
|
|
|
ctx := context.Background()
|
2019-02-24 22:38:05 +00:00
|
|
|
ctx = WithThreads(ctx, 1, func() error { return nil })
|
2018-12-06 04:40:46 +00:00
|
|
|
if err := Wait(ctx, nil); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("err", func(t *T) {
|
2019-02-05 20:18:17 +00:00
|
|
|
ctx := context.Background()
|
2019-02-24 22:38:05 +00:00
|
|
|
ctx = WithThreads(ctx, 1, func() error { return testErr })
|
2018-12-06 04:40:46 +00:00
|
|
|
if err := Wait(ctx, nil); err != testErr {
|
|
|
|
t.Fatalf("should have got test error, got: %v", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("block", func(t *T) {
|
|
|
|
t.Run("noErr", func(t *T) {
|
2019-02-05 20:18:17 +00:00
|
|
|
ctx := context.Background()
|
2019-02-24 22:38:05 +00:00
|
|
|
ctx = WithThreads(ctx, 1, func() error {
|
2018-12-06 04:40:46 +00:00
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
if err := wait(ctx, 1*time.Second); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("err", func(t *T) {
|
2019-02-05 20:18:17 +00:00
|
|
|
ctx := context.Background()
|
2019-02-24 22:38:05 +00:00
|
|
|
ctx = WithThreads(ctx, 1, func() error {
|
2018-12-06 04:40:46 +00:00
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
return testErr
|
|
|
|
})
|
|
|
|
if err := wait(ctx, 1*time.Second); err != testErr {
|
|
|
|
t.Fatalf("should have got test error, got: %v", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("canceled", func(t *T) {
|
2019-02-05 20:18:17 +00:00
|
|
|
ctx := context.Background()
|
2019-02-24 22:38:05 +00:00
|
|
|
ctx = WithThreads(ctx, 1, func() error {
|
2018-12-06 04:40:46 +00:00
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
return testErr
|
|
|
|
})
|
|
|
|
if err := Wait(ctx, cancelCh(500*time.Millisecond)); err != ErrDone {
|
|
|
|
t.Fatalf("should have got ErrDone, got: %v", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2019-02-05 20:18:17 +00:00
|
|
|
ctxWithChild := func() (context.Context, context.Context) {
|
|
|
|
ctx := context.Background()
|
|
|
|
return ctx, mctx.NewChild(ctx, "child")
|
2018-12-06 04:40:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("children", func(t *T) {
|
|
|
|
t.Run("noBlock", func(t *T) {
|
|
|
|
t.Run("noErr", func(t *T) {
|
|
|
|
ctx, childCtx := ctxWithChild()
|
2019-02-24 22:38:05 +00:00
|
|
|
childCtx = WithThreads(childCtx, 1, func() error { return nil })
|
2019-02-05 20:18:17 +00:00
|
|
|
ctx = mctx.WithChild(ctx, childCtx)
|
2018-12-06 04:40:46 +00:00
|
|
|
if err := Wait(ctx, nil); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("err", func(t *T) {
|
|
|
|
ctx, childCtx := ctxWithChild()
|
2019-02-24 22:38:05 +00:00
|
|
|
childCtx = WithThreads(childCtx, 1, func() error { return testErr })
|
2019-02-05 20:18:17 +00:00
|
|
|
ctx = mctx.WithChild(ctx, childCtx)
|
2018-12-06 04:40:46 +00:00
|
|
|
if err := Wait(ctx, nil); err != testErr {
|
|
|
|
t.Fatalf("should have got test error, got: %v", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("block", func(t *T) {
|
|
|
|
t.Run("noErr", func(t *T) {
|
|
|
|
ctx, childCtx := ctxWithChild()
|
2019-02-24 22:38:05 +00:00
|
|
|
childCtx = WithThreads(childCtx, 1, func() error {
|
2018-12-06 04:40:46 +00:00
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
return nil
|
|
|
|
})
|
2019-02-05 20:18:17 +00:00
|
|
|
ctx = mctx.WithChild(ctx, childCtx)
|
2018-12-06 04:40:46 +00:00
|
|
|
if err := wait(ctx, 1*time.Second); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("err", func(t *T) {
|
|
|
|
ctx, childCtx := ctxWithChild()
|
2019-02-24 22:38:05 +00:00
|
|
|
childCtx = WithThreads(childCtx, 1, func() error {
|
2018-12-06 04:40:46 +00:00
|
|
|
time.Sleep(1 * time.Second)
|
|
|
|
return testErr
|
|
|
|
})
|
2019-02-05 20:18:17 +00:00
|
|
|
ctx = mctx.WithChild(ctx, childCtx)
|
2018-12-06 04:40:46 +00:00
|
|
|
if err := wait(ctx, 1*time.Second); err != testErr {
|
|
|
|
t.Fatalf("should have got test error, got: %v", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("canceled", func(t *T) {
|
|
|
|
ctx, childCtx := ctxWithChild()
|
2019-02-24 22:38:05 +00:00
|
|
|
childCtx = WithThreads(childCtx, 1, func() error {
|
2018-12-06 04:40:46 +00:00
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
return testErr
|
|
|
|
})
|
2019-02-05 20:18:17 +00:00
|
|
|
ctx = mctx.WithChild(ctx, childCtx)
|
2018-12-06 04:40:46 +00:00
|
|
|
if err := Wait(ctx, cancelCh(500*time.Millisecond)); err != ErrDone {
|
|
|
|
t.Fatalf("should have got ErrDone, got: %v", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|