class TestJobHandler(unittest.TestCase): NO_LOG_RESPONSE = """ { "value": [] } """ JOB_LOG_RESPONSE = """ { "value": [ { "MessageTS": 12345, "MessageType": "JobLog" } ] } """ TIMEOUT = 15 def setUp(self): super(TestJobHandler, self).setUp() self.post_patch = mock.patch( 'opserver_util.OpServerUtils.post_url_http') self.sleep_patch = mock.patch('gevent.sleep') self.post_mock = self.post_patch.start() self.sleep_mock = self.sleep_patch.start() self.vnc_api = mock.Mock() self.logger = mock.Mock() self.job_type = ['test-job'] self.job_input = {'key1': 'value1', 'key2': 'value2'} self.device_list = ['device1'] self.analytic_config = {'ip': '1.2.3.4', 'port': '8082'} self.job_handler = JobHandler(self.job_type, self.job_input, self.device_list, self.analytic_config, self.vnc_api, self.logger) # end setUp def tearDown(self): super(TestJobHandler, self).tearDown() self.post_patch.stop() self.sleep_patch.stop() # end tearDown def test_job_executed_successfully(self): self.assertFalse(self.job_handler.is_job_done()) self.vnc_api.execute_job.return_value = {'job_execution_id': 'job-1'} self.post_mock.return_value = self.JOB_LOG_RESPONSE self.assertEqual(self.job_handler.get_job_status(), JobStatus.INIT) self.job_handler.push() self.vnc_api.execute_job.assert_called_with( job_template_fq_name=self.job_type, job_input=self.job_input, device_list=self.device_list) self.assertEqual(self.post_mock.call_args[0][1], 'http://1.2.3.4:8082/analytics/query') self.assertEqual(self.post_mock.call_count, 1) self.assertTrue(self.job_handler.is_job_done()) self.assertEqual(self.job_handler.get_job_status(), JobStatus.COMPLETE) self.assertEqual(self.sleep_mock.call_args_list, []) # end test_job_executed_successfully def test_job_stays_in_progress_then_completes(self): return_values = [ self.NO_LOG_RESPONSE, self.NO_LOG_RESPONSE, self.JOB_LOG_RESPONSE ] def side_effect(*_): self.assertFalse(self.job_handler.is_job_done()) self.assertEqual(self.job_handler.get_job_status(), JobStatus.IN_PROGRESS) side_effect.counter += 1 return return_values[side_effect.counter - 1] # end side_effect side_effect.counter = 0 self.assertFalse(self.job_handler.is_job_done()) self.vnc_api.execute_job.return_value = {'job_execution_id': 'job-1'} self.post_mock.side_effect = side_effect self.assertEqual(self.job_handler.get_job_status(), JobStatus.INIT) self.job_handler.push() self.vnc_api.execute_job.assert_called_with( job_template_fq_name=self.job_type, job_input=self.job_input, device_list=self.device_list) self.assertEqual(self.post_mock.call_count, 3) self.assertTrue(self.job_handler.is_job_done()) self.assertEqual(self.job_handler.get_job_status(), JobStatus.COMPLETE) self.assertEqual(self.sleep_mock.call_args_list, [mock.call(self.TIMEOUT)]) # end test_job_stays_in_progress_then_completes def test_job_failed(self): self.assertFalse(self.job_handler.is_job_done()) self.vnc_api.execute_job.return_value = {'job_execution_id': 'job-1'} self.post_mock.side_effect = [ self.NO_LOG_RESPONSE, self.JOB_LOG_RESPONSE ] self.assertEqual(self.job_handler.get_job_status(), JobStatus.INIT) self.assertRaises(Exception, self.job_handler.push) self.vnc_api.execute_job.assert_called_with( job_template_fq_name=self.job_type, job_input=self.job_input, device_list=self.device_list) self.assertEqual(self.post_mock.call_count, 2) self.assertTrue(self.job_handler.is_job_done()) self.assertEqual(self.job_handler.get_job_status(), JobStatus.FAILED) self.assertEqual(self.sleep_mock.call_args_list, []) # end test_job_failed def test_execute_job_throws(self): self.assertFalse(self.job_handler.is_job_done()) self.vnc_api.execute_job.side_effect = \ cfgm_common.exceptions.HttpError(500, "execute-job failed") self.assertEqual(self.job_handler.get_job_status(), JobStatus.INIT) self.assertRaises(Exception, self.job_handler.push) self.vnc_api.execute_job.assert_called_with( job_template_fq_name=self.job_type, job_input=self.job_input, device_list=self.device_list) self.post_mock.assert_not_called() self.assertTrue(self.job_handler.is_job_done()) self.assertEqual(self.job_handler.get_job_status(), JobStatus.FAILED) self.sleep_mock.assert_not_called() # end test_execute_job_throws def test_check_status_throws(self): self.assertFalse(self.job_handler.is_job_done()) self.vnc_api.execute_job.return_value = {'job_execution_id': 'job-1'} self.post_mock.side_effect = requests.exceptions.HTTPError() self.assertEqual(self.job_handler.get_job_status(), JobStatus.INIT) self.assertRaises(Exception, self.job_handler.push) self.vnc_api.execute_job.assert_called_with( job_template_fq_name=self.job_type, job_input=self.job_input, device_list=self.device_list) self.assertEqual(self.post_mock.call_count, 1) self.assertTrue(self.job_handler.is_job_done()) self.assertEqual(self.job_handler.get_job_status(), JobStatus.FAILED) self.sleep_mock.assert_not_called() # end test_check_status_throws def test_max_retries_done(self): self.assertFalse(self.job_handler.is_job_done()) self.vnc_api.execute_job.return_value = {'job_execution_id': 'job-1'} self.post_mock.side_effect = [ self.NO_LOG_RESPONSE, self.NO_LOG_RESPONSE, self.NO_LOG_RESPONSE, self.NO_LOG_RESPONSE, self.NO_LOG_RESPONSE, self.NO_LOG_RESPONSE ] self.assertEqual(self.job_handler.get_job_status(), JobStatus.INIT) self.assertRaises(Exception, self.job_handler.push, self.TIMEOUT, 3) self.vnc_api.execute_job.assert_called_with( job_template_fq_name=self.job_type, job_input=self.job_input, device_list=self.device_list) self.assertEqual(self.post_mock.call_count, 6) self.assertTrue(self.job_handler.is_job_done()) self.assertEqual(self.job_handler.get_job_status(), JobStatus.FAILED) self.assertEqual(self.sleep_mock.call_args_list, [mock.call(self.TIMEOUT), mock.call(self.TIMEOUT)])
class TestJobHandler(unittest.TestCase): JOB_SUCCESS = AttrDict({ "job_status": "SUCCESS" }) JOB_FAILURE = AttrDict({ "job_status": "FAILURE" }) JOB_IN_PROGRESS = AttrDict({ "job_status": "IN_PROGRESS" }) TIMEOUT = 15 MAX_RETRIES = 30 def setUp(self): super(TestJobHandler, self).setUp() self.sleep_patch = mock.patch('gevent.sleep') self.sleep_mock = self.sleep_patch.start() self.logger = mock.Mock() self.amqp_client = mock.Mock() self.message = mock.Mock() self.job_template_name = ['test-job'] self.job_input = {'key1': 'value1', 'key2': 'value2'} self.device_list = ['device1'] self.api_server_config = { 'ips': ["1.2.3.4"], 'port': "8082", 'username': "******", 'password': "******", 'tenant': "default", 'use_ssl': False } self.args = AttrDict({ 'api_server_ip': '127.0.0.1', 'admin_user': '******', 'admin_password': '******', 'admin_tenant_name': 'test', 'api_server_port': 8082, 'api_server_use_ssl': False }) self.job_handler = JobHandler(self.job_template_name, self.job_input, self.device_list, self.api_server_config, self.logger, self.amqp_client, self.args) # end setUp def tearDown(self): super(TestJobHandler, self).tearDown() self.sleep_patch.stop() # end tearDown def test_job_executed_successfully(self): def side_effect(*_): self.assertFalse(self.job_handler._is_job_done()) self.assertEqual(self.job_handler.get_job_status(), JobStatus.STARTING) _, kwargs = self.amqp_client.add_consumer.call_args_list[0] callback = kwargs['callback'] callback(self.JOB_SUCCESS, self.message) # end side_effect self.sleep_mock.side_effect = side_effect self.assertFalse(self.job_handler._is_job_done()) self.job_handler.push(self.TIMEOUT, self.MAX_RETRIES) self.amqp_client.add_consumer.assert_called_once() self.amqp_client.publish.assert_called_once() args, kwargs = self.amqp_client.publish.call_args_list[0] job_payload = args[0] job_execution_id = job_payload.get('job_execution_id') self.assertEqual(args[1], JobHandler.JOB_REQUEST_EXCHANGE) self.assertEqual(kwargs['routing_key'], JobHandler.JOB_REQUEST_ROUTING_KEY) args, kwargs = self.amqp_client.add_consumer.call_args_list[0] self.assertEqual(args[0], JobHandler.JOB_STATUS_CONSUMER + job_execution_id) self.assertEqual(args[1], JobHandler.JOB_STATUS_EXCHANGE) self.assertEqual(kwargs['routing_key'], JobHandler.JOB_STATUS_ROUTING_KEY + job_execution_id) self.assertEqual(kwargs['auto_delete'], True) self.message.ack.assert_called_once() self.amqp_client.remove_consumer.assert_called_once() self.assertTrue(self.job_handler._is_job_done()) self.assertEqual(self.job_handler.get_job_status(), JobStatus.SUCCESS) # end test_job_executed_successfully def test_job_stays_in_progress_then_completes(self): job_statuses = [self.JOB_IN_PROGRESS, self.JOB_IN_PROGRESS, self.JOB_SUCCESS] def side_effect(*_): side_effect.counter += 1 _, kwargs = self.amqp_client.add_consumer.call_args_list[0] callback = kwargs['callback'] callback(job_statuses[side_effect.counter-1], self.message) # end side_effect side_effect.counter = 0 self.sleep_mock.side_effect = side_effect self.assertFalse(self.job_handler._is_job_done()) self.job_handler.push(self.TIMEOUT, self.MAX_RETRIES) self.amqp_client.publish.assert_called_once() self.assertEqual(side_effect.counter, 3) self.assertTrue(self.job_handler._is_job_done()) self.assertEqual(self.job_handler.get_job_status(), JobStatus.SUCCESS) # end test_job_stays_in_progress_then_completes def test_job_failed(self): job_statuses = [self.JOB_IN_PROGRESS, self.JOB_FAILURE] def side_effect(*_): side_effect.counter += 1 _, kwargs = self.amqp_client.add_consumer.call_args_list[0] callback = kwargs['callback'] callback(job_statuses[side_effect.counter-1], self.message) # end side_effect side_effect.counter = 0 self.sleep_mock.side_effect = side_effect self.assertFalse(self.job_handler._is_job_done()) self.assertRaises(Exception, self.job_handler.push, self.TIMEOUT, self.MAX_RETRIES) self.amqp_client.publish.assert_called_once() self.assertEqual(side_effect.counter, 2) self.assertTrue(self.job_handler._is_job_done()) self.assertEqual(self.job_handler.get_job_status(), JobStatus.FAILURE) # end test_job_failed def test_execute_job_throws(self): self.assertFalse(self.job_handler._is_job_done()) self.amqp_client.publish.side_effect = \ cfgm_common.exceptions.TimeOutError(500) self.assertRaises(Exception, self.job_handler.push, self.TIMEOUT, self.MAX_RETRIES) self.amqp_client.publish.assert_called_once() self.sleep_mock.assert_not_called() self.assertTrue(self.job_handler._is_job_done()) self.assertEqual(self.job_handler.get_job_status(), JobStatus.FAILURE) # end test_execute_job_throws def test_max_retries_done(self): job_statuses = [self.JOB_IN_PROGRESS, self.JOB_IN_PROGRESS, self.JOB_IN_PROGRESS] def side_effect(*_): side_effect.counter += 1 _, kwargs = self.amqp_client.add_consumer.call_args_list[0] callback = kwargs['callback'] callback(job_statuses[side_effect.counter-1], self.message) # end side_effect side_effect.counter = 0 self.sleep_mock.side_effect = side_effect self.assertFalse(self.job_handler._is_job_done()) self.assertRaises(Exception, self.job_handler.push, self.TIMEOUT, 3) self.amqp_client.publish.assert_called_once() self.assertEqual(side_effect.counter, 3) self.assertTrue(self.job_handler._is_job_done()) self.assertEqual(self.job_handler.get_job_status(), JobStatus.FAILURE)