Added getRoute to control api
This commit is contained in:
@@ -36,11 +36,13 @@ func Run(bindAddr string) {
|
|||||||
func configRouter() *mux.Router {
|
func configRouter() *mux.Router {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/routes/{id}", removeRoute).
|
r.HandleFunc("/routes/{id}", removeRoute).
|
||||||
Methods("DELETE")
|
Methods(http.MethodDelete)
|
||||||
|
r.HandleFunc("/routes/{id}", getRoute).
|
||||||
|
Methods(http.MethodGet)
|
||||||
r.HandleFunc("/routes", listRoutes).
|
r.HandleFunc("/routes", listRoutes).
|
||||||
Methods("GET")
|
Methods(http.MethodGet)
|
||||||
r.HandleFunc("/routes", addRoute).
|
r.HandleFunc("/routes", addRoute).
|
||||||
Methods("POST")
|
Methods(http.MethodPost)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +86,7 @@ func addRoute(res http.ResponseWriter, req *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if route.Method == "" {
|
if route.Method == "" {
|
||||||
|
spec / test / features / control / get / success.feature
|
||||||
res.WriteHeader(http.StatusUnprocessableEntity)
|
res.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -112,3 +115,16 @@ func addRoute(res http.ResponseWriter, req *http.Request) {
|
|||||||
res.Header().Set("Content-Type", "application/json")
|
res.Header().Set("Content-Type", "application/json")
|
||||||
_, _ = res.Write(createdBytes)
|
_, _ = res.Write(createdBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var funcGet func(string) (model.Route, error) = user.Routes.Get
|
||||||
|
|
||||||
|
func getRoute(res http.ResponseWriter, req *http.Request) {
|
||||||
|
id := mux.Vars(req)["id"]
|
||||||
|
if r, err := funcGet(id); err != nil {
|
||||||
|
res.WriteHeader(http.StatusNotFound)
|
||||||
|
} else {
|
||||||
|
res.Header().Set("Content-Type", "application/json")
|
||||||
|
rBytes, _ := json.Marshal(r)
|
||||||
|
_, _ = res.Write(rBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package control
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -28,6 +29,7 @@ import (
|
|||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/BBVA/kapow/internal/server/model"
|
"github.com/BBVA/kapow/internal/server/model"
|
||||||
|
"github.com/BBVA/kapow/internal/server/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfigRouterHasRoutesWellConfigured(t *testing.T) {
|
func TestConfigRouterHasRoutesWellConfigured(t *testing.T) {
|
||||||
@@ -37,10 +39,10 @@ func TestConfigRouterHasRoutesWellConfigured(t *testing.T) {
|
|||||||
mustMatch bool
|
mustMatch bool
|
||||||
vars []string
|
vars []string
|
||||||
}{
|
}{
|
||||||
{"/routes/ROUTE_YYYYYYYYYYYYYYY", http.MethodGet, 0, false, []string{}},
|
{"/routes/FOO", http.MethodGet, reflect.ValueOf(getRoute).Pointer(), true, []string{"id"}},
|
||||||
{"/routes/ROUTE_YYYYYYYYYYYYYYY", http.MethodPut, 0, false, []string{}},
|
{"/routes/FOO", http.MethodPut, 0, false, []string{}},
|
||||||
{"/routes/ROUTE_YYYYYYYYYYYYYYY", http.MethodPost, 0, false, []string{}},
|
{"/routes/FOO", http.MethodPost, 0, false, []string{}},
|
||||||
{"/routes/ROUTE_YYYYYYYYYYYYYYY", http.MethodDelete, reflect.ValueOf(removeRoute).Pointer(), true, []string{"id"}},
|
{"/routes/FOO", http.MethodDelete, reflect.ValueOf(removeRoute).Pointer(), true, []string{"id"}},
|
||||||
{"/routes", http.MethodGet, reflect.ValueOf(listRoutes).Pointer(), true, []string{}},
|
{"/routes", http.MethodGet, reflect.ValueOf(listRoutes).Pointer(), true, []string{}},
|
||||||
{"/routes", http.MethodPut, 0, false, []string{}},
|
{"/routes", http.MethodPut, 0, false, []string{}},
|
||||||
{"/routes", http.MethodPost, reflect.ValueOf(addRoute).Pointer(), true, []string{}},
|
{"/routes", http.MethodPost, reflect.ValueOf(addRoute).Pointer(), true, []string{}},
|
||||||
@@ -402,3 +404,43 @@ func TestListRoutesReturnsTwoElementsList(t *testing.T) {
|
|||||||
t.Errorf("Response mismatch. Expected %#v, got: %#v", expectedRouteList, respJson)
|
t.Errorf("Response mismatch. Expected %#v, got: %#v", expectedRouteList, respJson)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetRouteReturns404sWhenRouteDoesntExist(t *testing.T) {
|
||||||
|
handler := mux.NewRouter()
|
||||||
|
handler.HandleFunc("/routes/{id}", getRoute).
|
||||||
|
Methods("GET")
|
||||||
|
r := httptest.NewRequest(http.MethodGet, "/routes/FOO", nil)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
handler.ServeHTTP(w, r)
|
||||||
|
|
||||||
|
resp := w.Result()
|
||||||
|
if resp.StatusCode != http.StatusNotFound {
|
||||||
|
t.Errorf("HTTP status mismatch. Expected: %d, got: %d", http.StatusNotFound, resp.StatusCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRouteReturnsTheRequestedRoute(t *testing.T) {
|
||||||
|
handler := mux.NewRouter()
|
||||||
|
handler.HandleFunc("/routes/{id}", getRoute).
|
||||||
|
Methods("GET")
|
||||||
|
r := httptest.NewRequest(http.MethodGet, "/routes/FOO", nil)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
user.Routes.Append(model.Route{ID: "FOO"})
|
||||||
|
handler.ServeHTTP(w, r)
|
||||||
|
|
||||||
|
resp := w.Result()
|
||||||
|
respJson := model.Route{}
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
t.Errorf("HTTP status mismatch. Expected: %d, got: %d", http.StatusOK, resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
bBytes, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
if err := json.Unmarshal(bBytes, &respJson); err != nil {
|
||||||
|
t.Errorf("Invalid JSON response. %s", string(bBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
if respJson.ID != "FOO" {
|
||||||
|
t.Errorf(`Route mismatch. Expected: "FOO". Got: %s`, respJson.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -80,3 +80,16 @@ func (srl *safeRouteList) Delete(ID string) error {
|
|||||||
srl.m.Unlock()
|
srl.m.Unlock()
|
||||||
return errors.New("Route not found")
|
return errors.New("Route not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (srl *safeRouteList) Get(ID string) (r model.Route, err error) {
|
||||||
|
srl.m.RLock()
|
||||||
|
defer srl.m.RUnlock()
|
||||||
|
for _, r = range srl.rs {
|
||||||
|
if r.ID == ID {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = errors.New("Route not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -364,3 +364,69 @@ func TestDeleteUpdatesMuxWithRemainingRoutes(t *testing.T) {
|
|||||||
t.Fatalf("Unexpected error: %v", err)
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetReturnsAnErrorWhenEmptyList(t *testing.T) {
|
||||||
|
srl := New()
|
||||||
|
|
||||||
|
if _, err := srl.Get("FOO"); err == nil {
|
||||||
|
t.Error("Expected error not returned")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetReturnsAnErrorWhenRouteNotExists(t *testing.T) {
|
||||||
|
srl := New()
|
||||||
|
srl.Append(model.Route{ID: "FOO"})
|
||||||
|
|
||||||
|
if _, err := srl.Get("BAR"); err == nil {
|
||||||
|
t.Error("Expected error not returned")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetReturnsTheRequestedRoute(t *testing.T) {
|
||||||
|
srl := New()
|
||||||
|
srl.Append(model.Route{ID: "FOO"})
|
||||||
|
|
||||||
|
if r, err := srl.Get("FOO"); err != nil {
|
||||||
|
t.Errorf("Unexpected error %+v", err)
|
||||||
|
} else if r.ID != "FOO" {
|
||||||
|
t.Errorf(`Route mismatch. Expected: "FOO". Got %q`, r.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetWaitsForTheWriterToFinish(t *testing.T) {
|
||||||
|
srl := New()
|
||||||
|
srl.Append(model.Route{ID: "FOO"})
|
||||||
|
|
||||||
|
srl.m.Lock()
|
||||||
|
defer srl.m.Unlock()
|
||||||
|
|
||||||
|
c := make(chan model.Route)
|
||||||
|
go func() { r, _ := srl.Get("FOO"); c <- r }()
|
||||||
|
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-c:
|
||||||
|
t.Error("Route list readed while mutex was acquired")
|
||||||
|
default: // This default prevents the select from being blocking
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetNonBlockingReadWithOtherReaders(t *testing.T) {
|
||||||
|
srl := New()
|
||||||
|
srl.Append(model.Route{ID: "FOO"})
|
||||||
|
|
||||||
|
srl.m.RLock()
|
||||||
|
defer srl.m.RUnlock()
|
||||||
|
|
||||||
|
c := make(chan model.Route)
|
||||||
|
go func() { r, _ := srl.Get("FOO"); c <- r }()
|
||||||
|
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-c:
|
||||||
|
default: // This default prevents the select from being blocking
|
||||||
|
t.Error("Route list couldn't be readed while mutex was acquired for read")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user