Skip to content

Commit

Permalink
refactor: add unit test for entity
Browse files Browse the repository at this point in the history
  • Loading branch information
Tochemey committed Oct 7, 2023
1 parent 8525777 commit 53d2c47
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 1 deletion.
11 changes: 10 additions & 1 deletion engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type Engine struct {
discoveryConfig discovery.Config // discoveryConfig is the discovery provider config for clustering
telemetry *telemetry.Telemetry // telemetry is the observability engine
partitionsCount uint64 // partitionsCount specifies the number of partitions
started atomic.Bool
}

// NewEngine creates an instance of Engine
Expand All @@ -40,6 +41,7 @@ func NewEngine(name string, eventsStore eventstore.EventsStore, opts ...Option)
for _, opt := range opts {
opt.Apply(e)
}
e.started.Store(false)
return e
}

Expand Down Expand Up @@ -71,10 +73,17 @@ func (x *Engine) Start(ctx context.Context) error {
return err
}
// start the actor system
return x.actorSystem.Start(ctx)
if err := x.actorSystem.Start(ctx); err != nil {
return err
}
// set the started to true
x.started.Store(true)
return nil
}

// Stop stops the ego engine
func (x *Engine) Stop(ctx context.Context) error {
// set the started to false
x.started.Store(false)
return x.actorSystem.Stop(ctx)
}
25 changes: 25 additions & 0 deletions entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ import (
"github.com/tochemey/goakt/actors"
)

var (
// ErrEngineRequired is returned when the eGo engine is not set
ErrEngineRequired = errors.New("eGo engine is not defined")
// ErrEngineNotStarted is returned when the eGo engine has not started
ErrEngineNotStarted = errors.New("eGo engine has not started")
// ErrUndefinedEntity is returned when sending a command to an undefined entity
ErrUndefinedEntity = errors.New("eGo entity is not defined")
)

// Entity defines the event sourced persistent entity
// This handles commands in order
type Entity[T State] struct {
Expand All @@ -18,6 +27,15 @@ type Entity[T State] struct {

// NewEntity creates an instance of Entity
func NewEntity[T State](ctx context.Context, behavior EntityBehavior[T], engine *Engine) (*Entity[T], error) {
// check whether the ego engine is defined
if engine == nil {
return nil, ErrEngineRequired
}
// check whether the eGo engine has started or not
if !engine.started.Load() {
return nil, ErrEngineNotStarted
}

// create the instance of the actor
pid, err := engine.actorSystem.Spawn(ctx, behavior.ID(), newActor(behavior, engine.eventsStore))
// return the error in case there is one
Expand All @@ -34,7 +52,14 @@ func NewEntity[T State](ctx context.Context, behavior EntityBehavior[T], engine
// 2. nil when there is no resulting state or no event persisted
// 3. an error in case of error
func (x Entity[T]) SendCommand(ctx context.Context, command Command) (resultingState T, revision uint64, err error) {
// define a nil state
var nilT T

// check whether the underlying actor is set and running
if x.actor == nil || !x.actor.IsRunning() {
return nilT, 0, ErrUndefinedEntity
}

// send the command to the actor
reply, err := actors.Ask(ctx, x.actor, command, time.Second)
// handle the error
Expand Down
49 changes: 49 additions & 0 deletions entity_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package ego

import (
"context"
"testing"

"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tochemey/ego/eventstore/memory"
samplepb "github.com/tochemey/ego/example/pbs/sample/pb/v1"
)

func TestNewEntity(t *testing.T) {
t.Run("With engine not defined", func(t *testing.T) {
ctx := context.TODO()
behavior := NewAccountBehavior(uuid.NewString())
// create an entity
entity, err := NewEntity[*samplepb.Account](ctx, behavior, nil)
require.Error(t, err)
require.Nil(t, entity)
assert.EqualError(t, err, ErrEngineRequired.Error())
})
t.Run("With engine not started", func(t *testing.T) {
ctx := context.TODO()
// create the event store
eventStore := memory.NewEventsStore()
// create the ego engine
engine := NewEngine("Sample", eventStore)
behavior := NewAccountBehavior(uuid.NewString())
// create an entity
entity, err := NewEntity[*samplepb.Account](ctx, behavior, engine)
require.Error(t, err)
require.Nil(t, entity)
assert.EqualError(t, err, ErrEngineNotStarted.Error())
})
}

func TestSendCommand(t *testing.T) {
t.Run("With entity not defined", func(t *testing.T) {
ctx := context.TODO()
entity := &Entity[*samplepb.Account]{}
resultingState, revision, err := entity.SendCommand(ctx, new(samplepb.CreateAccount))
require.Nil(t, resultingState)
require.Zero(t, revision)
require.Error(t, err)
assert.EqualError(t, err, ErrUndefinedEntity.Error())
})
}

0 comments on commit 53d2c47

Please sign in to comment.