fix lint errors
This commit is contained in:
parent
8b92e9e143
commit
85e39191b8
56
machine.go
56
machine.go
@ -3,65 +3,65 @@
|
|||||||
package machine
|
package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
type State string
|
type State string
|
||||||
|
|
||||||
type Stater interface {
|
type Stater interface {
|
||||||
AddStates(name ...State)
|
AddStates(name ...State)
|
||||||
GetState(name string) State
|
GetState(name string) State
|
||||||
AddTransition(trigger string, source State, dest State)
|
AddTransition(trigger string, source State, dest State)
|
||||||
AddSubscription(transition string, subscription Subscriber) error
|
AddSubscription(transition string, subscription Subscriber) error
|
||||||
AddModel(m Modeler)
|
AddModel(m Modeler)
|
||||||
Trigger(transition string) error
|
Trigger(transition string) error
|
||||||
CurrentState() State
|
CurrentState() State
|
||||||
}
|
}
|
||||||
|
|
||||||
type Definition struct {
|
type Definition struct {
|
||||||
states []State
|
states []State
|
||||||
triggers map[string]Transitioner
|
triggers map[string]Transitioner
|
||||||
model Modeler
|
model Modeler
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(initial State) Stater {
|
func New(initial State) Stater {
|
||||||
return &Definition{ model: NewModel(initial), triggers: make(map[string]Transitioner) }
|
return &Definition{model: NewModel(initial), triggers: make(map[string]Transitioner)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Definition) AddStates(name ...State) {
|
func (d *Definition) AddStates(name ...State) {
|
||||||
d.states = append(d.states, name...)
|
d.states = append(d.states, name...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Definition) AddTransition(trigger string, source State, dest State) {
|
func (d *Definition) AddTransition(trigger string, source State, dest State) {
|
||||||
d.triggers[trigger] = NewTransition(trigger, source, dest)
|
d.triggers[trigger] = NewTransition(trigger, source, dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Definition) GetState(name string) State {
|
func (d *Definition) GetState(name string) State {
|
||||||
var r State
|
var r State
|
||||||
for _,s := range(d.states) {
|
for _, s := range d.states {
|
||||||
if string(s) == name {
|
if string(s) == name {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Definition) AddModel(m Modeler) {
|
func (d *Definition) AddModel(m Modeler) {
|
||||||
d.model = m
|
d.model = m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Definition) Trigger(transition string) error {
|
func (d *Definition) Trigger(transition string) error {
|
||||||
return d.triggers[transition].Run(d.model)
|
return d.triggers[transition].Run(d.model)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Definition) CurrentState() State {
|
func (d *Definition) CurrentState() State {
|
||||||
return d.model.InspectState()
|
return d.model.InspectState()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Definition) AddSubscription(transition string, subscription Subscriber) error {
|
func (d *Definition) AddSubscription(transition string, subscription Subscriber) error {
|
||||||
if t,ok := d.triggers[transition]; ok {
|
if t, ok := d.triggers[transition]; ok {
|
||||||
t.Subscribe(subscription)
|
t.Subscribe(subscription)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return errors.New("Transition does not exist")
|
return errors.New("Transition does not exist")
|
||||||
}
|
}
|
||||||
|
@ -2,68 +2,68 @@
|
|||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
import(
|
import (
|
||||||
"log"
|
|
||||||
"testing"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupStater(initial State) Stater {
|
func setupStater(initial State) Stater {
|
||||||
s := New(initial)
|
s := New(initial)
|
||||||
if s == nil {
|
if s == nil {
|
||||||
log.Fatal("Failed creating new Stater")
|
log.Fatal("Failed creating new Stater")
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMachineStater(t *testing.T) {
|
func TestMachineStater(t *testing.T) {
|
||||||
s := setupStater("disconnected")
|
s := setupStater("disconnected")
|
||||||
|
|
||||||
s.AddStates("disconnected", "start_connection", "connected")
|
s.AddStates("disconnected", "start_connection", "connected")
|
||||||
r := s.GetState("connected")
|
r := s.GetState("connected")
|
||||||
if r != "connected" {
|
if r != "connected" {
|
||||||
t.Errorf("Failed checking state: %s", r)
|
t.Errorf("Failed checking state: %s", r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMachineCurrentState(t *testing.T) {
|
func TestMachineCurrentState(t *testing.T) {
|
||||||
s := setupStater("disconnected")
|
s := setupStater("disconnected")
|
||||||
|
|
||||||
s.AddStates("disconnected", "start_connection", "connected")
|
s.AddStates("disconnected", "start_connection", "connected")
|
||||||
r := s.CurrentState()
|
r := s.CurrentState()
|
||||||
if r != "disconnected" {
|
if r != "disconnected" {
|
||||||
t.Errorf("Failed checking state: %s", r)
|
t.Errorf("Failed checking state: %s", r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMachineAddTransition(t *testing.T) {
|
func TestMachineAddTransition(t *testing.T) {
|
||||||
s := setupStater("disconnected")
|
s := setupStater("disconnected")
|
||||||
s.AddStates("disconnected", "start_connection", "connected")
|
s.AddStates("disconnected", "start_connection", "connected")
|
||||||
s.AddTransition("connect", "disconnected", "start_connection")
|
s.AddTransition("connect", "disconnected", "start_connection")
|
||||||
s.AddModel(setupModel("disconnected"))
|
s.AddModel(setupModel("disconnected"))
|
||||||
// worker gets a trigger message
|
// worker gets a trigger message
|
||||||
assert.Nil(t, s.Trigger("connect"))
|
assert.Nil(t, s.Trigger("connect"))
|
||||||
|
|
||||||
// machine generates transition event mesages
|
// machine generates transition event mesages
|
||||||
if s.CurrentState() != "start_connection" {
|
if s.CurrentState() != "start_connection" {
|
||||||
t.Errorf("State transition failed for: connect - %s", s.CurrentState())
|
t.Errorf("State transition failed for: connect - %s", s.CurrentState())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMachineAddSubscription(t *testing.T) {
|
func TestMachineAddSubscription(t *testing.T) {
|
||||||
x := setupSubscriber()
|
x := setupSubscriber()
|
||||||
s := setupStater("disconnected")
|
s := setupStater("disconnected")
|
||||||
s.AddStates("disconnected", "start_connection", "connected")
|
s.AddStates("disconnected", "start_connection", "connected")
|
||||||
s.AddTransition("connect", "disconnected", "start_connection")
|
s.AddTransition("connect", "disconnected", "start_connection")
|
||||||
assert.Nil(t, s.AddSubscription("connect", x))
|
assert.Nil(t, s.AddSubscription("connect", x))
|
||||||
s.AddModel(setupModel("disconnected"))
|
s.AddModel(setupModel("disconnected"))
|
||||||
s.Trigger("connect")
|
s.Trigger("connect")
|
||||||
exitMessage := <- *x.(*EventChannel)
|
exitMessage := <-*x.(*EventChannel)
|
||||||
enterMessage := <- *x.(*EventChannel)
|
enterMessage := <-*x.(*EventChannel)
|
||||||
if exitMessage.on == EXITSTATEEVENT && exitMessage.source == "disconnected" {
|
if exitMessage.on == EXITSTATEEVENT && exitMessage.source == "disconnected" {
|
||||||
if enterMessage.on == ENTERSTATEEVENT && enterMessage.dest == "start_connection" {
|
if enterMessage.on == ENTERSTATEEVENT && enterMessage.dest == "start_connection" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.Errorf("Unexpected event message in state transition notification: exit: %s, enter: %s", exitMessage, enterMessage)
|
t.Errorf("Unexpected event message in state transition notification: exit: %s, enter: %s", exitMessage, enterMessage)
|
||||||
}
|
}
|
||||||
|
16
message.go
16
message.go
@ -3,28 +3,28 @@
|
|||||||
package machine
|
package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ENTERSTATEEVENT = iota
|
ENTERSTATEEVENT = iota
|
||||||
EXITSTATEEVENT
|
EXITSTATEEVENT
|
||||||
)
|
)
|
||||||
|
|
||||||
type Eventtype int
|
type Eventtype int
|
||||||
|
|
||||||
type EventMessage struct {
|
type EventMessage struct {
|
||||||
on Eventtype
|
on Eventtype
|
||||||
source State
|
source State
|
||||||
dest State
|
dest State
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventChannel chan EventMessage
|
type EventChannel chan EventMessage
|
||||||
|
|
||||||
func (e *EventChannel) Notify(m *EventMessage) {
|
func (e *EventChannel) Notify(m *EventMessage) {
|
||||||
*e <- *m
|
*e <- *m
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m EventMessage) String() string {
|
func (m EventMessage) String() string {
|
||||||
return fmt.Sprintf("{on: %d, source: %s, dest: %s}", m.on, m.source, m.dest)
|
return fmt.Sprintf("{on: %d, source: %s, dest: %s}", m.on, m.source, m.dest)
|
||||||
}
|
}
|
||||||
|
20
model.go
20
model.go
@ -3,29 +3,29 @@
|
|||||||
package machine
|
package machine
|
||||||
|
|
||||||
type Modeler interface {
|
type Modeler interface {
|
||||||
Trigger(transition Transitioner) error
|
Trigger(transition Transitioner) error
|
||||||
ChangeState(target State) State
|
ChangeState(target State) State
|
||||||
InspectState() State
|
InspectState() State
|
||||||
}
|
}
|
||||||
|
|
||||||
type Model struct {
|
type Model struct {
|
||||||
state State
|
state State
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewModel(initial State) Modeler {
|
func NewModel(initial State) Modeler {
|
||||||
return &Model{ state: initial }
|
return &Model{state: initial}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) Trigger(transition Transitioner) error {
|
func (m *Model) Trigger(transition Transitioner) error {
|
||||||
return transition.Run(m)
|
return transition.Run(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) ChangeState(target State) State {
|
func (m *Model) ChangeState(target State) State {
|
||||||
oldState := m.state
|
oldState := m.state
|
||||||
m.state = target
|
m.state = target
|
||||||
return oldState
|
return oldState
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) InspectState() State {
|
func (m *Model) InspectState() State {
|
||||||
return m.state
|
return m.state
|
||||||
}
|
}
|
||||||
|
@ -3,27 +3,27 @@
|
|||||||
package machine
|
package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupModel(initial State) Modeler {
|
func setupModel(initial State) Modeler {
|
||||||
return NewModel(initial)
|
return NewModel(initial)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMachineModel(t *testing.T) {
|
func TestMachineModel(t *testing.T) {
|
||||||
m := setupModel("")
|
m := setupModel("")
|
||||||
if m == nil {
|
if m == nil {
|
||||||
t.Errorf("Failed creating new model")
|
t.Errorf("Failed creating new model")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMachineModelChangeState(t *testing.T) {
|
func TestMachineModelChangeState(t *testing.T) {
|
||||||
m := setupModel("")
|
m := setupModel("")
|
||||||
oldState := m.ChangeState("connected")
|
oldState := m.ChangeState("connected")
|
||||||
if oldState != "" {
|
if oldState != "" {
|
||||||
t.Errorf("Failed changing state in model")
|
t.Errorf("Failed changing state in model")
|
||||||
}
|
}
|
||||||
if m.InspectState() != "connected" {
|
if m.InspectState() != "connected" {
|
||||||
t.Errorf("Failed changing state in model")
|
t.Errorf("Failed changing state in model")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
state.go
5
state.go
@ -3,10 +3,9 @@
|
|||||||
package machine
|
package machine
|
||||||
|
|
||||||
type mState struct {
|
type mState struct {
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewState(name string) *mState {
|
func NewState(name string) *mState {
|
||||||
return &mState{ name: name }
|
return &mState{name: name}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
package machine
|
package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMachineState(t *testing.T) {
|
func TestMachineState(t *testing.T) {
|
||||||
s := NewState("connected")
|
s := NewState("connected")
|
||||||
if s == nil {
|
if s == nil {
|
||||||
t.Errorf("Failed creating new state")
|
t.Errorf("Failed creating new state")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,5 +3,5 @@
|
|||||||
package machine
|
package machine
|
||||||
|
|
||||||
type Subscriber interface {
|
type Subscriber interface {
|
||||||
Notify(m *EventMessage)
|
Notify(m *EventMessage)
|
||||||
}
|
}
|
||||||
|
@ -3,45 +3,45 @@
|
|||||||
package machine
|
package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
_ "errors"
|
||||||
"errors"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Transitioner interface {
|
type Transitioner interface {
|
||||||
Run(m Modeler) error
|
Run(m Modeler) error
|
||||||
Subscribe(s Subscriber)
|
Subscribe(s Subscriber)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Transition struct {
|
type Transition struct {
|
||||||
trigger string
|
trigger string
|
||||||
source State
|
source State
|
||||||
dest State
|
dest State
|
||||||
subscriptions []Subscriber
|
subscriptions []Subscriber
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTransition(trigger string, source State, dest State) Transitioner {
|
func NewTransition(trigger string, source State, dest State) Transitioner {
|
||||||
return &Transition{ trigger: trigger, source: source, dest: dest }
|
return &Transition{trigger: trigger, source: source, dest: dest}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Transition) Run(m Modeler) error {
|
func (r *Transition) Run(m Modeler) error {
|
||||||
currentState := m.InspectState()
|
currentState := m.InspectState()
|
||||||
if currentState == r.source {
|
if currentState == r.source {
|
||||||
res := m.ChangeState(r.dest)
|
res := m.ChangeState(r.dest)
|
||||||
if res == currentState {
|
if res == currentState {
|
||||||
r.Notify(EXITSTATEEVENT, currentState, r.dest)
|
r.Notify(EXITSTATEEVENT, currentState, r.dest)
|
||||||
r.Notify(ENTERSTATEEVENT, currentState, r.dest)
|
r.Notify(ENTERSTATEEVENT, currentState, r.dest)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return errors.New(fmt.Sprintf("Transition from %s to %s failed on model state %s", r.source, r.dest, currentState))
|
return fmt.Errorf("Transition from %s to %s failed on model state %s", r.source, r.dest, currentState)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Transition) Subscribe(s Subscriber) {
|
func (r *Transition) Subscribe(s Subscriber) {
|
||||||
r.subscriptions = append(r.subscriptions, s)
|
r.subscriptions = append(r.subscriptions, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Transition) Notify(on Eventtype, source State, dest State) {
|
func (r *Transition) Notify(on Eventtype, source State, dest State) {
|
||||||
for _,s := range r.subscriptions {
|
for _, s := range r.subscriptions {
|
||||||
s.Notify(&EventMessage{ on: on, source: source, dest: dest})
|
s.Notify(&EventMessage{on: on, source: source, dest: dest})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,53 +3,53 @@
|
|||||||
package machine
|
package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"testing"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupTransition() Transitioner {
|
func setupTransition() Transitioner {
|
||||||
t := NewTransition("open", "closed", "open")
|
t := NewTransition("open", "closed", "open")
|
||||||
if t == nil {
|
if t == nil {
|
||||||
log.Fatal("Failed creating new transition")
|
log.Fatal("Failed creating new transition")
|
||||||
}
|
}
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupSubscriber() Subscriber {
|
func setupSubscriber() Subscriber {
|
||||||
c := make(EventChannel, 2)
|
c := make(EventChannel, 2)
|
||||||
return &c
|
return &c
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewTransition(t *testing.T) {
|
func TestNewTransition(t *testing.T) {
|
||||||
s := NewTransition("connect", "disconnected", "connected")
|
s := NewTransition("connect", "disconnected", "connected")
|
||||||
if s == nil {
|
if s == nil {
|
||||||
t.Errorf("Failed creating new transition")
|
t.Errorf("Failed creating new transition")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTransitionExecution(t *testing.T) {
|
func TestTransitionExecution(t *testing.T) {
|
||||||
s := setupTransition()
|
s := setupTransition()
|
||||||
m := setupModel("closed")
|
m := setupModel("closed")
|
||||||
assert.Nil(t, s.Run(m))
|
assert.Nil(t, s.Run(m))
|
||||||
state := m.InspectState()
|
state := m.InspectState()
|
||||||
if state != "open" {
|
if state != "open" {
|
||||||
t.Errorf("Failed to transition state: %s", state)
|
t.Errorf("Failed to transition state: %s", state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTransitionSubscribe(t *testing.T) {
|
func TestTransitionSubscribe(t *testing.T) {
|
||||||
c := setupSubscriber()
|
c := setupSubscriber()
|
||||||
s := setupTransition()
|
s := setupTransition()
|
||||||
s.Subscribe(c)
|
s.Subscribe(c)
|
||||||
m := setupModel("closed")
|
m := setupModel("closed")
|
||||||
assert.Nil(t, s.Run(m))
|
assert.Nil(t, s.Run(m))
|
||||||
exitEvent := <- *c.(*EventChannel)
|
exitEvent := <-*c.(*EventChannel)
|
||||||
enterEvent := <- *c.(*EventChannel)
|
enterEvent := <-*c.(*EventChannel)
|
||||||
if exitEvent.on != EXITSTATEEVENT {
|
if exitEvent.on != EXITSTATEEVENT {
|
||||||
t.Errorf("Invalid exit event")
|
t.Errorf("Invalid exit event")
|
||||||
}
|
}
|
||||||
if enterEvent.on != ENTERSTATEEVENT {
|
if enterEvent.on != ENTERSTATEEVENT {
|
||||||
t.Errorf("Invalid enter event")
|
t.Errorf("Invalid enter event")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user