multi: added fix state changing after callback, test refactoring, example

This commit is contained in:
x88 2020-08-05 16:41:19 +03:00
parent 64d74db35a
commit a4021121cf
6 changed files with 134 additions and 88 deletions

View File

@ -1,6 +1,8 @@
package main
import (
"github.com/depools/dc4bc/fsm/fsm"
"github.com/depools/dc4bc/fsm/types/responses"
"log"
"github.com/depools/dc4bc/fsm/state_machines"
@ -28,8 +30,44 @@ func main() {
},
},
)
log.Println("Response", resp)
log.Println("Err", err)
log.Println("Dump", string(dump))
processResponse(resp)
}
func processResponse(resp *fsm.Response) {
switch resp.State {
// Await proposals
case fsm.State("validate_proposal"):
data, ok := resp.Data.(responses.ProposalParticipantInvitationsResponse)
if !ok {
log.Printf("undefined response type for state \"%s\"\n", resp.State)
return
}
sendInvitations(data)
case fsm.State("validation_canceled_by_participant"):
updateDashboardWithCanceled("Participant")
case fsm.State("validation_canceled_by_timeout"):
updateDashboardWithCanceled("Timeout")
default:
log.Printf("undefined response type for state \"%s\"\n", resp.State)
}
}
func sendInvitations(invitations responses.ProposalParticipantInvitationsResponse) {
for _, invitation := range invitations {
log.Printf(
"Dear %s, please encrypt value \"%s\" with your key, fingerprint: %s\n",
invitation.Title,
invitation.EncryptedInvitation,
invitation.PubKeyFingerprint,
)
}
}
func updateDashboardWithCanceled(msg string) {
log.Printf("Breaking news! Proposal canceled with reason: %s\n", msg)
}

View File

@ -246,6 +246,9 @@ func (f *FSM) Do(event Event, args ...interface{}) (resp *Response, err error) {
}
err = f.setState(event)
if err == nil {
resp.State = f.currentState
}
return
}

View File

@ -1,67 +0,0 @@
package fsm
type testMachineFSM struct {
*FSM
}
const (
FSM1Name = "fsm1"
// Init process from global idle state
FSM1StateInit = StateGlobalIdle
FSM2StateInit = StateGlobalIdle
// Set up data
FSM1StateStage1 = State("state_fsm1_stage1")
// Process data
FSM1StateStage2 = State("state_fsm1_stage2")
// Cancelled with internal event
FSM1StateCanceledByInternal = State("state_fsm1_canceled")
// Cancelled with external event
FSM1StateCanceled2 = State("state_fsm1_canceled2")
// Out endpoint to switch
FSM1StateOutToFSM2 = State("state_fsm1_out_to_fsm2")
FSM1StateOutToFSM3 = State("state_fsm1_out_to_fsm3")
// Events
EventFSM1Init = Event("event_fsm1_init")
EventFSM1Cancel = Event("event_fsm1_cancel")
EventFSM1Process = Event("event_fsm1_process")
// Internal events
EventFSM1Internal = Event("event_internal_fsm1")
EventFSM1CancelByInternal = Event("event_internal_fsm1_cancel")
EventFSM1InternalOut2 = Event("event_internal_fsm1_out")
)
var (
testing1Events = []EventDesc{
// Init
{Name: EventFSM1Init, SrcState: []State{FSM2StateInit}, DstState: FSM1StateStage1},
{Name: EventFSM1Internal, SrcState: []State{FSM1StateStage1}, DstState: FSM1StateStage2, IsInternal: true},
// Cancellation events
{Name: EventFSM1CancelByInternal, SrcState: []State{FSM1StateStage2}, DstState: FSM1StateCanceledByInternal, IsInternal: true},
{Name: EventFSM1Cancel, SrcState: []State{FSM1StateStage2}, DstState: FSM1StateCanceled2},
// Out
{Name: EventFSM1Process, SrcState: []State{FSM1StateStage2}, DstState: FSM1StateOutToFSM2},
{Name: EventFSM1InternalOut2, SrcState: []State{FSM1StateStage2}, DstState: FSM1StateOutToFSM3, IsInternal: true},
}
testing1Callbacks = Callbacks{
EventFSM1Init: actionSetUpData,
EventFSM1InternalOut2: actionEmitOut2,
EventFSM1Process: actionProcessData,
}
)
func actionSetUpData(event Event, args ...interface{}) (response interface{}, err error) {
return
}
func actionProcessData(event Event, args ...interface{}) (response interface{}, err error) {
return
}
func actionEmitOut2(event Event, args ...interface{}) (response interface{}, err error) {
return
}

View File

@ -4,14 +4,68 @@ import (
"testing"
)
var testingFSM *FSM
const (
testName = "fsm_test"
// Init process from global idle state
stateInit = StateGlobalIdle
// Set up data
stateStage1 = State("state_stage1")
// Process data
stateStage2 = State("state_stage2")
// Cancelled with internal event
stateCanceledByInternal = State("state_canceled")
// Cancelled with external event
stateCanceled2 = State("state_canceled2")
// Out endpoint to switch
stateOutToFSM2 = State("state_out_to_fsm2")
// Events
eventInit = Event("event_init")
eventCancel = Event("event_cancel")
eventProcess = Event("event_process")
// Internal events
eventInternal = Event("event_internal")
eventCancelByInternal = Event("event_internal_cancel")
eventInternalOut2 = Event("event_internal_out")
)
var (
testingFSM *FSM
testingEvents = []EventDesc{
// Init
{Name: eventInit, SrcState: []State{stateInit}, DstState: stateStage1},
{Name: eventInternal, SrcState: []State{stateStage1}, DstState: stateStage2, IsInternal: true},
// Cancellation events
{Name: eventCancelByInternal, SrcState: []State{stateStage2}, DstState: stateCanceledByInternal, IsInternal: true},
{Name: eventCancel, SrcState: []State{stateStage2}, DstState: stateCanceled2},
// Out
{Name: eventProcess, SrcState: []State{stateStage2}, DstState: stateOutToFSM2},
{Name: eventInternalOut2, SrcState: []State{stateStage2}, DstState: stateOutToFSM2, IsInternal: true},
}
testingCallbacks = Callbacks{
eventInit: func(event Event, args ...interface{}) (interface{}, error) {
return nil, nil
},
eventInternalOut2: func(event Event, args ...interface{}) (interface{}, error) {
return nil, nil
},
eventProcess: func(event Event, args ...interface{}) (interface{}, error) {
return nil, nil
},
}
)
func init() {
testingFSM = MustNewFSM(
FSM1Name,
FSM1StateInit,
testing1Events,
testing1Callbacks,
testName,
stateInit,
testingEvents,
testingCallbacks,
)
}
@ -212,22 +266,22 @@ func TestMustNewFSM_State_Final_Not_Found_Panic(t *testing.T) {
}
func TestFSM_Name(t *testing.T) {
if testingFSM.Name() != FSM1Name {
t.Errorf("expected machine name \"%s\"", FSM1Name)
if testingFSM.Name() != testName {
t.Errorf("expected machine name \"%s\"", testName)
}
}
func TestFSM_EntryEvent(t *testing.T) {
if testingFSM.InitialState() != FSM1StateInit {
t.Errorf("expected initial state \"%s\"", FSM1StateInit)
if testingFSM.InitialState() != stateInit {
t.Errorf("expected initial state \"%s\"", stateInit)
}
}
func TestFSM_EventsList(t *testing.T) {
eventsList := []Event{
EventFSM1Init,
EventFSM1Cancel,
EventFSM1Process,
eventInit,
eventCancel,
eventProcess,
}
if !compareEventsArr(testingFSM.EventsList(), eventsList) {
@ -238,9 +292,9 @@ func TestFSM_EventsList(t *testing.T) {
func TestFSM_StatesList(t *testing.T) {
statesList := []State{
FSM1StateInit,
FSM1StateStage1,
FSM1StateStage2,
stateInit,
stateStage1,
stateStage2,
}
if !compareStatesArr(testingFSM.StatesSourcesList(), statesList) {

View File

@ -72,13 +72,27 @@ func (s *SignatureProposalFSM) actionInitProposal(event fsm.Event, args ...inter
}
}
/*s.state = &fsm_pool.FSMachine{
Id: signingId,
State: stateAwaitProposalConfirmation,
// Make response
responseData := make(responses.ProposalParticipantInvitationsResponse, 0)
for participantId, proposal := range payload.ProposalPayload {
encryptedInvitationSecret, err := encryptWithPubKey(proposal.PublicKey, proposal.InvitationSecret)
if err != nil {
return nil, errors.New("cannot encryptWithPubKey")
}
responseEntry := &responses.ProposalParticipantInvitationEntryResponse{
Title: proposal.Title,
PubKeyFingerprint: participantId,
EncryptedInvitation: encryptedInvitationSecret,
}
responseData = append(responseData, responseEntry)
}
s.state.Payload.ProposalPayload = &privateParticipantsList*/
// Change state
return internal.MachineCombinedResponse{
Response: responses.ProposalParticipantInvitationsResponse{},
Response: responseData,
Payload: &payload,
}, nil
}

View File

@ -57,3 +57,7 @@ func generateRandomString(s int) (string, error) {
b, err := generateRandomBytes(s)
return base64.URLEncoding.EncodeToString(b), err
}
func encryptWithPubKey(key []byte, value string) (string, error) {
return value, nil
}