Some data server handlers
Co-authored-by: Hector Hurtado <hector.hurtado@bbva.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/BBVA/kapow/internal/server/model"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func getRequestBody(w http.ResponseWriter, r *http.Request, h *model.Handler) {
|
||||
w.Header().Add("Content-Type", "application/octet-stream")
|
||||
n, err := io.Copy(w, h.Request.Body)
|
||||
if err != nil {
|
||||
if n == 0 {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
} else {
|
||||
// Only way to abort current connection as of go 1.13
|
||||
// https://github.com/golang/go/issues/16542
|
||||
panic("Truncated body")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getRequestMethod(w http.ResponseWriter, r *http.Request, h *model.Handler) {
|
||||
w.Header().Add("Content-Type", "application/octet-stream")
|
||||
w.Write([]byte(h.Request.Method))
|
||||
}
|
||||
|
||||
func getRequestHost(w http.ResponseWriter, r *http.Request, h *model.Handler) {
|
||||
w.Header().Add("Content-Type", "application/octet-stream")
|
||||
w.Write([]byte(h.Request.Host))
|
||||
}
|
||||
|
||||
func getRequestPath(w http.ResponseWriter, r *http.Request, h *model.Handler) {
|
||||
w.Header().Add("Content-Type", "application/octet-stream")
|
||||
// TODO: Discuss a how to obtain URL.EscapedPath() instead
|
||||
w.Write([]byte(h.Request.URL.Path))
|
||||
}
|
||||
|
||||
func getRequestMatches(w http.ResponseWriter, r *http.Request, h *model.Handler) {
|
||||
w.Header().Add("Content-Type", "application/octet-stream")
|
||||
name := mux.Vars(r)["name"]
|
||||
vars := mux.Vars(h.Request)
|
||||
if value, ok := vars[name]; ok {
|
||||
w.Write([]byte(value))
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
func getRequestParams(w http.ResponseWriter, r *http.Request, h *model.Handler) {
|
||||
w.Header().Add("Content-Type", "application/octet-stream")
|
||||
name := mux.Vars(r)["name"]
|
||||
if value, ok := h.Request.URL.Query()[name]; ok {
|
||||
w.Write([]byte(value[0]))
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,438 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/BBVA/kapow/internal/server/model"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type badReader struct {
|
||||
errorMessage string
|
||||
}
|
||||
|
||||
func (r *badReader) Read(p []byte) (int, error) {
|
||||
return 0, errors.New(r.errorMessage)
|
||||
}
|
||||
|
||||
func BadReader(m string) io.Reader {
|
||||
return &badReader{errorMessage: m}
|
||||
}
|
||||
|
||||
type errorOnSecondReadReader struct {
|
||||
r io.Reader
|
||||
last bool
|
||||
}
|
||||
|
||||
func (r *errorOnSecondReadReader) Read(p []byte) (int, error) {
|
||||
if r.last {
|
||||
return 0, errors.New("Second read failed by design")
|
||||
} else {
|
||||
r.last = true
|
||||
return r.r.Read(p)
|
||||
}
|
||||
}
|
||||
|
||||
func ErrorOnSecondReadReader(r io.Reader) io.Reader {
|
||||
return &errorOnSecondReadReader{r: r}
|
||||
}
|
||||
|
||||
func TestGetRequestBody200sOnHappyPath(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("POST", "/", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := httptest.NewRequest("GET", "/not-important-here", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestBody(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
t.Error("Status code mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestBodySetsOctectStreamContentType(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("POST", "/", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := httptest.NewRequest("GET", "/not-important-here", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestBody(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if res.Header.Get("Content-Type") != "application/octet-stream" {
|
||||
t.Error("Content Type mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestBodyWritesHandlerRequestBodyToResponseWriter(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("POST", "/", strings.NewReader("BAR")),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := httptest.NewRequest("GET", "/not-important-here", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestBody(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if body, _ := ioutil.ReadAll(res.Body); string(body) != "BAR" {
|
||||
t.Error("Body mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestBody500sWhenHandlerRequestErrors(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("POST", "/", BadReader("User closed the connection")),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := httptest.NewRequest("GET", "/not-important-here", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestBody(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if res.StatusCode != http.StatusInternalServerError {
|
||||
t.Error("status not 500")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestBodyClosesConnectionWhenReaderErrorsAfterWrite(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("POST", "/", ErrorOnSecondReadReader(strings.NewReader("FOO"))),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := httptest.NewRequest("GET", "/not-important-here", nil)
|
||||
w := httptest.NewRecorder()
|
||||
defer func() {
|
||||
if rec := recover(); rec == nil {
|
||||
t.Error("Didn't panic")
|
||||
}
|
||||
}()
|
||||
|
||||
getRequestBody(w, r, &h)
|
||||
}
|
||||
|
||||
func TestGetRequestMethod200sOnHappyPath(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("POST", "/", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := httptest.NewRequest("GET", "/not-important-here", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestMethod(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
t.Error("Status code mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestMethodSetsOctectStreamContentType(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("POST", "/", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := httptest.NewRequest("GET", "/not-important-here", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestMethod(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if res.Header.Get("Content-Type") != "application/octet-stream" {
|
||||
t.Error("Content Type mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestMethodReturnsTheCorrectMethod(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("FOO", "/", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := httptest.NewRequest("GET", "/not-important-here", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestMethod(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if body, _ := ioutil.ReadAll(res.Body); string(body) != "FOO" {
|
||||
t.Error("Body mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestHost200sOnHappyPath(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("POST", "/", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := httptest.NewRequest("GET", "/not-important-here", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestHost(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
t.Error("Status code mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestHostReturnsTheCorrectHostname(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("POST", "http://www.foo.bar:8080/", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := httptest.NewRequest("GET", "/not-important-here", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestHost(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if body, _ := ioutil.ReadAll(res.Body); string(body) != "www.foo.bar:8080" {
|
||||
t.Error("Body mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestHostSetsOctectStreamContentType(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("POST", "/", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := httptest.NewRequest("GET", "/not-important-here", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestHost(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if res.Header.Get("Content-Type") != "application/octet-stream" {
|
||||
t.Error("Content Type mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestPath200sOnHappyPath(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("POST", "/", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := httptest.NewRequest("GET", "/not-important-here", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestPath(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
t.Error("Status code mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestPathSetsOctectStreamContentType(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("POST", "/", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := httptest.NewRequest("GET", "/not-important-here", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestPath(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if res.Header.Get("Content-Type") != "application/octet-stream" {
|
||||
t.Error("Content Type mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestPathReturnsPath(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("POST", "/foo", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := httptest.NewRequest("GET", "/not-important-here", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestPath(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if body, _ := ioutil.ReadAll(res.Body); string(body) != "/foo" {
|
||||
t.Error("Body mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestPathDoesntReturnQueryStringParams(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("POST", "/foo?bar=1", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := httptest.NewRequest("GET", "/not-important-here", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestPath(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if body, _ := ioutil.ReadAll(res.Body); string(body) != "/foo" {
|
||||
t.Errorf("Body mismatch. Expected: /foo. Got: %v", string(body))
|
||||
}
|
||||
}
|
||||
|
||||
func createMuxRequest(pattern, url, method string) (req *http.Request) {
|
||||
m := mux.NewRouter()
|
||||
m.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) { req = r })
|
||||
m.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest(method, url, nil))
|
||||
return
|
||||
}
|
||||
|
||||
func TestGetRequestMatches200sOnHappyPath(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: createMuxRequest("/foo/{bar}", "/foo/BAZ", "GET"),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := createMuxRequest("/handlers/HANDLERID/request/matches/{name}", "/handlers/HANDLERID/request/matches/bar", "GET")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestMatches(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
t.Error("Status code mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestMatchesSetsOctectStreamContentType(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: createMuxRequest("/foo/{bar}", "/foo/BAZ", "GET"),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := createMuxRequest("/handlers/HANDLERID/request/matches/{name}", "/handlers/HANDLERID/request/matches/bar", "GET")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestMatches(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if res.Header.Get("Content-Type") != "application/octet-stream" {
|
||||
t.Error("Content Type mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestMatchesReturnsTheCorrectMatchValue(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: createMuxRequest("/foo/{bar}", "/foo/BAZ", "GET"),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := createMuxRequest("/handlers/HANDLERID/request/matches/{name}", "/handlers/HANDLERID/request/matches/bar", "GET")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestMatches(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if body, _ := ioutil.ReadAll(res.Body); string(body) != "BAZ" {
|
||||
t.Errorf("Body mismatch. Expected: BAZ. Got: %v", string(body))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetRequestMatchesReturnsNotFoundWhenMatchDoesntExists(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: createMuxRequest("/", "/", "GET"),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
|
||||
r := createMuxRequest("/handlers/HANDLERID/request/matches/{name}", "/handlers/HANDLERID/request/matches/foo", "GET")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestMatches(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if res.StatusCode != http.StatusNotFound {
|
||||
t.Errorf("Status code mismatch. Expected: 404. Got: %d", res.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestParams200sOnHappyPath(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("GET", "/foo?bar=BAZ", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := createMuxRequest("/handlers/HANDLERID/request/params/{name}", "/handlers/HANDLERID/request/params/bar", "GET")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestParams(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
t.Error("Status code mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestParamsSetsOctectStreamContentType(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("GET", "/foo?bar=BAZ", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := createMuxRequest("/handlers/HANDLERID/request/params/{name}", "/handlers/HANDLERID/request/params/bar", "GET")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestParams(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if res.Header.Get("Content-Type") != "application/octet-stream" {
|
||||
t.Error("Content Type mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestParamsReturnsTheCorrectMatchValue(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("GET", "/foo?bar=BAZ", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := createMuxRequest("/handlers/HANDLERID/request/params/{name}", "/handlers/HANDLERID/request/params/bar", "GET")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestParams(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if body, _ := ioutil.ReadAll(res.Body); string(body) != "BAZ" {
|
||||
t.Errorf("Body mismatch. Expected: BAZ. Got: %v", string(body))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRequestParams404sWhenParamDoesntExist(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("GET", "/foo", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := createMuxRequest("/handlers/HANDLERID/request/params/{name}", "/handlers/HANDLERID/request/params/bar", "GET")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestParams(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if res.StatusCode != http.StatusNotFound {
|
||||
t.Errorf("Status code mismatch. Expected: 404. Got: %d", res.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Discuss how return multiple values
|
||||
func TestGetRequestParamsReturnsTheFirstCorrectMatchValue(t *testing.T) {
|
||||
h := model.Handler{
|
||||
Request: httptest.NewRequest("GET", "/foo?bar=BAZ&bar=QUX", nil),
|
||||
Writer: httptest.NewRecorder(),
|
||||
}
|
||||
r := createMuxRequest("/handlers/HANDLERID/request/params/{name}", "/handlers/HANDLERID/request/params/bar", "GET")
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
getRequestParams(w, r, &h)
|
||||
|
||||
res := w.Result()
|
||||
if body, _ := ioutil.ReadAll(res.Body); string(body) != "BAZ" {
|
||||
t.Errorf("Body mismatch. Expected: BAZ. Got: %v", string(body))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user