package v2 import ( "fmt" "testing" "time" "github.com/stretchr/testify/assert" "github.com/tendermint/tendermint/libs/log" ) type eventA struct { priorityNormal } var done = fmt.Errorf("done") func simpleHandler(event Event) (Event, error) { switch event.(type) { case eventA: return noOp, done } return noOp, nil } func TestRoutineFinal(t *testing.T) { routine := newRoutine("simpleRoutine", simpleHandler) assert.False(t, routine.isRunning(), "expected an initialized routine to not be running") go routine.start() <-routine.ready() assert.True(t, routine.isRunning(), "expected an started routine") assert.True(t, routine.trySend(eventA{}), "expected sending to a ready routine to succeed") assert.Equal(t, done, <-routine.final(), "expected the final event to be done") assert.False(t, routine.isRunning(), "expected an completed routine to no longer be running") } func TestRoutineStop(t *testing.T) { routine := newRoutine("simpleRoutine", simpleHandler) assert.False(t, routine.trySend(eventA{}), "expected sending to an unstarted routine to fail") go routine.start() <-routine.ready() assert.True(t, routine.trySend(eventA{}), "expected sending to a running routine to succeed") routine.stop() assert.False(t, routine.trySend(eventA{}), "expected sending to a stopped routine to fail") } type finalCount struct { count int } func (f finalCount) Error() string { return "end" } func genStatefulHandler(maxCount int) handleFunc { counter := 0 return func(event Event) (Event, error) { if _, ok := event.(eventA); ok { counter += 1 if counter >= maxCount { return noOp, finalCount{counter} } return eventA{}, nil } return noOp, nil } } func feedback(r *Routine) { for event := range r.next() { r.trySend(event) } } func TestStatefulRoutine(t *testing.T) { count := 10 handler := genStatefulHandler(count) routine := newRoutine("statefulRoutine", handler) routine.setLogger(log.TestingLogger()) go routine.start() go feedback(routine) <-routine.ready() assert.True(t, routine.trySend(eventA{}), "expected sending to a started routine to succeed") final := <-routine.final() if fnl, ok := final.(finalCount); ok { assert.Equal(t, count, fnl.count, "expected the routine to count to 10") } else { t.Fail() } } type lowPriorityEvent struct { priorityLow } type highPriorityEvent struct { priorityHigh } func handleWithPriority(event Event) (Event, error) { switch event.(type) { case lowPriorityEvent: return noOp, nil case highPriorityEvent: return noOp, done } return noOp, nil } func TestPriority(t *testing.T) { // XXX: align with buffer size routine := newRoutine("priorityRoutine", handleWithPriority) go routine.start() <-routine.ready() go func() { for { routine.trySend(lowPriorityEvent{}) time.Sleep(1 * time.Millisecond) } }() time.Sleep(10 * time.Millisecond) assert.True(t, routine.isRunning(), "expected an started routine") assert.True(t, routine.trySend(highPriorityEvent{}), "expected send to succeed even when saturated") assert.Equal(t, done, <-routine.final()) assert.False(t, routine.isRunning(), "expected an started routine") }