2019-03-29 18:47:40 +00:00
|
|
|
package testutil
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"sync"
|
|
|
|
)
|
|
|
|
|
|
|
|
// assert ResponseRecorder implements the http.ResponseWriter interface
|
|
|
|
var _ http.ResponseWriter = (*ResponseRecorder)(nil)
|
|
|
|
|
|
|
|
// ResponseRecorder implements a ResponseWriter which can be written to and
|
|
|
|
// read from concurrently. For use in testing streaming APIs where
|
|
|
|
// httptest.ResponseRecorder is unsafe for concurrent access. Uses
|
|
|
|
// httptest.ResponseRecorder internally and exposes most of the functionality.
|
|
|
|
type ResponseRecorder struct {
|
|
|
|
rr *httptest.ResponseRecorder
|
|
|
|
mu sync.Mutex
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewResponseRecorder() *ResponseRecorder {
|
|
|
|
return &ResponseRecorder{
|
|
|
|
rr: httptest.NewRecorder(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Flush sets Flushed=true.
|
|
|
|
func (r *ResponseRecorder) Flush() {
|
|
|
|
r.mu.Lock()
|
|
|
|
defer r.mu.Unlock()
|
|
|
|
r.rr.Flush()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Flushed returns true if Flush has been called.
|
|
|
|
func (r *ResponseRecorder) Flushed() bool {
|
|
|
|
r.mu.Lock()
|
|
|
|
defer r.mu.Unlock()
|
|
|
|
return r.rr.Flushed
|
|
|
|
}
|
|
|
|
|
|
|
|
// Header returns the response headers. Readers should call HeaderMap() to
|
|
|
|
// avoid races due to the server concurrently mutating headers.
|
|
|
|
func (r *ResponseRecorder) Header() http.Header {
|
|
|
|
r.mu.Lock()
|
|
|
|
defer r.mu.Unlock()
|
|
|
|
return r.rr.Header()
|
|
|
|
}
|
|
|
|
|
|
|
|
// HeaderMap returns the HTTP headers written before WriteHeader was called.
|
|
|
|
func (r *ResponseRecorder) HeaderMap() http.Header {
|
|
|
|
r.mu.Lock()
|
|
|
|
defer r.mu.Unlock()
|
2022-01-12 15:10:25 +00:00
|
|
|
return r.rr.Result().Header
|
2019-03-29 18:47:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Write to the underlying response buffer. Safe to call concurrent with Read.
|
|
|
|
func (r *ResponseRecorder) Write(p []byte) (int, error) {
|
|
|
|
r.mu.Lock()
|
|
|
|
defer r.mu.Unlock()
|
|
|
|
return r.rr.Body.Write(p)
|
|
|
|
}
|
|
|
|
|
|
|
|
// WriteHeader sets the response code and freezes the headers returned by
|
|
|
|
// HeaderMap. Safe to call concurrent with Read and HeaderMap.
|
|
|
|
func (r *ResponseRecorder) WriteHeader(statusCode int) {
|
|
|
|
r.mu.Lock()
|
|
|
|
defer r.mu.Unlock()
|
|
|
|
r.rr.WriteHeader(statusCode)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read available response bytes. Safe to call concurrently with Write().
|
|
|
|
func (r *ResponseRecorder) Read(p []byte) (int, error) {
|
|
|
|
r.mu.Lock()
|
|
|
|
defer r.mu.Unlock()
|
|
|
|
return r.rr.Body.Read(p)
|
|
|
|
}
|