-
Notifications
You must be signed in to change notification settings - Fork 369
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make MockHTTPServer for tests (#888)
Factored out the httptest.Server / handler into one struct for easier reuse in tests.
- Loading branch information
1 parent
f97e5d1
commit 1c01916
Showing
3 changed files
with
96 additions
and
114 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package testutility | ||
|
||
import ( | ||
"log" | ||
"net/http" | ||
"net/http/httptest" | ||
"os" | ||
"strings" | ||
"sync" | ||
"testing" | ||
) | ||
|
||
type MockHTTPServer struct { | ||
*httptest.Server | ||
mu sync.Mutex | ||
response map[string][]byte // path -> response | ||
authorization string // expected Authorization header contents | ||
} | ||
|
||
// NewMockHTTPServer starts and returns a new simple HTTP Server for mocking basic requests. | ||
// The Server will automatically be shut down with Close() in the test Cleanup function. | ||
// | ||
// Use the SetResponse / SetResponseFromFile to set the responses for specific URL paths. | ||
func NewMockHTTPServer(t *testing.T) *MockHTTPServer { | ||
t.Helper() | ||
mock := &MockHTTPServer{response: make(map[string][]byte)} | ||
mock.Server = httptest.NewServer(mock) | ||
t.Cleanup(func() { mock.Server.Close() }) | ||
|
||
return mock | ||
} | ||
|
||
// SetResponse sets the Server's response for the URL path to be response bytes. | ||
func (m *MockHTTPServer) SetResponse(t *testing.T, path string, response []byte) { | ||
t.Helper() | ||
m.mu.Lock() | ||
defer m.mu.Unlock() | ||
path = strings.TrimPrefix(path, "/") | ||
m.response[path] = response | ||
} | ||
|
||
// SetResponseFromFile sets the Server's response for the URL path to be the contents of the file at filename. | ||
func (m *MockHTTPServer) SetResponseFromFile(t *testing.T, path string, filename string) { | ||
t.Helper() | ||
b, err := os.ReadFile(filename) | ||
if err != nil { | ||
t.Fatalf("failed to read response file: %v", err) | ||
} | ||
m.SetResponse(t, path, b) | ||
} | ||
|
||
// SetAuthorization sets the contents of the 'Authorization' header the server expects for all endpoints. | ||
// | ||
// The incoming requests' headers must match the auth string exactly, otherwise the server will response with 401 Unauthorized. | ||
// If authorization is unset or empty, the server will not require authorization. | ||
func (m *MockHTTPServer) SetAuthorization(t *testing.T, auth string) { | ||
t.Helper() | ||
m.mu.Lock() | ||
defer m.mu.Unlock() | ||
m.authorization = auth | ||
} | ||
|
||
// ServeHTTP is the http.Handler for the underlying httptest.Server. | ||
func (m *MockHTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
path := r.URL.RawPath | ||
if path == "" { | ||
path = r.URL.Path | ||
} | ||
m.mu.Lock() | ||
wantAuth := m.authorization | ||
resp, ok := m.response[strings.TrimPrefix(path, "/")] | ||
m.mu.Unlock() | ||
|
||
if wantAuth != "" && r.Header.Get("Authorization") != wantAuth { | ||
w.WriteHeader(http.StatusUnauthorized) | ||
resp = []byte("unauthorized") | ||
} else if !ok { | ||
w.WriteHeader(http.StatusNotFound) | ||
resp = []byte("not found") | ||
} | ||
|
||
if _, err := w.Write(resp); err != nil { | ||
log.Fatalf("Write: %v", err) | ||
} | ||
} |