diff --git a/internal/server/user/state/state.go b/internal/server/user/state/state.go index e647a55..eac0fe9 100644 --- a/internal/server/user/state/state.go +++ b/internal/server/user/state/state.go @@ -1,6 +1,7 @@ package state import ( + "errors" "sync" "github.com/BBVA/kapow/internal/server/model" @@ -43,3 +44,16 @@ func (srl *safeRouteList) List() []model.Route { } return rs } + +func (srl *safeRouteList) Delete(ID string) error { + srl.m.Lock() + defer srl.m.Unlock() + + for i := 0; i < len(srl.rs); i++ { + if srl.rs[i].ID == ID { + srl.rs = append(srl.rs[:i], srl.rs[i+1:]...) + return nil + } + } + return errors.New("Route not found") +} diff --git a/internal/server/user/state/state_test.go b/internal/server/user/state/state_test.go index 53da5ba..672d35e 100644 --- a/internal/server/user/state/state_test.go +++ b/internal/server/user/state/state_test.go @@ -190,3 +190,84 @@ func TestListReturnsANumberedListOfRoutes(t *testing.T) { } } } + +func TestDeleteReturnsAnErrorOnEmptyListOfRoutes(t *testing.T) { + srl := New() + + err := srl.Delete("FOO") + + if err == nil { + t.Error("Expected error not returned") + } +} + +func TestDeleteReturnsNilWhenTheRouteIsInTheList(t *testing.T) { + srl := New() + srl.rs = append(srl.rs, model.Route{ID: "FOO"}) + + err := srl.Delete("FOO") + + if err != nil { + t.Errorf("Nil was expected but an error was returned %q", err) + } +} + +func TestDeleteActuallyRemovesTheElementFromTheList(t *testing.T) { + srl := New() + srl.rs = append(srl.rs, model.Route{ID: "FOO"}) + + _ = srl.Delete("FOO") + + if len(srl.rs) != 0 { + t.Error("The route was not removed from the list") + } +} + +func TestDeleteRemovesARouteFromTheMiddleOfTheList(t *testing.T) { + srl := New() + srl.rs = append(srl.rs, model.Route{ID: "FOO"}) + srl.rs = append(srl.rs, model.Route{ID: "BAR"}) + srl.rs = append(srl.rs, model.Route{ID: "QUX"}) + + _ = srl.Delete("BAR") + + if len(srl.rs) != 2 || srl.rs[0].ID != "FOO" || srl.rs[1].ID != "QUX" { + t.Error("The route was not properly removed") + } +} + +func TestDeleteWaitsForWriterToFinishWriting(t *testing.T) { + srl := New() + + srl.m.Lock() + defer srl.m.Unlock() + + c := make(chan error) + go func() { c <- srl.Delete("FOO") }() + + time.Sleep(10 * time.Millisecond) + + select { + case <-c: + t.Error("Didn't wait for the writer to finish") + default: + } +} + +func TestDeleteWaitsForReadersToFinishReading(t *testing.T) { + srl := New() + + srl.m.RLock() + defer srl.m.RUnlock() + + c := make(chan error) + go func() { c <- srl.Delete("FOO") }() + + time.Sleep(10 * time.Millisecond) + + select { + case <-c: + t.Error("Didn't wait for the reader to finish") + default: + } +}