PPysolate SpineREAD THE CODE · UNDERSTAND THE SYSTEM
课程与章节
源码索引 / 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)
	}
}