swappableMux is now public and Append() now updates Server.Handler

Co-authored-by: Roberto Abdelkader Martínez Pérez <robertomartinezp@gmail.com>
This commit is contained in:
pancho horrillo
2019-10-10 20:06:05 +02:00
parent 0c408497a3
commit df5d38e94f
8 changed files with 74 additions and 42 deletions
+7 -7
View File
@@ -8,34 +8,34 @@ import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
type swappableMux struct { type SwappableMux struct {
m sync.RWMutex m sync.RWMutex
root *mux.Router root *mux.Router
} }
func New() *swappableMux { func New() *SwappableMux {
return &swappableMux{ return &SwappableMux{
root: mux.NewRouter(), root: mux.NewRouter(),
} }
} }
func (sm *swappableMux) get() *mux.Router { func (sm *SwappableMux) get() *mux.Router {
sm.m.RLock() sm.m.RLock()
defer sm.m.RUnlock() defer sm.m.RUnlock()
return sm.root return sm.root
} }
func (sm *swappableMux) set(mux *mux.Router) { func (sm *SwappableMux) set(mux *mux.Router) {
sm.m.Lock() sm.m.Lock()
sm.root = mux sm.root = mux
sm.m.Unlock() sm.m.Unlock()
} }
func (sm *swappableMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (sm *SwappableMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
sm.get().ServeHTTP(w, r) sm.get().ServeHTTP(w, r)
} }
func (sm *swappableMux) Update(rs []model.Route) { func (sm *SwappableMux) Update(rs []model.Route) {
sm.set(gorillize(rs, handlerBuilder)) sm.set(gorillize(rs, handlerBuilder))
} }
+11 -11
View File
@@ -30,7 +30,7 @@ func TestNewReturnsAProperlyInitializedMux(t *testing.T) {
} }
func TestSwappableMuxGetReturnsTheCurrentMux(t *testing.T) { func TestSwappableMuxGetReturnsTheCurrentMux(t *testing.T) {
sm := swappableMux{} sm := SwappableMux{}
mux := sm.get() mux := sm.get()
if !reflect.DeepEqual(mux, sm.root) { if !reflect.DeepEqual(mux, sm.root) {
t.Errorf("Returned mux is not the same %#v", mux) t.Errorf("Returned mux is not the same %#v", mux)
@@ -38,7 +38,7 @@ func TestSwappableMuxGetReturnsTheCurrentMux(t *testing.T) {
} }
func TestSwappableMuxGetReturnsADifferentInstance(t *testing.T) { func TestSwappableMuxGetReturnsADifferentInstance(t *testing.T) {
sm := swappableMux{} sm := SwappableMux{}
mux := sm.get() mux := sm.get()
if &mux == &sm.root { if &mux == &sm.root {
t.Error("Returned mux is the same instance") t.Error("Returned mux is the same instance")
@@ -46,7 +46,7 @@ func TestSwappableMuxGetReturnsADifferentInstance(t *testing.T) {
} }
func TestSwappableMuxGetWaitsForTheMutexToBeReleased(t *testing.T) { func TestSwappableMuxGetWaitsForTheMutexToBeReleased(t *testing.T) {
sm := swappableMux{} sm := SwappableMux{}
sm.m.Lock() sm.m.Lock()
defer sm.m.Unlock() defer sm.m.Unlock()
@@ -64,7 +64,7 @@ func TestSwappableMuxGetWaitsForTheMutexToBeReleased(t *testing.T) {
} }
func TestSwappableMuxGetIsAbleToReadWhileOthersAreReading(t *testing.T) { func TestSwappableMuxGetIsAbleToReadWhileOthersAreReading(t *testing.T) {
sm := swappableMux{} sm := SwappableMux{}
sm.m.RLock() sm.m.RLock()
defer sm.m.RUnlock() defer sm.m.RUnlock()
@@ -82,7 +82,7 @@ func TestSwappableMuxGetIsAbleToReadWhileOthersAreReading(t *testing.T) {
} }
func TestSwappableMuxSetSetsTheGivenMux(t *testing.T) { func TestSwappableMuxSetSetsTheGivenMux(t *testing.T) {
sm := swappableMux{} sm := SwappableMux{}
m := mux.NewRouter() m := mux.NewRouter()
// nolint // nolint
m.KeepContext = true m.KeepContext = true
@@ -96,7 +96,7 @@ func TestSwappableMuxSetSetsTheGivenMux(t *testing.T) {
} }
func TestSwappableMuxSetSetsTheSameInstance(t *testing.T) { func TestSwappableMuxSetSetsTheSameInstance(t *testing.T) {
sm := swappableMux{} sm := SwappableMux{}
m := mux.NewRouter() m := mux.NewRouter()
sm.set(m) sm.set(m)
@@ -107,7 +107,7 @@ func TestSwappableMuxSetSetsTheSameInstance(t *testing.T) {
} }
func TestSwappableMuxSetWaitsForWriterToReleaseMutex(t *testing.T) { func TestSwappableMuxSetWaitsForWriterToReleaseMutex(t *testing.T) {
sm := swappableMux{} sm := SwappableMux{}
sm.m.Lock() sm.m.Lock()
defer sm.m.Unlock() defer sm.m.Unlock()
@@ -125,7 +125,7 @@ func TestSwappableMuxSetWaitsForWriterToReleaseMutex(t *testing.T) {
} }
func TestSwappableMuxSetWaitsForReadersToReleaseMutex(t *testing.T) { func TestSwappableMuxSetWaitsForReadersToReleaseMutex(t *testing.T) {
sm := swappableMux{} sm := SwappableMux{}
sm.m.RLock() sm.m.RLock()
defer sm.m.RUnlock() defer sm.m.RUnlock()
@@ -148,7 +148,7 @@ func TestServeHTTPCallsInnerMux(t *testing.T) {
m := mux.NewRouter() m := mux.NewRouter()
m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { called = true }) m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { called = true })
sm := swappableMux{root: m} sm := SwappableMux{root: m}
req := httptest.NewRequest("GET", "/", nil) req := httptest.NewRequest("GET", "/", nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
@@ -166,7 +166,7 @@ func TestServeHTTPCanServeWhenMuxIsReadLocked(t *testing.T) {
m := mux.NewRouter() m := mux.NewRouter()
m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { called = true }) m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { called = true })
sm := swappableMux{root: m} sm := SwappableMux{root: m}
sm.m.RLock() sm.m.RLock()
req := httptest.NewRequest("GET", "/", nil) req := httptest.NewRequest("GET", "/", nil)
@@ -187,7 +187,7 @@ func TestServeHTTPCallsInnerMuxAfterAcquiringLock(t *testing.T) {
m := mux.NewRouter() m := mux.NewRouter()
m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { called = true }) m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { called = true })
sm := swappableMux{root: m} sm := SwappableMux{root: m}
sm.m.Lock() sm.m.Lock()
req := httptest.NewRequest("GET", "/", nil) req := httptest.NewRequest("GET", "/", nil)
-7
View File
@@ -1,7 +0,0 @@
package user
import (
"github.com/BBVA/kapow/internal/server/user/state"
)
var Routes = state.New()
-14
View File
@@ -1,14 +0,0 @@
package user
import (
"reflect"
"testing"
"github.com/BBVA/kapow/internal/server/user/state"
)
func TestPackageHaveASingletonEmptyRouteList(t *testing.T) {
if !reflect.DeepEqual(Routes, state.New()) {
t.Error("Routes is not an empty safeRouteList")
}
}
+5 -1
View File
@@ -2,9 +2,13 @@ package user
import ( import (
"net/http" "net/http"
"github.com/BBVA/kapow/internal/server/user/mux"
) )
var Server http.Server var Server = http.Server{
Handler: mux.New(),
}
func Run() { func Run() {
} }
+38
View File
@@ -1,3 +1,41 @@
package user package user
import (
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/BBVA/kapow/internal/server/model"
"github.com/BBVA/kapow/internal/server/user/mux"
)
// TODO TestRunRunsAnHTTPServer(t *testing.T) {} // TODO TestRunRunsAnHTTPServer(t *testing.T) {}
func TestAppendUpdatesMuxWithProvideRoute(t *testing.T) {
Server = http.Server{
Handler: mux.New(),
}
srl := New()
route := model.Route{
Method: "GET",
Pattern: "/",
Entrypoint: "/bin/sh -c",
Command: "jaillover > /tmp/kapow-test-append-updates-mux",
}
os.Remove("/tmp/kapow-test-append-updates-mux")
defer os.Remove("/tmp/kapow-test-append-updates-mux")
srl.Append(route)
req := httptest.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
Server.Handler.ServeHTTP(w, req)
if _, err := os.Stat("/tmp/kapow-test-append-updates-mux"); os.IsNotExist(err) {
t.Error("Routes not updated")
} else if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
}
@@ -1,10 +1,11 @@
package state package user
import ( import (
"errors" "errors"
"sync" "sync"
"github.com/BBVA/kapow/internal/server/model" "github.com/BBVA/kapow/internal/server/model"
"github.com/BBVA/kapow/internal/server/user/mux"
) )
type safeRouteList struct { type safeRouteList struct {
@@ -12,6 +13,8 @@ type safeRouteList struct {
m *sync.RWMutex m *sync.RWMutex
} }
var Routes safeRouteList = New()
func New() safeRouteList { func New() safeRouteList {
return safeRouteList{ return safeRouteList{
rs: []model.Route{}, rs: []model.Route{},
@@ -25,6 +28,8 @@ func (srl *safeRouteList) Append(r model.Route) model.Route {
l := len(srl.rs) l := len(srl.rs)
srl.m.Unlock() srl.m.Unlock()
Server.Handler.(*mux.SwappableMux).Update(srl.Snapshot())
return model.Route{Index: l - 1} return model.Route{Index: l - 1}
} }
@@ -1,6 +1,6 @@
// +build !race // +build !race
package state package user
import ( import (
"reflect" "reflect"
@@ -271,3 +271,9 @@ func TestDeleteWaitsForReadersToFinishReading(t *testing.T) {
default: default:
} }
} }
func TestPackageHaveASingletonEmptyRouteList(t *testing.T) {
if !reflect.DeepEqual(Routes, New()) {
t.Error("Routes is not an empty safeRouteList")
}
}