175 lines
4.5 KiB
Go
175 lines
4.5 KiB
Go
|
|
package stario
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"errors"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestWaitUntilContextReturnsWorkerError(t *testing.T) {
|
||
|
|
want := errors.New("worker failed")
|
||
|
|
err := WaitUntilContext(context.Background(), func(ctx context.Context) error {
|
||
|
|
return want
|
||
|
|
})
|
||
|
|
if !errors.Is(err, want) {
|
||
|
|
t.Fatalf("unexpected error: got %v want %v", err, want)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestWaitUntilContextReturnsDeadlineExceeded(t *testing.T) {
|
||
|
|
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Millisecond)
|
||
|
|
defer cancel()
|
||
|
|
workerReturned := make(chan struct{})
|
||
|
|
err := WaitUntilContext(ctx, func(ctx context.Context) error {
|
||
|
|
<-ctx.Done()
|
||
|
|
close(workerReturned)
|
||
|
|
return nil
|
||
|
|
})
|
||
|
|
if !errors.Is(err, context.DeadlineExceeded) {
|
||
|
|
t.Fatalf("unexpected context error: %v", err)
|
||
|
|
}
|
||
|
|
select {
|
||
|
|
case <-workerReturned:
|
||
|
|
case <-time.After(200 * time.Millisecond):
|
||
|
|
t.Fatal("worker did not return after context deadline")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestWaitUntilContextFinishedReturnsCanceled(t *testing.T) {
|
||
|
|
ctx, cancel := context.WithCancel(context.Background())
|
||
|
|
cancel()
|
||
|
|
result := WaitUntilContextFinished(ctx, func(ctx context.Context) error {
|
||
|
|
<-ctx.Done()
|
||
|
|
return nil
|
||
|
|
})
|
||
|
|
err, ok := <-result
|
||
|
|
if !ok {
|
||
|
|
t.Fatal("result channel closed without value")
|
||
|
|
}
|
||
|
|
if !errors.Is(err, context.Canceled) {
|
||
|
|
t.Fatalf("unexpected context error: %v", err)
|
||
|
|
}
|
||
|
|
if _, ok := <-result; ok {
|
||
|
|
t.Fatal("result channel should be closed after delivering the outcome")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestWaitUntilContextDoneBridgesDoneChannel(t *testing.T) {
|
||
|
|
ctx, cancel := context.WithCancel(context.Background())
|
||
|
|
doneClosed := make(chan struct{})
|
||
|
|
go func() {
|
||
|
|
time.Sleep(20 * time.Millisecond)
|
||
|
|
cancel()
|
||
|
|
}()
|
||
|
|
err := WaitUntilContextDone(ctx, func(done <-chan struct{}) error {
|
||
|
|
<-done
|
||
|
|
close(doneClosed)
|
||
|
|
return nil
|
||
|
|
})
|
||
|
|
if !errors.Is(err, context.Canceled) {
|
||
|
|
t.Fatalf("unexpected context error: %v", err)
|
||
|
|
}
|
||
|
|
select {
|
||
|
|
case <-doneClosed:
|
||
|
|
case <-time.After(200 * time.Millisecond):
|
||
|
|
t.Fatal("done channel was not closed when context canceled")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestWaitUntilContextDoneFinishedReturnsCanceled(t *testing.T) {
|
||
|
|
ctx, cancel := context.WithCancel(context.Background())
|
||
|
|
doneClosed := make(chan struct{})
|
||
|
|
go func() {
|
||
|
|
time.Sleep(20 * time.Millisecond)
|
||
|
|
cancel()
|
||
|
|
}()
|
||
|
|
result := WaitUntilContextDoneFinished(ctx, func(done <-chan struct{}) error {
|
||
|
|
<-done
|
||
|
|
close(doneClosed)
|
||
|
|
return nil
|
||
|
|
})
|
||
|
|
err, ok := <-result
|
||
|
|
if !ok {
|
||
|
|
t.Fatal("result channel closed without value")
|
||
|
|
}
|
||
|
|
if !errors.Is(err, context.Canceled) {
|
||
|
|
t.Fatalf("unexpected context error: %v", err)
|
||
|
|
}
|
||
|
|
select {
|
||
|
|
case <-doneClosed:
|
||
|
|
case <-time.After(200 * time.Millisecond):
|
||
|
|
t.Fatal("done channel was not closed when context canceled")
|
||
|
|
}
|
||
|
|
if _, ok := <-result; ok {
|
||
|
|
t.Fatal("result channel should be closed after delivering the outcome")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestWaitUntilTimeoutReturnsWorkerError(t *testing.T) {
|
||
|
|
want := errors.New("worker failed")
|
||
|
|
err := WaitUntilTimeout(time.Second, func(stop chan struct{}) error {
|
||
|
|
return want
|
||
|
|
})
|
||
|
|
if !errors.Is(err, want) {
|
||
|
|
t.Fatalf("unexpected error: got %v want %v", err, want)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestWaitUntilTimeoutTimesOutWithoutBlockingWorkerReturn(t *testing.T) {
|
||
|
|
workerReturned := make(chan struct{})
|
||
|
|
err := WaitUntilTimeout(20*time.Millisecond, func(stop chan struct{}) error {
|
||
|
|
<-stop
|
||
|
|
close(workerReturned)
|
||
|
|
return nil
|
||
|
|
})
|
||
|
|
if !errors.Is(err, ERR_TIMEOUT) {
|
||
|
|
t.Fatalf("unexpected timeout error: %v", err)
|
||
|
|
}
|
||
|
|
select {
|
||
|
|
case <-workerReturned:
|
||
|
|
case <-time.After(200 * time.Millisecond):
|
||
|
|
t.Fatal("worker did not return after timeout signal")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestWaitUntilFinishedReturnsWorkerError(t *testing.T) {
|
||
|
|
want := errors.New("worker failed")
|
||
|
|
err := <-WaitUntilFinished(func() error {
|
||
|
|
return want
|
||
|
|
})
|
||
|
|
if !errors.Is(err, want) {
|
||
|
|
t.Fatalf("unexpected error: got %v want %v", err, want)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestWaitUntilTimeoutFinishedReturnsTimeout(t *testing.T) {
|
||
|
|
result := WaitUntilTimeoutFinished(20*time.Millisecond, func(stop chan struct{}) error {
|
||
|
|
<-stop
|
||
|
|
return nil
|
||
|
|
})
|
||
|
|
err, ok := <-result
|
||
|
|
if !ok {
|
||
|
|
t.Fatal("result channel closed without value")
|
||
|
|
}
|
||
|
|
if !errors.Is(err, ERR_TIMEOUT) {
|
||
|
|
t.Fatalf("unexpected timeout error: %v", err)
|
||
|
|
}
|
||
|
|
if _, ok := <-result; ok {
|
||
|
|
t.Fatal("result channel should be closed after delivering the outcome")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestWaitUntilTimeoutFinishedReturnsWorkerError(t *testing.T) {
|
||
|
|
want := errors.New("worker failed")
|
||
|
|
err, ok := <-WaitUntilTimeoutFinished(time.Second, func(stop chan struct{}) error {
|
||
|
|
return want
|
||
|
|
})
|
||
|
|
if !ok {
|
||
|
|
t.Fatal("result channel closed without value")
|
||
|
|
}
|
||
|
|
if !errors.Is(err, want) {
|
||
|
|
t.Fatalf("unexpected error: got %v want %v", err, want)
|
||
|
|
}
|
||
|
|
}
|