All checks were successful
Go CI/CD / go-ci (push) Successful in 36s
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.
274 lines
5.8 KiB
Go
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")
|
|
}
|
|
}
|