13dab7dd24
* Divest api/ package of deps elsewhere in the nomad repo. This will allow making api/ a module without then pulling in the external repo, leading to a package name conflict. This required some migration of tests to an apitests/ folder (can be moved anywhere as it has no deps on it). It also required some duplication of code, notably some test helpers from api/ -> apitests/ and part (but not all) of testutil/ -> api/testutil/. Once there's more separation and an e.g. sdk/ folder those can be removed in favor of a dep on the sdk/ folder, provided the sdk/ folder doesn't depend on api/ or /. * Also remove consul dep from api/ package * Fix stupid linters * Some restructuring
77 lines
2 KiB
Go
77 lines
2 KiB
Go
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()
|
|
return r.rr.HeaderMap
|
|
}
|
|
|
|
// 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)
|
|
}
|