Skip to content

Instantly share code, notes, and snippets.

@rotemtam
Created May 18, 2020 05:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rotemtam/f21e17e03f21468895fe59000fe5f8c5 to your computer and use it in GitHub Desktop.
Save rotemtam/f21e17e03f21468895fe59000fe5f8c5 to your computer and use it in GitHub Desktop.
Over DRY
package loader
import (
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
)
type Requester func(t *testing.T, srv *httptest.Server) *http.Response
type Validator struct {
predicate func(r *http.Response) (bool, error)
errorMessage string
}
func (v Validator) Validate(t *testing.T, resp *http.Response) {
if valid, err := v.predicate(resp); err != nil {
t.Fatal(err)
} else if !valid {
t.Fatal(v.errorMessage)
}
}
func runWebserverTest(t *testing.T, request Requester, validators []Validator) {
srv := createTestWebserver()
defer srv.Close()
response := request(t, srv)
for _, validator := range validators {
validator.Validate(t, response)
}
}
func getRequester(path string) Requester {
return func(t *testing.T, srv *httptest.Server) *http.Response {
resp, err := http.Get(srv.URL + path)
if err != nil {
t.Fatal("failed calling test server")
return nil
}
return resp
}
}
func getBodyValidator(expectedBody string) Validator {
return Validator{
predicate: func(r *http.Response) (bool, error) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
return false, err
}
fmt.Println(string(body))
return string(body) == expectedBody, nil
},
errorMessage: fmt.Sprintf("Expected body to be [%s]", expectedBody),
}
}
func getStatusCodeValidator(expectedStatus int) Validator {
return Validator{
predicate: func(r *http.Response) (bool, error) {
return r.StatusCode == expectedStatus, nil
},
errorMessage: fmt.Sprintf("Expected status to be [%d]", expectedStatus),
}
}
func getHeaderValidator(headerName string, expectedValue string) Validator {
return Validator{
predicate: func(r *http.Response) (bool, error) {
return r.Header.Get(headerName) == expectedValue, nil
},
errorMessage: fmt.Sprintf("Expected header [%s] to be [%s]", headerName, expectedValue),
}
}
func Test_DRY_bad_path_500(t *testing.T) {
runWebserverTest(t,
getRequester("/bad/path"),
[]Validator{
getStatusCodeValidator(500),
getBodyValidator("500 internal server error: failed handling /bad/path"),
})
}
func Test_DRY_unknown_path_404(t *testing.T) {
runWebserverTest(t,
getRequester("/unknown/path"),
[]Validator{
getStatusCodeValidator(404),
getHeaderValidator("X-Sensitive-Header", ""),
})
}
func TestWebserver_bad_path_500(t *testing.T) {
srv := createTestWebserver()
defer srv.Close()
resp, err := http.Get(srv.URL + "/bad/path")
if err != nil {
t.Fatal("failed calling test server")
}
if resp.StatusCode != 500 {
t.Fatalf("expected response code to be 500")
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatal("failed reading body bytes")
}
if string(body) != "500 internal server error: failed handling /bad/path" {
t.Fatalf("body does not match expected")
}
}
func TestWebserver_unknown_path_404(t *testing.T) {
srv := createTestWebserver()
defer srv.Close()
resp, err := http.Get(srv.URL + "/unknown/path")
if err != nil {
t.Fatal("failed calling test server")
}
if resp.StatusCode != 404 {
t.Fatalf("expected response code to be 400")
}
if resp.Header.Get("X-Sensitive-Header") != "" {
t.Fatalf("expecting sensitive header not to be sent")
}
}
func createTestWebserver() *httptest.Server {
mux := http.NewServeMux()
mux.HandleFunc("/bad/path", func(writer http.ResponseWriter, request *http.Request) {
writer.WriteHeader(500)
body := fmt.Sprintf("500 internal server error: failed handling %s", request.URL.Path)
_, _ = writer.Write([]byte(body))
})
return httptest.NewServer(mux)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment