context: setup timeout context

This commit is contained in:
vinchent 2024-09-21 20:20:15 +02:00
parent d49f952035
commit 0b181ccf0f
2 changed files with 65 additions and 14 deletions

View File

@ -7,10 +7,24 @@ import (
type Store interface { type Store interface {
Fetch() string Fetch() string
Cancel()
} }
func Server(store Store) http.HandlerFunc { func Server(store Store) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, store.Fetch()) ctx := r.Context()
data := make(chan string, 1)
go func() {
data <- store.Fetch()
}()
select {
case d := <-data:
fmt.Fprint(w, d)
case <-ctx.Done():
store.Cancel()
}
} }
} }

View File

@ -1,22 +1,32 @@
package context package context
import ( import (
"context"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"time"
) )
type SpyStore struct { type SpyStore struct {
response string response string
cancelled bool
} }
func (s *SpyStore) Fetch() string { func (s *SpyStore) Fetch() string {
time.Sleep(100 * time.Millisecond)
return s.response return s.response
} }
func (s *SpyStore) Cancel() {
s.cancelled = true
}
func TestServer(t *testing.T) { func TestServer(t *testing.T) {
t.Run("basic get store", func(t *testing.T) {
data := "hello, world" data := "hello, world"
srv := Server(&SpyStore{data}) store := &SpyStore{response: data}
srv := Server(store)
request := httptest.NewRequest(http.MethodGet, "/", nil) request := httptest.NewRequest(http.MethodGet, "/", nil)
response := httptest.NewRecorder() response := httptest.NewRecorder()
@ -26,4 +36,31 @@ func TestServer(t *testing.T) {
if response.Body.String() != data { if response.Body.String() != data {
t.Errorf(`got "%s", want "%s"`, response.Body.String(), data) t.Errorf(`got "%s", want "%s"`, response.Body.String(), data)
} }
if store.cancelled {
t.Error("it should not have cancelled the store")
}
})
t.Run("tells store to cancel work if request is cancelled", func(t *testing.T) {
data := "hello, world"
store := &SpyStore{response: data}
srv := Server(store)
request := httptest.NewRequest(http.MethodGet, "/", nil)
cancellingCtx, cancel := context.WithCancel(request.Context())
// Wait 5ms to call cancel
time.AfterFunc(5*time.Millisecond, cancel)
request = request.WithContext(cancellingCtx)
response := httptest.NewRecorder()
srv.ServeHTTP(response, request)
if !store.cancelled {
t.Error("store was not told to cancel")
}
})
} }