def test_load_specific_version(config): ''' one should be able to request a specific version of a process, thus overriding the process described by the previous test ''' xml = Xml.load(config, 'oldest.2018-02-14') assert xml.filename == 'oldest.2018-02-14.xml' assert xml.public is False
def test_get_state(config): xml = Xml.load(config, 'milestones') assert xml.get_state() == { '_type': ':sorted_map', 'items': { 'start': { '_type': 'node', 'actors': {'_type': ':map', 'items': {}}, 'comment': '', 'id': 'start', 'state': 'unfilled', 'type': 'action', 'milestone': False, 'name': '', 'description': '', }, 'end': { '_type': 'node', 'actors': {'_type': ':map', 'items': {}}, 'comment': '', 'id': 'end', 'state': 'unfilled', 'type': 'validation', 'milestone': True, 'name': '', 'description': '', }, }, 'item_order': ['start', 'end'], }
def start_process(): validate_json(request.json, ['process_name']) try: xml = Xml.load(app.config, request.json['process_name']) except ProcessNotFound: raise NotFound([{ 'detail': '{} process does not exist'.format(request.json['process_name']), 'where': 'request.body.process_name', }]) except MalformedProcess as e: raise UnprocessableEntity([{ 'detail': str(e), 'where': 'request.body.process_name', }]) xmliter = iter(xml) node = make_node(next(xmliter), xmliter) # Check for authorization validate_auth(node, g.user) # check if there are any forms present input = node.validate_input(request.json) # get rabbit channel for process queue channel = get_channel() execution = xml.start(node, input, mongo.db, channel, g.user.identifier) return { 'data': execution.to_json(), }, 201
def find_process(name): def add_form(xml): json_xml = xml.to_json() forms = [] xmliter = iter(xml) first_node = next(xmliter) xmliter.parser.expandNode(first_node) for form in first_node.getElementsByTagName('form'): forms.append(form_to_dict(form)) json_xml['form_array'] = forms return json_xml version = request.args.get('version', '') if version: version = ".{}".format(version) process_name = "{}{}".format(name, version) try: xml = Xml.load(app.config, process_name) except ProcessNotFound: raise NotFound([{ 'detail': '{} process does not exist'.format(process_name), 'where': 'request.body.process_name', }]) return jsonify({ 'data': add_form(xml), })
def step(self, message: dict): ''' Handles deleting a pointer from the current node and creating a new one on the next ''' pointer, user, input = self.recover_step(message) execution = pointer.execution.get() xml = Xml.load(self.config, execution.process_name, direct=True) xmliter = iter(xml) node = make_node( xmliter.find(lambda e: e.getAttribute('id') == pointer.node_id), xmliter) # node's lifetime ends here self.teardown(node, pointer, user, input) execution.reload() # compute the next node in the sequence try: next_node, state = self.next(xml, node, execution) except EndOfProcess: # finish the execution return self.finish_execution(execution) self.wakeup_and_notify(next_node, execution, state)
def test_skip_else(config): xmliter = iter(Xml.load(config, 'else')) xmliter.find(lambda x: x.getAttribute('id') == 'action01') with pytest.raises(StopIteration): xmliter.next_skipping_elifelse()
def test_resolve_params(config): xml = Xml.load(config, 'exit_request') xmliter = iter(xml) next(xmliter) node = make_node(next(xmliter), xmliter) state = { 'values': [ { 'ref': 'exit_form', 'forms': [{ 'fields': [{ 'name': 'reason', 'value': 'nones', 'state': 'valid', }], }], }, ], 'actors': { 'requester': 'juan', }, } assert node.resolve_params(state, config) == { "identifier": 'juan', "relation": 'manager', "reason": 'nones', }
def test_load_last_matching_process(config): ''' a process is specified by its common name, but many versions may exist. when a process is requested for start we must use the last version of it ''' xml = Xml.load(config, 'oldest') assert xml.filename == 'oldest.2018-02-17.xml' assert xml.public is False
def test_get_actors(config): xml = Xml.load(config, 'noparam') xmliter = iter(xml) next(xmliter) node = make_node(next(xmliter), xmliter) found_users = node.get_actors(config, {}) assert len(found_users) == 1 assert found_users[0].identifier == 'foo'
def patch(self, message, channel): execution = Execution.get_or_exception(message['execution_id']) xml = Xml.load(self.config, execution.process_name, direct=True) mongo = self.get_mongo() execution_collection = mongo[self.config['EXECUTION_COLLECTION']] pointer_collection = mongo[self.config['POINTER_COLLECTION']] # set nodes with pointers as unfilled, delete pointers updates = {} for pointer in execution.proxy.pointers.q(): updates['state.items.{node}.state'.format( node=pointer.node_id, )] = 'unfilled' pointer.delete() pointer_collection.update_one({ 'id': pointer.id, }, { '$set': { 'state': 'cancelled', 'finished_at': datetime.now(), 'patch': { 'comment': message['comment'], 'inputs': message['inputs'], }, }, }) execution_collection.update_one({ 'id': execution.id, }, { '$set': updates, }) # retrieve updated state state = next(execution_collection.find({'id': execution.id})) state_updates = cascade_invalidate(xml, state, message['inputs'], message['comment']) # update state collection = mongo[self.config['EXECUTION_COLLECTION']] collection.update_one({ 'id': state['id'], }, { '$set': state_updates, }) # retrieve updated state state = next(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, channel, state)
def test_make_iterator(config): ''' test that the iter function actually returns an interator over the nodes and edges of the process ''' xml = Xml.load(config, 'simple') expected_nodes = [ 'action', 'action', ] for given, expected in zip(xml, expected_nodes): assert given.tagName == expected
def test_request_node(config, mocker): class ResponseMock: status_code = 200 text = 'request response' mock = MagicMock(return_value=ResponseMock()) mocker.patch('requests.request', new=mock) xml = Xml.load(config, 'request.2018-05-18') xmliter = iter(xml) next(xmliter) request = next(xmliter) node = make_node(request, xmliter) response = node.make_request({ 'request': { 'data': '123456', }, }) requests.request.assert_called_once() args = requests.request.call_args method, url = args[0] data = args[1]['data'] headers = args[1]['headers'] assert method == 'GET' assert url == 'http://localhost/mirror?data=123456' assert headers == { 'content-type': 'application/json', 'x-url-data': '123456', } assert data == '{"data":"123456"}' assert response == [{ 'id': 'request_node', 'items': [{ 'name': 'status_code', 'value': 200, 'type': 'int', 'label': 'Status Code', 'value_caption': '200', }, { 'name': 'raw_response', 'value': 'request response', 'type': 'text', 'label': 'Response', 'value_caption': 'request response', }], }]
def work(self, config, state, channel, mongo): xml = Xml.load(config, self.procname) xmliter = iter(xml) node = make_node(next(xmliter), xmliter) data = { 'form_array': [f.render(state['values']) for f in self.forms], } collected_input = node.validate_input(data) xml.start(node, collected_input, mongo, channel, '__system__') return []
def test_get_element_by(config): xml = Xml.load(config, 'exit_request') dom = xml.get_dom() node = get_element_by(dom, 'action', 'id', 'requester') assert node is not None assert node.getAttribute('id') == 'requester' form = get_element_by(node, 'form', 'id', 'exit_form') assert form is not None assert form.getAttribute('id') == 'exit_form' input = get_element_by(form, 'input', 'name', 'reason') assert input is not None assert input.getAttribute('name') == 'reason'
def find_process(name): version = request.args.get('version', '') if version: version = ".{}".format(version) process_name = "{}{}".format(name, version) try: xml = Xml.load(app.config, process_name) except ProcessNotFound: raise NotFound([{ 'detail': '{} process does not exist'.format(process_name), 'where': 'request.body.process_name', }]) return jsonify({'data': xml.to_json()})
def xml_process(name): version = request.args.get('version', '') if version: version = ".{}".format(version) process_name = "{}{}".format(name, version) try: xml = Xml.load(app.config, process_name) except ProcessNotFound: raise NotFound([{ 'detail': '{} process does not exist'.format(process_name), 'where': 'request.body.process_name', }]) ruta = os.path.join(app.config['XML_PATH'], xml.filename) return open(ruta).read(), {'Content-Type': 'text/xml; charset=utf-8'}
def test_resistance_node_not_found(config, mongo): handler = Handler(config) ptr = make_pointer('wrong.2018-04-11.xml', 'start_node') exc = ptr.proxy.execution.get() user = make_user('juan', 'Juan') mongo[config["EXECUTION_COLLECTION"]].insert_one({ '_type': 'execution', 'id': exc.id, 'state': Xml.load(config, exc.process_name).get_state(), }) # this is what we test handler(MagicMock(), MagicMock(), None, json.dumps({ 'command': 'step', 'pointer_id': ptr.id, 'user_identifier': user.identifier, 'input': {}, }))
def test_find(config): xmliter = iter(Xml.load(config, 'simple')) start = next(xmliter) assert start.tagName == 'action' assert start.getAttribute('id') == 'start_node' echo = xmliter.find( lambda e: e.getAttribute('id') == 'mid_node' ) assert echo.tagName == 'action' assert echo.getAttribute('id') == 'mid_node' end = xmliter.find( lambda e: e.getAttribute('id') == 'final_node' ) assert end.tagName == 'action' assert end.getAttribute('id') == 'final_node'
def call(self, message: dict, channel): pointer, user, input = self.recover_step(message) execution = pointer.proxy.execution.get() xml = Xml.load(self.config, execution.process_name, direct=True) xmliter = iter(xml) node = make_node(xmliter.find( lambda e: e.getAttribute('id') == pointer.node_id ), xmliter) # node's lifetime ends here self.teardown(node, pointer, user, input) # compute the next node in the sequence try: next_node, state = self.next(xml, node, execution) except EndOfProcess: # finish the execution return self.finish_execution(execution) self.wakeup_and_notify(next_node, execution, channel, state)
def list_process(): def add_form(xml): json_xml = xml.to_json() forms = [] xmliter = iter(xml) first_node = next(xmliter) xmliter.parser.expandNode(first_node) for form in first_node.getElementsByTagName('form'): forms.append(form_to_dict(form)) json_xml['form_array'] = forms return json_xml return jsonify({ 'data': list(filter(lambda x: x, map( add_form, Xml.list(app.config), ))), })
def test_resolve_params(config): xml = Xml.load(config, 'exit_request') xmliter = iter(xml) next(xmliter) node = make_node(next(xmliter), xmliter) state = { 'values': { 'exit_form': { 'reason': 'nones', }, }, 'actors': { 'requester': 'juan', }, } assert node.resolve_params(state) == { "identifier": 'juan', "relation": 'manager', "reason": 'nones', }
def test_resistance_node_not_found(config, mongo): handler = Handler(config) ptr = make_pointer('wrong.2018-04-11.xml', 'start_node') exc = ptr.execution.get() user = make_user('juan', 'Juan') mongo[config["EXECUTION_COLLECTION"]].insert_one({ '_type': 'execution', 'id': exc.id, 'state': Xml.load(config, exc.process_name).get_state(), }) with pytest.raises(MisconfiguredProvider): handler( json.dumps({ 'command': 'step', 'pointer_id': ptr.id, 'user_identifier': user.identifier, 'input': {}, }))
def test_create_pointer(config): handler = Handler(config) xml = Xml.load(config, 'simple') xmliter = iter(xml) node = Action(next(xmliter), xmliter) exc = Execution.validate( process_name='simple.2018-02-19.xml', name='nombre', name_template='nombre', description='description', description_template='description', started_at=make_date(2020, 8, 21, 4, 5, 6), status='ongoing', ).save() pointer = handler.create_pointer(node, exc) execution = pointer.proxy.execution.get() assert pointer.node_id == 'start_node' assert execution.process_name == 'simple.2018-02-19.xml' assert execution.proxy.pointers.count() == 1
def test_load_not_found(config): ''' if a process file is not found, raise an exception ''' with pytest.raises(ProcessNotFound): Xml.load(config, 'notfound')
def test_invalidated_conditional(config, mongo): ''' a condiitonal depends on an invalidated field, if it changes during the second response it must take the second value ''' # test setup handler = Handler(config) user = make_user('juan', 'Juan') process_filename = 'condition_invalidated.2019-10-08.xml' ptr = make_pointer(process_filename, 'start_node') execution = ptr.proxy.execution.get() mongo[config["EXECUTION_COLLECTION"]].insert_one({ '_type': 'execution', 'id': execution.id, 'state': Xml.load(config, execution.process_name).get_state(), 'values': { '_execution': [{ 'name': '', 'description': '', }], }, }) # initial rabbit call channel = MagicMock() handler.call( { 'command': 'step', 'pointer_id': ptr.id, 'user_identifier': user.identifier, 'input': [ Form.state_json('form1', [ { 'name': 'value', 'type': 'int', 'value': 3, 'value_caption': '3', }, ]) ], }, channel) channel.basic_publish.assert_called_once() # arrives to if_node ptr = Pointer.get_all()[0] assert ptr.node_id == 'if_node' # if_node's condition is True args = channel.basic_publish.call_args[1] rabbit_call = { 'command': 'step', 'pointer_id': ptr.id, 'input': [ Form.state_json('if_node', [ { 'name': 'condition', 'state': 'valid', 'type': 'bool', 'value': True, 'value_caption': 'True', }, ]) ], 'user_identifier': '__system__', } assert json.loads(args['body']) == rabbit_call # if rabbit call channel.reset_mock() handler.call(rabbit_call, channel) channel.basic_publish.assert_called_once() # arrives to if_validation ptr = Pointer.get_all()[0] assert ptr.node_id == 'if_validation_node' # if's call to validation channel.reset_mock() handler.call( { 'command': 'step', 'pointer_id': ptr.id, 'user_identifier': user.identifier, 'input': [ Form.state_json('if_validation_node', [ { 'name': 'response', 'value': 'reject', 'value_caption': 'reject', }, { 'name': 'comment', 'value': 'I do not like it', 'value_caption': 'I do not like it', }, { 'name': 'inputs', 'value': [{ 'ref': 'start_node.juan.0:form1.value', }], 'value_caption': '', }, ]) ], }, channel) channel.basic_publish.assert_called_once() # returns to start_node ptr = Pointer.get_all()[0] assert ptr.node_id == 'start_node' # second lap channel.reset_mock() handler.call( { 'command': 'step', 'pointer_id': ptr.id, 'user_identifier': user.identifier, 'input': [ Form.state_json('form1', [ { 'name': 'value', 'type': 'int', 'value': -3, 'value_caption': '-3', }, ]) ], }, channel) channel.basic_publish.assert_called_once() # arrives to if_node again ptr = Pointer.get_all()[0] assert ptr.node_id == 'if_node' args = channel.basic_publish.call_args[1] rabbit_call = { 'command': 'step', 'pointer_id': ptr.id, 'input': [ Form.state_json('if_node', [ { 'name': 'condition', 'state': 'valid', 'type': 'bool', 'value': False, 'value_caption': 'False', }, ]) ], 'user_identifier': '__system__', } assert json.loads(args['body']) == rabbit_call # if second rabbit call channel.reset_mock() handler.call(rabbit_call, channel) channel.basic_publish.assert_called_once() # arrives to elif_node ptr = Pointer.get_all()[0] assert ptr.node_id == 'elif_node' # elif node's condition is true args = channel.basic_publish.call_args[1] rabbit_call = { 'command': 'step', 'pointer_id': ptr.id, 'input': [ Form.state_json('elif_node', [ { 'name': 'condition', 'state': 'valid', 'type': 'bool', 'value': True, 'value_caption': 'True', }, ]) ], 'user_identifier': '__system__', } assert json.loads(args['body']) == rabbit_call # elif rabbit call channel.reset_mock() handler.call(rabbit_call, channel) channel.basic_publish.assert_called_once() # arrives to elif_validation ptr = Pointer.get_all()[0] assert ptr.node_id == 'elif_validation_node' # elif's call to validation channel.reset_mock() handler.call( { 'command': 'step', 'pointer_id': ptr.id, 'user_identifier': user.identifier, 'input': [ Form.state_json('elif_validation_node', [ { 'name': 'response', 'value': 'reject', 'value_caption': 'reject', }, { 'name': 'comment', 'value': 'Ugly... nope', 'value_caption': 'Ugly... nope', }, { 'name': 'inputs', 'value': [{ 'ref': 'start_node.juan.0:form1.value', }], 'value_caption': '', }, ]) ], }, channel) channel.basic_publish.assert_called_once() # returns to start_node ptr = Pointer.get_all()[0] assert ptr.node_id == 'start_node' # third lap channel.reset_mock() handler.call( { 'command': 'step', 'pointer_id': ptr.id, 'user_identifier': user.identifier, 'input': [ Form.state_json('form1', [ { 'name': 'value', 'type': 'int', 'value': 0, 'value_caption': '0', }, ]) ], }, channel) channel.basic_publish.assert_called_once() # arrives to if_node again again ptr = Pointer.get_all()[0] assert ptr.node_id == 'if_node' args = channel.basic_publish.call_args[1] rabbit_call = { 'command': 'step', 'pointer_id': ptr.id, 'input': [ Form.state_json('if_node', [ { 'name': 'condition', 'state': 'valid', 'type': 'bool', 'value': False, 'value_caption': 'False', }, ]) ], 'user_identifier': '__system__', } assert json.loads(args['body']) == rabbit_call # if third rabbit call channel.reset_mock() handler.call(rabbit_call, channel) channel.basic_publish.assert_called_once() # arrives to elif_node again ptr = Pointer.get_all()[0] assert ptr.node_id == 'elif_node' args = channel.basic_publish.call_args[1] rabbit_call = { 'command': 'step', 'pointer_id': ptr.id, 'input': [ Form.state_json('elif_node', [ { 'name': 'condition', 'state': 'valid', 'type': 'bool', 'value': False, 'value_caption': 'False', }, ]) ], 'user_identifier': '__system__', } assert json.loads(args['body']) == rabbit_call # elif second rabbit call channel.reset_mock() handler.call(rabbit_call, channel) channel.basic_publish.assert_called_once() # arrives to else_node ptr = Pointer.get_all()[0] assert ptr.node_id == 'else_node' # else node's condition is true args = channel.basic_publish.call_args[1] rabbit_call = { 'command': 'step', 'pointer_id': ptr.id, 'input': [ Form.state_json('else_node', [ { 'name': 'condition', 'state': 'valid', 'type': 'bool', 'value': True, 'value_caption': 'True', }, ]) ], 'user_identifier': '__system__', } assert json.loads(args['body']) == rabbit_call # else rabbit call channel.reset_mock() handler.call(rabbit_call, channel) channel.basic_publish.assert_called_once() # arrives to if_validation ptr = Pointer.get_all()[0] assert ptr.node_id == 'else_validation_node' # else's call to validation channel.reset_mock() handler.call( { 'command': 'step', 'pointer_id': ptr.id, 'user_identifier': user.identifier, 'input': [ Form.state_json('else_validation_node', [ { 'name': 'response', 'value': 'reject', 'value_caption': 'reject', }, { 'name': 'comment', 'value': 'What? No!', 'value_caption': 'What? No!', }, { 'name': 'inputs', 'value': [{ 'ref': 'start_node.juan.0:form1.value', }], 'value_caption': '', }, ]) ], }, channel) channel.basic_publish.assert_called_once() # returns to start_node ptr = Pointer.get_all()[0] assert ptr.node_id == 'start_node' # state is coherent state = next(mongo[config["EXECUTION_COLLECTION"]].find({ 'id': execution.id, })) del state['_id'] assert state == { '_type': 'execution', 'id': execution.id, 'name': '', 'description': '', 'state': { '_type': ':sorted_map', 'items': { 'start_node': { '_type': 'node', 'type': 'action', 'id': 'start_node', 'state': 'ongoing', 'comment': 'What? No!', 'actors': { '_type': ':map', 'items': { 'juan': { '_type': 'actor', 'forms': [ Form.state_json( 'form1', [ { 'name': 'value', 'type': 'int', 'value': 0, 'value_caption': '0', 'state': 'invalid', }, ], state='invalid', ) ], 'state': 'invalid', 'user': { '_type': 'user', 'identifier': 'juan', 'fullname': 'Juan', }, }, }, }, 'milestone': False, 'name': 'Node 1', 'description': 'the value subject to inspection', }, 'if_node': { '_type': 'node', 'type': 'if', 'id': 'if_node', 'state': 'invalid', 'comment': 'What? No!', 'actors': { '_type': ':map', 'items': { '__system__': { '_type': 'actor', 'forms': [ Form.state_json( 'if_node', [ { 'name': 'condition', 'value': False, 'value_caption': 'False', 'type': 'bool', 'state': 'invalid', }, ], state='invalid', ) ], 'state': 'invalid', 'user': { '_type': 'user', 'identifier': '__system__', 'fullname': 'System', }, }, }, }, 'milestone': False, 'name': 'IF if_node', 'description': 'IF if_node', }, 'if_validation_node': { '_type': 'node', 'type': 'validation', 'id': 'if_validation_node', 'state': 'invalid', 'comment': 'What? No!', 'actors': { '_type': ':map', 'items': { 'juan': { '_type': 'actor', 'forms': [ Form.state_json( 'if_validation_node', [ { 'name': 'response', 'value': 'reject', 'value_caption': 'reject', 'state': 'invalid', }, { 'name': 'comment', 'value': 'I do not like it', 'value_caption': ('I do not like it'), }, { 'name': 'inputs', 'value': [{ 'ref': ('start_node.juan.0:form1' '.value'), }], 'value_caption': '', }, ], state='invalid', ) ], 'state': 'invalid', 'user': { '_type': 'user', 'fullname': 'Juan', 'identifier': 'juan' }, } } }, 'name': 'The validation', 'description': 'This node invalidates the original value', 'milestone': False, }, 'elif_node': { '_type': 'node', 'type': 'elif', 'id': 'elif_node', 'state': 'invalid', 'comment': 'What? No!', 'actors': { '_type': ':map', 'items': { '__system__': { '_type': 'actor', 'state': 'invalid', 'user': { '_type': 'user', 'fullname': 'System', 'identifier': '__system__' }, 'forms': [ Form.state_json( 'elif_node', [ { 'name': 'condition', 'value': False, 'value_caption': 'False', 'type': 'bool', 'state': 'invalid', }, ], state='invalid', ) ], } } }, 'name': 'ELIF elif_node', 'description': 'ELIF elif_node', 'milestone': False, }, 'elif_validation_node': { '_type': 'node', 'type': 'validation', 'id': 'elif_validation_node', 'state': 'invalid', 'comment': 'What? No!', 'actors': { '_type': ':map', 'items': { 'juan': { '_type': 'actor', 'state': 'invalid', 'user': { '_type': 'user', 'fullname': 'Juan', 'identifier': 'juan' }, 'forms': [ Form.state_json( 'elif_validation_node', [ { 'name': 'response', 'value': 'reject', 'value_caption': 'reject', 'state': 'invalid', }, { 'name': 'comment', 'value': 'Ugly... nope', 'value_caption': ('Ugly... nope'), }, { 'name': 'inputs', 'value': [{ 'ref': ('start_node.juan.0:form1' '.value'), }], 'value_caption': '', }, ], state='invalid', ) ], } } }, 'name': 'The validation', 'description': ('This node also invalidates the original value'), 'milestone': False, }, 'else_node': { '_type': 'node', 'type': 'else', 'id': 'else_node', 'state': 'invalid', 'comment': 'What? No!', 'actors': { '_type': ':map', 'items': { '__system__': { '_type': 'actor', 'state': 'invalid', 'user': { '_type': 'user', 'fullname': 'System', 'identifier': '__system__' }, 'forms': [ Form.state_json( 'else_node', [ { 'name': 'condition', 'value': True, 'value_caption': 'True', 'type': 'bool', 'state': 'invalid', }, ], state='invalid', ) ], } } }, 'name': 'ELSE else_node', 'description': 'ELSE else_node', 'milestone': False, }, 'else_validation_node': { '_type': 'node', 'type': 'validation', 'id': 'else_validation_node', 'state': 'invalid', 'comment': 'What? No!', 'actors': { '_type': ':map', 'items': { 'juan': { '_type': 'actor', 'state': 'invalid', 'user': { '_type': 'user', 'fullname': 'Juan', 'identifier': 'juan' }, 'forms': [ Form.state_json('else_validation_node', [ { 'name': 'response', 'value': 'reject', 'value_caption': 'reject', 'state': 'invalid', }, { 'name': 'comment', 'value': 'What? No!', 'value_caption': 'What? No!', }, { 'name': 'inputs', 'value': [{ 'ref': ('start_node.juan.0:form1' '.value'), }], 'value_caption': '', }, ], state='invalid'), ], } } }, 'name': 'The validation', 'description': ('This node invalidates the original value, too'), 'milestone': False, } }, 'item_order': [ 'start_node', 'if_node', 'if_validation_node', 'elif_node', 'elif_validation_node', 'else_node', 'else_validation_node' ], }, 'values': { '_execution': [{ 'name': '', 'description': '', }], 'form1': [{ 'value': 0, }], 'if_node': [{ 'condition': False, }], 'if_validation_node': [ { 'response': 'reject', 'comment': 'I do not like it', 'inputs': [ { 'ref': 'start_node.juan.0:form1.value' }, ], }, ], 'elif_node': [ { 'condition': False, }, ], 'elif_validation_node': [ { 'response': 'reject', 'comment': 'Ugly... nope', 'inputs': [ { 'ref': 'start_node.juan.0:form1.value', }, ], }, ], 'else_node': [ { 'condition': True, }, ], 'else_validation_node': [ { 'response': 'reject', 'comment': 'What? No!', 'inputs': [ { 'ref': 'start_node.juan.0:form1.value', }, ], }, ], }, 'actors': { 'start_node': 'juan', 'if_node': '__system__', 'if_validation_node': 'juan', 'elif_node': '__system__', 'elif_validation_node': 'juan', 'else_node': '__system__', 'else_validation_node': 'juan', }, 'actor_list': [{ 'node': 'start_node', 'identifier': 'juan', }, { 'node': 'if_node', 'identifier': '__system__', }, { 'node': 'if_validation_node', 'identifier': 'juan', }, { 'node': 'elif_node', 'identifier': '__system__', }, { 'node': 'elif_validation_node', 'identifier': 'juan', }, { 'node': 'else_node', 'identifier': '__system__', }, { 'node': 'else_validation_node', 'identifier': 'juan', }], }
def test_anidated_conditions(config, mongo): ''' conditional node won't be executed if its condition is false ''' # test setup handler = Handler(config) user = make_user('juan', 'Juan') ptr = make_pointer('anidated-conditions.2018-05-17.xml', 'a') channel = MagicMock() mongo[config["EXECUTION_COLLECTION"]].insert_one({ '_type': 'execution', 'id': ptr.proxy.execution.get().id, 'state': Xml.load(config, 'anidated-conditions').get_state(), }) handler.call( { 'command': 'step', 'pointer_id': ptr.id, 'user_identifier': user.identifier, 'input': [ Form.state_json('a', [ { 'name': 'a', 'value': '1', 'value_caption': '1', }, ]) ], }, channel) # assertions assert Pointer.get(ptr.id) is None ptr = Pointer.get_all()[0] assert ptr.node_id == 'outer' # rabbit called args = channel.basic_publish.call_args[1] rabbit_call = { 'command': 'step', 'pointer_id': ptr.id, 'input': [ Form.state_json('outer', [ { 'name': 'condition', 'state': 'valid', 'type': 'bool', 'value': True, 'value_caption': 'True', }, ]) ], 'user_identifier': '__system__', } assert json.loads(args['body']) == rabbit_call handler.call(rabbit_call, channel) # assertions assert Pointer.get(ptr.id) is None ptr = Pointer.get_all()[0] assert ptr.node_id == 'b' handler.call( { 'command': 'step', 'pointer_id': ptr.id, 'user_identifier': user.identifier, 'input': [ Form.state_json('b', [ { 'name': 'b', 'value': '-1', 'value_caption': '-1', }, ]) ], }, channel) # assertions assert Pointer.get(ptr.id) is None ptr = Pointer.get_all()[0] assert ptr.node_id == 'inner1' # rabbit called args = channel.basic_publish.call_args[1] rabbit_call = { 'command': 'step', 'pointer_id': ptr.id, 'input': [ Form.state_json('inner1', [ { 'name': 'condition', 'name': 'condition', 'state': 'valid', 'type': 'bool', 'value': False, 'value_caption': 'False', }, ]) ], 'user_identifier': '__system__', } assert json.loads(args['body']) == rabbit_call handler.call(rabbit_call, channel) # assertions assert Pointer.get(ptr.id) is None ptr = Pointer.get_all()[0] assert ptr.node_id == 'f' handler.call( { 'command': 'step', 'pointer_id': ptr.id, 'user_identifier': user.identifier, 'input': [ Form.state_json('f', [ { 'name': 'f', 'value': '-1', 'value_caption': '-1', }, ]) ], }, channel) ptr = Pointer.get_all()[0] assert ptr.node_id == 'g'
def test_ifelifelse_else(config, mongo): ''' else will be executed if preceding condition is false''' # test setup handler = Handler(config) user = make_user('juan', 'Juan') ptr = make_pointer('else.2018-07-10.xml', 'start_node') channel = MagicMock() mongo[config["EXECUTION_COLLECTION"]].insert_one({ '_type': 'execution', 'id': ptr.proxy.execution.get().id, 'state': Xml.load(config, 'else').get_state(), }) handler.call( { 'command': 'step', 'pointer_id': ptr.id, 'user_identifier': user.identifier, 'input': [ Form.state_json('secret01', [ { 'name': 'password', 'type': 'text', 'value': 'cuca', 'value_caption': 'cuca', }, ]) ], }, channel) # pointer moved assert Pointer.get(ptr.id) is None ptr = Pointer.get_all()[0] assert ptr.node_id == 'condition01' # rabbit called channel.basic_publish.assert_called_once() args = channel.basic_publish.call_args[1] rabbit_call = { 'command': 'step', 'pointer_id': ptr.id, 'input': [ Form.state_json('condition01', [ { 'name': 'condition', 'name': 'condition', 'state': 'valid', 'type': 'bool', 'value': False, 'value_caption': 'False', }, ]) ], 'user_identifier': '__system__', } assert json.loads(args['body']) == rabbit_call channel = MagicMock() handler.call(rabbit_call, channel) # pointer moved assert Pointer.get(ptr.id) is None ptr = Pointer.get_all()[0] assert ptr.node_id == 'elif01' # rabbit called channel.basic_publish.assert_called_once() args = channel.basic_publish.call_args[1] rabbit_call = { 'command': 'step', 'pointer_id': ptr.id, 'input': [ Form.state_json('elif01', [ { 'name': 'condition', 'state': 'valid', 'type': 'bool', 'value': False, 'value_caption': 'False', }, ]) ], 'user_identifier': '__system__', } assert json.loads(args['body']) == rabbit_call channel = MagicMock() handler.call(rabbit_call, channel) # pointer moved assert Pointer.get(ptr.id) is None ptr = Pointer.get_all()[0] assert ptr.node_id == 'else01' # rabbit called channel.basic_publish.assert_called_once() args = channel.basic_publish.call_args[1] rabbit_call = { 'command': 'step', 'pointer_id': ptr.id, 'input': [ Form.state_json('else01', [ { 'name': 'condition', 'state': 'valid', 'type': 'bool', 'value': True, 'value_caption': 'True', }, ]) ], 'user_identifier': '__system__', } assert json.loads(args['body']) == rabbit_call channel = MagicMock() handler.call(rabbit_call, channel) # pointer moved assert Pointer.get(ptr.id) is None ptr = Pointer.get_all()[0] assert ptr.node_id == 'action03' # rabbit called to notify the user channel.basic_publish.assert_called_once() args = channel.basic_publish.call_args[1] assert args['exchange'] == 'charpe_notify' channel = MagicMock() handler.call( { 'command': 'step', 'pointer_id': ptr.id, 'user_identifier': user.identifier, 'input': [ Form.state_json('form01', [ { 'name': 'answer', 'value': 'answer', 'value_caption': 'answer', }, ]) ], }, channel) # execution finished assert len(Pointer.get_all()) == 0 assert len(Execution.get_all()) == 0
def test_load_respects_name(config): ''' if there are two xmls whose name starts with the same prefix, the one matching the exact name should be resolved ''' xml = Xml.load(config, 'exit') assert xml.filename == 'exit.2018-05-03.xml'
def test_false_condition_node(config, mongo): ''' conditional node won't be executed if its condition is false ''' # test setup handler = Handler(config) user = make_user('juan', 'Juan') ptr = make_pointer('condition.2018-05-17.xml', 'start_node') execution = ptr.proxy.execution.get() channel = MagicMock() mongo[config["EXECUTION_COLLECTION"]].insert_one({ '_type': 'execution', 'id': execution.id, 'state': Xml.load(config, execution.process_name).get_state(), }) handler.call( { 'command': 'step', 'pointer_id': ptr.id, 'user_identifier': user.identifier, 'input': [ Form.state_json('mistery', [ { 'name': 'password', 'type': 'text', 'value': '123456', 'value_caption': '123456', }, ]) ], }, channel) # assertions assert Pointer.get(ptr.id) is None ptr = Pointer.get_all()[0] assert ptr.node_id == 'condition1' # rabbit called channel.basic_publish.assert_called_once() args = channel.basic_publish.call_args[1] rabbit_call = { 'command': 'step', 'pointer_id': ptr.id, 'input': [ Form.state_json('condition1', [ { 'name': 'condition', 'state': 'valid', 'type': 'bool', 'value': False, 'value_caption': 'False', }, ]) ], 'user_identifier': '__system__', } assert json.loads(args['body']) == rabbit_call handler.call(rabbit_call, channel) # pointer moved assert Pointer.get(ptr.id) is None ptr = Pointer.get_all()[0] assert ptr.node_id == 'condition2'
def test_load_process(config): ''' a process file can be found using only its prefix or common name ''' xml = Xml.load(config, 'simple') assert xml.filename == 'simple.2018-02-19.xml' assert xml.public is True