diff --git a/internal/server/user/mux.go b/internal/server/user/mux.go new file mode 100644 index 0000000..c47aaca --- /dev/null +++ b/internal/server/user/mux.go @@ -0,0 +1,25 @@ +package user + +import ( + "sync" + + "github.com/gorilla/mux" +) + +type swappableMux struct { + m sync.RWMutex + root mux.Router +} + +func (sm *swappableMux) get() mux.Router { + sm.m.RLock() + defer sm.m.RUnlock() + + return sm.root +} + +func (sm *swappableMux) set(mux mux.Router) { + sm.m.Lock() + sm.root = mux + sm.m.Unlock() +} diff --git a/internal/server/user/mux_test.go b/internal/server/user/mux_test.go new file mode 100644 index 0000000..154c0b5 --- /dev/null +++ b/internal/server/user/mux_test.go @@ -0,0 +1,121 @@ +package user + +import ( + "reflect" + "testing" + "time" + + "github.com/gorilla/mux" +) + +func TestSwappableMuxGetReturnsTheCurrentMux(t *testing.T) { + sm := swappableMux{} + mux := sm.get() + if !reflect.DeepEqual(mux, sm.root) { + t.Errorf("Returned mux is not the same %#v", mux) + } +} + +func TestSwappableMuxGetReturnsADifferentInstance(t *testing.T) { + sm := swappableMux{} + mux := sm.get() + if &mux == &sm.root { + t.Error("Returned mux is the same instance") + } +} + +func TestSwappableMuxGetWaitsForTheMutexToBeReleased(t *testing.T) { + sm := swappableMux{} + + sm.m.Lock() + defer sm.m.Unlock() + + c := make(chan mux.Router) + go func() { c <- sm.get() }() + + time.Sleep(10 * time.Millisecond) + + select { + case <-c: + t.Error("Didn't acquire the mutex") + default: + } +} + +func TestSwappableMuxGetIsAbleToReadWhileOthersAreReading(t *testing.T) { + sm := swappableMux{} + + sm.m.RLock() + defer sm.m.RUnlock() + + c := make(chan mux.Router) + go func() { c <- sm.get() }() + + time.Sleep(10 * time.Millisecond) + + select { + case <-c: + default: + t.Error("The mutex cannot be acquired") + } +} + +func TestSwappableMuxSetSetsTheGivenMux(t *testing.T) { + sm := swappableMux{} + mux := mux.Router{ + KeepContext: true, + } + + sm.set(mux) + + if !sm.root.KeepContext { + t.Error("mux not set") + } +} + +func TestSwappableMuxSetSetsADifferentInstance(t *testing.T) { + sm := swappableMux{} + mux := mux.Router{} + + sm.set(mux) + + if &mux == &sm.root { + t.Error("Set mux is the same instance") + } +} + +func TestSwappableMuxSetWaitsForWriterToReleaseMutex(t *testing.T) { + sm := swappableMux{} + + sm.m.Lock() + defer sm.m.Unlock() + + c := make(chan bool) + go func() { sm.set(mux.Router{}); c <- true }() + + time.Sleep(10 * time.Millisecond) + + select { + case <-c: + t.Error("Didn't acquire the mutex") + default: + } +} + +func TestSwappableMuxSetWaitsForReadersToReleaseMutex(t *testing.T) { + sm := swappableMux{} + + sm.m.RLock() + defer sm.m.RUnlock() + + c := make(chan bool) + go func() { sm.set(mux.Router{}); c <- true }() + + time.Sleep(10 * time.Millisecond) + + select { + case <-c: + t.Error("Didn't acquire the mutex") + default: + } +} diff --git a/internal/server/user/server.go b/internal/server/user/server.go index 98edb84..ff8b332 100644 --- a/internal/server/user/server.go +++ b/internal/server/user/server.go @@ -2,29 +2,8 @@ package user import ( "net/http" - "sync" - - "github.com/gorilla/mux" ) -type swappableMux struct { - m sync.RWMutex - root mux.Router -} - -func (sm *swappableMux) get() mux.Router { - sm.m.RLock() - defer sm.m.RUnlock() - - return sm.root -} - -func (sm *swappableMux) set(mux mux.Router) { - sm.m.Lock() - sm.root = mux - sm.m.Unlock() -} - var Server http.Server func Run() { diff --git a/internal/server/user/server_test.go b/internal/server/user/server_test.go index c7d1777..d5eed30 100644 --- a/internal/server/user/server_test.go +++ b/internal/server/user/server_test.go @@ -1,123 +1,3 @@ package user -import ( - "reflect" - "testing" - "time" - - "github.com/gorilla/mux" -) - // TODO TestRunRunsAnHTTPServer(t *testing.T) {} - -func TestSwappableMuxGetReturnsTheCurrentMux(t *testing.T) { - sm := swappableMux{} - mux := sm.get() - if !reflect.DeepEqual(mux, sm.root) { - t.Errorf("Returned mux is not the same %#v", mux) - } -} - -func TestSwappableMuxGetReturnsADifferentInstance(t *testing.T) { - sm := swappableMux{} - mux := sm.get() - if &mux == &sm.root { - t.Error("Returned mux is the same instance") - } -} - -func TestSwappableMuxGetWaitsForTheMutexToBeReleased(t *testing.T) { - sm := swappableMux{} - - sm.m.Lock() - defer sm.m.Unlock() - - c := make(chan mux.Router) - go func() { c <- sm.get() }() - - time.Sleep(10 * time.Millisecond) - - select { - case <-c: - t.Error("Didn't acquire the mutex") - default: - } -} - -func TestSwappableMuxGetIsAbleToReadWhileOthersAreReading(t *testing.T) { - sm := swappableMux{} - - sm.m.RLock() - defer sm.m.RUnlock() - - c := make(chan mux.Router) - go func() { c <- sm.get() }() - - time.Sleep(10 * time.Millisecond) - - select { - case <-c: - default: - t.Error("The mutex cannot be acquired") - } -} - -func TestSwappableMuxSetSetsTheGivenMux(t *testing.T) { - sm := swappableMux{} - mux := mux.Router{ - KeepContext: true, - } - - sm.set(mux) - - if !sm.root.KeepContext { - t.Error("mux not set") - } -} - -func TestSwappableMuxSetSetsADifferentInstance(t *testing.T) { - sm := swappableMux{} - mux := mux.Router{} - - sm.set(mux) - - if &mux == &sm.root { - t.Error("Set mux is the same instance") - } -} - -func TestSwappableMuxSetWaitsForWriterToReleaseMutex(t *testing.T) { - sm := swappableMux{} - - sm.m.Lock() - defer sm.m.Unlock() - - c := make(chan bool) - go func() { sm.set(mux.Router{}); c <- true }() - - time.Sleep(10 * time.Millisecond) - - select { - case <-c: - t.Error("Didn't acquire the mutex") - default: - } -} - -func TestSwappableMuxSetWaitsForReadersToReleaseMutex(t *testing.T) { - sm := swappableMux{} - - sm.m.RLock() - defer sm.m.RUnlock() - - c := make(chan bool) - go func() { sm.set(mux.Router{}); c <- true }() - - time.Sleep(10 * time.Millisecond) - - select { - case <-c: - t.Error("Didn't acquire the mutex") - default: - } -}