def test_poll_tasks_claim_one(self):
        """Test if task is correctly claimed."""

        task = Task()
        task.uuid = 'de305d54-75b4-431b-adb2-eb6b9e546013'
        task.test_id = 'de305d54-75b4-431b-adb2-eb6b9e546013'
        task.type = 'task-type-1'
        task.version = 1
        task.data = "{}"
        db.session.add(task)
        db.session.commit()

        resp = self.test_app.post_json('/tasks', {
            'protocol': 1,
            'agent_id': 'de305d54-75b4-431b-adb2-eb6b9e546013',
            'agent_name': 'Agent 007',
            'agent_location': {
                'country': 'FI',
                'region': '18'
            },
            'agent_time': '2012-04-23T18:25:43.511Z',
            'agent_capabilities': {
                'task-type-1': {'version': 1},
                'task-type-2': {'version': 2}
            },
            'max_tasks': 5
        })
        jsonschema.validate(resp.json, TestPolling.task_request_response_schema)
        self.assertEqual(len(resp.json['tasks']), 1)
def post_task():
    data = request.json

    if data is None:
        abort(400)

    try:
        jsonschema.validate(data, POST_TASK_SCHEMA)
    except jsonschema.ValidationError:
        abort(400)

    task_uuid = str(data['task_id'])
    task_type = str(data['task_type'])
    task_test_id = (data['test_id'])
    task_data = ""

    task = Task(uuid=task_uuid,
                type=task_type,
                version=int(data['task_version']),
                test_id=task_test_id)

    if 'task_data' in data:
        task_data = json.dumps(data['task_data'])
        task.data = task_data

    try:
        db.session.add(task)
    except IntegrityError:
        db.session.rollback()
        abort(400)

    try:
        db.session.commit()
    except (IntegrityError, ProgrammingError):
        db.session.rollback()
        current_app.logger.error(
            "Failed to commit database changes for BPMS task POST")
        abort(400)

    current_app.logger.info(
        "Task posted by BPMS - Task's type: {}, test process id: {}, uuid: {}, parameters: {}"
        .format(task_type, task_test_id, task_uuid, task_data))

    return ('', 200)
def post_task():
    data = request.json

    if data is None:
        abort(400)

    try:
        jsonschema.validate(data, POST_TASK_SCHEMA)
    except jsonschema.ValidationError:
        abort(400)

    task_uuid = str(data['task_id'])
    task_type = str(data['task_type'])
    task_test_id = (data['test_id'])
    task_data = ""

    task = Task(
        uuid=task_uuid,
        type=task_type,
        version=int(data['task_version']),
        test_id=task_test_id
    )

    if 'task_data' in data:
        task_data = json.dumps(data['task_data'])
        task.data = task_data

    try:
        db.session.add(task)
    except IntegrityError:
        db.session.rollback()
        abort(400)

    try:
        db.session.commit()
    except (IntegrityError, ProgrammingError):
        db.session.rollback()
        current_app.logger.error("Failed to commit database changes for BPMS task POST")
        abort(400)

    current_app.logger.info("Task posted by BPMS - Task's type: {}, test process id: {}, uuid: {}, parameters: {}"
                            .format(task_type, task_test_id, task_uuid, task_data))

    return ('', 200)
def request_tasks():
    data = request.json

    if data is None:
        current_app.logger.error('No JSON data provided with request.')
        abort(400)

    try:
        jsonschema.validate(data, TASK_REQUEST_SCHEMA)
    except jsonschema.ValidationError:
        current_app.logger.error('Invalid JSON data provided with request.')
        abort(400)

    protocol = int(data['protocol'])
    agent_uuid = str(data['agent_id'])
    agent_name = str(data['agent_name'])
    agent_capabilities = data['agent_capabilities']
    max_tasks = int(data['max_tasks'])
    # agent_time = data['agent_time']
    # agent_location = data['agent_location'] if 'agent_location' in data else None

    # Only protocol 1 supported for now
    if protocol != 1:
        abort(400)

    # Update agent details in DB
    agent = Agent.get_agent(agent_uuid, agent_name)
    agent.update_capabilities(agent_capabilities)
    agent.last_seen = datetime.utcnow()

    # Calculate return time for the agent (next polling time)
    return_time = (
        datetime.now(tz.tzlocal()) +
        timedelta(0, current_app.config.get('AGENT_RETURN_TIME'))).isoformat()

    # Claim tasks for agent
    tasks = [{
        'task_id': task.uuid,
        'task_type': task.type,
        'task_version': task.version,
        'task_data': json.loads(task.data)
    } for task in Task.claim_tasks(agent, max_tasks)]
    if len(tasks) > 0:
        current_app.logger.info("Assigning tasks {} to agent {}, {}".format(
            [task['task_id'] for task in tasks], agent_name, agent_uuid))
        current_app.logger.debug("Task details: {}".format(tasks))

    response = jsonify(tasks=tasks, return_time=return_time)

    # commit only after serializing the response
    db.session.commit()

    return response
def request_tasks():
    data = request.json

    if data is None:
        current_app.logger.error('No JSON data provided with request.')
        abort(400)

    try:
        jsonschema.validate(data, TASK_REQUEST_SCHEMA)
    except jsonschema.ValidationError:
        current_app.logger.error('Invalid JSON data provided with request.')
        abort(400)

    protocol = int(data['protocol'])
    agent_uuid = str(data['agent_id'])
    agent_name = str(data['agent_name'])
    agent_capabilities = data['agent_capabilities']
    max_tasks = int(data['max_tasks'])
    # agent_time = data['agent_time']
    # agent_location = data['agent_location'] if 'agent_location' in data else None

    # Only protocol 1 supported for now
    if protocol != 1:
        abort(400)

    # Update agent details in DB
    agent = Agent.get_agent(agent_uuid, agent_name)
    agent.update_capabilities(agent_capabilities)
    agent.last_seen = datetime.utcnow()

    # Calculate return time for the agent (next polling time)
    return_time = (datetime.now(tz.tzlocal()) + timedelta(0, current_app.config.get('AGENT_RETURN_TIME'))).isoformat()

    # Claim tasks for agent
    tasks = [{'task_id': task.uuid, 'task_type': task.type, 'task_version': task.version,
              'task_data': json.loads(task.data)} for task in Task.claim_tasks(agent, max_tasks)]
    if len(tasks) > 0:
        current_app.logger.info("Assigning tasks {} to agent {}, {}"
                                .format([task['task_id'] for task in tasks], agent_name, agent_uuid))
        current_app.logger.debug("Task details: {}".format(tasks))

    response = jsonify(tasks=tasks, return_time=return_time)

    # commit only after serializing the response
    db.session.commit()

    return response
    def test_post_task_duplicate(self):
        task1 = Task()
        task1.uuid = 'de305d54-75b4-431b-adb2-eb6b9e546018'
        task1.test_id = 'de305d54-75b4-431b-adb2-eb6b9e546018'
        task1.claimed = datetime.utcnow()
        task1.data = json.dumps({'wait_time': 123})
        db.session.add(task1)
        db.session.commit()
        db.session.close()

        assert self.test_app.post_json('/task', {
            'task_id': 'de305d54-75b4-431b-adb2-eb6b9e546018',
            'test_id': 'de305d54-75b4-431b-adb2-eb6b9e546013',
            'task_type': 'wait',
            'task_version': 1
        }, expect_errors=True).status_int == 400
    def test_push_response(self):
        task = Task()
        task.uuid = 'de305d54-75b4-431b-adb2-eb6b9e546013'
        task.test_id = 'de305d54-75b4-431b-adb2-eb6b9e546013'
        task.claimed = datetime.utcnow()
        db.session.add(task)
        db.session.commit()

        r = self.test_app.post_json('/tasks/response', {
            'protocol': 1,
            'task_id': 'de305d54-75b4-431b-adb2-eb6b9e546013',
            'task_data': {
                'key': 'value',
                'another_key': 5
            }
        })
        print(r)

        task = db.session.query(Task).filter(Task.uuid == 'de305d54-75b4-431b-adb2-eb6b9e546013').one()

        self.assertIsNotNone(task.completed)
        self.assertIsNotNone(task.completed)
        self.assertIsNotNone(task.result_data)
        self.assertIsNone(task.failed)
        self.assertIsNone(task.error)

        task.completed = None
        task.result_data = None
        db.session.commit()
        self.test_app.post_json('/tasks/response', {
            'protocol': 1,
            'task_id': 'de305d54-75b4-431b-adb2-eb6b9e546013',
            'task_error': 'Something went terribly wrong'
        })

        task = db.session.query(Task).filter(Task.uuid == 'de305d54-75b4-431b-adb2-eb6b9e546013').one()

        assert task.completed is None
        assert task.result_data is None
        assert task.failed is not None
        assert task.error is not None
    def test_pull_task(self):
        task1 = Task()
        task1.uuid = 'de305d54-75b4-431b-adb2-eb6b9e546018'
        task1.test_id = 'de305d54-75b4-431b-adb2-eb6b9e546018'
        task1.claimed = datetime.utcnow()
        task1.data = json.dumps({'wait_time': 123})
        db.session.add(task1)

        task2 = Task()
        task2.uuid = 'de305d54-75b4-431b-adb2-eb6b9e546019'
        task2.test_id = 'de305d54-75b4-431b-adb2-eb6b9e546019'
        task2.claimed = datetime.utcnow()
        task2.completed = datetime.utcnow()
        task2.result_data = json.dumps({'result': 'epic success'})
        db.session.add(task2)

        task3 = Task()
        task3.uuid = 'de305d54-75b4-431b-adb2-eb6b9e546020'
        task3.test_id = 'de305d54-75b4-431b-adb2-eb6b9e546020'
        task3.claimed = datetime.utcnow()
        task3.failed = datetime.utcnow()
        task3.error = 'unknown error'
        db.session.add(task3)

        db.session.commit()

        self.test_app.get('/task/de305d54-75b4-431b-adb2-eb6b9e546018')
        self.test_app.get('/task/de305d54-75b4-431b-adb2-eb6b9e546019')
        self.test_app.get('/task/de305d54-75b4-431b-adb2-eb6b9e546020')