源码索引 / CURRENT IMPLEMENTATION
learning/go-patterns/stages/04-context/main_test.go
78 行 · 点击行号可定位;函数链接随声明位置更新,不手填行号。
跳到函数 / 声明
package main
import (
"context"
"errors"
"testing"
"time"
)
func TestQuoteReturnsDeadlineExceeded(t *testing.T) {
service := NewService(NewDelayedCatalog(
Catalog{"book": {Item: "book", Cents: 2100}},
time.Hour,
))
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
defer cancel()
_, err := service.Quote(ctx, "book")
if !errors.Is(err, context.DeadlineExceeded) {
t.Fatalf("errors.Is(%v, context.DeadlineExceeded) = false", err)
}
}
type blockingSource struct {
started chan struct{}
}
func (s *blockingSource) Lookup(ctx context.Context, _ string) (Price, error) {
close(s.started)
<-ctx.Done()
return Price{}, ctx.Err()
}
func TestQuotePropagatesCancellationToSource(t *testing.T) {
source := &blockingSource{started: make(chan struct{})}
service := NewService(source)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
result := make(chan error, 1)
go func() {
_, err := service.Quote(ctx, "book")
result <- err
}()
select {
case <-source.started:
case <-time.After(time.Second):
t.Fatal("source did not start")
}
cancel()
select {
case err := <-result:
if !errors.Is(err, context.Canceled) {
t.Fatalf("errors.Is(%v, context.Canceled) = false", err)
}
case <-time.After(time.Second):
t.Fatal("Quote did not return after cancellation")
}
}
func TestQuoteReturnsPriceBeforeDeadline(t *testing.T) {
service := NewService(NewDelayedCatalog(
Catalog{"book": {Item: "book", Cents: 2100}},
5*time.Millisecond,
))
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
got, err := service.Quote(ctx, "book")
if err != nil {
t.Fatalf("Quote returned error: %v", err)
}
if got.Cents != 2100 {
t.Fatalf("Quote returned %#v", got)
}
}