Пример #1
0
    def recover_step(self, message: dict):
        ''' given an execution id and a pointer from the persistent storage,
        return the asociated process node to continue its execution '''
        try:
            pointer = Pointer.get_or_exception(message['pointer_id'])
            if pointer.status != 'ongoing':
                raise ModelNotFoundError(
                    'Specified pointer never existed, and never will', )

        except ModelNotFoundError:
            raise InconsistentState('Queued dead pointer')

        user = User.get_by('identifier', message.get('user_identifier'))

        if user is None:
            if message.get('user_identifier') == '__system__':
                user = User(identifier='__system__', fullname='System').save()
            else:
                raise InconsistentState('sent identifier of unexisten user')

        return (
            pointer,
            user,
            message['input'],
        )
Пример #2
0
    def create_pointer(self, node, execution: Execution):
        ''' Given a node, its process, and a specific execution of the former
        create a persistent pointer to the current execution state '''
        pointer = Pointer(
            node_id=node.id,
            name=node.name,
            description=node.description,
        ).save()

        pointer.proxy.execution.set(execution)

        return pointer
Пример #3
0
    def start(self, node, input, mongo, user_identifier):
        # the first set of values
        context = compact_values(input)

        # save the data
        execution = Execution(
            process_name=self.filename,
            name=self.get_name(context),
            name_template=self.name_template(),
            description=self.get_description(context),
            description_template=self.description_template(),
            started_at=datetime.now(),
            status='ongoing',
        ).save()

        pointer = Pointer(
            node_id=node.id,
            name=node.get_name(context),
            description=node.get_description(context),
            started_at=execution.started_at,
            status='ongoing',
        ).save()
        pointer.execution.set(execution)

        # log to mongo
        collection = mongo[self.config['POINTER_COLLECTION']]
        collection.insert_one(pointer_entry(
            node,
            pointer.name,
            pointer.description,
            execution,
            pointer
        ))

        collection = mongo[self.config['EXECUTION_COLLECTION']]
        collection.insert_one(execution_entry(
            execution,
            self.get_state(),
        ))

        # trigger rabbit
        from .tasks import handle

        handle.delay(json.dumps({
            'command': 'step',
            'pointer_id': pointer.id,
            'user_identifier': user_identifier,
            'input': input,
        }))

        return execution
Пример #4
0
    def _create_pointer(self, node_id: str, name: str, description: str,
                        execution: Execution):
        ''' Given a node, its process, and a specific execution of the former
        create a persistent pointer to the current execution state '''
        pointer = Pointer(
            node_id=node_id,
            name=name,
            description=description,
            started_at=datetime.now(),
            status='ongoing',
        ).save()

        pointer.execution.set(execution)

        return pointer
Пример #5
0
    def start(self, node, input, mongo, channel, user_identifier):
        # save the data
        execution = Execution(
            process_name=self.filename,
            name=self.get_name(input),
            description=self.get_description(input),
        ).save()
        pointer = Pointer(
            node_id=node.id,
            name=node.name,
            description=node.description,
        ).save()
        pointer.proxy.execution.set(execution)

        # log to mongo
        collection = mongo[self.config['POINTER_COLLECTION']]
        collection.insert_one(node.pointer_entry(execution, pointer))

        collection = mongo[self.config['EXECUTION_COLLECTION']]
        collection.insert_one({
            '_type': 'execution',
            'id': execution.id,
            'name': execution.name,
            'description': execution.description,
            'status': 'ongoing',
            'started_at': datetime.now(),
            'finished_at': None,
            'state': self.get_state(),
            'values': {},
            'actors': {},
        })

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

        return execution
Пример #6
0
def make_pointer(
    process_name,
    node_id,
    execution_status=None,
    pointer_status=None,
):
    exc = Execution(
        process_name=process_name,
        status=execution_status or 'ongoing',
    ).save()
    ptr = Pointer(
        node_id=node_id,
        status=pointer_status or 'ongoing',
    ).save()
    ptr.execution.set(exc)

    return ptr
Пример #7
0
def test_handle_request_node(config, mocker, mongo):
    class ResponseMock:
        status_code = 200
        text = 'request response'

    mock = MagicMock(return_value=ResponseMock())

    mocker.patch('requests.request', new=mock)

    handler = Handler(config)
    user = make_user('juan', 'Juan')
    ptr = make_pointer('request.2018-05-18.xml', 'start_node')
    channel = MagicMock()
    execution = ptr.proxy.execution.get()
    value = random_string()

    mongo[config["EXECUTION_COLLECTION"]].insert_one({
        '_type':
        'execution',
        'id':
        execution.id,
        'state':
        Xml.load(config, 'request').get_state(),
    })

    # teardown of first node and wakeup of request node
    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('request', [
                    {
                        'name': 'data',
                        'value': value,
                        'value_caption': value,
                    },
                ])
            ],
        }, channel)
    assert Pointer.get(ptr.id) is None
    ptr = execution.proxy.pointers.get()[0]
    assert ptr.node_id == 'request_node'

    # assert requests is called
    requests.request.assert_called_once()
    args, kwargs = requests.request.call_args

    assert args[0] == 'GET'
    assert args[1] == 'http://localhost/mirror?data=' + value

    assert kwargs['data'] == '{"data":"' + value + '"}'
    assert kwargs['headers'] == {
        'content-type': 'application/json',
        'x-url-data': value,
    }

    # aditional rabbit call for new process
    args = channel.basic_publish.call_args_list[0][1]

    expected_inputs = [
        Form.state_json('request_node', [
            {
                'name': 'status_code',
                'state': 'valid',
                'type': 'int',
                'value': 200,
                'value_caption': '200',
                'hidden': False,
                'label': 'Status Code',
            },
            {
                'name': 'raw_response',
                'state': 'valid',
                'type': 'text',
                'value': 'request response',
                'value_caption': 'request response',
                'hidden': False,
                'label': 'Response',
            },
        ])
    ]

    assert args['exchange'] == ''
    assert args['routing_key'] == config['RABBIT_QUEUE']
    assert json.loads(args['body']) == {
        'command': 'step',
        'pointer_id': ptr.id,
        'user_identifier': '__system__',
        'input': expected_inputs,
    }

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

    state = mongo[config["EXECUTION_COLLECTION"]].find_one({
        'id': execution.id,
    })

    assert state['state']['items']['request_node'] == {
        '_type': 'node',
        'type': 'request',
        'id': 'request_node',
        'comment': '',
        'state': 'valid',
        'actors': {
            '_type': ':map',
            'items': {
                '__system__': {
                    '_type': 'actor',
                    'state': 'valid',
                    'user': {
                        '_type': 'user',
                        'fullname': 'System',
                        'identifier': '__system__',
                    },
                    'forms': expected_inputs,
                },
            },
        },
        'milestone': False,
        'name': 'Request request_node',
        'description': 'Request request_node',
    }
Пример #8
0
def test_store_data_from_response(config, mocker, mongo):
    mocker.patch('cacahuate.tasks.handle.delay')

    expected_name = random_string()
    expected_age_1 = randint(0, 100)
    expected_age_2 = randint(0, 100)

    request_response = {
        'params': {
            'name': expected_name,
        },
        'items': [
            [
                {
                    'age': expected_age_1,
                },
                {
                    'age': expected_age_2,
                },
            ],
        ],
    }
    request_response_s = json.dumps(request_response)

    class ResponseMock:
        status_code = 200
        text = request_response_s

        def json(self):
            return request_response

    mock = MagicMock(return_value=ResponseMock())

    mocker.patch('requests.request', new=mock)

    handler = Handler(config)
    user = make_user('juan', 'Juan')
    ptr = make_pointer('request-captures.2019-08-08.xml', 'start_node')
    execution = ptr.execution.get()
    execution.started_at = datetime(2018, 4, 1, 21, 45)
    execution.save()
    value = random_string()

    mongo[config["EXECUTION_COLLECTION"]].insert_one({
        '_type':
        'execution',
        'id':
        execution.id,
        'state':
        Xml.load(config, 'request-captures').get_state(),
        'values': [
            {
                '_type':
                'fgroup',
                'ref':
                '_execution',
                'forms': [{
                    'ref':
                    '_execution',
                    'fields': [
                        {
                            '_type': 'field',
                            'name': 'name',
                            'label': 'name',
                            'hidden': False,
                            'value': '',
                            'value_caption': '',
                            'state': 'valid',
                            'actor': {
                                'identifier': '__system__',
                            },
                            'set_at': execution.started_at,
                        },
                        {
                            '_type': 'field',
                            'name': 'description',
                            'label': 'description',
                            'hidden': False,
                            'value': '',
                            'value_caption': '',
                            'state': 'valid',
                            'actor': {
                                'identifier': '__system__',
                            },
                            'set_at': execution.started_at,
                        },
                    ],
                }],
            },
        ],
    })

    # teardown of first node and wakeup of request node
    handler.step({
        'command':
        'step',
        'pointer_id':
        ptr.id,
        'user_identifier':
        user.identifier,
        'input': [
            Form.state_json('request', [
                {
                    'name': 'data',
                    'value': value,
                    'value_caption': value,
                    'state': 'valid',
                },
            ])
        ],
    })
    assert Pointer.get(ptr.id).status == 'finished'
    ptr = next(execution.pointers.q().filter(status='ongoing'))
    assert ptr.node_id == 'request_node'

    # assert requests is called
    requests.request.assert_called_once()
    args, kwargs = requests.request.call_args

    assert args[0] == 'GET'
    assert args[1] == 'http://localhost/'

    assert kwargs['data'] == ''
    assert kwargs['headers'] == {
        'content-type': 'application/json',
    }

    # aditional rabbit call for new process
    args = handle.delay.call_args[0][0]

    expected_inputs = [
        Form.state_json('request_node', [
            {
                'name': 'status_code',
                'state': 'valid',
                'type': 'int',
                'value': 200,
                'value_caption': '200',
                'hidden': False,
                'label': 'Status Code',
            },
            {
                'name': 'raw_response',
                'state': 'valid',
                'type': 'text',
                'value': request_response_s,
                'value_caption': request_response_s,
                'hidden': False,
                'label': 'Response',
            },
        ]),
        Form.state_json('capture1', [
            {
                'name': 'name',
                'state': 'valid',
                'type': 'text',
                'value': expected_name,
                'value_caption': expected_name,
                'hidden': False,
                'label': 'Nombre',
            },
        ]),
        Form.state_json('capture2', [
            {
                'name': 'age',
                'state': 'valid',
                'type': 'int',
                'value': expected_age_1,
                'value_caption': str(expected_age_1),
                'hidden': False,
                'label': 'Edad',
            },
        ]),
        Form.state_json('capture2', [
            {
                'name': 'age',
                'state': 'valid',
                'type': 'int',
                'value': expected_age_2,
                'value_caption': str(expected_age_2),
                'hidden': False,
                'label': 'Edad',
            },
        ]),
    ]

    assert json.loads(args) == {
        'command': 'step',
        'pointer_id': ptr.id,
        'user_identifier': '__system__',
        'input': expected_inputs,
    }

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

    state = mongo[config["EXECUTION_COLLECTION"]].find_one({
        'id': execution.id,
    })

    assert state['state']['items']['request_node'] == {
        '_type': 'node',
        'type': 'request',
        'id': 'request_node',
        'comment': '',
        'state': 'valid',
        'actors': {
            '_type': ':map',
            'items': {
                '__system__': {
                    '_type': 'actor',
                    'state': 'valid',
                    'user': {
                        '_type': 'user',
                        'fullname': 'System',
                        'identifier': '__system__',
                        'email': None,
                    },
                    'forms': expected_inputs,
                },
            },
        },
        'milestone': False,
        'name': 'Request request_node',
        'description': 'Request request_node',
    }

    values = state.pop('values')

    eval_context = make_context({'values': values}, {})
    eval_actor_map = make_actor_map({'values': values})

    expected_context = {
        '_env': [{}],
        '_execution': [{
            'name': '',
            'get_name_display': '',
            'description': '',
            'get_description_display': '',
        }],
        'capture1': [{
            'name': expected_name,
            'get_name_display': expected_name,
        }],
        'capture2': [
            {
                'age': expected_age_1,
                'get_age_display': str(expected_age_1),
            },
            {
                'age': expected_age_2,
                'get_age_display': str(expected_age_2),
            },
        ],
        'request': [{
            'data': value,
            'get_data_display': value,
        }],
        'request_node': [{
            'raw_response': request_response_s,
            'get_raw_response_display': request_response_s,
            'status_code': 200,
            'get_status_code_display': '200',
        }],
    }

    assert {k: list(v.all())
            for k, v in eval_context.items()} == expected_context

    expected_actor_map = {
        '_execution': [{
            'name': {
                'actor': '__system__',
            },
            'description': {
                'actor': '__system__',
            },
        }],
        'capture1': [{
            'name': {
                'actor': '__system__',
            },
        }],
        'capture2': [{
            'age': {
                'actor': '__system__',
            },
        }, {
            'age': {
                'actor': '__system__',
            },
        }],
        'request': [{
            'data': {
                'actor': 'juan',
            },
        }],
        'request_node': [{
            'raw_response': {
                'actor': '__system__',
            },
            'status_code': {
                'actor': '__system__',
            },
        }],
    }

    for frms in eval_actor_map.values():
        for frm in frms:
            for fld in frm.values():
                assert fld.pop('set_at')
    assert eval_actor_map == expected_actor_map
Пример #9
0
def test_wakeup(config, mongo):
    ''' the first stage in a node's lifecycle '''
    # setup stuff
    handler = Handler(config)

    pointer = make_pointer('simple.2018-02-19.xml', 'start_node')
    execution = pointer.proxy.execution.get()
    juan = User(identifier='juan').save()
    manager = User(
        identifier='juan_manager',
        email='*****@*****.**'
    ).save()

    mongo[config["EXECUTION_COLLECTION"]].insert_one({
        '_type': 'execution',
        'id': execution.id,
        'state': Xml.load(config, execution.process_name).get_state(),
        'actors': {'start_node': 'juan'},
    })

    channel = MagicMock()

    # will wakeup the second node
    handler.call({
        'command': 'step',
        'pointer_id': pointer.id,
        'user_identifier': juan.identifier,
        'input': [],
    }, channel)

    # test manager is notified
    channel.basic_publish.assert_called_once()
    channel.exchange_declare.assert_called_once()

    args = channel.basic_publish.call_args[1]

    assert args['exchange'] == config['RABBIT_NOTIFY_EXCHANGE']
    assert args['routing_key'] == 'email'
    assert json.loads(args['body']) == {
        'recipient': '*****@*****.**',
        'subject': '[procesos] Tarea asignada',
        'template': 'assigned-task.html',
        'data': {
            'pointer': Pointer.get_all()[0].to_json(
                include=['*', 'execution']
            ),
            'cacahuate_url': config['GUI_URL'],
        },
    }

    # pointer collection updated
    reg = next(mongo[config["POINTER_COLLECTION"]].find())

    assert_near_date(reg['started_at'])
    assert reg['finished_at'] is None
    assert reg['execution']['id'] == execution.id
    assert reg['node'] == {
        'id': 'mid_node',
        'type': 'action',
        'description': 'añadir información',
        'name': 'Segundo paso',
    }
    assert reg['actors'] == {
        '_type': ':map',
        'items': {},
    }
    assert reg['notified_users'] == [manager.to_json()]
    assert reg['state'] == 'ongoing'

    # execution collection updated
    reg = next(mongo[config["EXECUTION_COLLECTION"]].find())

    assert reg['state']['items']['mid_node']['state'] == 'ongoing'

    # tasks where asigned
    assert manager.proxy.tasks.count() == 1

    task = manager.proxy.tasks.get()[0]

    assert isinstance(task, Pointer)
    assert task.node_id == 'mid_node'
    assert task.proxy.execution.get().id == execution.id
Пример #10
0
def test_call_handler_delete_process(config, mongo):
    handler = Handler(config)
    channel = MagicMock()
    method = {'delivery_tag': True}
    properties = ""
    pointer = make_pointer('simple.2018-02-19.xml', 'requester')
    execution_id = pointer.proxy.execution.get().id
    body = '{"command":"cancel", "execution_id":"%s", "pointer_id":"%s"}'\
        % (execution_id, pointer.id)

    mongo[config["EXECUTION_COLLECTION"]].insert_one({
        'started_at': datetime(2018, 4, 1, 21, 45),
        'finished_at': None,
        'status': 'ongoing',
        'id': execution_id
    })

    ptr_id_1 = 'RANDOMPOINTERNAME'
    ptr_id_2 = 'MORERANDOMNAME'
    ptr_id_3 = 'NOTSORANDOMNAME'

    mongo[config["POINTER_COLLECTION"]].insert_many([
        {
            'execution': {
                'id': execution_id,
            },
            'state': 'finished',
            'id': ptr_id_1,
        },
        {
            'execution': {
                'id': execution_id,
            },
            'state': 'ongoing',
            'id': ptr_id_2,
        },
        {
            'execution': {
                'id': execution_id[::-1],
            },
            'state': 'ongoing',
            'id': ptr_id_3,
        },
    ])

    handler(channel, method, properties, body)

    reg = next(mongo[config["EXECUTION_COLLECTION"]].find())

    assert reg['id'] == execution_id
    assert reg['status'] == "cancelled"
    assert_near_date(reg['finished_at'])

    assert Execution.count() == 0
    assert Pointer.count() == 0

    assert mongo[config["POINTER_COLLECTION"]].find_one({
        'id': ptr_id_1,
    })['state'] == 'finished'
    assert mongo[config["POINTER_COLLECTION"]].find_one({
        'id': ptr_id_2,
    })['state'] == 'cancelled'
    assert mongo[config["POINTER_COLLECTION"]].find_one({
        'id': ptr_id_3,
    })['state'] == 'ongoing'
Пример #11
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',
                },
            ])
        ],
    })
Пример #12
0
def test_reject_with_dependencies(config, mongo):
    handler = Handler(config)
    user = make_user('juan', 'Juan')
    ptr = make_pointer('validation-reloaded.2018-05-17.xml', 'node1')
    channel = MagicMock()
    execution = ptr.proxy.execution.get()

    mongo[config["EXECUTION_COLLECTION"]].insert_one({
        '_type':
        'execution',
        'id':
        execution.id,
        'state':
        Xml.load(config, 'validation-reloaded').get_state(),
        'values': {
            '_execution': [{
                'name': '',
                'description': '',
            }],
        },
    })

    # first call to node1
    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('form1', [
                    {
                        'name': 'task',
                        'value': '1',
                        'value_caption': '1',
                    },
                ])
            ],
        }, channel)
    ptr = Pointer.get_all()[0]
    assert ptr.node_id == 'node2'

    # first call to node2
    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('form2', [
                    {
                        'name': 'task',
                        'value': '1',
                        'value_caption': '1',
                    },
                ])
            ],
        }, channel)
    ptr = Pointer.get_all()[0]
    assert ptr.node_id == 'node3'

    # first call to node3
    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('form3', [
                    {
                        'name': 'task',
                        'value': '1',
                        'value_caption': '1',
                    },
                ])
            ],
        }, channel)
    ptr = Pointer.get_all()[0]
    assert ptr.node_id == 'node4'

    # first call to validation
    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('node4', [
                    {
                        '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': 'node1.juan.0:form1.task',
                        }],
                        'value_caption': '',
                    },
                ])
            ],
        }, channel)
    ptr = Pointer.get_all()[0]
    assert ptr.node_id == 'node1'

    # second call to node1
    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('form1', [
                    {
                        'name': 'task',
                        'value': '2',
                        'value_caption': '2',
                    },
                ])
            ],
        }, channel)
    ptr = Pointer.get_all()[0]
    assert ptr.node_id == 'node2'

    # second call to node2
    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('form2', [
                    {
                        'name': 'task',
                        'value': '2',
                        'value_caption': '2',
                    },
                ])
            ],
        }, channel)
    ptr = Pointer.get_all()[0]
    assert ptr.node_id == 'node4'

    # second call to validation
    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('node4', [
                    {
                        'name': 'response',
                        'value': 'accept',
                        'value_caption': 'accept',
                    },
                    {
                        'name': 'comment',
                        'value': 'I like it',
                        'value_caption': 'I like it',
                    },
                    {
                        'name': 'inputs',
                        'value': None,
                        'value_caption': 'None',
                    },
                ])
            ],
        }, channel)
    ptr = Pointer.get_all()[0]
    assert ptr.node_id == 'node5'

    # first call to last node
    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('form5', [
                    {
                        'name': 'task',
                        'value': '1',
                        'value_caption': '1',
                    },
                ])
            ],
        }, channel)
    assert Pointer.get_all() == []

    # state is coherent
    state = next(mongo[config["EXECUTION_COLLECTION"]].find({
        'id': execution.id,
    }))

    del state['_id']
    del state['finished_at']

    assert state == {
        '_type':
        'execution',
        'id':
        execution.id,
        'name':
        '',
        'description':
        '',
        'state': {
            '_type': ':sorted_map',
            'items': {
                'node1': {
                    '_type': 'node',
                    'type': 'action',
                    'id': 'node1',
                    'state': 'valid',
                    'comment': 'I do not like it',
                    'actors': {
                        '_type': ':map',
                        'items': {
                            'juan': {
                                '_type':
                                'actor',
                                'forms': [
                                    Form.state_json('form1', [
                                        {
                                            'name': 'task',
                                            'value': '2',
                                            'value_caption': '2',
                                        },
                                    ])
                                ],
                                'state':
                                'valid',
                                'user': {
                                    '_type': 'user',
                                    'identifier': 'juan',
                                    'fullname': 'Juan',
                                },
                            },
                        },
                    },
                    'milestone': False,
                    'name': 'Primer paso',
                    'description': 'información original',
                },
                'node2': {
                    '_type': 'node',
                    'type': 'action',
                    'id': 'node2',
                    'state': 'valid',
                    'comment': 'I do not like it',
                    'actors': {
                        '_type': ':map',
                        'items': {
                            'juan': {
                                '_type':
                                'actor',
                                'forms': [
                                    Form.state_json('form2', [
                                        {
                                            'name': 'task',
                                            'value': '2',
                                            'value_caption': '2',
                                        },
                                    ])
                                ],
                                'state':
                                'valid',
                                'user': {
                                    '_type': 'user',
                                    'identifier': 'juan',
                                    'fullname': 'Juan',
                                },
                            },
                        },
                    },
                    'milestone': False,
                    'name': 'Segundo paso',
                    'description': 'depender de la info',
                },
                'node3': {
                    '_type': 'node',
                    'type': 'action',
                    'id': 'node3',
                    'state': 'valid',
                    'comment': '',
                    'actors': {
                        '_type': ':map',
                        'items': {
                            'juan': {
                                '_type':
                                'actor',
                                'forms': [
                                    Form.state_json('form3', [
                                        {
                                            'name': 'task',
                                            'value': '1',
                                            'value_caption': '1',
                                        },
                                    ])
                                ],
                                'state':
                                'valid',
                                'user': {
                                    '_type': 'user',
                                    'identifier': 'juan',
                                    'fullname': 'Juan',
                                },
                            },
                        },
                    },
                    'milestone': False,
                    'name': 'Tercer paso',
                    'description': 'no depender de nada',
                },
                'node4': {
                    '_type': 'node',
                    'type': 'validation',
                    'id': 'node4',
                    'state': 'valid',
                    'comment': 'I do not like it',
                    'actors': {
                        '_type': ':map',
                        'items': {
                            'juan': {
                                '_type':
                                'actor',
                                'forms': [
                                    Form.state_json('node4', [
                                        {
                                            'name': 'response',
                                            'value': 'accept',
                                            'value_caption': 'accept',
                                        },
                                        {
                                            'name': 'comment',
                                            'value': 'I like it',
                                            'value_caption': 'I like it',
                                        },
                                        {
                                            'name': 'inputs',
                                            'value': None,
                                            'value_caption': 'None',
                                        },
                                    ])
                                ],
                                'state':
                                'valid',
                                'user': {
                                    '_type': 'user',
                                    'identifier': 'juan',
                                    'fullname': 'Juan',
                                },
                            },
                        },
                    },
                    'milestone': False,
                    'name': 'Cuarto paso',
                    'description': 'validar',
                },
                'node5': {
                    '_type': 'node',
                    'type': 'action',
                    'id': 'node5',
                    'state': 'valid',
                    'comment': '',
                    'actors': {
                        '_type': ':map',
                        'items': {
                            'juan': {
                                '_type':
                                'actor',
                                'forms': [
                                    Form.state_json('form5', [
                                        {
                                            'name': 'task',
                                            'value': '1',
                                            'value_caption': '1',
                                        },
                                    ])
                                ],
                                'state':
                                'valid',
                                'user': {
                                    '_type': 'user',
                                    'identifier': 'juan',
                                    'fullname': 'Juan',
                                },
                            },
                        },
                    },
                    'milestone': False,
                    'name': 'Quinto paso',
                    'description': 'terminar',
                },
            },
            'item_order': ['node1', 'node2', 'node3', 'node4', 'node5'],
        },
        'status':
        'finished',
        'values': {
            '_execution': [{
                'name': '',
                'description': '',
            }],
            'node4': [{
                'comment': 'I like it',
                'inputs': None,
                'response': 'accept',
            }],
            'form1': [{
                'task': '2'
            }],
            'form2': [{
                'task': '2'
            }],
            'form3': [{
                'task': '1'
            }],
            'form5': [{
                'task': '1'
            }],
        },
        'actors': {
            'node1': 'juan',
            'node2': 'juan',
            'node3': 'juan',
            'node4': 'juan',
            'node5': 'juan',
        },
        'actor_list': [
            {
                'node': 'node1',
                'identifier': 'juan',
            },
            {
                'node': 'node2',
                'identifier': 'juan',
            },
            {
                'node': 'node3',
                'identifier': 'juan',
            },
            {
                'node': 'node4',
                'identifier': 'juan',
            },
            {
                'node': 'node5',
                'identifier': 'juan',
            },
        ],
    }
Пример #13
0
def test_approve(config, mongo):
    ''' tests that a validation node can go forward on approval '''
    # test setup
    handler = Handler(config)
    user = make_user('juan', 'Juan')
    ptr = make_pointer('validation.2018-05-09.xml', 'approval_node')
    channel = MagicMock()

    mongo[config["POINTER_COLLECTION"]].insert_one({
        'id':
        ptr.id,
        'started_at':
        datetime(2018, 4, 1, 21, 45),
        'finished_at':
        None,
        'execution': {
            'id': ptr.proxy.execution.get().id,
        },
        'node': {
            'id': 'approval_node',
        },
        'actors': {
            '_type': ':map',
            'items': {},
        },
    })

    mongo[config["EXECUTION_COLLECTION"]].insert_one({
        '_type':
        'execution',
        'id':
        ptr.proxy.execution.get().id,
        'state':
        Xml.load(config, 'validation.2018-05-09').get_state(),
        'actors': {
            'start_node': 'juan',
        },
        'values': {
            '_execution': [{
                'name': '',
                'description': '',
            }],
        },
    })

    # thing to test
    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('approval_node', [
                    {
                        'name': 'response',
                        'value': 'accept',
                        'value_caption': 'accept',
                    },
                    {
                        'name': 'comment',
                        'value': 'I like it',
                        'value_caption': 'I like it',
                    },
                    {
                        'name': 'inputs',
                        'value': [{
                            'ref': 'start_node.juan.0.task',
                        }],
                        'value_caption': '',
                    },
                ])
            ],
        }, channel)

    # assertions
    assert Pointer.get(ptr.id) is None

    new_ptr = Pointer.get_all()[0]
    assert new_ptr.node_id == 'final_node'

    reg = next(mongo[config["POINTER_COLLECTION"]].find())

    assert reg['started_at'] == datetime(2018, 4, 1, 21, 45)
    assert_near_date(reg['finished_at'])
    assert reg['execution']['id'] == ptr.execution
    assert reg['node']['id'] == 'approval_node'
    assert reg['actors'] == {
        '_type': ':map',
        'items': {
            'juan': {
                '_type':
                'actor',
                'state':
                'valid',
                'user': {
                    '_type': 'user',
                    'identifier': 'juan',
                    'fullname': 'Juan',
                },
                'forms': [
                    Form.state_json('approval_node', [
                        {
                            'name': 'response',
                            'name': 'response',
                            'value': 'accept',
                            'value_caption': 'accept',
                        },
                        {
                            'name': 'comment',
                            'name': 'comment',
                            'value': 'I like it',
                            'value_caption': 'I like it',
                        },
                        {
                            'name': 'inputs',
                            'name': 'inputs',
                            'value': [{
                                'ref': 'start_node.juan.0.task',
                            }],
                            'value_caption': '',
                        },
                    ])
                ],
            },
        },
    }
Пример #14
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)
Пример #15
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
Пример #16
0
def test_reject_with_dependencies(config, mongo):
    handler = Handler(config)
    user = make_user('juan', 'Juan')
    ptr = make_pointer('validation-reloaded.2018-05-17.xml', 'node1')
    execution = ptr.execution.get()
    execution.started_at = datetime(2018, 4, 1, 21, 45)
    execution.save()

    mongo[config["EXECUTION_COLLECTION"]].insert_one({
        '_type': 'execution',
        'id': execution.id,
        'state': Xml.load(config, 'validation-reloaded').get_state(),
        'values': [
            {
                '_type': 'fgroup',
                'ref': '_execution',
                'forms': [{
                    'ref': '_execution',
                    'fields': [
                        {
                            '_type': 'field',
                            'name': 'name',
                            'value': '',
                            'value_caption': '',
                            'state': 'valid',
                            'actor': {
                                'identifier': '__system__',
                            },
                            'set_at': execution.started_at,
                        },
                        {
                            '_type': 'field',
                            'name': 'description',
                            'value': '',
                            'value_caption': '',
                            'state': 'valid',
                            'actor': {
                                'identifier': '__system__',
                            },
                            'set_at': execution.started_at,
                        },
                    ],
                }],
            },
        ],
    })

    # first call to node1
    handler.step({
        'command': 'step',
        'pointer_id': ptr.id,
        'user_identifier': user.identifier,
        'input': [Form.state_json('form1', [
            {
                'name': 'task',
                'value': '1',
                'value_caption': '1',
                'state': 'valid',
            },
        ])],
    })
    ptr = next(Pointer.q().filter(status='ongoing'))
    assert ptr.node_id == 'node2'

    # first call to node2
    handler.step({
        'command': 'step',
        'pointer_id': ptr.id,
        'user_identifier': user.identifier,
        'input': [Form.state_json('form2', [
            {
                'name': 'task',
                'value': '1',
                'value_caption': '1',
                'state': 'valid',
            },
        ])],
    })
    ptr = next(Pointer.q().filter(status='ongoing'))
    assert ptr.node_id == 'node3'

    # first call to node3
    handler.step({
        'command': 'step',
        'pointer_id': ptr.id,
        'user_identifier': user.identifier,
        'input': [Form.state_json('form3', [
            {
                'name': 'task',
                'value': '1',
                'value_caption': '1',
                'state': 'valid',
            },
        ])],
    })
    ptr = next(Pointer.q().filter(status='ongoing'))
    assert ptr.node_id == 'node4'

    # first call to validation
    handler.step({
        'command': 'step',
        'pointer_id': ptr.id,
        'user_identifier': user.identifier,
        'input': [Form.state_json('node4', [
            {
                'name': 'response',
                'value': 'reject',
                'value_caption': 'reject',
                'state': 'valid',
            },
            {
                'name': 'comment',
                'value': 'I do not like it',
                'value_caption': 'I do not like it',
                'state': 'valid',
            },
            {
                'name': 'inputs',
                'value': [{
                    'ref': 'node1.juan.0:form1.task',
                }],
                'value_caption': '',
                'state': 'valid',
            },
        ])],
    })
    ptr = next(Pointer.q().filter(status='ongoing'))
    assert ptr.node_id == 'node1'

    # second call to node1
    handler.step({
        'command': 'step',
        'pointer_id': ptr.id,
        'user_identifier': user.identifier,
        'input': [Form.state_json('form1', [
            {
                'name': 'task',
                'value': '2',
                'value_caption': '2',
                'state': 'valid',
            },
        ])],
    })
    ptr = next(Pointer.q().filter(status='ongoing'))
    assert ptr.node_id == 'node2'

    # second call to node2
    handler.step({
        'command': 'step',
        'pointer_id': ptr.id,
        'user_identifier': user.identifier,
        'input': [Form.state_json('form2', [
            {
                'name': 'task',
                'value': '2',
                'value_caption': '2',
                'state': 'valid',
            },
        ])],
    })
    ptr = next(Pointer.q().filter(status='ongoing'))
    assert ptr.node_id == 'node4'

    # second call to validation
    handler.step({
        'command': 'step',
        'pointer_id': ptr.id,
        'user_identifier': user.identifier,
        'input': [Form.state_json('node4', [
            {
                'name': 'response',
                'value': 'accept',
                'value_caption': 'accept',
                'state': 'valid',
            },
            {
                'name': 'comment',
                'value': 'I like it',
                'value_caption': 'I like it',
                'state': 'valid',
            },
            {
                'name': 'inputs',
                'value': None,
                'value_caption': 'None',
                'state': 'valid',
            },
        ])],
    })
    ptr = next(Pointer.q().filter(status='ongoing'))
    assert ptr.node_id == 'node5'

    # first call to last node
    handler.step({
        'command': 'step',
        'pointer_id': ptr.id,
        'user_identifier': user.identifier,
        'input': [Form.state_json('form5', [
            {
                'name': 'task',
                'value': '1',
                'value_caption': '1',
                'state': 'valid',
            },
        ])],
    })
    assert list(Pointer.q().filter(status='ongoing')) == []

    # state is coherent
    state = next(mongo[config["EXECUTION_COLLECTION"]].find({
        'id': execution.id,
    }))

    del state['_id']
    del state['finished_at']

    values = state.pop('values')

    assert state == {
        '_type': 'execution',
        'id': execution.id,
        'name': '',
        'description': '',
        'state': {
            '_type': ':sorted_map',
            'items': {
                'node1': {
                    '_type': 'node',
                    'type': 'action',
                    'id': 'node1',
                    'state': 'valid',
                    'comment': 'I do not like it',
                    'actors': {
                        '_type': ':map',
                        'items': {
                            'juan': {
                                '_type': 'actor',
                                'forms': [Form.state_json('form1', [
                                    {
                                        'name': 'task',
                                        'value': '2',
                                        'value_caption': '2',
                                        'state': 'valid',
                                    },
                                ])],
                                'state': 'valid',
                                'user': {
                                    '_type': 'user',
                                    'identifier': 'juan',
                                    'fullname': 'Juan',
                                    'email': None,
                                },
                            },
                        },
                    },
                    'milestone': False,
                    'name': 'Primer paso',
                    'description': 'información original',
                },

                'node2': {
                    '_type': 'node',
                    'type': 'action',
                    'id': 'node2',
                    'state': 'valid',
                    'comment': 'I do not like it',
                    'actors': {
                        '_type': ':map',
                        'items': {
                            'juan': {
                                '_type': 'actor',
                                'forms': [Form.state_json('form2', [
                                    {
                                        'name': 'task',
                                        'value': '2',
                                        'value_caption': '2',
                                        'state': 'valid',
                                    },
                                ])],
                                'state': 'valid',
                                'user': {
                                    '_type': 'user',
                                    'identifier': 'juan',
                                    'fullname': 'Juan',
                                    'email': None,
                                },
                            },
                        },
                    },
                    'milestone': False,
                    'name': 'Segundo paso',
                    'description': 'depender de la info',
                },

                'node3': {
                    '_type': 'node',
                    'type': 'action',
                    'id': 'node3',
                    'state': 'valid',
                    'comment': '',
                    'actors': {
                        '_type': ':map',
                        'items': {
                            'juan': {
                                '_type': 'actor',
                                'forms': [Form.state_json('form3', [
                                    {
                                        'name': 'task',
                                        'value': '1',
                                        'value_caption': '1',
                                        'state': 'valid',
                                    },
                                ])],
                                'state': 'valid',
                                'user': {
                                    '_type': 'user',
                                    'identifier': 'juan',
                                    'fullname': 'Juan',
                                    'email': None,
                                },
                            },
                        },
                    },
                    'milestone': False,
                    'name': 'Tercer paso',
                    'description': 'no depender de nada',
                },

                'node4': {
                    '_type': 'node',
                    'type': 'validation',
                    'id': 'node4',
                    'state': 'valid',
                    'comment': 'I do not like it',
                    'actors': {
                        '_type': ':map',
                        'items': {
                            'juan': {
                                '_type': 'actor',
                                'forms': [Form.state_json('node4', [
                                    {
                                        'name': 'response',
                                        'value': 'accept',
                                        'value_caption': 'accept',
                                        'state': 'valid',
                                    },
                                    {
                                        'name': 'comment',
                                        'value': 'I like it',
                                        'value_caption': 'I like it',
                                        'state': 'valid',
                                    },
                                    {
                                        'name': 'inputs',
                                        'value': None,
                                        'value_caption': 'None',
                                        'state': 'valid',
                                    },
                                ])],
                                'state': 'valid',
                                'user': {
                                    '_type': 'user',
                                    'identifier': 'juan',
                                    'fullname': 'Juan',
                                    'email': None,
                                },
                            },
                        },
                    },
                    'milestone': False,
                    'name': 'Cuarto paso',
                    'description': 'validar',
                },

                'node5': {
                    '_type': 'node',
                    'type': 'action',
                    'id': 'node5',
                    'state': 'valid',
                    'comment': '',
                    'actors': {
                        '_type': ':map',
                        'items': {
                            'juan': {
                                '_type': 'actor',
                                'forms': [Form.state_json('form5', [
                                    {
                                        'name': 'task',
                                        'value': '1',
                                        'value_caption': '1',
                                        'state': 'valid',
                                    },
                                ])],
                                'state': 'valid',
                                'user': {
                                    '_type': 'user',
                                    'identifier': 'juan',
                                    'fullname': 'Juan',
                                    'email': None,
                                },
                            },
                        },
                    },
                    'milestone': False,
                    'name': 'Quinto paso',
                    'description': 'terminar',
                },
            },
            'item_order': ['node1', 'node2', 'node3', 'node4', 'node5'],
        },
        'status': 'finished',
        'actors': {
            'node1': 'juan',
            'node2': 'juan',
            'node3': 'juan',
            'node4': 'juan',
            'node5': 'juan',
        },
    }

    eval_context = make_context({'values': values}, {})
    eval_actor_map = make_actor_map({'values': values})

    expected_context = {
        '_env': [{}],
        '_execution': [{
            'name': '',
            'get_name_display': '',
            'description': '',
            'get_description_display': '',
        }],
        'node4': [{
            'comment': 'I like it',
            'get_comment_display': 'I like it',
            'inputs': None,
            'get_inputs_display': 'None',
            'response': 'accept',
            'get_response_display': 'accept',
        }],
        'form1': [{
            'task': '2',
            'get_task_display': '2',
        }],
        'form2': [{
            'task': '2',
            'get_task_display': '2',
        }],
        'form3': [{
            'task': '1',
            'get_task_display': '1',
        }],
        'form5': [{
            'task': '1',
            'get_task_display': '1',
        }],
    }

    assert {
        k: list(v.all()) for k, v in eval_context.items()
    } == expected_context

    expected_actor_map = {
        '_execution': [
            {
                'name': {
                    'actor': '__system__',
                },
                'description': {
                    'actor': '__system__',
                },
            }
        ],
        'node4': [
            {
                'comment': {
                    'actor': 'juan',
                },
                'response': {
                    'actor': 'juan',
                },
                'inputs': {
                    'actor': 'juan',
                },
            }
        ],
        'form1': [
            {
                'task': {
                    'actor': 'juan',
                },
            },
        ],
        'form2': [
            {
                'task': {
                    'actor': 'juan',
                },
            },
        ],
        'form3': [
            {
                'task': {
                    'actor': 'juan',
                },
            },
        ],
        'form5': [
            {
                'task': {
                    'actor': 'juan',
                },
            },
        ],
    }

    for frms in eval_actor_map.values():
        for frm in frms:
            for fld in frm.values():
                assert fld.pop('set_at')
    assert eval_actor_map == expected_actor_map
Пример #17
0
def test_reject(config, mongo):
    ''' tests that a rejection moves the pointer to a backward position '''
    # test setup
    handler = Handler(config)
    user = make_user('juan', 'Juan')
    ptr = make_pointer('validation.2018-05-09.xml', 'approval_node')
    execution = ptr.execution.get()
    execution.started_at = datetime(2018, 4, 1, 21, 45)
    execution.save()

    mongo[config["POINTER_COLLECTION"]].insert_one({
        'id': ptr.id,
        'started_at': datetime(2018, 4, 1, 21, 45),
        'finished_at': None,
        'execution': {
            'id': execution.id,
        },
        'node': {
            'id': 'approval_node',
        },
        'actors': {
            '_type': ':map',
            'items': {},
        },
        'actor_list': [],
    })

    state = Xml.load(config, 'validation.2018-05-09').get_state()

    state['items']['start_node']['state'] = 'valid'
    state['items']['start_node']['actors']['items']['juan'] = {
        '_type': 'actor',
        'state': 'valid',
        'user': {
            '_type': 'user',
            'identifier': 'juan',
            'fullname': 'Juan',
            'email': None,
        },
        'forms': [Form.state_json('work', [
            {
                'name': 'task',
                '_type': 'field',
                'state': 'valid',
                'value': '2',
            },
        ])],
    }

    mongo[config["EXECUTION_COLLECTION"]].insert_one({
        '_type': 'execution',
        'id': execution.id,
        'state': state,
        'values': [
            {
                '_type': 'fgroup',
                'ref': '_execution',
                'forms': [{
                    'ref': '_execution',
                    'fields': [
                        {
                            '_type': 'field',
                            'name': 'name',
                            'value': '',
                            'value_caption': '',
                            'state': 'valid',
                            'actor': {
                                'identifier': '__system__',
                            },
                            'set_at': execution.started_at,
                        },
                        {
                            '_type': 'field',
                            'name': 'description',
                            'value': '',
                            'value_caption': '',
                            'state': 'valid',
                            'actor': {
                                'identifier': '__system__',
                            },
                            'set_at': execution.started_at,
                        },
                    ],
                }],
            },
            {
                '_type': 'fgroup',
                'ref': 'work',
                'forms': [{
                    'ref': 'work',
                    'fields': [
                        {
                            '_type': 'field',
                            'name': 'task',
                            'value': '',
                            'value_caption': '',
                            'state': 'valid',
                            'actor': {
                                'identifier': 'juan',
                            },
                            'set_at': execution.started_at,
                        },
                    ],
                }],
            },
        ],
    })

    # will teardown the approval node
    handler.step({
        'command': 'step',
        'pointer_id': ptr.id,
        'user_identifier': user.identifier,
        'input': [Form.state_json('approval_node', [
            {
                'name': 'response',
                'value': 'reject',
                'value_caption': 'reject',
                'state': 'valid',
            },
            {
                'name': 'comment',
                'value': 'I do not like it',
                'value_caption': 'I do not like it',
                'state': 'valid',
            },
            {
                'name': 'inputs',
                'value': [{
                    'ref': 'start_node.juan.0:work.task',
                }],
                'value_caption': '',
                'state': 'valid',
            },
        ])],
    })

    # assertions
    assert Pointer.get(ptr.id).status == 'finished'

    new_ptr = next(Pointer.q().filter(status='ongoing'))
    assert new_ptr.node_id == 'start_node'

    assert new_ptr in user.tasks

    # data is invalidated
    state = next(mongo[config["EXECUTION_COLLECTION"]].find({
        'id': execution.id,
    }))

    del state['_id']

    values = state.pop('values')

    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': 'I do not like it',
                    'actors': {
                        '_type': ':map',
                        'items': {
                            'juan': {
                                '_type': 'actor',
                                'forms': [Form.state_json('work', [
                                    {
                                        'name': 'task',
                                        '_type': 'field',
                                        'state': 'invalid',
                                        'value': '2',
                                    },
                                ], state='invalid')],
                                'state': 'invalid',
                                'user': {
                                    '_type': 'user',
                                    'identifier': 'juan',
                                    'fullname': 'Juan',
                                    'email': None,
                                },
                            },
                        },
                    },
                    'milestone': False,
                    'name': 'Primer paso',
                    'description': 'Resolver una tarea',
                },

                'approval_node': {
                    '_type': 'node',
                    'type': 'validation',
                    'id': 'approval_node',
                    'state': 'invalid',
                    'comment': 'I do not like it',
                    'actors': {
                        '_type': ':map',
                        'items': {
                            'juan': {
                                '_type': 'actor',
                                'forms': [Form.state_json('approval_node', [
                                    {
                                        'name': 'response',
                                        'state': 'invalid',
                                        'value': 'reject',
                                        'value_caption': 'reject',
                                    },
                                    {
                                        'name': 'comment',
                                        'value': 'I do not like it',
                                        'value_caption': 'I do not like it',
                                        'state': 'valid',
                                    },
                                    {
                                        'name': 'inputs',
                                        'value': [{
                                            'ref': 'start_node.'
                                                   'juan.0:work.task',
                                        }],
                                        'value_caption': '',
                                        'state': 'valid',
                                    },
                                ], state='invalid')],
                                'state': 'invalid',
                                'user': {
                                    '_type': 'user',
                                    'identifier': 'juan',
                                    'fullname': 'Juan',
                                    'email': None,
                                },
                            },
                        },
                    },
                    'milestone': False,
                    'name': 'Aprobación gerente reserva',
                    'description': 'aprobar reserva',
                },

                'final_node': {
                    '_type': 'node',
                    'type': 'action',
                    'id': 'final_node',
                    'state': 'unfilled',
                    'comment': '',
                    'actors': {
                        '_type': ':map',
                        'items': {},
                    },
                    'milestone': False,
                    'name': '',
                    'description': '',
                },
            },
            'item_order': ['start_node', 'approval_node', 'final_node'],
        },
        'actors': {
            'approval_node': 'juan',
        },
    }

    eval_context = make_context({'values': values}, {})
    eval_actor_map = make_actor_map({'values': values})

    expected_context = {
        '_env': [{}],
        '_execution': [{
            'name': '',
            'get_name_display': '',
            'description': '',
            'get_description_display': '',
        }],
        'work': [{}],
        'approval_node': [{
            'comment': 'I do not like it',
            'get_comment_display': 'I do not like it',
            'response': 'reject',
            'get_response_display': 'reject',
            'inputs': [{'ref': 'start_node.juan.0:work.task'}],
            'get_inputs_display': [{'ref': 'start_node.juan.0:work.task'}],
        }],
    }

    assert {
        k: list(v.all()) for k, v in eval_context.items()
    } == expected_context

    expected_actor_map = {
        '_execution': [
            {
                'name': {
                    'actor': '__system__',
                },
                'description': {
                    'actor': '__system__',
                },
            }
        ],
        'work': [{}],
        'approval_node': [
            {
                'comment': {
                    'actor': 'juan',
                },
                'response': {
                    'actor': 'juan',
                },
                'inputs': {
                    'actor': 'juan',
                },
            }
        ],
    }

    for frms in eval_actor_map.values():
        for frm in frms:
            for fld in frm.values():
                assert fld.pop('set_at')
    assert eval_actor_map == expected_actor_map

    # mongo has the data
    reg = next(mongo[config["POINTER_COLLECTION"]].find())

    assert reg['started_at'] == datetime(2018, 4, 1, 21, 45)
    assert (reg['finished_at'] - datetime.now()).total_seconds() < 2
    assert reg['execution']['id'] == new_ptr.execution.get().id
    assert reg['node']['id'] == 'approval_node'
    assert reg['actor_list'] == [
        {
            'form': 'approval_node',
            'actor': {
                '_type': 'user',
                'fullname': 'Juan',
                'identifier': 'juan',
                'email': None,
            },
        },
    ]
    assert reg['actors'] == {
        '_type': ':map',
        'items': {
            'juan': {
                '_type': 'actor',
                'forms': [Form.state_json('approval_node', [
                    {
                        'name': 'response',
                        'value': 'reject',
                        'value_caption': 'reject',
                        'state': 'valid',
                    },
                    {
                        'name': 'comment',
                        'value': 'I do not like it',
                        'value_caption': 'I do not like it',
                        'state': 'valid',
                    },
                    {
                        'name': 'inputs',
                        'value': [{
                            'ref': 'start_node.juan.0:work.task',
                        }],
                        'value_caption': '',
                        'state': 'valid',
                    },
                ])],
                'state': 'valid',
                'user': {
                    '_type': 'user',
                    'identifier': 'juan',
                    'fullname': 'Juan',
                    'email': None,
                },
            },
        },
    }
Пример #18
0
def test_approve(config, mongo):
    ''' tests that a validation node can go forward on approval '''
    # test setup
    handler = Handler(config)
    user = make_user('juan', 'Juan')
    ptr = make_pointer('validation.2018-05-09.xml', 'approval_node')

    mongo[config["POINTER_COLLECTION"]].insert_one({
        'id': ptr.id,
        'started_at': datetime(2018, 4, 1, 21, 45),
        'finished_at': None,
        'execution': {
            'id': ptr.execution.get().id,
        },
        'node': {
            'id': 'approval_node',
        },
        'actors': {
            '_type': ':map',
            'items': {},
        },
        'actor_list': [],
    })

    execution = ptr.execution.get()
    execution.started_at = datetime(2018, 4, 1, 21, 45)
    execution.save()

    mongo[config["EXECUTION_COLLECTION"]].insert_one({
        '_type': 'execution',
        'id': execution.id,
        'state': Xml.load(config, 'validation.2018-05-09').get_state(),
        'actors': {
            'start_node': 'juan',
        },
        'values': [
            {
                '_type': 'fgroup',
                'ref': '_execution',
                'forms': [{
                    'ref': '_execution',
                    'fields': [
                        {
                            '_type': 'field',
                            'name': 'name',
                            'value': '',
                            'value_caption': '',
                            'state': 'valid',
                            'actor': {
                                'identifier': '__system__',
                            },
                            'set_at': execution.started_at,
                        },
                        {
                            '_type': 'field',
                            'name': 'description',
                            'value': '',
                            'value_caption': '',
                            'state': 'valid',
                            'actor': {
                                'identifier': '__system__',
                            },
                            'set_at': execution.started_at,
                        },
                    ],
                }],
            },
            {
                '_type': 'fgroup',
                'ref': 'work',
                'forms': [{
                    'ref': 'work',
                    'fields': [
                        {
                            '_type': 'field',
                            'name': 'task',
                            'value': '',
                            'value_caption': '',
                            'state': 'valid',
                            'actor': {
                                'identifier': 'juan',
                            },
                            'set_at': execution.started_at,
                        },
                    ],
                }],
            },
        ],
    })

    # thing to test
    handler.step({
        'command': 'step',
        'pointer_id': ptr.id,
        'user_identifier': user.identifier,
        'input': [Form.state_json('approval_node', [
            {
                'name': 'response',
                'value': 'accept',
                'value_caption': 'accept',
                'state': 'valid',
            },
            {
                'name': 'comment',
                'value': 'I like it',
                'value_caption': 'I like it',
                'state': 'valid',
            },
            {
                'name': 'inputs',
                'value': [{
                    'ref': 'start_node.juan.0.task',
                }],
                'value_caption': '',
                'state': 'valid',
            },
        ])],
    })

    # assertions
    assert Pointer.get(ptr.id).status == 'finished'

    new_ptr = next(Pointer.q().filter(status='ongoing'))
    assert new_ptr.node_id == 'final_node'

    reg = next(mongo[config["POINTER_COLLECTION"]].find())

    assert reg['started_at'] == datetime(2018, 4, 1, 21, 45)
    assert_near_date(reg['finished_at'])
    assert reg['execution']['id'] == new_ptr.execution.get().id
    assert reg['node']['id'] == 'approval_node'
    assert reg['actor_list'] == [
        {
            'form': 'approval_node',
            'actor': {
                '_type': 'user',
                'fullname': 'Juan',
                'identifier': 'juan',
                'email': None,
            },
        },
    ]
    assert reg['actors'] == {
        '_type': ':map',
        'items': {
            'juan': {
                '_type': 'actor',
                'state': 'valid',
                'user': {
                    '_type': 'user',
                    'identifier': 'juan',
                    'fullname': 'Juan',
                    'email': None,
                },
                'forms': [Form.state_json('approval_node', [
                    {
                        'name': 'response',
                        'name': 'response',
                        'value': 'accept',
                        'value_caption': 'accept',
                        'state': 'valid',
                    },
                    {
                        'name': 'comment',
                        'name': 'comment',
                        'value': 'I like it',
                        'value_caption': 'I like it',
                        'state': 'valid',
                    },
                    {
                        'name': 'inputs',
                        'name': 'inputs',
                        'value': [{
                            'ref': 'start_node.juan.0.task',
                        }],
                        'value_caption': '',
                        'state': 'valid',
                    },
                ])],
            },
        },
    }

    # data is invalidated
    state = next(mongo[config["EXECUTION_COLLECTION"]].find({
        'id': ptr.execution.get().id,
    }))

    del state['_id']

    values = state.pop('values')

    eval_context = make_context({'values': values}, {})
    eval_actor_map = make_actor_map({'values': values})

    expected_context = {
        '_env': [{}],
        '_execution': [{
            'name': '',
            'get_name_display': '',
            'description': '',
            'get_description_display': '',
        }],
        'work': [{
            'task': '',
            'get_task_display': '',
        }],
        'approval_node': [{
            'comment': 'I like it',
            'get_comment_display': 'I like it',
            'response': 'accept',
            'get_response_display': 'accept',
            'inputs': [{'ref': 'start_node.juan.0.task'}],
            'get_inputs_display': [{'ref': 'start_node.juan.0.task'}],
        }],
    }

    assert {
        k: list(v.all()) for k, v in eval_context.items()
    } == expected_context

    expected_actor_map = {
        '_execution': [
            {
                'name': {
                    'actor': '__system__',
                },
                'description': {
                    'actor': '__system__',
                },
            }
        ],
        'work': [
            {
                'task': {
                    'actor': 'juan',
                },
            },
        ],
        'approval_node': [
            {
                'comment': {
                    'actor': 'juan',
                },
                'response': {
                    'actor': 'juan',
                },
                'inputs': {
                    'actor': 'juan',
                },
            }
        ],
    }

    for frms in eval_actor_map.values():
        for frm in frms:
            for fld in frm.values():
                assert fld.pop('set_at')
    assert eval_actor_map == expected_actor_map
Пример #19
0
def test_store_data_from_response(config, mocker, mongo):
    expected_name = random_string()
    expected_age_1 = randint(0, 100)
    expected_age_2 = randint(0, 100)

    request_response = {
        'params': {
            'name': expected_name,
        },
        'items': [
            [
                {
                    'age': expected_age_1,
                },
                {
                    'age': expected_age_2,
                },
            ],
        ],
    }
    request_response_s = json.dumps(request_response)

    class ResponseMock:
        status_code = 200
        text = request_response_s

        def json(self):
            return request_response

    mock = MagicMock(return_value=ResponseMock())

    mocker.patch('requests.request', new=mock)

    handler = Handler(config)
    user = make_user('juan', 'Juan')
    ptr = make_pointer('request-captures.2019-08-08.xml', 'start_node')
    channel = MagicMock()
    execution = ptr.proxy.execution.get()
    value = random_string()

    mongo[config["EXECUTION_COLLECTION"]].insert_one({
        '_type':
        'execution',
        'id':
        execution.id,
        'state':
        Xml.load(config, 'request-captures').get_state(),
        'values': {
            '_execution': [{
                'name': '',
                'description': '',
            }],
        }
    })

    # teardown of first node and wakeup of request node
    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('request', [
                    {
                        'name': 'data',
                        'value': value,
                        'value_caption': value,
                    },
                ])
            ],
        }, channel)
    assert Pointer.get(ptr.id) is None
    ptr = execution.proxy.pointers.get()[0]
    assert ptr.node_id == 'request_node'

    # assert requests is called
    requests.request.assert_called_once()
    args, kwargs = requests.request.call_args

    assert args[0] == 'GET'
    assert args[1] == 'http://localhost/'

    assert kwargs['data'] == ''
    assert kwargs['headers'] == {
        'content-type': 'application/json',
    }

    # aditional rabbit call for new process
    args = channel.basic_publish.call_args_list[0][1]

    expected_inputs = [
        Form.state_json('request_node', [
            {
                'name': 'status_code',
                'state': 'valid',
                'type': 'int',
                'value': 200,
                'value_caption': '200',
                'hidden': False,
                'label': 'Status Code',
            },
            {
                'name': 'raw_response',
                'state': 'valid',
                'type': 'text',
                'value': request_response_s,
                'value_caption': request_response_s,
                'hidden': False,
                'label': 'Response',
            },
        ]),
        Form.state_json('capture1', [
            {
                'name': 'name',
                'state': 'valid',
                'type': 'text',
                'value': expected_name,
                'value_caption': expected_name,
                'hidden': False,
                'label': 'Nombre',
            },
        ]),
        Form.state_json('capture2', [
            {
                'name': 'age',
                'state': 'valid',
                'type': 'int',
                'value': expected_age_1,
                'value_caption': str(expected_age_1),
                'hidden': False,
                'label': 'Edad',
            },
        ]),
        Form.state_json('capture2', [
            {
                'name': 'age',
                'state': 'valid',
                'type': 'int',
                'value': expected_age_2,
                'value_caption': str(expected_age_2),
                'hidden': False,
                'label': 'Edad',
            },
        ]),
    ]

    assert args['exchange'] == ''
    assert args['routing_key'] == config['RABBIT_QUEUE']
    assert json.loads(args['body']) == {
        'command': 'step',
        'pointer_id': ptr.id,
        'user_identifier': '__system__',
        'input': expected_inputs,
    }

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

    state = mongo[config["EXECUTION_COLLECTION"]].find_one({
        'id': execution.id,
    })

    assert state['state']['items']['request_node'] == {
        '_type': 'node',
        'type': 'request',
        'id': 'request_node',
        'comment': '',
        'state': 'valid',
        'actors': {
            '_type': ':map',
            'items': {
                '__system__': {
                    '_type': 'actor',
                    'state': 'valid',
                    'user': {
                        '_type': 'user',
                        'fullname': 'System',
                        'identifier': '__system__',
                    },
                    'forms': expected_inputs,
                },
            },
        },
        'milestone': False,
        'name': 'Request request_node',
        'description': 'Request request_node',
    }
    assert state['values'] == {
        '_execution': [{
            'name': '',
            'description': '',
        }],
        'capture1': [{
            'name': expected_name,
        }],
        'capture2': [
            {
                'age': expected_age_1,
            },
            {
                'age': expected_age_2,
            },
        ],
        'request': [{
            'data': value,
        }],
        'request_node': [{
            'raw_response': request_response_s,
            'status_code': 200,
        }],
    }
Пример #20
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'
Пример #21
0
def make_pointer(process_name, node_id):
    exc = Execution(process_name=process_name, ).save()
    ptr = Pointer(node_id=node_id, ).save()
    ptr.proxy.execution.set(exc)

    return ptr
Пример #22
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',
        }],
    }
Пример #23
0
def test_reject(config, mongo):
    ''' tests that a rejection moves the pointer to a backward position '''
    # test setup
    handler = Handler(config)
    user = make_user('juan', 'Juan')
    ptr = make_pointer('validation.2018-05-09.xml', 'approval_node')
    channel = MagicMock()
    execution = ptr.proxy.execution.get()

    mongo[config["POINTER_COLLECTION"]].insert_one({
        'id':
        ptr.id,
        'started_at':
        datetime(2018, 4, 1, 21, 45),
        'finished_at':
        None,
        'execution': {
            'id': execution.id,
        },
        'node': {
            'id': 'approval_node',
        },
        'actors': {
            '_type': ':map',
            'items': {},
        },
    })

    state = Xml.load(config, 'validation.2018-05-09').get_state()

    state['items']['start_node']['state'] = 'valid'
    state['items']['start_node']['actors']['items']['juan'] = {
        '_type':
        'actor',
        'state':
        'valid',
        'user': {
            '_type': 'user',
            'identifier': 'juan',
            'fullname': 'Juan',
        },
        'forms': [
            Form.state_json('work', [
                {
                    'name': 'task',
                    '_type': 'field',
                    'state': 'valid',
                    'value': '2',
                },
            ])
        ],
    }

    mongo[config["EXECUTION_COLLECTION"]].insert_one({
        '_type': 'execution',
        'id': execution.id,
        'state': state,
        'values': {
            '_execution': [{
                'name': '',
                'description': '',
            }],
        },
    })

    # will teardown the approval node
    handler.call(
        {
            'command':
            'step',
            'pointer_id':
            ptr.id,
            'user_identifier':
            user.identifier,
            'input': [
                Form.state_json('approval_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:work.task',
                        }],
                        'value_caption': '',
                    },
                ])
            ],
        }, channel)

    # assertions
    assert Pointer.get(ptr.id) is None

    new_ptr = Pointer.get_all()[0]
    assert new_ptr.node_id == 'start_node'

    assert new_ptr in user.proxy.tasks

    # data is invalidated
    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': 'I do not like it',
                    'actors': {
                        '_type': ':map',
                        'items': {
                            'juan': {
                                '_type':
                                'actor',
                                'forms': [
                                    Form.state_json('work', [
                                        {
                                            'name': 'task',
                                            '_type': 'field',
                                            'state': 'invalid',
                                            'value': '2',
                                        },
                                    ],
                                                    state='invalid')
                                ],
                                'state':
                                'invalid',
                                'user': {
                                    '_type': 'user',
                                    'identifier': 'juan',
                                    'fullname': 'Juan',
                                },
                            },
                        },
                    },
                    'milestone': False,
                    'name': 'Primer paso',
                    'description': 'Resolver una tarea',
                },
                'approval_node': {
                    '_type': 'node',
                    'type': 'validation',
                    'id': 'approval_node',
                    'state': 'invalid',
                    'comment': 'I do not like it',
                    'actors': {
                        '_type': ':map',
                        'items': {
                            'juan': {
                                '_type':
                                'actor',
                                'forms': [
                                    Form.state_json('approval_node', [
                                        {
                                            'name': 'response',
                                            'state': 'invalid',
                                            '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:work.task',
                                            }],
                                            'value_caption':
                                            '',
                                        },
                                    ],
                                                    state='invalid')
                                ],
                                'state':
                                'invalid',
                                'user': {
                                    '_type': 'user',
                                    'identifier': 'juan',
                                    'fullname': 'Juan',
                                },
                            },
                        },
                    },
                    'milestone': False,
                    'name': 'Aprobación gerente reserva',
                    'description': 'aprobar reserva',
                },
                'final_node': {
                    '_type': 'node',
                    'type': 'action',
                    'id': 'final_node',
                    'state': 'unfilled',
                    'comment': '',
                    'actors': {
                        '_type': ':map',
                        'items': {},
                    },
                    'milestone': False,
                    'name': '',
                    'description': '',
                },
            },
            'item_order': ['start_node', 'approval_node', 'final_node'],
        },
        'values': {
            '_execution': [{
                'name': '',
                'description': '',
            }],
            'approval_node': [{
                'comment':
                'I do not like it',
                'response':
                'reject',
                'inputs': [{
                    'ref': 'start_node.juan.0:work.task'
                }],
            }],
        },
        'actors': {
            'approval_node': 'juan',
        },
        'actor_list': [{
            'node': 'approval_node',
            'identifier': 'juan',
        }],
    }

    # mongo has the data
    reg = next(mongo[config["POINTER_COLLECTION"]].find())

    assert reg['started_at'] == datetime(2018, 4, 1, 21, 45)
    assert (reg['finished_at'] - datetime.now()).total_seconds() < 2
    assert reg['execution']['id'] == ptr.execution
    assert reg['node']['id'] == 'approval_node'
    assert reg['actors'] == {
        '_type': ':map',
        'items': {
            'juan': {
                '_type':
                'actor',
                'forms': [
                    Form.state_json('approval_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:work.task',
                            }],
                            'value_caption': '',
                        },
                    ])
                ],
                'state':
                'valid',
                'user': {
                    '_type': 'user',
                    'identifier': 'juan',
                    'fullname': 'Juan',
                },
            },
        },
    }
Пример #24
0
def test_call_handler_delete_process(config, mongo):
    handler = Handler(config)

    pointer = make_pointer('simple.2018-02-19.xml', 'requester')
    execution = pointer.execution.get()

    body = '{"command":"cancel", "execution_id":"%s", "pointer_id":"%s"}'\
        % (execution.id, pointer.id)

    mongo[config["EXECUTION_COLLECTION"]].insert_one({
        'started_at':
        datetime(2018, 4, 1, 21, 45),
        'finished_at':
        None,
        'status':
        'ongoing',
        'id':
        execution.id
    })

    ptr_id_1 = 'RANDOMPOINTERNAME'
    ptr_id_2 = 'MORERANDOMNAME'
    ptr_id_3 = 'NOTSORANDOMNAME'

    mongo[config["POINTER_COLLECTION"]].insert_many([
        {
            'execution': {
                'id': execution.id,
            },
            'state': 'finished',
            'id': ptr_id_1,
        },
        {
            'execution': {
                'id': execution.id,
            },
            'state': 'ongoing',
            'id': ptr_id_2,
        },
        {
            'execution': {
                'id': execution.id[::-1],
            },
            'state': 'ongoing',
            'id': ptr_id_3,
        },
    ])

    handler(body)

    reg = next(mongo[config["EXECUTION_COLLECTION"]].find())

    assert reg['id'] == execution.id
    assert reg['status'] == "cancelled"
    assert_near_date(reg['finished_at'])

    assert list(Execution.q().filter(status='ongoing')) == []
    assert list(Pointer.q().filter(status='ongoing')) == []

    assert mongo[config["POINTER_COLLECTION"]].find_one({
        'id': ptr_id_1,
    })['state'] == 'finished'
    assert mongo[config["POINTER_COLLECTION"]].find_one({
        'id': ptr_id_2,
    })['state'] == 'cancelled'
    assert mongo[config["POINTER_COLLECTION"]].find_one({
        'id': ptr_id_3,
    })['state'] == 'ongoing'
Пример #25
0
def task_read(id):
    pointer = Pointer.get_or_exception(id)

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

    execution = pointer.proxy.execution.get()
    collection = mongo.db[app.config['EXECUTION_COLLECTION']]
    state = collection.find_one({
        'id': execution.id,
    })

    xml = Xml.load(app.config, execution.process_name, direct=True)
    xmliter = iter(xml)
    node = xmliter.find(lambda e: e.getAttribute('id') == pointer.node_id)

    xmliter.parser.expandNode(node)

    # Response body
    json_data = pointer.to_json(include=['*', 'execution'])

    # Append node info
    json_data['node_type'] = node.tagName

    # Append forms
    forms = []
    for form in node.getElementsByTagName('form'):
        forms.append(form_to_dict(form))
    json_data['form_array'] = forms

    # If any append previous work done
    node_state = state['state']['items'][pointer.node_id]
    node_actors = node_state['actors']

    user_identifier = g.user.identifier
    if user_identifier in node_actors['items']:
        action = node_actors['items'][user_identifier]

        json_data['prev_work'] = action['forms']

    # Append validation
    if node.tagName == 'validation':
        deps = list(
            map(lambda node: get_text(node), node.getElementsByTagName('dep')))

        fields = []
        for dep in deps:
            form_ref, input_name = dep.split('.')

            # TODO this could be done in O(log N + K)
            for node in state['state']['items'].values():
                if node['state'] != 'valid':
                    continue

                for identifier in node['actors']['items']:
                    actor = node['actors']['items'][identifier]
                    if actor['state'] != 'valid':
                        continue

                    for form_ix, form in enumerate(actor['forms']):
                        if form['state'] != 'valid':
                            continue

                        if form['ref'] != form_ref:
                            continue

                        if input_name not in form['inputs']['items']:
                            continue

                        input = form['inputs']['items'][input_name]

                        state_ref = [
                            node['id'],
                            identifier,
                            str(form_ix),
                        ]
                        state_ref = '.'.join(state_ref)
                        state_ref = state_ref + ':' + dep

                        field = {
                            'ref': state_ref,
                            **input,
                        }
                        del field['state']

                        fields.append(field)

        json_data['fields'] = fields

    return jsonify({
        'data': json_data,
    })
Пример #26
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
Пример #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
Пример #28
0
def test_send_request_multiple(config, mongo, mocker):
    ''' Tests that values are stored in such a way that they can be iterated
    in a jinja template. Specifically in this test they'll be used as part of
    a request node, thus also testing that all of the values can be used '''

    # test setup
    class ResponseMock:
        status_code = 200
        text = 'request response'

    mock = MagicMock(return_value=ResponseMock())

    mocker.patch('requests.request', new=mock)

    handler = Handler(config)
    user = make_user('juan', 'Juan')
    ptr = make_pointer('request-multiple.2019-11-14.xml', 'start_node')
    execution = ptr.proxy.execution.get()
    channel = MagicMock()
    names = [random_string() for _ in '123']

    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('form1', [
                    {
                        'name': 'name',
                        'type': 'text',
                        'value': names[0],
                        'value_caption': names[0],
                    },
                ]),
                Form.state_json('form1', [
                    {
                        'name': 'name',
                        'type': 'text',
                        'value': names[1],
                        'value_caption': names[1],
                    },
                ]),
                Form.state_json('form1', [
                    {
                        'name': 'name',
                        'type': 'text',
                        'value': names[2],
                        'value_caption': names[2],
                    },
                ]),
            ],
        }, channel)

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

    # request is made with correct data
    requests.request.assert_called_once()
    args, kwargs = requests.request.call_args

    assert args[0] == 'POST'
    assert args[1] == 'http://localhost/'

    assert kwargs['data'] == '{{"names": ["{}","{}","{}"]}}'.format(*names)
    assert kwargs['headers'] == {
        'content-type': 'application/json',
    }
Пример #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'
Пример #30
0
def test_teardown(config, mongo):
    ''' second and last stage of a node's lifecycle '''
    # test setup
    handler = Handler(config)

    p_0 = make_pointer('simple.2018-02-19.xml', 'mid_node')
    execution = p_0.proxy.execution.get()

    User(identifier='juan').save()
    manager = User(identifier='manager').save()
    manager2 = User(identifier='manager2').save()

    assert manager not in execution.proxy.actors.get()
    assert execution not in manager.proxy.activities.get()

    manager.proxy.tasks.set([p_0])
    manager2.proxy.tasks.set([p_0])

    state = Xml.load(config, execution.process_name).get_state()
    state['items']['start_node']['state'] = 'valid'

    mongo[config["EXECUTION_COLLECTION"]].insert_one({
        '_type': 'execution',
        'id': execution.id,
        'state': state,
        'values': {
            '_execution': [{
                'name': '',
                'description': '',
            }],
        },
        'actors': {
            'start_node': 'juan',
        },
    })

    mongo[config["POINTER_COLLECTION"]].insert_one({
        'id': p_0.id,
        'started_at': datetime(2018, 4, 1, 21, 45),
        'finished_at': None,
        'execution': {
            'id': execution.id,
        },
        'node': {
            'id': p_0.node_id,
        },
        'actors': {
            '_type': ':map',
            'items': {},
        },
    })

    channel = MagicMock()

    # will teardown mid_node
    handler.call({
        'command': 'step',
        'pointer_id': p_0.id,
        'user_identifier': manager.identifier,
        'input': [Form.state_json('mid_form', [
            {
                '_type': 'field',
                'state': 'valid',
                'value': 'yes',
                'value_caption': 'yes',
                'name': 'data',
            },
        ])],
    }, channel)

    # assertions
    assert Pointer.get(p_0.id) is None

    assert Pointer.count() == 1
    assert Pointer.get_all()[0].node_id == 'final_node'

    # mongo has a registry
    reg = next(mongo[config["POINTER_COLLECTION"]].find())

    assert reg['started_at'] == datetime(2018, 4, 1, 21, 45)
    assert_near_date(reg['finished_at'])
    assert reg['execution']['id'] == execution.id
    assert reg['node']['id'] == p_0.node_id
    assert reg['actors'] == {
        '_type': ':map',
        'items': {
            'manager': {
                '_type': 'actor',
                'state': 'valid',
                'user': {
                    '_type': 'user',
                    'identifier': 'manager',
                    'fullname': None,
                },
                'forms': [Form.state_json('mid_form', [
                    {
                        '_type': 'field',
                        'state': 'valid',
                        'value': 'yes',
                        'value_caption': 'yes',
                        'name': 'data',
                    },
                ])],
            },
        },
    }

    # tasks where deleted from user
    assert manager.proxy.tasks.count() == 0
    assert manager2.proxy.tasks.count() == 0

    # state
    reg = next(mongo[config["EXECUTION_COLLECTION"]].find())

    assert reg['state'] == {
        '_type': ':sorted_map',
        'items': {
            'start_node': {
                '_type': 'node',
                'type': 'action',
                'id': 'start_node',
                'state': 'valid',
                'comment': '',
                'actors': {
                    '_type': ':map',
                    'items': {},
                },
                'milestone': False,
                'name': 'Primer paso',
                'description': 'Resolver una tarea',
            },

            'mid_node': {
                '_type': 'node',
                'type': 'action',
                'id': 'mid_node',
                'state': 'valid',
                'comment': '',
                'actors': {
                    '_type': ':map',
                    'items': {
                        'manager': {
                            '_type': 'actor',
                            'state': 'valid',
                            'user': {
                                '_type': 'user',
                                'identifier': 'manager',
                                'fullname': None,
                            },
                            'forms': [Form.state_json('mid_form', [
                                {
                                    '_type': 'field',
                                    'state': 'valid',
                                    'value': 'yes',
                                    'value_caption': 'yes',
                                    'name': 'data',
                                },
                            ])],
                        },
                    },
                },
                'milestone': False,
                'name': 'Segundo paso',
                'description': 'añadir información',
            },

            'final_node': {
                '_type': 'node',
                'type': 'action',
                'id': 'final_node',
                'state': 'ongoing',
                'comment': '',
                'actors': {
                    '_type': ':map',
                    'items': {},
                },
                'milestone': False,
                'name': '',
                'description': '',
            },
        },
        'item_order': [
            'start_node',
            'mid_node',
            'final_node',
        ],
    }

    assert reg['values'] == {
        '_execution': [{
            'name': '',
            'description': '',
        }],
        'mid_form': [{
            'data': 'yes',
        }],
    }

    assert reg['actors'] == {
        'start_node': 'juan',
        'mid_node': 'manager',
    }

    assert manager in execution.proxy.actors
    assert execution in manager.proxy.activities