def test_key_mapping_decision(self): """ :return: """ dec = decision.KeyMappingDecisionMaker({"key": "value"}, "strategy") message1 = framework.OperationMessage("SENSED_MESSAGE", "id1", {"strategy": "key"}) message2 = framework.OperationMessage("SENSED_MESSAGE", "id1", {}) self.assertIsInstance(dec.decision_logic(message1), framework.OperationMessage) self.assertRaises(exception.ETypeMismatch, dec.decision_logic, message2)
def decision_logic(self, message): """ :param message: :return: """ decided_message = framework.OperationMessage("DECIDED_MESSAGE", message.operation_id, message.params) return decided_message
def test_callback_executor(self, mock_send): """ :return: """ mock_send.return_value = None exe = executor.CallbackExecutor(DemoExecFuncSet()) message = framework.OperationMessage("DECIDED_MESSAGE", "id1", {".inner_executor_key": "demo"}) ret = exe.execute_message(message) self.assertDictEqual(ret, {"code": 0})
def decision_logic(self, message): """ 状态机决策逻辑,该函数直接根据Message生成决策完成的消息对象 :param Message message: 感知完成的消息对象 :return: 决策完成的消息对象 :rtype: Message """ decided_message = framework.OperationMessage( "DECIDED_MESSAGE", message.operation_id, message.params) return decided_message
def test_multi_process_executor(self, mock_send): """ :return: """ mock_send.return_value = None exe = executor.MultiProcessExecutor() mes1 = framework.IDLEMessage() mes2 = framework.OperationMessage("DECIDED_MESSAGE", "id1", {}) exe.on_execute_message(mes1) exe.on_execute_message(mes2) exe.on_execute_message(mes1) mes3 = framework.OperationMessage("SENSED_MESSAGE", "id1", {}) self.assertRaises(exception.EUnknownEvent, exe.on_execute_message, mes3) exe._concerned_message_list = [ "IDLE_MESSAGE", "DECIDED_MESSAGE", "SENSED_MESSAGE" ] exe.on_execute_message(mes3) self.assertRaises(exception.ENotImplement, exe.execute_message, mes3)
def test_messagepumb(self): """ :return: """ listener1 = framework.Listener() listener1.register(["IDLE_MESSAGE", "SENSED_MESSAGE"]) listener2 = framework.Listener() pumb = framework.MessagePump() pumb.add_listener(listener1) self.assertRaises(ValueError, pumb.del_listener, listener2) concern = pumb.list_listener_concern(listener1) self.assertItemsEqual(["IDLE_MESSAGE", "SENSED_MESSAGE"], concern) message_operation = framework.OperationMessage( "SENSED_MESSAGE", "id2", {}) message_operation2 = framework.OperationMessage( "DECIDED_MESSAGE", "id3", {}) thread = threading.Thread( target=self.__run_thread_assistant, args=(pumb, )) thread.daemon = True thread.start() time.sleep(1) pumb.send(message_operation) pumb.send(message_operation2) time.sleep(3) pumb._stop_tag = True time.sleep(2) sen = framework.BaseSensor() dec = framework.BaseDecisionMaker() exe = framework.BaseExecutor() assistant_sensor = "demo" pumb._listener_list = [sen, dec, exe] pumb.validate_listeners() pumb.add_listener(dec) self.assertRaises(exception.ETypeMismatch, pumb.validate_listeners) pumb._listener_list = [sen,dec, exe, assistant_sensor] self.assertRaises(exception.ETypeMismatch, pumb.validate_listeners)
def test_decision_maker(self, mock_dec, mock_send): """ :return: """ mock_send.return_value = None mock_dec.return_value = framework.IDLEMessage() dec = decision.DecisionMaker() message = framework.IDLEMessage() mes_sen = framework.OperationMessage("SENSED_MESSAGE", "ID1", {}) dec.on_decision_message(mes_sen) mes_complete = framework.OperationMessage("COMPLETE_MESSAGE", "ID1", {}) dec.on_decision_message(mes_complete) dec._concerned_message_list = [ "SENSED_MESSAGE", "COMPLETE_MESSAGE", "IDLE_MESSAGE" ] dec.on_decision_message(message) mes_unconcerned = framework.OperationMessage("UNKNOWN_MESSAGE", "ID1", {}) self.assertRaises(exception.EUnknownEvent, dec.on_decision_message, mes_unconcerned)
def test_message(self): """ :return: """ mes = framework.Message("IDLE_MESSAGE") self.assertEqual("IDLE_MESSAGE", mes.name) mes = framework.IDLEMessage() self.assertEqual("IDLE_MESSAGE", mes.name) mes = framework.OperationMessage("SENSED_MESSAGE", "id1", {}) self.assertEqual("SENSED_MESSAGE", mes.name) self.assertEqual("id1", mes.operation_id) self.assertDictEqual({}, mes.params) mes.params = {"a":"b"} self.assertDictEqual({"a":"b"}, mes.params)
def message_handler(self, message): """ 消息处理逻辑,该函数调用具体的消息执行函数,并获取结果放入结果队列中 .. Note:: 由于操作异步执行,因此各子进程执行结果统一放入多进程安全的结果队列, 由主进程统一进程结果的后续处理 :param Message message: 消息对象 :return: 无返回 :rtype: None """ try: ret = self.execute_message(message) except Exception as e: ret = "err:{}".format(e) message = framework.OperationMessage("COMPLETE_MESSAGE", message.operation_id, ret) self._result_queue.put(message) return
def decision_logic(self, message): """ 具体决策逻辑 :param Message message: 消息对象 :return: 决策完成的消息 :rtype: Message :raises ETypeMismatch: 事件参数不匹配异常 """ log.info("begin decision logic, message:{}".format(message.name)) operation_id = message.operation_id params = message.params if self._from_key in params \ and params[self._from_key] in self._mapping: params_cp = copy.deepcopy(params) params_cp[self._to_key] = self._mapping[params_cp[self._from_key]] decided_message = framework.OperationMessage( "DECIDED_MESSAGE", operation_id, params_cp) return decided_message else: raise exception.ETypeMismatch( "{} not in params or params[{}] not in " "mapping".format(self._from_key, self._from_key))
def graph_start(self, state_machine): """ 状态机启动执行。状态机启动后,会根据每个节点执行的返回值,执行下一个节点,直到返回 结束或执行异常。在每个节点执行完成后,会向结果队列中发送消息,由主进程进行处理 :param StateMachine state_machine: 状态机实例 :return: 无返回 :rtype: None """ session = state_machine.session while True: try: control = copy.deepcopy(self._control_message[session.id]) except KeyError: control = None if control is not None: # 状态机第一次处理控制消息或控制消息为最新还没被处理 if session.last_control_id is None \ or session.last_control_id != control['control_id']: control_message = copy.deepcopy(control['message']) session.last_control_id = control['control_id'] else: control_message = None else: control_message = None session.control_message = control_message #第一次运行的状态机,记录第一个节点信息 if state_machine.status == state_machine.Status.INITED: todo_params = state_machine.dump() todo_node = todo_params["current_node"] todo_params = { "session": session, "finished_node": None, "current_node": todo_node, "timestamp": int(time.time()) } todo_notice = framework.OperationMessage( "STATE_COMPLETE_MESSAGE", str(session.id), todo_params) self._result_queue.put(todo_notice) state_machine.status = state_machine.Status.RUNNING if state_machine.status == state_machine.Status.RUNNING: try: log.info("state machine run state:{}".format(session.id)) todo_params = state_machine.dump() todo_node = todo_params["current_node"] state_machine.run_next() finished_params = state_machine.dump() session.status = finished_params["status"] #状态机Session的current_node为节点,而不再是节点的名称 session.current_node = state_machine.get_node( finished_params["current_node"]) session.nodes_process = copy.copy( finished_params["nodes_process"]) session.nodes_process[session.current_node] = True current_node = session.current_node if \ session.current_node.name != "ARK_NODE_END" else None params = { "session": session, "finished_node": todo_node, "current_node": current_node, "timestamp": int(time.time()) } notice = framework.OperationMessage( "STATE_COMPLETE_MESSAGE", str(session.id), params) if todo_node != current_node or session.reset_flush( ): #节点变更或业务方指定持久化Session self._result_queue.put(notice) except Exception as e: log.warning("graph run exception:{}".format(e)) log.warning("err:{}".format(traceback.format_exc())) state_machine.status = state_machine.Status.FAILED break else: break del self._control_message[session.id] log.info("state machine run finished, operationId:{}".format( session.id))
def graph_start(self, state_machine): """ 状态机启动执行。状态机启动后,会根据每个节点执行的返回值,执行下一个节点,直到返回 结束或执行异常。在每个节点执行完成后,会向结果队列中发送消息,由主进程进行处理 :param StateMachine state_machine: 状态机实例 :return: 无返回 :rtype: None """ session = state_machine.session while True: try: control_message = copy.deepcopy( self._control_message[session.id]) except KeyError: control_message = None session.control_message = control_message self._control_message[session.id] = None #第一次运行的状态机,记录第一个节点信息 if state_machine.status == state_machine.Status.INITED: todo_params = state_machine.dump() todo_node = todo_params["current_node"] todo_params = { "session": session, "finished_node": None, "current_node": todo_node, "timestamp": int(time.time()) } todo_notice = framework.OperationMessage( "STATE_COMPLETE_MESSAGE", str(session.id), todo_params) self._result_queue.put(todo_notice) state_machine.status = state_machine.Status.RUNNING if state_machine.status == state_machine.Status.RUNNING: try: log.info("state machine run state:{}".format(session.id)) todo_params = state_machine.dump() todo_node = todo_params["current_node"] state_machine.run_next() finished_params = state_machine.dump() session.status = finished_params["status"] session.current_node = finished_params["current_node"] session.nodes_process = copy.copy( finished_params["nodes_process"]) session.nodes_process[session.current_node] = True current_node = session.current_node if \ session.current_node != "ARK_NODE_END" else None params = { "session": session, "finished_node": todo_node, "current_node": current_node, "timestamp": int(time.time()) } notice = framework.OperationMessage( "STATE_COMPLETE_MESSAGE", str(session.id), params) self._result_queue.put(notice) except Exception as e: log.warning("graph run exception:{}".format(e)) log.warning("err:{}".format(traceback.format_exc())) state_machine.status = state_machine.Status.FAILED break else: break del self._control_message[session.id] log.info("state machine run finished, operationId:{}".format( session.id)) message = framework.OperationMessage("COMPLETE_MESSAGE", str(session.id), session.__dict__) self._result_queue.put(message)