def test_with_scheduled_call_none(self, mock_increment_failure, mock_request): exc = Exception() task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = { '1': 'for the money', 'tags': ['test_tags'], 'scheduled_call_id': None } class EInfo(object): """ on_failure handler expects an instance of celery's ExceptionInfo class as one of the attributes. It stores string representation of traceback in it's traceback instance variable. This is a stub to imitate that behavior. """ def __init__(self): self.traceback = "string_repr_of_traceback" einfo = EInfo() mock_request.called_directly = False TaskStatus(task_id).save() task = tasks.Task() task.on_failure(exc, task_id, args, kwargs, einfo) self.assertFalse(mock_increment_failure.called)
def test_async_result(self, mock_request): retval = AsyncResult('foo-id') task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = { '1': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_2 } mock_request.called_directly = False task_status = TaskStatus(task_id).save() self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatus.objects(task_id=task_id).first() self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], None) self.assertFalse(new_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(new_task_status['finish_time']) self.assertEqual(new_task_status['spawned_tasks'], ['foo-id'])
def test_updates_task_status_correctly(self, mock_request): exc = Exception() task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags']} class EInfo(object): """ on_failure handler expects an instance of celery's ExceptionInfo class as one of the attributes. It stores string representation of traceback in it's traceback instance variable. This is a stub to imitate that behavior. """ def __init__(self): self.traceback = "string_repr_of_traceback" einfo = EInfo() mock_request.called_directly = False task_status = TaskStatus(task_id).save() self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) self.assertEqual(task_status['traceback'], None) task = tasks.Task() task.on_failure(exc, task_id, args, kwargs, einfo) new_task_status = TaskStatus.objects(task_id=task_id).first() self.assertEqual(new_task_status['state'], 'error') self.assertFalse(new_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(new_task_status['finish_time']) self.assertEqual(new_task_status['traceback'], einfo.traceback)
def test_apply_async_task_status(self, apply_async): """ Assert that apply_async() creates new task status. """ args = [1, 'b', 'iii'] kwargs = { '1': 'for the money', 'tags': ['test_tags'], 'queue': WORKER_1_QUEUE } apply_async.return_value = celery.result.AsyncResult('test_task_id') task = tasks.Task() task.apply_async(*args, **kwargs) task_statuses = list(TaskStatusManager.find_all()) self.assertEqual(len(task_statuses), 1) new_task_status = task_statuses[0] self.assertEqual(new_task_status['task_id'], 'test_task_id') self.assertEqual(new_task_status['queue'], WORKER_1_QUEUE) self.assertEqual(new_task_status['tags'], kwargs['tags']) self.assertEqual(new_task_status['state'], 'waiting') self.assertEqual(new_task_status['error'], None) self.assertEqual(new_task_status['spawned_tasks'], []) self.assertEqual(new_task_status['progress_report'], {}) self.assertEqual(new_task_status['task_type'], 'pulp.server.async.tasks.Task') self.assertEqual(new_task_status['start_time'], None) self.assertEqual(new_task_status['finish_time'], None) self.assertEqual(new_task_status['result'], None)
def test_creates_task_status_with_group_id(self, apply_async): args = [1, 'b', 'iii'] group_id = uuid.uuid4() kwargs = { 'a': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_1, 'group_id': group_id } apply_async.return_value = celery.result.AsyncResult('test_task_id') task = tasks.Task() task.apply_async(*args, **kwargs) task_statuses = TaskStatus.objects() self.assertEqual(task_statuses.count(), 1) new_task_status = task_statuses[0] self.assertEqual(new_task_status['task_id'], 'test_task_id') self.assertEqual(new_task_status['group_id'], group_id) self.assertEqual(new_task_status['worker_name'], WORKER_1) self.assertEqual(new_task_status['tags'], kwargs['tags']) self.assertEqual(new_task_status['state'], 'waiting') self.assertEqual(new_task_status['error'], None) self.assertEqual(new_task_status['spawned_tasks'], []) self.assertEqual(new_task_status['progress_report'], {}) self.assertEqual(new_task_status['task_type'], 'pulp.server.async.tasks.Task') self.assertEqual(new_task_status['start_time'], None) self.assertEqual(new_task_status['finish_time'], None) self.assertEqual(new_task_status['result'], None)
def test_on_success_handler_async_result(self, mock_request): """ Make sure that overridden on_success handler updates task status correctly """ retval = AsyncResult('foo-id') task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = { '1': 'for the money', 'tags': ['test_tags'], 'queue': WORKER_2_QUEUE } mock_request.called_directly = False task_status = TaskStatusManager.create_task_status( task_id, 'some_queue') self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], None) self.assertFalse(new_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(new_task_status['finish_time']) self.assertEqual(new_task_status['spawned_tasks'], ['foo-id'])
def test_on_success_with_canceled_task(self, mock_request): """ Make sure on_success() does not move a canceled Task to 'finished' state. """ retval = 'random_return_value' task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = { '1': 'for the money', 'tags': ['test_tags'], 'queue': WORKER_2_QUEUE } mock_request.called_directly = False task_status = TaskStatusManager.create_task_status( task_id, 'some_queue', state=CALL_CANCELED_STATE) task = tasks.Task() # This should not update the task status to finished, since this task was canceled. task.on_success(retval, task_id, args, kwargs) updated_task_status = TaskStatusManager.find_by_task_id(task_id) # Make sure the task is still canceled. self.assertEqual(updated_task_status['state'], CALL_CANCELED_STATE) self.assertEqual(updated_task_status['result'], retval) self.assertFalse(updated_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(updated_task_status['finish_time'])
def test_apply_async_with_reservation_calls_apply_async( self, apply_async, _reserve_resource, _queue_release_resource): """ Assert that apply_async_with_reservation() calls Celery's apply_async. """ class MockAsyncResult(object): def __init__(self): self.id = 'some_task_id' # Let's make up the return value from Celery mock_async_result = MockAsyncResult() apply_async.return_value = mock_async_result some_args = [1, 'b', 'iii'] some_kwargs = { '1': 'for the money', '2': 'for the show', 'queue': WORKER_1_QUEUE } resource_id = 'three_to_get_ready' resource_type = 'reserve_me' task = tasks.Task() async_result = task.apply_async_with_reservation( resource_type, resource_id, *some_args, **some_kwargs) self.assertEqual(async_result, mock_async_result) expected_resource_id = ":".join([resource_type, resource_id]) _reserve_resource.assert_called_once_with( (expected_resource_id, ), queue=tasks.RESOURCE_MANAGER_QUEUE) apply_async.assert_called_once_with(task, *some_args, **some_kwargs) _queue_release_resource.apply_async.assert_called_once_with( (expected_resource_id, ), queue=WORKER_1_QUEUE)
def test_on_success_handler_spawned_task_dict(self, mock_request): """ Make sure that overridden on_success handler updates task status correctly """ retval = tasks.TaskResult(spawned_tasks=[{ 'task_id': 'foo-id' }], result='bar') task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = { '1': 'for the money', 'tags': ['test_tags'], 'queue': WORKER_2_QUEUE } mock_request.called_directly = False task_status = TaskStatusManager.create_task_status( task_id, 'some_queue') self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], 'bar') self.assertFalse(new_task_status['finish_time'] is None) self.assertEqual(new_task_status['spawned_tasks'], ['foo-id'])
def test_spawned_task_status(self, mock_request): async_result = AsyncResult('foo-id') retval = tasks.TaskResult(error=PulpException('error-foo'), result='bar') retval.spawned_tasks = [async_result] task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = { '1': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_2 } mock_request.called_directly = False task_status = TaskStatusManager.create_task_status(task_id) self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], 'bar') self.assertEqual(new_task_status['error']['description'], 'error-foo') self.assertFalse(new_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(new_task_status['finish_time']) self.assertEqual(new_task_status['spawned_tasks'], ['foo-id'])
def test_task_status_not_modified_when_task_status_exists( self, apply_async): args = [1, 'b', 'iii'] kwargs = {'a': 'for the money', 'tags': ['test_tags']} task_id = 'test_task_id' # This simulates the case where a task had already completed # prior to apply_sync attempting to create a TaskStatus. # https://pulp.plan.io/issues/2959 TaskStatus(task_id, 'test-worker', state=CALL_FINISHED_STATE, result='any_result', start_time='2017-09-20T10:00:00Z', finish_time='2017-09-20T11:00:00Z').save() apply_async.return_value = celery.result.AsyncResult(task_id) task = tasks.Task() task.apply_async(*args, **kwargs) task_status = TaskStatus.objects(task_id=task_id).first() # Fields which were missing on the object have been added self.assertEqual(task_status['task_type'], 'pulp.server.async.tasks.Task') self.assertEqual(task_status['tags'], ['test_tags']) # Fields which already existed on the object are retained self.assertEqual(task_status['state'], 'finished') self.assertEqual(task_status['start_time'], '2017-09-20T10:00:00Z') self.assertEqual(task_status['finish_time'], '2017-09-20T11:00:00Z') self.assertEqual(task_status['result'], 'any_result')
def test_spawned_task_dict(self, mock_request): retval = tasks.TaskResult(spawned_tasks=[{ 'task_id': 'foo-id' }], result='bar') task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = { '1': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_2 } mock_request.called_directly = False task_status = TaskStatus(task_id).save() self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatus.objects(task_id=task_id).first() self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], 'bar') self.assertFalse(new_task_status['finish_time'] is None) self.assertEqual(new_task_status['spawned_tasks'], ['foo-id'])
def test_exception_task_status_with_bad_group_id(self, apply_async): args = [1, 'b', 'iii'] kwargs = {'a': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_1, 'group_id': 'string-id'} apply_async.return_value = celery.result.AsyncResult('test_task_id') task = tasks.Task() self.assertRaises(ValidationError, task.apply_async, *args, **kwargs)
def test_calls_parent_apply_async(self, apply_async): args = [1, 'b', 'iii'] kwargs = {'a': 'for the money', 'tags': ['test_tags'], 'routing_key': 'asdf'} apply_async.return_value = celery.result.AsyncResult('test_task_id') task = tasks.Task() task.apply_async(*args, **kwargs) apply_async.assert_called_once_with(1, 'b', 'iii', a='for the money', routing_key='asdf')
def test_returns_apply_async_result_including_tags(self, apply_async): args = [1, 'b', 'iii'] kwargs = {'a': 'for the money', 'tags': ['test_tags']} async_result = celery.result.AsyncResult('test_task_id') apply_async.return_value = async_result task = tasks.Task() result = task.apply_async(*args, **kwargs) self.assertEqual(result.tags, ['test_tags'])
def test_with_scheduled_call(self, mock_reset_failure, mock_request): retval = 'random_return_value' task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_2, 'scheduled_call_id': '12345'} mock_request.called_directly = False TaskStatus(task_id).save() task = tasks.Task() task.on_success(retval, task_id, args, kwargs) mock_reset_failure.assert_called_once_with('12345')
def test_task_status_not_modified_when_task_status_exists(self, apply_async): args = [1, 'b', 'iii'] kwargs = {'a': 'for the money', 'tags': ['test_tags']} task_id = 'test_task_id' TaskStatus(task_id, 'test-worker', state=CALL_CANCELED_STATE).save() apply_async.return_value = celery.result.AsyncResult(task_id) task = tasks.Task() task.apply_async(*args, **kwargs) task_status = TaskStatus.objects(task_id=task_id).first() self.assertEqual(task_status['state'], 'canceled') self.assertEqual(task_status['start_time'], None)
def test_with_scheduled_call_none(self, mock_reset_failure, mock_request): """ Ensure that if scheduled_call_id exists but is `None`, do not fail. """ retval = 'random_return_value' task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_2, 'scheduled_call_id': None} mock_request.called_directly = False TaskStatus(task_id).save() task = tasks.Task() task.on_success(retval, task_id, args, kwargs) self.assertFalse(mock_reset_failure.called)
def test_saves_passed_in_routing_key_as_worker_name(self, apply_async): args = [1, 'b', 'iii'] kwargs = {'a': 'for the money', 'tags': ['test_tags'], 'routing_key': 'othername'} apply_async.return_value = celery.result.AsyncResult('test_task_id') task = tasks.Task() task.apply_async(*args, **kwargs) task_statuses = TaskStatus.objects() self.assertEqual(len(task_statuses), 1) new_task_status = task_statuses[0] self.assertEqual(new_task_status['task_id'], 'test_task_id') self.assertEqual(new_task_status['worker_name'], 'othername') self.assertEqual(new_task_status['tags'], kwargs['tags']) self.assertEqual(new_task_status['state'], 'waiting')
def test_saves_default_routing_key_as_worker_name(self, apply_async): args = [1, 'b', 'iii'] kwargs = {'a': 'for the money', 'tags': ['test_tags']} apply_async.return_value = celery.result.AsyncResult('test_task_id') task = tasks.Task() task.apply_async(*args, **kwargs) task_statuses = TaskStatus.objects() self.assertEqual(len(task_statuses), 1) new_task_status = task_statuses[0] self.assertEqual(new_task_status['task_id'], 'test_task_id') self.assertEqual(new_task_status['worker_name'], defaults.NAMESPACES['CELERY']['DEFAULT_ROUTING_KEY'].default) self.assertEqual(new_task_status['tags'], kwargs['tags']) self.assertEqual(new_task_status['state'], 'waiting')
def test_with_canceled_task(self, mock_request): retval = 'random_return_value' task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_2} mock_request.called_directly = False TaskStatus(task_id, state=CALL_CANCELED_STATE).save() task = tasks.Task() # This should not update the task status to finished, since this task was canceled. task.on_success(retval, task_id, args, kwargs) updated_task_status = TaskStatus.objects(task_id=task_id).first() # Make sure the task is still canceled. self.assertEqual(updated_task_status['state'], CALL_CANCELED_STATE) self.assertEqual(updated_task_status['result'], retval) self.assertFalse(updated_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(updated_task_status['finish_time'])
def test_apply_async_task_canceled(self, apply_async): """ Assert that apply_async() honors 'canceled' task status. """ args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags']} task_id = 'test_task_id' now = datetime.utcnow() TaskStatusManager.create_task_status(task_id, Worker('test-worker', now), state=CALL_CANCELED_STATE) apply_async.return_value = celery.result.AsyncResult(task_id) task = tasks.Task() task.apply_async(*args, **kwargs) task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(task_status['state'], 'canceled') self.assertEqual(task_status['start_time'], None)
def test_apply_async_task_status_default_queue(self, apply_async): """ Assert that apply_async() creates new task status when we do not pass the queue kwarg. It default to the default Celery queue. """ args = [1, 'b', 'iii'] kwargs = {'1': 'for the money', 'tags': ['test_tags']} apply_async.return_value = celery.result.AsyncResult('test_task_id') task = tasks.Task() task.apply_async(*args, **kwargs) task_statuses = list(TaskStatusManager.find_all()) self.assertEqual(len(task_statuses), 1) new_task_status = task_statuses[0] self.assertEqual(new_task_status['task_id'], 'test_task_id') self.assertEqual( new_task_status['queue'], defaults.NAMESPACES['CELERY']['DEFAULT_QUEUE'].default) self.assertEqual(new_task_status['tags'], kwargs['tags']) self.assertEqual(new_task_status['state'], 'waiting')
def test_updates_task_status_correctly(self, mock_request): retval = 'random_return_value' task_id = str(uuid.uuid4()) args = [1, 'b', 'iii'] kwargs = { '1': 'for the money', 'tags': ['test_tags'], 'routing_key': WORKER_2 } mock_request.called_directly = False task_status = TaskStatusManager.create_task_status(task_id) self.assertEqual(task_status['state'], 'waiting') self.assertEqual(task_status['finish_time'], None) task = tasks.Task() task.on_success(retval, task_id, args, kwargs) new_task_status = TaskStatusManager.find_by_task_id(task_id) self.assertEqual(new_task_status['state'], 'finished') self.assertEqual(new_task_status['result'], retval) self.assertFalse(new_task_status['finish_time'] is None) # Make sure that parse_iso8601_datetime is able to parse the finish_time without errors dateutils.parse_iso8601_datetime(new_task_status['finish_time'])