internal/testserver/testserver.go (64 lines of code) (raw):
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package testserver provides utility functions for stubbing HTTP requests in tests.
package testserver
import (
"net/http"
"net/http/httptest"
"testing"
)
type config struct {
httpStatus int
responseFile string
responseJSON string
mockURL *string
}
// Option configures test servers.
type Option func(o *config)
// WithStatus sets the http response code to return.
func WithStatus(httpStatus int) Option {
return func(c *config) {
c.httpStatus = httpStatus
}
}
// WithJSON sets the JSON payload the server send in the response body.
func WithJSON(json string) Option {
return func(c *config) {
c.responseJSON = json
}
}
// WithFile sets the path of a file the server should send as a response.
func WithFile(path string) Option {
return func(c *config) {
c.responseFile = path
}
}
// WithMockURL stubs the provided URL to point to this test server for the duration of a unit test.
func WithMockURL(url *string) Option {
return func(c *config) {
c.mockURL = url
}
}
// New creates and starts a test server with the provided configurations and returns its URL.
func New(t *testing.T, opts ...Option) *httptest.Server {
t.Helper()
options := config{}
for _, o := range opts {
o(&options)
}
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if options.httpStatus != 0 {
w.WriteHeader(options.httpStatus)
}
if options.responseFile != "" {
http.ServeFile(w, r, options.responseFile)
return
}
if options.responseJSON != "" {
w.Header().Set("Content-Type", "application/json")
}
if _, err := w.Write([]byte(options.responseJSON)); err != nil {
// Not using Fatalf because this runs in a separate Go Routine.
t.Errorf("sending stubbed http response: %v", err)
}
}))
t.Cleanup(svr.Close)
if options.mockURL != nil {
origVal := *options.mockURL
t.Cleanup(func() {
*options.mockURL = origVal
})
*options.mockURL = svr.URL + "?p1=%s&p2=%s&p3=%s"
}
return svr
}