diff --git a/src/core/opcua-iiot-core-connector.ts b/src/core/opcua-iiot-core-connector.ts index 823d9de0..e48f9f6e 100644 --- a/src/core/opcua-iiot-core-connector.ts +++ b/src/core/opcua-iiot-core-connector.ts @@ -17,7 +17,8 @@ import {TodoTypeAny} from "../types/placeholders"; import {ClientSession, OPCUAClient, OPCUADiscoveryServer, UserIdentityInfo} from "node-opcua"; import {OPCUAClientOptions} from "node-opcua-client/dist/opcua_client"; import {Node} from "node-red"; -import {createMachine, interpret} from "@xstate/fsm"; +import {createMachine, interpret, StateMachine} from "@xstate/fsm"; +import Service = StateMachine.Service; export type ConnectorIIoT = { endpoints: string[], @@ -28,7 +29,10 @@ export type ConnectorIIoT = { discoveryServerEndpointUrl?: string hasOpcUaSubscriptions: boolean userIdentity?: UserIdentityInfo - stateMachine?: Stately.machine + //stateMachine?: Stately.machine + stateMachine?: TodoTypeAny + stateService?: TodoTypeAny + stateSubscription?: TodoTypeAny opcuaClientOptions?: OPCUAClientOptions registeredNodeList?: Record functions?: Record TodoTypeAny> @@ -59,7 +63,7 @@ const initConnectorNode = (): ConnectorIIoT => { } } - +/* export type CoreMachineStates = 'IDLE' | 'INITOPCUA' | @@ -76,8 +80,11 @@ export type CoreMachineStates = 'STOPPED' | 'END'; + */ + // export type CoreStateMachine = Record> +/* // TODO: @xstate/fsm is a good package to replace it. See: modbus contribution package core client // many functions are now available and working well in node-opcua and maybe it needs less control from our package function createConnectorStatelyMachine() { @@ -162,10 +169,10 @@ function createConnectorStatelyMachine() { logger.detailDebugLog('FSM events:' + stateMachine.getMachineEvents()) return stateMachine } - + */ interface ConnectorTestContext { - testString?: string + debugContext?: string } type ConnectorEvent = @@ -176,9 +183,11 @@ type ConnectorEvent = | { type: 'SESSIONREQUEST'} | { type: 'IDLE'} | { type: 'LOCK'} + | { type: 'UNLOCK'} | { type: 'END'} | { type: 'CLOSE'} | { type: 'OPEN'} + | { type: 'STOP'} | { type: 'RESTART'} | { type: 'RENEW'} | { type: 'RECONFIGURE'}; @@ -190,7 +199,6 @@ type ConnectorState = | { value: 'sessionRequested'; context: ConnectorTestContext & { testString: undefined } } | { value: 'sessionActive'; context: ConnectorTestContext & { testString: undefined } } | { value: 'sessionClosed'; context: ConnectorTestContext & { testString: undefined } } - | { value: 'sessionStart'; context: ConnectorTestContext & { testString: undefined } } | { value: 'sessionRestart'; context: ConnectorTestContext & { testString: undefined } } | { value: 'closed'; context: ConnectorTestContext & { testString: undefined } } | { value: 'locked'; context: ConnectorTestContext & { testString: undefined } } @@ -200,10 +208,27 @@ type ConnectorState = | { value: 'reconfigured'; context: ConnectorTestContext & { testString: undefined }} | { value: 'renewed'; context: ConnectorTestContext & { testString: undefined } }; +export enum fsmConnectorStates { + StateIdle = 'idle', + StateInit = 'init', + StateOpened = 'opened', + StateSessionRequested = 'sessionRequested', + StateSessionActive = 'sessionActive', + StateSessionClosed = 'sessionClosed', + StateSessionRestart = 'sessionRestart', + StateClosed = 'closed', + StateLocked = 'locked', + StateUnlocked = 'unlocked', + StateStopped = 'stopped', + StateEnd = 'end', + StateReconfigured = 'reconfigured', + StateRenewed = 'renewed', +} + const createConnectorFinalStateMachine = function () { return createMachine({ id: 'connector', - initial: 'new', + initial: 'idle', states:{ idle: { on: { INITOPCUA: 'init', @@ -232,13 +257,60 @@ const createConnectorFinalStateMachine = function () { END: 'end' } }, - sessionActive: { on: {}}, - sessionClosed: { on: {}}, - sessionStart: { on: {}}, - sessionRestart: { on: {}}, - closed: { on: {}}, - locked: { on: {}}, - unlocked: { on: {}}, + sessionActive: { on: { + OPEN: 'opened', + SESSIONCLOSE: 'sessionClosed', + LOCK: 'locked', + END: 'end' + } + }, + sessionClosed: { on: { + IDLE: 'idle', + OPEN: 'opened', + CLOSE: 'closed', + SESSIONRESTART: 'sessionRestart', + LOCK: 'locked', + UNLOCK: 'unlocked', + END: 'end' + } + }, + sessionRestart: { on: { + IDLE: 'idle', + SESSIONCLOSE: 'sessionClosed', + OPEN: 'opened', + CLOSE: 'closed', + LOCK: 'locked', + END: 'end' + } + }, + closed: { on: { + OPEN: 'opened', + LOCK: 'locked', + UNLOCK: 'unlocked', + END: 'end', + IDLE: 'idle' + } + }, + locked: { on: { + SESSIONCLOSE: 'sessionClosed', + OPEN: 'opened', + CLOSE: 'closed', + LOCK: 'locked', + UNLOCK: 'unlocked', + SESSIONRESTART: 'sessionRestart', + RECONFIGURE: 'reconfigured', + STOP: 'stopped', + RENEW: 'renewed', + END: 'end' + } + }, + unlocked: { on: { + IDLE: 'idle', + OPEN: 'opened', + END: 'end', + LOCK: 'locked' + } + }, stopped: { on: {}}, end: { on: {}}, reconfigured: { on: {}}, @@ -251,6 +323,12 @@ const startConnectorMachineService = (toggleMachine: any) => { return interpret(toggleMachine).start() } +const subscribeConnectorFSMService = (service: TodoTypeAny, eventFn: (state: any) => void) => { + if(service === undefined || eventFn === undefined) throw new Error('Service or event handler missing') + + return service.subscribe(eventFn) +} + function setListenerToClient(node: TodoTypeAny) { if (!node.iiot.opcuaClient) { @@ -380,9 +458,10 @@ function checkEndpoint(endpoint: string, errorHandler: (err: Error) => void) { const coreConnector = { initConnectorNode, - createConnectorStatelyMachine, + //createConnectorStatelyMachine, createConnectorFinalStateMachine, startConnectorMachineService, + subscribeConnectorFSMService, setListenerToClient, logSessionInformation, checkEndpoint, diff --git a/src/opcua-iiot-connector.ts b/src/opcua-iiot-connector.ts index 8a280fd7..8f2fdfcd 100644 --- a/src/opcua-iiot-connector.ts +++ b/src/opcua-iiot-connector.ts @@ -30,7 +30,7 @@ import { StatusCodes, VariableTypeIds } from "node-opcua"; -import coreConnector, {ConnectorIIoT, logger, Stately} from "./core/opcua-iiot-core-connector"; +import coreConnector, {ConnectorIIoT, logger, Stately, fsmConnectorStates} from "./core/opcua-iiot-core-connector"; import {FindServerResults} from "node-opcua-client/source/tools/findservers"; import _, {isUndefined} from "underscore"; import {UserTokenType} from "node-opcua-service-endpoints"; @@ -71,8 +71,6 @@ export type OPCUAIIoTConnectorNode = nodered.Node connectionStopDelay: number maxBadSessionRequests: number securedCommunication?: boolean - stateMachine: TodoTypeAny - stateService: TodoTypeAny iiot?: ConnectorIIoT functions?: { [key: string]: Function @@ -152,9 +150,6 @@ module.exports = function (RED: nodered.NodeAPI) { this.connectionStopDelay = config.connectionStopDelay || CONNECTION_STOP_DELAY this.maxBadSessionRequests = parseInt(config.maxBadSessionRequests.toString()) || 10 - this.stateMachine = null - this.stateService = null - this.iiot = coreConnector.initConnectorNode() if (!this.iiot) throw Error('IIoT Initialization Failed') @@ -277,7 +272,8 @@ module.exports = function (RED: nodered.NodeAPI) { handleError(err) } else { internalDebugLog('Client Is Connected To ' + this.endpoint) - this.iiot.stateMachine.open() + //this.iiot.stateMachine.open() + this.iiot.stateService.send('OPEN') } } else { internalDebugLog('iiot not valid on connect resolve') @@ -290,7 +286,8 @@ module.exports = function (RED: nodered.NodeAPI) { opcuaDirectDisconnect(() => { if (isUndefined(this.iiot)) return; renewFiniteStateMachine() - this.iiot.stateMachine.idle().initopcua(); + //this.iiot.stateMachine.idle().initopcua(); + this.iiot.stateService.send('INITOPCUA') done() }) } else { @@ -377,15 +374,15 @@ module.exports = function (RED: nodered.NodeAPI) { } if (isInactiveOnOPCUA()) { - internalDebugLog('State Is Not Active While Start Session-> ' + this.iiot.stateMachine.getMachineState()) + internalDebugLog('State Is Not Active While Start Session-> ' + this.iiot.stateService.state.value) if (this.showErrors) { this.error(new Error('OPC UA Connector Is Not Active'), {payload: 'Create Session Error'}) } return } - if (this.iiot.stateMachine.getMachineState() !== 'OPEN') { - internalDebugLog('Session Request Not Allowed On State ' + this.iiot.stateMachine.getMachineState()) + if (this.iiot.stateService.state.value !== 'OPEN') { + internalDebugLog('Session Request Not Allowed On State ' + this.iiot.stateService.state.value) if (this.showErrors) { this.error(new Error('OPC UA Connector Is Not Open'), {payload: 'Create Session Error'}) } @@ -393,21 +390,23 @@ module.exports = function (RED: nodered.NodeAPI) { } if (!this.iiot.opcuaClient) { - internalDebugLog('OPC UA Client Connection Is Not Valid On State ' + this.iiot.stateMachine.getMachineState()) + internalDebugLog('OPC UA Client Connection Is Not Valid On State ' + this.iiot.stateService.state.value) if (this.showErrors) { this.error(new Error('OPC UA Client Connection Is Not Valid'), {payload: 'Create Session Error'}) } return } - this.iiot.stateMachine.sessionrequest() + //this.iiot.stateMachine.sessionrequest() + this.iiot.stateService.send('SESSIONREQUEST') const res = await this.iiot.opcuaClient.createSession(this.iiot.userIdentity) .then((session: ClientSession) => { if (isUndefined(this.iiot)) return session.requestedMaxReferencesPerNode = 100000 this.iiot.opcuaSession = session - this.iiot.stateMachine.sessionactive() + //this.iiot.stateMachine.sessionactive() + this.iiot.stateService.send('SESSIONACTIVATE') detailDebugLog('Session Created On ' + this.endpoint + ' For ' + callerInfo) coreConnector.logSessionInformation(this) @@ -417,7 +416,8 @@ module.exports = function (RED: nodered.NodeAPI) { }) }).catch((err: Error) => { if (isInitializedIIoTNode(this.iiot)) { - this.iiot.stateMachine.lock().stopopcua() + //this.iiot.stateMachine.lock().stopopcua() + this.iiot.stateService.send('STOP') handleError(err) } else { internalDebugLog(err.message) @@ -439,13 +439,14 @@ module.exports = function (RED: nodered.NodeAPI) { } if (this.iiot.sessionNodeRequests > this.maxBadSessionRequests) { - internalDebugLog('Reset Bad Session Request On State ' + this.iiot.stateMachine.getMachineState()) + internalDebugLog('Reset Bad Session Request On State ' + this.iiot.stateService.state.value) resetOPCUAConnection('ToManyBadSessionRequests') } } const isInactiveOnOPCUA = () => { - let state = this.iiot?.stateMachine?.getMachineState() + //let state = this.iiot?.stateMachine?.getMachineState() + let state = this.iiot?.stateService?.state.value return (state === 'STOPPED' || state === 'END' || state === 'RENEW' || state === 'RECONFIGURED') } @@ -455,7 +456,8 @@ module.exports = function (RED: nodered.NodeAPI) { return } - this.iiot.stateMachine.lock().renew() + //this.iiot.stateMachine.lock().renew() + this.iiot.stateService.send('RENEW') this.emit('reset_opcua_connection') closeSession(() => { renewConnection(() => { @@ -478,7 +480,7 @@ module.exports = function (RED: nodered.NodeAPI) { } if (this.iiot?.opcuaClient && this.iiot?.opcuaSession) { - detailDebugLog('Close Session And Remove Subscriptions From Session On State ' + this.iiot.stateMachine.getMachineState()) + detailDebugLog('Close Session And Remove Subscriptions From Session On State ' + this.iiot.stateService.state.value) try { this.iiot.opcuaSession.removeAllListeners() @@ -496,7 +498,7 @@ module.exports = function (RED: nodered.NodeAPI) { this.iiot.opcuaSession = undefined } } else { - internalDebugLog('Close Session Without Session On State ' + this.iiot.stateMachine.getMachineState()) + internalDebugLog('Close Session Without Session On State ' + this.iiot.stateService.state.value) done() } } @@ -522,8 +524,9 @@ module.exports = function (RED: nodered.NodeAPI) { coreConnector.logSessionInformation(this) - if (this.iiot?.stateMachine && this.iiot.stateMachine.getMachineState() !== 'SESSIONRESTART') { - this.iiot.stateMachine.lock().sessionclose() + if (this.iiot?.stateMachine && this.iiot.stateService.state.value !== 'SESSIONRESTART') { + //this.iiot.stateMachine.lock().sessionclose() + this.iiot.stateService.send('SESSIONCLOSE') } } @@ -533,7 +536,7 @@ module.exports = function (RED: nodered.NodeAPI) { return } - internalDebugLog('OPC UA Disconnect Connector On State ' + this.iiot.stateMachine.getMachineState()) + internalDebugLog('OPC UA Disconnect Connector On State ' + this.iiot.stateService.state.value) if (this.iiot?.opcuaClient) { internalDebugLog('Close Node Disconnect Connector From ' + this.endpoint) @@ -573,14 +576,14 @@ module.exports = function (RED: nodered.NodeAPI) { resetIiotNode(this) done() } else { - detailDebugLog('OPC UA Client Is Active On Close Node With State ' + this.iiot.stateMachine.getMachineState()) - if (this.iiot.stateMachine.getMachineState() === 'SESSIONACTIVE') { + detailDebugLog('OPC UA Client Is Active On Close Node With State ' + this.iiot.stateService.state.value) + if (this.iiot.stateService.state.value === 'SESSIONACTIVE') { closeConnector(() => { resetIiotNode(this) done() }) } else { - internalDebugLog(this.iiot.stateMachine.getMachineState() + ' -> !!! CHECK CONNECTOR STATE ON CLOSE !!!') + internalDebugLog(this.iiot.stateService.state.value + ' -> !!! CHECK CONNECTOR STATE ON CLOSE !!!') resetIiotNode(this) done() } @@ -621,14 +624,15 @@ module.exports = function (RED: nodered.NodeAPI) { return } - detailDebugLog('OPC UA Disconnect From Connector ' + this.iiot.stateMachine.getMachineState()) + detailDebugLog('OPC UA Disconnect From Connector ' + this.iiot.stateService.state.value) disconnectNodeOPCUA(() => { if (isUndefined(this.iiot)) { done() return } - this.iiot.stateMachine.lock().close() - let fsmState = this.iiot.stateMachine.getMachineState() + //this.iiot.stateMachine.lock().close() + this.iiot.stateService.send('CLOSE') + let fsmState = this.iiot.stateService.state.value detailDebugLog('Disconnected On State ' + fsmState) if (!isInactiveOnOPCUA() && fsmState !== 'CLOSED') { done() @@ -641,7 +645,7 @@ module.exports = function (RED: nodered.NodeAPI) { if (isUndefined(this.iiot)) { return } - detailDebugLog('Close Connector ' + this.iiot.stateMachine.getMachineState()) + detailDebugLog('Close Connector ' + this.iiot.stateService.value) if (isInactiveOnOPCUA()) { detailDebugLog('OPC UA Client Is Not Active On Close Connector') @@ -661,8 +665,9 @@ module.exports = function (RED: nodered.NodeAPI) { if (isUndefined(this.iiot)) { return } - internalDebugLog('Renew With Flex Connector Request On State ' + this.iiot.stateMachine.getMachineState()) - this.iiot.stateMachine.lock().reconfigure() + internalDebugLog('Renew With Flex Connector Request On State ' + this.iiot.stateService.state.value) + //this.iiot.stateMachine.lock().reconfigure() + this.iiot.stateService.send('RECONFIGURE') updateSettings(config) initCertificatesAndKeys() renewConnection(done) @@ -721,8 +726,131 @@ module.exports = function (RED: nodered.NodeAPI) { /* ######### FSM ######### */ - this.stateMachine = coreConnector.createStateMachineService() - this.stateService = coreConnector.startMachineService(this.stateMachine) + const connectorStateEventFunction = async (state: any) =>{ + if(!state.changed) return; + if(this.iiot === undefined) return; + + switch (state.value) { + case fsmConnectorStates.StateIdle: + detailDebugLog('Connector IDLE Event FSM') + resetOPCUAObjects() + break + case fsmConnectorStates.StateInit: + detailDebugLog('Connector Init OPC UA Event FSM') + + if (!this.iiot) { + return + } + + resetOPCUAObjects() + resetAllTimer() + this.emit('connector_init', this) + initCertificatesAndKeys() + + if (clientStartTimeout) { + clearTimeout(clientStartTimeout) + clientStartTimeout = null + } + detailDebugLog('connecting OPC UA with delay of msec: ' + this.connectionStartDelay) + clientStartTimeout = setTimeout(() => { + if (isInitializedIIoTNode(this.iiot)) { + try { + connectOPCUAEndpoint() + } catch (err: any) { + handleError(err) + resetOPCUAObjects() + //this.iiot.stateMachine.lock().stopopcua() + this.iiot.stateService.send('STOP') + } + } + }, this.connectionStartDelay) + break + case fsmConnectorStates.StateOpened: + detailDebugLog('Connector Open Event FSM') + if (isInitializedIIoTNode(this.iiot)) { + this.emit('connection_started', this.iiot.opcuaClient, statusHandler) + internalDebugLog('Client Connected To ' + this.endpoint) + detailDebugLog('Client Options ' + JSON.stringify(this.iiot.opcuaClientOptions)) + await startSession('Open Event') + } + break + case fsmConnectorStates.StateSessionRequested: + detailDebugLog('Connector Session Request Event FSM') + break + case fsmConnectorStates.StateSessionActive: + detailDebugLog('Connector Session Active Event FSM') + if (!isUndefined(this.iiot)) + this.iiot.sessionNodeRequests = 0 + this.emit('session_started', this.iiot?.opcuaSession) + break + case fsmConnectorStates.StateSessionRestart: + detailDebugLog('Connector Session Restart Event FSM') + this.emit('session_restart') + break + case fsmConnectorStates.StateSessionClosed: + detailDebugLog('Connector Session Close Event FSM') + this.emit('session_closed') + if (isInitializedIIoTNode(this.iiot)) { + this.iiot.opcuaSession = undefined + } + break + case fsmConnectorStates.StateClosed: + detailDebugLog('Connector Client Close Event FSM') + this.emit('connection_closed') + if (isInitializedIIoTNode(this.iiot)) { + if (Object.keys(this.iiot.opcuaClient || {}).length > 1) { + this.iiot.opcuaClient?.disconnect((err?: Error) => { + if (err) { + handleError(err) + } + }) + this.iiot.opcuaClient = undefined + } + } + break + case fsmConnectorStates.StateLocked: + detailDebugLog('Connector Lock Event FSM') + break + case fsmConnectorStates.StateUnlocked: + detailDebugLog('Connector Unlock Event FSM') + break + case fsmConnectorStates.StateStopped: + detailDebugLog('Connector Stopped Event FSM') + this.emit('connection_stopped') + if (isInitializedIIoTNode(this.iiot)) { + resetAllTimer() + } + break + case fsmConnectorStates.StateEnd: + detailDebugLog('Connector End Event FSM') + this.emit('connection_end') + if (isInitializedIIoTNode(this.iiot)) { + resetAllTimer() + } + break + case fsmConnectorStates.StateReconfigured: + detailDebugLog('Connector Reconfigure Event FSM') + this.emit('connection_reconfigure') + if (isInitializedIIoTNode(this.iiot)) { + resetAllTimer() + } + break + case fsmConnectorStates.StateRenewed: + detailDebugLog('Connector Renew Event FSM') + this.emit('connection_renew') + if (isInitializedIIoTNode(this.iiot)) { + resetAllTimer() + } + break + default: + throw new Error('Connector FSM is not in a valid state') + } + + } + + this.iiot.stateMachine = coreConnector.createConnectorFinalStateMachine() + this.iiot.stateService = coreConnector.startConnectorMachineService(this.iiot.stateMachine) + this.iiot.stateSubscription = coreConnector.subscribeConnectorFSMService(this.iiot.stateService, connectorStateEventFunction) const subscribeFSMEvents = (fsm: Stately.stateMachine) => { /* ######### FSM EVENTS ######### */ @@ -878,8 +1006,17 @@ module.exports = function (RED: nodered.NodeAPI) { if (isUndefined(this.iiot)) return this.iiot.stateMachine = null + this.iiot.stateService = null + this.iiot.stateSubscription = null + + /* Stately this.iiot.stateMachine = coreConnector.createConnectorStatelyMachine() subscribeFSMEvents(this.iiot.stateMachine) + */ + // @xstate/fsm + this.iiot.stateMachine = coreConnector.createConnectorFinalStateMachine() + this.iiot.stateService = coreConnector.startConnectorMachineService(this.iiot.stateMachine) + this.iiot.stateSubscription = coreConnector.subscribeConnectorFSMService(this.iiot.stateService, connectorStateEventFunction) } const registerForOPCUA = (opcuaNode: nodered.Node, onAlias: (event: string, ...args: any) => void) => { @@ -898,7 +1035,7 @@ module.exports = function (RED: nodered.NodeAPI) { this.iiot.registeredNodeList[opcuaNode.id] = opcuaNode onAlias('opcua_client_not_ready', () => { - if (isInitializedIIoTNode(this.iiot) && this.iiot.stateMachine.getMachineState() !== 'END') { + if (isInitializedIIoTNode(this.iiot) && this.iiot.stateService.state.value !== 'END') { resetBadSession() } }) @@ -906,7 +1043,7 @@ module.exports = function (RED: nodered.NodeAPI) { if (Object.keys(this.iiot.registeredNodeList).length === 1) { internalDebugLog('Start Connector OPC UA Connection') renewFiniteStateMachine() - this.iiot.stateMachine.idle().initopcua(); + this.iiot.stateService.send('INITOPCUA'); } else { } } @@ -928,13 +1065,14 @@ module.exports = function (RED: nodered.NodeAPI) { internalDebugLog('Deregister In Connector NodeId: ' + opcuaNode.id) delete this.iiot.registeredNodeList[opcuaNode.id] - if (this.iiot.stateMachine.getMachineState() === 'STOPPED' || this.iiot.stateMachine.getMachineState() === 'END') { + if (this.iiot.stateService.state.value === 'STOPPED' || this.iiot.stateService.state.value === 'END') { done() return } if (Object.keys(this.iiot.registeredNodeList).length === 0) { - this.iiot.stateMachine.lock().stopopcua() + //this.iiot.stateMachine.lock().stopopcua() + this.iiot.stateService.send('STOP') if (this.iiot.opcuaClient) { detailDebugLog('OPC UA Direct Disconnect On Unregister Of All Nodes') try { diff --git a/test/units/opcua-iiot-connector.test.js b/test/units/opcua-iiot-connector.test.js index 5e740e6e..379b3c43 100644 --- a/test/units/opcua-iiot-connector.test.js +++ b/test/units/opcua-iiot-connector.test.js @@ -91,7 +91,8 @@ describe('OPC UA Connector node Unit Testing', function () { helper.load(nodesToLoadConnector, testFlows.testUnitConnectorFlow, () => { let n4 = helper.getNode('n4') if (n4) { - n4.iiot.stateMachine.lock().end() + //n4.iiot.stateMachine.lock().end() + n4.iiot.stateService.send('END') n4.functions.startSession() done() } @@ -102,7 +103,8 @@ describe('OPC UA Connector node Unit Testing', function () { helper.load(nodesToLoadConnector, testFlows.testUnitConnectorFlow, () => { let n4 = helper.getNode('n4') if (n4) { - n4.iiot.stateMachine.lock() + //n4.iiot.stateMachine.lock() + n4.iiot.stateService.send('LOCK') n4.functions.startSession() done() } @@ -113,7 +115,8 @@ describe('OPC UA Connector node Unit Testing', function () { helper.load(nodesToLoadConnector, testFlows.testUnitConnectorFlow, () => { let n4 = helper.getNode('n4') if (n4) { - n4.iiot.stateMachine.lock().open() + //n4.iiot.stateMachine.lock().open() + n4.iiot.stateService.send('OPEN') n4.functions.startSession() done() } @@ -121,22 +124,29 @@ describe('OPC UA Connector node Unit Testing', function () { }) // TODO whole new functions + + // Todo: Cannot change state to open in one jump, if the transition doesnt allow it it('should be loaded and do restart session on state is not RECONFIGURED', function (done) { helper.load(nodesToLoadConnector, testFlows.testUnitConnectorFlow, () => { let n4 = helper.getNode('n4') if (n4) { - n4.iiot.stateMachine.lock().open() - n4.functions.renewConnection(done) + //n4.iiot.stateMachine.lock().open() + n4.iiot.stateMachine.transition('locked', 'OPEN') + expect(n4.iiot.stateService.state.value).toBe('opened') + setTimeout(n4.functions.renewConnection(done), 1000) } }) }) + // Todo: Cannot change state to reconfigured in one jump, if the transition doesnt allow it it('should be loaded and do restart connection on state is RECONFIGURED', function (done) { helper.load(nodesToLoadConnector, testFlows.testUnitConnectorFlow, () => { let n4 = helper.getNode('n4') if (n4) { - n4.iiot.stateMachine.lock().reconfigure() - n4.functions.renewConnection(done) + //n4.iiot.stateMachine.lock().reconfigure() + n4.iiot.stateMachine.transition('locked', 'RECONFIGURE') + expect(n4.iiot.stateService.state.value).toBe('reconfigured') + setTimeout(n4.functions.renewConnection(done), 500) } }) }) @@ -145,7 +155,9 @@ describe('OPC UA Connector node Unit Testing', function () { helper.load(nodesToLoadConnector, testFlows.testUnitConnectorFlow, () => { let n4 = helper.getNode('n4') if (n4) { - n4.iiot.stateMachine.lock() + //n4.iiot.stateMachine.lock() + n4.iiot.stateService.send('LOCK') + expect(n4.iiot.stateService.state.value).toBe('locked') n4.iiot.sessionNodeRequests = 10 n4.functions.resetBadSession() setTimeout(done, 1000) @@ -157,7 +169,8 @@ describe('OPC UA Connector node Unit Testing', function () { helper.load(nodesToLoadConnector, testFlows.testUnitConnectorFlow, () => { let n4 = helper.getNode('n4') if (n4) { - n4.iiot.stateMachine.lock().reconfigure() + //n4.iiot.stateMachine.lock().reconfigure() + n4.iiot.stateService.send('RECONFIGURE') n4.iiot.sessionNodeRequests = 10 n4.functions.resetBadSession() setTimeout(done, 1000)