Ejemplo n.º 1
0
    def get_state(self):
        from cacahuate.node import make_node  # noqa

        xmliter = iter(self)
        items = []

        for node in xmliter:
            built_node = make_node(node, xmliter)

            items.append(built_node.get_state())

        return SortedMap(items, key='id').to_json()
Ejemplo n.º 2
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 == {
        'status_code': 200,
        'response': 'request response',
    }
Ejemplo n.º 3
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)
Ejemplo n.º 4
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',
    }
Ejemplo n.º 5
0
def cascade_invalidate(xml, state, invalidated, comment):
    ''' computes a set of fields to be marked as invalid given the
    original `invalidated` set of fields. '''
    # because this could cause a recursive import
    from cacahuate.node import make_node

    # find the first node that is invalid and select it
    set_values = {
        i['ref']: {
            'value': i['value'],
            'value_caption': i['value_caption'],
        }
        for i in invalidated if 'value' in i
    }
    invalid_refs = set(i['ref'] for i in invalidated)
    xmliter = iter(xml)

    for element in xmliter:
        node = make_node(element, xmliter)
        more_fields = node.get_invalidated_fields(invalid_refs, state)

        invalid_refs.update(more_fields)

    # computes the keys and values to be used in a mongodb update to set the
    # fields as invalid
    updates = dict()

    for key in invalid_refs:
        node, actor, form, input = key.split('.')
        index, ref = form.split(':')

        ref_index = get_ref_index(
            state=state,
            node=node,
            actor=actor,
            ref=ref,
            index=index,
        )

        node_path = 'state.items.{node}'.format(node=node)
        comment_path = node_path + '.comment'
        node_state_path = node_path + '.state'
        actor_path = node_path + '.actors.items.{actor}'.format(actor=actor)
        actor_state_path = actor_path + '.state'
        form_path = actor_path + '.forms.{index}'.format(index=index)
        form_state_path = form_path + '.state'
        input_path = form_path + '.inputs.items.{input}'.format(input=input)
        input_state_path = input_path + '.state'
        input_value_path = input_path + '.value'
        input_caption_path = input_path + '.value_caption'
        values_input_path = 'values.{ref}.{ref_index}.{input}'.format(
            ref=ref,
            ref_index=ref_index,
            input=input,
        )

        # inputs
        input_state = 'valid' if key in set_values else 'invalid'

        updates[input_state_path] = input_state

        if key in set_values:
            updates[input_value_path] = set_values[key]['value']
            updates[input_caption_path] = set_values[key]['value_caption']

            if ref_index is not None:
                updates[values_input_path] = set_values[key]['value']

        # forms
        if input_state == 'valid' and (form_state_path not in updates
                                       or updates[form_state_path] == 'valid'):
            form_state = 'valid'
        else:
            form_state = 'invalid'

        updates[form_state_path] = form_state

        # actors
        if form_state == 'valid' and (actor_state_path not in updates
                                      or updates[actor_state_path] == 'valid'):
            actor_state = 'valid'
        else:
            actor_state = 'invalid'

        updates[actor_state_path] = actor_state

        # nodes
        if actor_state == 'valid' and (node_state_path not in updates
                                       or updates[node_state_path] == 'valid'):
            node_state = 'valid'
        else:
            node_state = 'invalid'

        updates[node_state_path] = node_state
        updates[comment_path] = comment

    return updates
Ejemplo n.º 6
0
def continue_process():
    validate_json(request.json, ['execution_id', 'node_id'])

    execution_id = request.json['execution_id']
    node_id = request.json['node_id']

    try:
        execution = Execution.get_or_exception(execution_id)
    except ModelNotFoundError:
        raise BadRequest([{
            'detail': 'execution_id is not valid',
            'code': 'validation.invalid',
            'where': 'request.body.execution_id',
        }])

    xml = Xml.load(app.config, execution.process_name, direct=True)
    xmliter = iter(xml)

    try:
        continue_point = make_node(
            xmliter.find(lambda e: e.getAttribute('id') == node_id), xmliter)
    except ElementNotFound:
        raise BadRequest([{
            'detail': 'node_id is not a valid node',
            'code': 'validation.invalid_node',
            'where': 'request.body.node_id',
        }])

    try:
        pointer = next(execution.proxy.pointers.q().filter(node_id=node_id))
    except StopIteration:
        raise BadRequest([{
            'detail': 'node_id does not have a live pointer',
            'code': 'validation.no_live_pointer',
            'where': 'request.body.node_id',
        }])

    # Check for authorization
    if pointer not in g.user.proxy.tasks:
        raise Forbidden([{
            'detail': 'Provided user does not have this task assigned',
            'where': 'request.authorization',
        }])

    # Validate asociated forms
    collected_input = continue_point.validate_input(request.json)

    # trigger rabbit
    channel = get_channel()
    channel.basic_publish(
        exchange='',
        routing_key=app.config['RABBIT_QUEUE'],
        body=json.dumps({
            'command': 'step',
            'pointer_id': pointer.id,
            'user_identifier': g.user.identifier,
            'input': collected_input,
        }),
        properties=pika.BasicProperties(delivery_mode=2, ),
    )

    return {
        'data': 'accepted',
    }, 202
Ejemplo n.º 7
0
def test_variable_proc_name_mix(config, mongo):
    ''' Test where the name is related to
    multiple forms in diferent nodes of the execution'''
    handler = Handler(config)
    user = make_user('juan', 'Juan')
    channel = MagicMock()
    xml = Xml.load(config, 'variable_name_mix.2020-01-28.xml')
    xmliter = iter(xml)
    node = make_node(next(xmliter), xmliter)
    input = [
        Form.state_json('form01', [
            {
                'name': 'data01',
                'type': 'text',
                'value': '1',
                'value_caption': '1',
            },
        ])
    ]
    execution = xml.start(node, input, mongo, channel, user.identifier)
    ptr = execution.proxy.pointers.get()[0]

    handler.call(
        {
            'command': 'step',
            'pointer_id': ptr.id,
            'user_identifier': user.identifier,
            'input': input,
        }, channel)

    # pointer moved
    assert Pointer.get(ptr.id) is None
    ptr = Pointer.get_all()[0]
    assert ptr.node_id == 'node02'

    execution.reload()
    assert execution.name == 'Variable name process in step 10'
    assert execution.description == 'Description is also variable: 1, , '

    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('form02', [
                    {
                        'name': 'data02',
                        'type': 'text',
                        'value': '2',
                        'value_caption': '2',
                    },
                ])
            ],
        }, channel)

    # pointer moved
    assert Pointer.get(ptr.id) is None
    ptr = Pointer.get_all()[0]
    assert ptr.node_id == 'node03'

    execution.reload()
    assert execution.name == 'Variable name process in step 210'
    assert execution.description == 'Description is also variable: 1, 2, '

    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('form03', [
                    {
                        'name': 'data03',
                        'type': 'text',
                        'value': '3',
                        'value_caption': '3',
                    },
                ])
            ],
        }, channel)
Ejemplo n.º 8
0
def test_variable_proc_name_pointers(config, mongo):
    ''' Test pointer name's update'''
    handler = Handler(config)
    user = make_user('juan', 'Juan')
    channel = MagicMock()
    xml = Xml.load(config, 'variable_name_mix.2020-01-28.xml')
    xmliter = iter(xml)
    node = make_node(next(xmliter), xmliter)
    input = [
        Form.state_json('form01', [
            {
                'name': 'data01',
                'type': 'text',
                'value': '1',
                'value_caption': '1',
            },
        ])
    ]
    execution = xml.start(node, input, mongo, channel, user.identifier)
    ptr = execution.proxy.pointers.get()[0]

    handler.call(
        {
            'command': 'step',
            'pointer_id': ptr.id,
            'user_identifier': user.identifier,
            'input': input,
        }, channel)

    # pointer moved
    assert Pointer.get(ptr.id) is None
    ptr = Pointer.get_all()[0]
    assert ptr.node_id == 'node02'

    execution.reload()
    assert execution.name == 'Variable name process in step 10'
    assert execution.description == 'Description is also variable: 1, , '

    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('form02', [
                    {
                        'name': 'data02',
                        'type': 'text',
                        'value': '2',
                        'value_caption': '2',
                    },
                ])
            ],
        }, channel)

    # pointer moved
    assert Pointer.get(ptr.id) is None
    ptr = Pointer.get_all()[0]
    assert ptr.node_id == 'node03'

    execution.reload()
    assert execution.name == 'Variable name process in step 210'
    assert execution.description == 'Description is also variable: 1, 2, '

    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('form03', [
                    {
                        'name': 'data03',
                        'type': 'text',
                        'value': '3',
                        'value_caption': '3',
                    },
                ])
            ],
        }, channel)

    # now check pointers last state
    cursor = mongo[config["POINTER_COLLECTION"]].find({
        'execution.id':
        execution.id,
    })

    assert cursor.count() == 3

    expected_name = 'Variable name process in step 3210'
    expected_desc = 'Description is also variable: 1, 2, 3'

    for item in cursor:
        assert item['execution']['name'] == expected_name
        assert item['execution']['description'] == expected_desc
Ejemplo n.º 9
0
def test_variable_proc_name_mix(config, mongo):
    ''' Test where the name is related to
    multiple forms in diferent nodes of the execution'''
    handler = Handler(config)
    user = make_user('juan', 'Juan')
    xml = Xml.load(config, 'variable_name_mix.2020-01-28.xml')
    xmliter = iter(xml)
    node = make_node(next(xmliter), xmliter)
    input = [
        Form.state_json('form01', [
            {
                'name': 'data01',
                'type': 'text',
                'value': '1',
                'value_caption': '1',
                'state': 'valid',
            },
        ])
    ]
    execution = xml.start(node, input, mongo, user.identifier)
    ptr = next(execution.pointers.q().filter(status='ongoing'))

    handler.step({
        'command': 'step',
        'pointer_id': ptr.id,
        'user_identifier': user.identifier,
        'input': input,
    })

    # pointer moved
    assert Pointer.get(ptr.id).status == 'finished'
    ptr = next(Pointer.q().filter(status='ongoing'))
    assert ptr.node_id == 'node02'

    execution.reload()
    assert execution.name == 'Variable name process in step 10'
    assert execution.description == 'Description is also variable: 1, , '

    handler.step({
        'command':
        'step',
        'pointer_id':
        ptr.id,
        'user_identifier':
        user.identifier,
        'input': [
            Form.state_json('form02', [
                {
                    'name': 'data02',
                    'type': 'text',
                    'value': '2',
                    'value_caption': '2',
                    'state': 'valid',
                },
            ])
        ],
    })

    # pointer moved
    assert Pointer.get(ptr.id).status == 'finished'
    ptr = next(Pointer.q().filter(status='ongoing'))
    assert ptr.node_id == 'node03'

    execution.reload()
    assert execution.name == 'Variable name process in step 210'
    assert execution.description == 'Description is also variable: 1, 2, '

    handler.step({
        'command':
        'step',
        'pointer_id':
        ptr.id,
        'user_identifier':
        user.identifier,
        'input': [
            Form.state_json('form03', [
                {
                    'name': 'data03',
                    'type': 'text',
                    'value': '3',
                    'value_caption': '3',
                    'state': 'valid',
                },
            ])
        ],
    })
Ejemplo n.º 10
0
def test_variable_proc_name_pointers(config, mongo):
    ''' Test pointer name's update'''
    handler = Handler(config)
    user = make_user('juan', 'Juan')
    xml = Xml.load(config, 'variable_name_mix.2020-01-28.xml')
    xmliter = iter(xml)
    node = make_node(next(xmliter), xmliter)
    input = [
        Form.state_json('form01', [
            {
                'name': 'data01',
                'type': 'text',
                'value': '1',
                'value_caption': '1',
                'state': 'valid',
            },
        ])
    ]
    execution = xml.start(node, input, mongo, user.identifier)
    ptr = next(execution.pointers.q().filter(status='ongoing'))

    handler.step({
        'command': 'step',
        'pointer_id': ptr.id,
        'user_identifier': user.identifier,
        'input': input,
    })

    # pointer moved
    assert Pointer.get(ptr.id).status == 'finished'
    ptr = next(Pointer.q().filter(status='ongoing'))
    assert ptr.node_id == 'node02'

    execution.reload()
    assert execution.name == 'Variable name process in step 10'
    assert execution.description == 'Description is also variable: 1, , '

    handler.step({
        'command':
        'step',
        'pointer_id':
        ptr.id,
        'user_identifier':
        user.identifier,
        'input': [
            Form.state_json('form02', [
                {
                    'name': 'data02',
                    'type': 'text',
                    'value': '2',
                    'value_caption': '2',
                    'state': 'valid',
                },
            ])
        ],
    })

    # pointer moved
    assert Pointer.get(ptr.id).status == 'finished'
    ptr = next(Pointer.q().filter(status='ongoing'))
    assert ptr.node_id == 'node03'

    execution.reload()
    assert execution.name == 'Variable name process in step 210'
    assert execution.description == 'Description is also variable: 1, 2, '

    handler.step({
        'command':
        'step',
        'pointer_id':
        ptr.id,
        'user_identifier':
        user.identifier,
        'input': [
            Form.state_json('form03', [
                {
                    'name': 'data03',
                    'type': 'text',
                    'value': '3',
                    'value_caption': '3',
                    'state': 'valid',
                },
            ])
        ],
    })

    # now check pointers last state
    query = {'execution.id': execution.id}

    assert mongo[config["POINTER_COLLECTION"]].count_documents(query) == 3

    expected_name = 'Variable name process in step 3210'
    expected_desc = 'Description is also variable: 1, 2, 3'

    cursor = mongo[config["POINTER_COLLECTION"]].find(query)
    for item in cursor:
        assert item['execution']['name'] == expected_name
        assert item['execution']['description'] == expected_desc
Ejemplo n.º 11
0
def cascade_invalidate(xml, state, invalidated, comment):
    ''' computes a set of fields to be marked as invalid given the
    original `invalidated` set of fields. '''
    # because this could cause a recursive import
    from cacahuate.node import make_node

    # find the first node that is invalid and select it
    set_values = {
        i['ref']: {
            'value': i['value'],
            'value_caption': i['value_caption'],
        }
        for i in invalidated if 'value' in i
    }
    invalid_refs = set(i['ref'] for i in invalidated)
    xmliter = iter(xml)

    for element in xmliter:
        node = make_node(element, xmliter)
        more_fields = node.get_invalidated_fields(invalid_refs, state)

        invalid_refs.update(more_fields)

    # computes the keys and values to be used in a mongodb update to set the
    # fields as invalid
    updates = {}
    form_refs = []
    field_names = []

    array_filters = {}

    for key in invalid_refs:
        node, actor, form_parts, input_name = key.split('.')
        index, ref = form_parts.split(':')

        if ref not in form_refs:
            form_refs.append(ref)
        fg_index = form_refs.index(ref)

        if input_name not in field_names:
            field_names.append(input_name)
        fld_index = field_names.index(input_name)

        ref_index = get_ref_index(
            state=state,
            node=node,
            actor=actor,
            ref=ref,
            index=index,
        )

        array_filters[f'frmRef{fg_index}.ref'] = {
            f'frmRef{fg_index}.ref': ref,
        }
        array_filters[f'fldName{fld_index}.name'] = {
            f'fldName{fld_index}.name': input_name,
        }

        node_path = 'state.items.{node}'.format(node=node)
        comment_path = node_path + '.comment'
        node_state_path = node_path + '.state'
        actor_path = node_path + '.actors.items.{actor}'.format(actor=actor)
        actor_state_path = actor_path + '.state'
        form_path = actor_path + '.forms.{index}'.format(index=index)
        form_state_path = form_path + '.state'
        input_path = form_path + '.inputs.items.{input_name}'.format(
            input_name=input_name)
        input_state_path = input_path + '.state'
        input_value_path = input_path + '.value'
        input_caption_path = input_path + '.value_caption'
        values_form_path = 'values.$[frmRef{fg_index}].forms.{ref_index}'.format(
            fg_index=fg_index,
            ref_index=ref_index,
        )
        values_input_path = values_form_path + '.fields.$[fldName{fld_index}]'.format(
            fld_index=fld_index, )
        values_input_value_path = values_input_path + '.value'
        values_input_value_caption_path = values_input_path + '.value_caption'
        values_input_state_path = values_input_path + '.state'

        # inputs
        input_state = 'valid' if key in set_values else 'invalid'

        updates[input_state_path] = input_state
        updates[values_input_state_path] = input_state

        if key in set_values:
            updates[input_value_path] = set_values[key]['value']
            updates[input_caption_path] = set_values[key]['value_caption']

            if ref_index is not None:
                updates[values_input_value_path] = set_values[key]['value']
                updates[values_input_value_caption_path] = set_values[key][
                    'value_caption']

        # forms
        if input_state == 'valid' and (form_state_path not in updates
                                       or updates[form_state_path] == 'valid'):
            form_state = 'valid'
        else:
            form_state = 'invalid'

        updates[form_state_path] = form_state

        # actors
        if form_state == 'valid' and (actor_state_path not in updates
                                      or updates[actor_state_path] == 'valid'):
            actor_state = 'valid'
        else:
            actor_state = 'invalid'

        updates[actor_state_path] = actor_state

        # nodes
        if actor_state == 'valid' and (node_state_path not in updates
                                       or updates[node_state_path] == 'valid'):
            node_state = 'valid'
        else:
            node_state = 'invalid'

        updates[node_state_path] = node_state
        updates[comment_path] = comment

    return updates, list(array_filters.values())