Files
next.orly.dev/pkg/event/routing/routing_test.go
mleku 24383ef1f4
Some checks failed
Go / build-and-release (push) Has been cancelled
Decompose handle-event.go into DDD domain services (v0.36.15)
Major refactoring of event handling into clean, testable domain services:

- Add pkg/event/validation: JSON hex validation, signature verification,
  timestamp bounds, NIP-70 protected tag validation
- Add pkg/event/authorization: Policy and ACL authorization decisions,
  auth challenge handling, access level determination
- Add pkg/event/routing: Event router registry with ephemeral and delete
  handlers, kind-based dispatch
- Add pkg/event/processing: Event persistence, delivery to subscribers,
  and post-save hooks (ACL reconfig, sync, relay groups)
- Reduce handle-event.go from 783 to 296 lines (62% reduction)
- Add comprehensive unit tests for all new domain services
- Refactor database tests to use shared TestMain setup
- Fix blossom URL test expectations (missing "/" separator)
- Add go-memory-optimization skill and analysis documentation
- Update DDD_ANALYSIS.md to reflect completed decomposition

Files modified:
- app/handle-event.go: Slim orchestrator using domain services
- app/server.go: Service initialization and interface wrappers
- app/handle-event-types.go: Shared types (OkHelper, result types)
- pkg/event/validation/*: New validation service package
- pkg/event/authorization/*: New authorization service package
- pkg/event/routing/*: New routing service package
- pkg/event/processing/*: New processing service package
- pkg/database/*_test.go: Refactored to shared TestMain
- pkg/blossom/http_test.go: Fixed URL format expectations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-25 05:30:07 +01:00

241 lines
5.1 KiB
Go

package routing
import (
"errors"
"testing"
"git.mleku.dev/mleku/nostr/encoders/event"
)
func TestNew(t *testing.T) {
r := New()
if r == nil {
t.Fatal("New() returned nil")
}
if r.handlers == nil {
t.Fatal("handlers map is nil")
}
if r.kindChecks == nil {
t.Fatal("kindChecks slice is nil")
}
}
func TestResultConstructors(t *testing.T) {
// ContinueResult
r := ContinueResult()
if r.Action != Continue {
t.Error("ContinueResult should have Action=Continue")
}
// HandledResult
r = HandledResult("success")
if r.Action != Handled {
t.Error("HandledResult should have Action=Handled")
}
if r.Message != "success" {
t.Error("HandledResult should preserve message")
}
// ErrorResult
err := errors.New("test error")
r = ErrorResult(err)
if r.Action != Error {
t.Error("ErrorResult should have Action=Error")
}
if r.Error != err {
t.Error("ErrorResult should preserve error")
}
}
func TestDefaultRouter_Register(t *testing.T) {
r := New()
called := false
handler := func(ev *event.E, authedPubkey []byte) Result {
called = true
return HandledResult("handled")
}
r.Register(1, handler)
ev := event.New()
ev.Kind = 1
result := r.Route(ev, nil)
if !called {
t.Error("handler should have been called")
}
if result.Action != Handled {
t.Error("result should be Handled")
}
}
func TestDefaultRouter_RegisterKindCheck(t *testing.T) {
r := New()
called := false
handler := func(ev *event.E, authedPubkey []byte) Result {
called = true
return HandledResult("ephemeral")
}
// Register handler for ephemeral events (20000-29999)
r.RegisterKindCheck("ephemeral", func(k uint16) bool {
return k >= 20000 && k < 30000
}, handler)
ev := event.New()
ev.Kind = 20001
result := r.Route(ev, nil)
if !called {
t.Error("kind check handler should have been called")
}
if result.Action != Handled {
t.Error("result should be Handled")
}
}
func TestDefaultRouter_NoMatch(t *testing.T) {
r := New()
// Register handler for kind 1
r.Register(1, func(ev *event.E, authedPubkey []byte) Result {
return HandledResult("kind 1")
})
ev := event.New()
ev.Kind = 2 // Different kind
result := r.Route(ev, nil)
if result.Action != Continue {
t.Error("unmatched kind should return Continue")
}
}
func TestDefaultRouter_ExactMatchPriority(t *testing.T) {
r := New()
exactCalled := false
checkCalled := false
// Register exact match for kind 20001
r.Register(20001, func(ev *event.E, authedPubkey []byte) Result {
exactCalled = true
return HandledResult("exact")
})
// Register kind check for ephemeral (also matches 20001)
r.RegisterKindCheck("ephemeral", func(k uint16) bool {
return k >= 20000 && k < 30000
}, func(ev *event.E, authedPubkey []byte) Result {
checkCalled = true
return HandledResult("check")
})
ev := event.New()
ev.Kind = 20001
result := r.Route(ev, nil)
if !exactCalled {
t.Error("exact match should be called")
}
if checkCalled {
t.Error("kind check should not be called when exact match exists")
}
if result.Message != "exact" {
t.Errorf("expected 'exact', got '%s'", result.Message)
}
}
func TestDefaultRouter_HasHandler(t *testing.T) {
r := New()
// Initially no handlers
if r.HasHandler(1) {
t.Error("should not have handler for kind 1 yet")
}
// Register exact handler
r.Register(1, func(ev *event.E, authedPubkey []byte) Result {
return HandledResult("")
})
if !r.HasHandler(1) {
t.Error("should have handler for kind 1")
}
// Register kind check for ephemeral
r.RegisterKindCheck("ephemeral", func(k uint16) bool {
return k >= 20000 && k < 30000
}, func(ev *event.E, authedPubkey []byte) Result {
return HandledResult("")
})
if !r.HasHandler(20001) {
t.Error("should have handler for ephemeral kind 20001")
}
if r.HasHandler(19999) {
t.Error("should not have handler for kind 19999")
}
}
func TestDefaultRouter_PassesPubkey(t *testing.T) {
r := New()
var receivedPubkey []byte
r.Register(1, func(ev *event.E, authedPubkey []byte) Result {
receivedPubkey = authedPubkey
return HandledResult("")
})
testPubkey := []byte("testpubkey12345")
ev := event.New()
ev.Kind = 1
r.Route(ev, testPubkey)
if string(receivedPubkey) != string(testPubkey) {
t.Error("handler should receive the authed pubkey")
}
}
func TestDefaultRouter_MultipleKindChecks(t *testing.T) {
r := New()
firstCalled := false
secondCalled := false
// First check matches 10000-19999
r.RegisterKindCheck("first", func(k uint16) bool {
return k >= 10000 && k < 20000
}, func(ev *event.E, authedPubkey []byte) Result {
firstCalled = true
return HandledResult("first")
})
// Second check matches 15000-25000 (overlaps)
r.RegisterKindCheck("second", func(k uint16) bool {
return k >= 15000 && k < 25000
}, func(ev *event.E, authedPubkey []byte) Result {
secondCalled = true
return HandledResult("second")
})
// Kind 15000 matches both - first registered wins
ev := event.New()
ev.Kind = 15000
result := r.Route(ev, nil)
if !firstCalled {
t.Error("first check should be called")
}
if secondCalled {
t.Error("second check should not be called")
}
if result.Message != "first" {
t.Errorf("expected 'first', got '%s'", result.Message)
}
}