diff --git a/events.go b/events.go index 52b4b52..a4dae46 100644 --- a/events.go +++ b/events.go @@ -1,6 +1,8 @@ package authboss import ( + "fmt" + "github.com/friendsofgo/errors" "net/http" ) @@ -9,6 +11,8 @@ import ( // Event type is for describing events type Event int +var ErrHalt = fmt.Errorf("event halt") + // Event kinds const ( EventRegister Event = iota @@ -96,6 +100,13 @@ func (c *Events) call(evs []EventHandler, w http.ResponseWriter, r *http.Request for _, fn := range evs { interrupt, err := fn(w, r, handled) if err != nil { + if errors.Is(err, ErrHalt) { + if interrupt { + handled = true + } + break + } + return false, err } if interrupt { diff --git a/events_test.go b/events_test.go index 16ec9bc..9c2e5a6 100644 --- a/events_test.go +++ b/events_test.go @@ -92,6 +92,94 @@ func TestEventsHandled(t *testing.T) { } } +func TestEventsHaltHandled(t *testing.T) { + t.Parallel() + + ab := New() + firstCalled := false + secondCalled := false + + firstHandled := false + secondHandled := false + + ab.Events.Before(EventRegister, func(w http.ResponseWriter, r *http.Request, handled bool) (bool, error) { + firstCalled = true + firstHandled = handled + return true, ErrHalt + }) + ab.Events.Before(EventRegister, func(w http.ResponseWriter, r *http.Request, handled bool) (bool, error) { + secondCalled = true + secondHandled = handled + return false, nil + }) + + handled, err := ab.Events.FireBefore(EventRegister, nil, nil) + if err != nil { + t.Error("Unexpected error:", err) + } + if !handled { + t.Error("it should have been handled") + } + + if !firstCalled { + t.Error("expected first to have been called") + } + if firstHandled { + t.Error("first should not see the event as being handled") + } + + if secondCalled { + t.Error("expected second to not have been called") + } + if secondHandled { + t.Error("second should not see the event as being handled (as second should not be running at all)") + } +} + +func TestEventsHaltNotHandled(t *testing.T) { + t.Parallel() + + ab := New() + firstCalled := false + secondCalled := false + + firstHandled := false + secondHandled := false + + ab.Events.Before(EventRegister, func(w http.ResponseWriter, r *http.Request, handled bool) (bool, error) { + firstCalled = true + firstHandled = handled + return false, ErrHalt + }) + ab.Events.Before(EventRegister, func(w http.ResponseWriter, r *http.Request, handled bool) (bool, error) { + secondCalled = true + secondHandled = handled + return false, nil + }) + + handled, err := ab.Events.FireBefore(EventRegister, nil, nil) + if err != nil { + t.Error("Unexpected error:", err) + } + if handled { + t.Error("it should not have been handled") + } + + if !firstCalled { + t.Error("expected first to have been called") + } + if firstHandled { + t.Error("first should not see the event as being handled") + } + + if secondCalled { + t.Error("expected second to not have been called") + } + if secondHandled { + t.Error("second should not see the event as being handled (as second should not be running at all)") + } +} + func TestEventsErrors(t *testing.T) { t.Parallel()