Skip to content

Commit

Permalink
FMesh: add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hovsep committed Sep 16, 2024
1 parent 0814d21 commit 9ea0e7d
Show file tree
Hide file tree
Showing 9 changed files with 399 additions and 54 deletions.
7 changes: 6 additions & 1 deletion component/activation_result.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package component

import "fmt"

// ActivationResult defines the result (possibly an error) of the activation of given component in given cycle
type ActivationResult struct {
componentName string
Expand Down Expand Up @@ -81,7 +83,10 @@ func (c *Component) newActivationCodeWaitingForInput() *ActivationResult {

// newActivationCodeReturnedError builds a specific activation result
func (c *Component) newActivationCodeReturnedError(err error) *ActivationResult {
return NewActivationResult(c.Name()).SetActivated(true).WithActivationCode(ActivationCodeReturnedError).WithError(err)
return NewActivationResult(c.Name()).
SetActivated(true).
WithActivationCode(ActivationCodeReturnedError).
WithError(fmt.Errorf("component returned an error: %w", err))
}

// newActivationCodePanicked builds a specific activation result
Expand Down
10 changes: 3 additions & 7 deletions component/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"github.com/hovsep/fmesh/port"
"runtime/debug"
)

type ActivationFunc func(inputs port.Ports, outputs port.Ports) error
Expand Down Expand Up @@ -91,12 +90,9 @@ func (c *Component) hasActivationFunction() bool {
func (c *Component) MaybeActivate() (activationResult *ActivationResult) {
defer func() {
if r := recover(); r != nil {
errorFormat := "panicked with: %v, stacktrace: %s"
if _, ok := r.(error); ok {
errorFormat = "panicked with: %w, stacktrace: %s"
}
//TODO: add custom error
activationResult = c.newActivationCodePanicked(fmt.Errorf(errorFormat, r, debug.Stack()))
//Clear inputs and exit
c.inputs.ClearSignal()
activationResult = c.newActivationCodePanicked(fmt.Errorf("panicked with: %v", r))
}
}()

Expand Down
8 changes: 4 additions & 4 deletions component/component_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ func TestComponent_Activate(t *testing.T) {
wantActivationResult: NewActivationResult("c1").
SetActivated(true).
WithActivationCode(ActivationCodeReturnedError).
WithError(errors.New("failed to activate component: test error")),
WithError(errors.New("component returned an error: test error")),
},
{
name: "activated without error",
Expand Down Expand Up @@ -556,10 +556,10 @@ func TestComponent_Activate(t *testing.T) {
assert.Equal(t, got.Activated(), tt.wantActivationResult.Activated())
assert.Equal(t, got.ComponentName(), tt.wantActivationResult.ComponentName())
assert.Equal(t, got.Code(), tt.wantActivationResult.Code())
if !tt.wantActivationResult.HasError() {
assert.False(t, got.HasError())
if tt.wantActivationResult.HasError() {
assert.EqualError(t, got.Error(), tt.wantActivationResult.Error().Error())
} else {
assert.ErrorContains(t, got.Error(), tt.wantActivationResult.Error().Error())
assert.False(t, got.HasError())
}

})
Expand Down
9 changes: 6 additions & 3 deletions cycle/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ func (cycleResult *Result) HasActivatedComponents() bool {
return false
}

// Add adds a cycle result to existing collection
func (cycleResults Results) Add(cycleResult *Result) Results {
return append(cycleResults, cycleResult)
// Add adds cycle results to existing collection
func (cycleResults Results) Add(newCycleResults ...*Result) Results {
for _, cycleResult := range newCycleResults {
cycleResults = append(cycleResults, cycleResult)
}
return cycleResults
}
19 changes: 16 additions & 3 deletions cycle/result_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

func TestResults_Add(t *testing.T) {
type args struct {
cycleResult *Result
cycleResults []*Result
}
tests := []struct {
name string
Expand All @@ -21,11 +21,24 @@ func TestResults_Add(t *testing.T) {
name: "happy path",
cycleResults: NewResults(),
args: args{
cycleResult: NewResult().SetCycleNumber(1).WithActivationResults(component.NewActivationResult("c1").SetActivated(true)),
cycleResults: []*Result{
NewResult().
SetCycleNumber(1).
WithActivationResults(component.NewActivationResult("c1").SetActivated(false)),
NewResult().
SetCycleNumber(2).
WithActivationResults(component.NewActivationResult("c1").SetActivated(true)),
},
},
want: Results{
{
cycleNumber: 1,
activationResults: component.ActivationResults{
"c1": component.NewActivationResult("c1").SetActivated(false),
},
},
{
cycleNumber: 2,
activationResults: component.ActivationResults{
"c1": component.NewActivationResult("c1").SetActivated(true),
},
Expand All @@ -35,7 +48,7 @@ func TestResults_Add(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.cycleResults.Add(tt.args.cycleResult); !reflect.DeepEqual(got, tt.want) {
if got := tt.cycleResults.Add(tt.args.cycleResults...); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Add() = %v, want %v", got, tt.want)
}
})
Expand Down
6 changes: 0 additions & 6 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package fmesh

import (
"errors"
"fmt"
"github.com/hovsep/fmesh/cycle"
)

type ErrorHandlingStrategy int
Expand All @@ -19,7 +17,3 @@ var (
ErrHitAPanic = errors.New("f-mesh hit a panic and will be stopped")
ErrUnsupportedErrorHandlingStrategy = errors.New("unsupported error handling strategy")
)

func newFMeshStopError(err error, cycleResult *cycle.Result) error {
return fmt.Errorf("%w (cycle #%d activation results: %v)", err, cycleResult.CycleNumber(), cycleResult.ActivationResults())
}
14 changes: 7 additions & 7 deletions fmesh.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func (fm *FMesh) runCycle() *cycle.Result {
case aRes := <-activationResultsChan:
//@TODO :check for closed channel
cycleResult.Lock()
cycleResult = cycleResult.WithActivationResult(aRes)
cycleResult = cycleResult.WithActivationResults(aRes)
cycleResult.Unlock()
case <-doneChan:
return
Expand Down Expand Up @@ -104,15 +104,17 @@ func (fm *FMesh) drainComponents() {
// Run starts the computation until there is no component which activates (mesh has no unprocessed inputs)
func (fm *FMesh) Run() (cycle.Results, error) {
allCycles := cycle.NewResults()
cycleNumber := uint(0)
for {
cycleResult := fm.runCycle()
cycleNumber++
cycleResult := fm.runCycle().SetCycleNumber(cycleNumber)
allCycles = allCycles.Add(cycleResult)

mustStop, err := fm.mustStop(cycleResult)
if mustStop {
return allCycles, err
}

allCycles.Add(cycleResult)
fm.drainComponents()
}
}
Expand All @@ -126,14 +128,12 @@ func (fm *FMesh) mustStop(cycleResult *cycle.Result) (bool, error) {
//Check if mesh must stop because of configured error handling strategy
switch fm.errorHandlingStrategy {
case StopOnFirstError:
return cycleResult.HasErrors(), newFMeshStopError(ErrHitAnError, cycleResult)
return cycleResult.HasErrors(), ErrHitAnError
case StopOnFirstPanic:
return cycleResult.HasPanics(), newFMeshStopError(ErrHitAPanic, cycleResult)
return cycleResult.HasPanics(), ErrHitAPanic
case IgnoreAll:
return false, nil
default:
//@TODO: maybe better to return error

return true, ErrUnsupportedErrorHandlingStrategy
}
}
Loading

0 comments on commit 9ea0e7d

Please sign in to comment.