def test_wakeup(config, mongo): ''' the first stage in a node's lifecycle ''' # setup stuff handler = Handler(config) pointer = make_pointer('simple.2018-02-19.xml', 'start_node') execution = pointer.proxy.execution.get() juan = User(identifier='juan').save() manager = User( identifier='juan_manager', email='*****@*****.**' ).save() mongo[config["EXECUTION_COLLECTION"]].insert_one({ '_type': 'execution', 'id': execution.id, 'state': Xml.load(config, execution.process_name).get_state(), 'actors': {'start_node': 'juan'}, }) channel = MagicMock() # will wakeup the second node handler.call({ 'command': 'step', 'pointer_id': pointer.id, 'user_identifier': juan.identifier, 'input': [], }, channel) # test manager is notified channel.basic_publish.assert_called_once() channel.exchange_declare.assert_called_once() args = channel.basic_publish.call_args[1] assert args['exchange'] == config['RABBIT_NOTIFY_EXCHANGE'] assert args['routing_key'] == 'email' assert json.loads(args['body']) == { 'recipient': '*****@*****.**', 'subject': '[procesos] Tarea asignada', 'template': 'assigned-task.html', 'data': { 'pointer': Pointer.get_all()[0].to_json( include=['*', 'execution'] ), 'cacahuate_url': config['GUI_URL'], }, } # pointer collection updated reg = next(mongo[config["POINTER_COLLECTION"]].find()) assert_near_date(reg['started_at']) assert reg['finished_at'] is None assert reg['execution']['id'] == execution.id assert reg['node'] == { 'id': 'mid_node', 'type': 'action', 'description': 'añadir información', 'name': 'Segundo paso', } assert reg['actors'] == { '_type': ':map', 'items': {}, } assert reg['notified_users'] == [manager.to_json()] assert reg['state'] == 'ongoing' # execution collection updated reg = next(mongo[config["EXECUTION_COLLECTION"]].find()) assert reg['state']['items']['mid_node']['state'] == 'ongoing' # tasks where asigned assert manager.proxy.tasks.count() == 1 task = manager.proxy.tasks.get()[0] assert isinstance(task, Pointer) assert task.node_id == 'mid_node' assert task.proxy.execution.get().id == execution.id
def patch(self, message): execution = Execution.get_or_exception(message['execution_id']) if execution.status != 'ongoing': raise ModelNotFoundError( 'Specified execution never existed, and never will', ) xml = Xml.load(self.config, execution.process_name, direct=True) # set nodes with pointers as unfilled, delete pointers updates = {} user = User.get_by( 'identifier', message.get('user_identifier'), ) if user is None: if message.get('user_identifier') == '__system__': user = User(identifier='__system__', fullname='System').save() else: raise InconsistentState('sent identifier of unexisten user') for pointer in execution.pointers.q().filter(status='ongoing'): updates['state.items.{node}.state'.format( node=pointer.node_id, )] = 'unfilled' pointer.status = 'cancelled' pointer.finished_at = datetime.now() pointer.save() self.pointer_collection().update_one({ 'id': pointer.id, }, { '$set': { 'state': 'cancelled', 'finished_at': pointer.finished_at, 'patch': { 'comment': message['comment'], 'inputs': message['inputs'], 'actor': user.to_json(include=[ '_type', 'fullname', 'identifier', ]), }, }, }) self.execution_collection().update_one({ 'id': execution.id, }, { '$set': updates, }) # retrieve updated state state = next(self.execution_collection().find({'id': execution.id})) state_updates, array_filters = cascade_invalidate( xml, state, message['inputs'], message['comment']) # update state self.execution_collection().update_one( {'id': state['id']}, {'$set': state_updates}, array_filters=array_filters, ) # retrieve updated state state = next(self.execution_collection().find({'id': execution.id})) first_invalid_node = track_next_node(xml, state, self.get_mongo(), self.config) # wakeup and start execution from the found invalid node self.wakeup_and_notify(first_invalid_node, execution, state)