Example #1
0
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
Example #2
0
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'],
    }
Example #3
0
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
Example #4
0
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),
    })
Example #5
0
    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)
Example #6
0
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()
Example #7
0
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',
    }
Example #8
0
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
Example #9
0
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'
Example #10
0
    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)
Example #11
0
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
Example #12
0
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',
        }],
    }]
Example #13
0
    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 []
Example #14
0
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'
Example #15
0
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()})
Example #16
0
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'}
Example #17
0
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': {},
    }))
Example #18
0
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'
Example #19
0
    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)
Example #20
0
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),
        ))),
    })
Example #21
0
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',
    }
Example #22
0
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': {},
            }))
Example #23
0
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
Example #24
0
def test_load_not_found(config):
    ''' if a process file is not found, raise an exception '''
    with pytest.raises(ProcessNotFound):
        Xml.load(config, 'notfound')
Example #25
0
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',
        }],
    }
Example #26
0
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'
Example #27
0
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
Example #28
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'
Example #29
0
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'
Example #30
0
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