context: setup timeout context
This commit is contained in:
		@ -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()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,29 +1,66 @@
 | 
				
			|||||||
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 TestServer(t *testing.T) {
 | 
					func (s *SpyStore) Cancel() {
 | 
				
			||||||
	data := "hello, world"
 | 
						s.cancelled = true
 | 
				
			||||||
	srv := Server(&SpyStore{data})
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	request := httptest.NewRequest(http.MethodGet, "/", nil)
 | 
					func TestServer(t *testing.T) {
 | 
				
			||||||
	response := httptest.NewRecorder()
 | 
						t.Run("basic get store", func(t *testing.T) {
 | 
				
			||||||
 | 
							data := "hello, world"
 | 
				
			||||||
	srv.ServeHTTP(response, request)
 | 
							store := &SpyStore{response: data}
 | 
				
			||||||
 | 
							srv := Server(store)
 | 
				
			||||||
	if response.Body.String() != data {
 | 
					
 | 
				
			||||||
		t.Errorf(`got "%s", want "%s"`, response.Body.String(), data)
 | 
							request := httptest.NewRequest(http.MethodGet, "/", nil)
 | 
				
			||||||
	}
 | 
							response := httptest.NewRecorder()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							srv.ServeHTTP(response, request)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if 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")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user