From 36a1e66d7f671a1ede5d58d19c6af3952f3e1d33 Mon Sep 17 00:00:00 2001 From: Nate Meyer <672246+notnmeyer@users.noreply.github.com> Date: Thu, 19 Oct 2023 20:40:21 -0700 Subject: [PATCH 1/6] move the handler to a named function move the handler to a named function --- main.go | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/main.go b/main.go index a655790..373d0df 100644 --- a/main.go +++ b/main.go @@ -9,29 +9,7 @@ import ( ) func main() { - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - var ( - contentType = "application/json; charset=utf-8" - responseBody = r.Header["X-Response-Json"][0] - responseCode int - ) - - responseCode, err := validateResponseCode(r.Header) - if err != nil { - responseBody = err.Error() - contentType = "text/plain; charset=utf-8" - } - - if !isJSON(responseBody) { - responseBody = fmt.Errorf("x-response-json must be valid JSON").Error() - responseCode = http.StatusBadRequest - contentType = "text/plain; charset=utf-8" - } - - w.Header().Set("Content-Type", contentType) - w.WriteHeader(responseCode) - w.Write([]byte(responseBody)) - }) + http.HandleFunc("/", handler) listenAddr := ":8080" fmt.Printf("Listening on %s...\n", listenAddr) @@ -41,6 +19,30 @@ func main() { } } +func handler(w http.ResponseWriter, r *http.Request) { + var ( + contentType = "application/json; charset=utf-8" + responseBody = r.Header["X-Response-Json"][0] + responseCode int + ) + + responseCode, err := validateResponseCode(r.Header) + if err != nil { + responseBody = err.Error() + contentType = "text/plain; charset=utf-8" + } + + if !isJSON(responseBody) { + responseBody = fmt.Errorf("x-response-json must be valid JSON").Error() + responseCode = http.StatusBadRequest + contentType = "text/plain; charset=utf-8" + } + + w.Header().Set("Content-Type", contentType) + w.WriteHeader(responseCode) + w.Write([]byte(responseBody)) +} + func validateResponseCode(header map[string][]string) (int, error) { if val, exists := header["X-Response-Code"]; exists { // verify its a number From 4a6c11b650f3abcdf0847be332befa362971d62c Mon Sep 17 00:00:00 2001 From: Nate Meyer <672246+notnmeyer@users.noreply.github.com> Date: Thu, 19 Oct 2023 20:53:49 -0700 Subject: [PATCH 2/6] make port configurable make port configurable --- go.mod | 2 ++ main.go | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 92abac8..bf4b7bc 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module github.com/notnmeyer/mockpi go 1.20 + +require github.com/spf13/pflag v1.0.5 diff --git a/main.go b/main.go index 373d0df..bfcdf63 100644 --- a/main.go +++ b/main.go @@ -6,12 +6,24 @@ import ( "net/http" "os" "strconv" + + flag "github.com/spf13/pflag" ) +type config struct { + port int +} + +var c config + +func init() { + flag.IntVarP(&c.port, "port", "p", 8080, "the listen port") + flag.Parse() +} + func main() { http.HandleFunc("/", handler) - - listenAddr := ":8080" + listenAddr := fmt.Sprintf(":%d", c.port) fmt.Printf("Listening on %s...\n", listenAddr) if err := http.ListenAndServe(listenAddr, nil); err != nil { fmt.Println("server error: ", err) From dbaca695eab4f80feeaa5245a6f726ab8418ffaa Mon Sep 17 00:00:00 2001 From: Nate Meyer <672246+notnmeyer@users.noreply.github.com> Date: Thu, 19 Oct 2023 21:34:04 -0700 Subject: [PATCH 3/6] add handler test for the valid case add handler test for the valid case --- main_test.go | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/main_test.go b/main_test.go index 107efff..0c04b80 100644 --- a/main_test.go +++ b/main_test.go @@ -1,6 +1,47 @@ package main -import "testing" +import ( + "net/http" + "net/http/httptest" + "testing" +) + +func TestHandlerValidRequest(t *testing.T) { + expectedContentType := "application/json; charset=utf-8" + expectedResponseBody := `{"foo":"bar"}` + expectedResponseCode := "418" // http.StatusTeapot + + // set up the request + req, err := http.NewRequest("POST", "/test", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Add("X-Response-Json", expectedResponseBody) + req.Header.Add("X-Response-Code", expectedResponseCode) + + // make the request + rr := httptest.NewRecorder() + h := http.HandlerFunc(handler) + h.ServeHTTP(rr, req) + + // status code + if status := rr.Code; status != http.StatusTeapot { + t.Errorf("handler returned wrong status code: got '%d' want '%d'", status, http.StatusOK) + } + + // response body + if rr.Body.String() != expectedResponseBody { + t.Errorf("handler returned unexpected body: got '%s' want '%s'", rr.Body.String(), expectedResponseBody) + } + + // content-type + if rr.Header()["Content-Type"][0] != expectedContentType { + t.Errorf("handler returned wrong content-type: got '%s' wanted '%s'", rr.Header()["Content-Type"][0], expectedContentType) + } +} + +// TODO: test invalid x-response-json +// TODO: test invalid x-response-code func TestValidateResponseCode(t *testing.T) { valid := map[string][]string{ From 49de1c4be721f1c3d393de55b78476139b71c323 Mon Sep 17 00:00:00 2001 From: Nate Meyer <672246+notnmeyer@users.noreply.github.com> Date: Thu, 19 Oct 2023 21:41:56 -0700 Subject: [PATCH 4/6] fix the response code portion fix the response code portion --- main_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/main_test.go b/main_test.go index 0c04b80..155dc55 100644 --- a/main_test.go +++ b/main_test.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "net/http" "net/http/httptest" "testing" @@ -9,7 +10,7 @@ import ( func TestHandlerValidRequest(t *testing.T) { expectedContentType := "application/json; charset=utf-8" expectedResponseBody := `{"foo":"bar"}` - expectedResponseCode := "418" // http.StatusTeapot + expectedResponseCode := http.StatusTeapot // set up the request req, err := http.NewRequest("POST", "/test", nil) @@ -17,7 +18,7 @@ func TestHandlerValidRequest(t *testing.T) { t.Fatal(err) } req.Header.Add("X-Response-Json", expectedResponseBody) - req.Header.Add("X-Response-Code", expectedResponseCode) + req.Header.Add("X-Response-Code", fmt.Sprint(expectedResponseCode)) // make the request rr := httptest.NewRecorder() @@ -25,8 +26,8 @@ func TestHandlerValidRequest(t *testing.T) { h.ServeHTTP(rr, req) // status code - if status := rr.Code; status != http.StatusTeapot { - t.Errorf("handler returned wrong status code: got '%d' want '%d'", status, http.StatusOK) + if status := rr.Code; status != expectedResponseCode { + t.Errorf("handler returned wrong status code: got '%d' want '%d'", status, expectedResponseCode) } // response body From 969685d287afd375e7c0354210de771eab59803d Mon Sep 17 00:00:00 2001 From: Nate Meyer <672246+notnmeyer@users.noreply.github.com> Date: Sat, 21 Oct 2023 19:04:36 -0700 Subject: [PATCH 5/6] test error cases test error cases --- main.go | 4 +-- main_test.go | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index bfcdf63..38d62bb 100644 --- a/main.go +++ b/main.go @@ -42,9 +42,7 @@ func handler(w http.ResponseWriter, r *http.Request) { if err != nil { responseBody = err.Error() contentType = "text/plain; charset=utf-8" - } - - if !isJSON(responseBody) { + } else if !isJSON(responseBody) { responseBody = fmt.Errorf("x-response-json must be valid JSON").Error() responseCode = http.StatusBadRequest contentType = "text/plain; charset=utf-8" diff --git a/main_test.go b/main_test.go index 155dc55..2cca4bf 100644 --- a/main_test.go +++ b/main_test.go @@ -41,8 +41,75 @@ func TestHandlerValidRequest(t *testing.T) { } } -// TODO: test invalid x-response-json -// TODO: test invalid x-response-code +func TestHandlerWithInvalidXResponseJson(t *testing.T) { + expectedContentType := "text/plain; charset=utf-8" + invalidResponseBody := `{"foo":bar}` + expectedResponseBody := "x-response-json must be valid JSON" + expectedResponseCode := http.StatusBadRequest + + // set up the request + req, err := http.NewRequest("POST", "/test", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Add("X-Response-Json", invalidResponseBody) + req.Header.Add("X-Response-Code", fmt.Sprint(expectedResponseCode)) + + // make the request + rr := httptest.NewRecorder() + h := http.HandlerFunc(handler) + h.ServeHTTP(rr, req) + + // status code + if status := rr.Code; status != expectedResponseCode { + t.Errorf("handler returned wrong status code: got '%d' want '%d'", status, expectedResponseCode) + } + + // response body + if rr.Body.String() != expectedResponseBody { + t.Errorf("handler returned unexpected body: got '%s' want '%s'", rr.Body.String(), expectedResponseBody) + } + + // content-type + if rr.Header()["Content-Type"][0] != expectedContentType { + t.Errorf("handler returned wrong content-type: got '%s' wanted '%s'", rr.Header()["Content-Type"][0], expectedContentType) + } +} + +func TestHandlerWithInvalidXResponseCode(t *testing.T) { + expectedContentType := "text/plain; charset=utf-8" + expectedResponseBody := "x-response-code must be a number\n" + invalidResponseCode := "blah" + expectedResponseCode := http.StatusBadRequest + + // set up the request + req, err := http.NewRequest("POST", "/test", nil) + if err != nil { + t.Fatal(err) + } + req.Header.Add("X-Response-Json", "{}") + req.Header.Add("X-Response-Code", invalidResponseCode) + + // make the request + rr := httptest.NewRecorder() + h := http.HandlerFunc(handler) + h.ServeHTTP(rr, req) + + // status code + if status := rr.Code; status != expectedResponseCode { + t.Errorf("handler returned wrong status code: got '%d' want '%d'", status, expectedResponseCode) + } + + // response body + if rr.Body.String() != expectedResponseBody { + t.Errorf("handler returned unexpected body: got '%s' want '%s'", rr.Body.String(), expectedResponseBody) + } + + // content-type + if rr.Header()["Content-Type"][0] != expectedContentType { + t.Errorf("handler returned wrong content-type: got '%s' wanted '%s'", rr.Header()["Content-Type"][0], expectedContentType) + } +} func TestValidateResponseCode(t *testing.T) { valid := map[string][]string{ @@ -58,6 +125,13 @@ func TestValidateResponseCode(t *testing.T) { if _, err := validateResponseCode(invalid); err == nil { t.Errorf("expected %v to be an invalid response code\n", invalid) } + + invalidStr := map[string][]string{ + "X-Response-Code": {"hello"}, + } + if _, err := validateResponseCode(invalidStr); err == nil { + t.Errorf("expected %v to be an invalid response code\n", invalid) + } } func TestIsJSON(t *testing.T) { From 3d219adab4c4671d3969f67547779b14602b4675 Mon Sep 17 00:00:00 2001 From: Nate Meyer <672246+notnmeyer@users.noreply.github.com> Date: Sat, 21 Oct 2023 19:06:40 -0700 Subject: [PATCH 6/6] include go.sum include go.sum --- go.sum | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 go.sum diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..287f6fa --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=