gravity-wells/cqrs/singularity_test.go
Rene Nochebuena bc3c5aa846
All checks were successful
Go CI/CD / go-ci (push) Successful in 36s
Add CQRS library 'Singularity' with core handlers and tests
Introduces the 'Singularity' implementation, a CQRS Bus that supports commands, queries, and events, along with middleware extensibility. Includes comprehensive tests, modular files for commands, queries, and events, as well as CI/CD workflows.
2025-04-26 22:25:23 -06:00

274 lines
5.8 KiB
Go

package cqrs_test
import (
"context"
"errors"
"log"
"reflect"
"testing"
"gitstormr.dev/code-raider/gravity-wells/cqrs"
)
type testEvent struct {
Echo string
}
type testCommand struct {
Echo string
}
type testQuery struct {
Echo string
}
type successCommandHandler struct {
SendEvent bool
}
func (s *successCommandHandler) Handle(
ctx context.Context, cmd cqrs.Command,
) ([]cqrs.Event, error) {
command, _ := cmd.(*testCommand)
log.Printf("Processing command: %s\n", command.Echo)
if s.SendEvent {
return []cqrs.Event{testEvent{Echo: command.Echo}}, nil
} else {
return nil, nil
}
}
type successEventHandler struct{}
func (e *successEventHandler) Handle(
ctx context.Context, evt cqrs.Event,
) error {
event, _ := evt.(testEvent)
log.Printf("Processing event: %s\n", event.Echo)
return nil
}
type failureCommandHandler struct{}
func (e *failureCommandHandler) Handle(
ctx context.Context, cmd cqrs.Command,
) ([]cqrs.Event, error) {
return nil, errors.New("failed")
}
type successQueryHandler struct{}
func (e *successQueryHandler) Handle(
ctx context.Context, query cqrs.Query,
) (interface{}, error) {
return query, nil
}
type failureQueryHandler struct{}
func (e *failureQueryHandler) Handle(
ctx context.Context, query cqrs.Query,
) (interface{}, error) {
return nil, errors.New("failed")
}
type failureEventHandler struct{}
func (e *failureEventHandler) Handle(
ctx context.Context, evt cqrs.Event,
) error {
return errors.New("failed")
}
func logTestCommandMiddleware(next cqrs.CommandHandler) cqrs.CommandHandler {
return cqrs.CommandHandlerFunc(
func(ctx context.Context, cmd cqrs.Command) ([]cqrs.Event, error) {
log.Printf("Received command: %s\n", cmd)
return next.Handle(ctx, cmd)
},
)
}
func logTestQueryMiddleware(next cqrs.QueryHandler) cqrs.QueryHandler {
return cqrs.QueryHandlerFunc(
func(ctx context.Context, query cqrs.Query) (cqrs.Query, error) {
log.Printf("Received query: %s\n", query)
return next.Handle(ctx, query)
},
)
}
func logTestEventMiddleware(next cqrs.EventHandler) cqrs.EventHandler {
return cqrs.EventHandlerFunc(
func(ctx context.Context, evt cqrs.Event) error {
log.Printf("Received event: %s\n", evt)
return next.Handle(ctx, evt)
},
)
}
func TestNewRuneBringer(t *testing.T) {
bus := cqrs.NewSingularity()
if bus == nil {
t.Error("RuneBringer should not be nil")
}
busType := reflect.TypeOf(bus)
if busType.Kind() == reflect.Ptr {
busType = busType.Elem()
}
if busType.Name() != "singularity" {
t.Errorf(
"RuneBringer should be of type RuneBringer, got %s", busType.Name(),
)
}
}
func TestRuneBringer_CommandHandle(t *testing.T) {
tests := []struct {
SendEvent bool
}{
{true},
{false},
}
for _, tt := range tests {
bus := cqrs.NewSingularity()
bus.UseCommandMiddleware(logTestCommandMiddleware)
bus.UseEventMiddleware(logTestEventMiddleware)
bus.RegisterCommandHandler(
&testCommand{}, &successCommandHandler{SendEvent: tt.SendEvent},
)
bus.RegisterEventHandler(&testEvent{}, &successEventHandler{})
events, err := bus.ExecuteCommand(
context.Background(), &testCommand{Echo: "Hello"},
)
if err != nil {
t.Error("Error should be nil")
}
if tt.SendEvent {
if len(events) == 0 {
t.Errorf("Expected 1 event, got %d", len(events))
}
} else {
if len(events) != 0 {
t.Errorf("Expected 0 events, got %d", len(events))
}
}
}
}
func TestRuneBringer_CommandHandleFailure(t *testing.T) {
bus := cqrs.NewSingularity()
bus.UseCommandMiddleware(logTestCommandMiddleware)
bus.RegisterCommandHandler(
&testCommand{}, &failureCommandHandler{},
)
_, err := bus.ExecuteCommand(
context.Background(), &testCommand{Echo: "Hello"},
)
if err == nil {
t.Error("Error should not be nil")
}
}
func TestRuneBringer_CommandMissingHandler(t *testing.T) {
bus := cqrs.NewSingularity()
bus.UseCommandMiddleware(logTestCommandMiddleware)
_, err := bus.ExecuteCommand(
context.Background(), &testCommand{Echo: "Hello"},
)
if err == nil {
t.Error("Error should not be nil")
}
}
func TestRuneBringer_CommandHandleEventFailure(t *testing.T) {
tests := []struct {
SendEvent bool
EventHandler cqrs.EventHandler
}{
{true, &failureEventHandler{}},
{true, nil},
{false, nil},
}
for _, tt := range tests {
bus := cqrs.NewSingularity()
bus.UseCommandMiddleware(logTestCommandMiddleware)
bus.RegisterCommandHandler(
&testCommand{}, &successCommandHandler{SendEvent: tt.SendEvent},
)
if tt.EventHandler != nil {
bus.RegisterEventHandler(&testEvent{}, tt.EventHandler)
}
_, err := bus.ExecuteCommand(
context.Background(), &testCommand{Echo: "Hello"},
)
bus.RegisterEventHandler(&testEvent{}, tt.EventHandler)
if tt.SendEvent && tt.EventHandler != nil {
if err == nil {
t.Error("Error should not be nil")
}
} else {
if err != nil {
t.Error("Error should be nil")
}
}
}
}
func TestRuneBringer_QueryHandle(t *testing.T) {
bus := cqrs.NewSingularity()
bus.UseQueryMiddleware(logTestQueryMiddleware)
bus.RegisterQueryHandler(
&testQuery{}, &successQueryHandler{},
)
result, err := bus.ExecuteQuery(
context.Background(), &testQuery{Echo: "Hello"},
)
if err != nil {
t.Error("Error should be nil")
}
if result == nil {
t.Error("Result should not be nil")
}
}
func TestRuneBringer_QueryHandleFailure(t *testing.T) {
bus := cqrs.NewSingularity()
bus.UseQueryMiddleware(logTestQueryMiddleware)
bus.RegisterQueryHandler(
&testQuery{}, &failureQueryHandler{},
)
_, err := bus.ExecuteQuery(
context.Background(), &testQuery{Echo: "Hello"},
)
if err == nil {
t.Error("Error should not be nil")
}
}
func TestRuneBringer_QueryMissingHandler(t *testing.T) {
bus := cqrs.NewSingularity()
bus.UseQueryMiddleware(logTestQueryMiddleware)
_, err := bus.ExecuteQuery(
context.Background(), &testQuery{Echo: "Hello"},
)
if err == nil {
t.Error("Error should not be nil")
}
}