def mock_status_instance_side_effect(service, instance): # pragma: no cover (gevent) if instance in ['instance1', 'instance6', 'notaninstance', 'api_error']: # valid completed instance mock_mstatus = Mock(app_count=1, deploy_status='Running', expected_instance_count=2, running_instance_count=2) if instance == 'instance2': # too many marathon apps mock_mstatus = Mock(app_count=2, deploy_status='Running', expected_instance_count=2, running_instance_count=2) if instance == 'instance3': # too many running instances mock_mstatus = Mock(app_count=1, deploy_status='Running', expected_instance_count=2, running_instance_count=4) if instance == 'instance4': # still Deploying mock_mstatus = Mock(app_count=1, deploy_status='Deploying', expected_instance_count=2, running_instance_count=2) if instance == 'instance5': # not a marathon instance mock_mstatus = None if instance == 'instance7': # paasta stop'd mock_mstatus = Mock(app_count=1, deploy_status='Stopped', expected_instance_count=0, running_instance_count=0, desired_state='stop') if instance == 'instance8': # paasta has autoscaled to 0 mock_mstatus = Mock(app_count=1, deploy_status='Stopped', expected_instance_count=0, running_instance_count=0) mock_status = Mock() mock_status.git_sha = 'somesha' if instance == 'instance6': # running the wrong version mock_status.git_sha = 'anothersha' mock_status.marathon = mock_mstatus mock_result = mock_status mock_status_instance = Mock() mock_status_instance.result.return_value = mock_result if instance == 'notaninstance': # not an instance paasta can find mock_status_instance.result.side_effect = \ HTTPError(response=Mock(status_code=404)) if instance == 'api_error': # not an instance paasta can find mock_status_instance.result.side_effect = \ HTTPError(response=Mock(status_code=500)) return mock_status_instance
def test_scheduler_requeues_on_rwc_failure(in_memory_queue_connection, default_in_memory_producer, consume_queue): """Test scheduler requeues requests if RWC fails to start workflows.""" scheduler = WorkflowExecutionScheduler( connection=in_memory_queue_connection) in_memory_wsp = WorkflowSubmissionPublisher( connection=in_memory_queue_connection) in_memory_wsp.publish_workflow_submission("1", "workflow.1", {}) mock_rwc_api_client = Mock() mock_result_obj = Mock() mock_response = Mock() mock_response.status_code = 502 mock_result_obj.result = Mock(side_effect=HTTPError( mock_response, message="DB connection timed out.")) mock_rwc_api_client.api.set_workflow_status.return_value = mock_result_obj with patch.multiple( "reana_server.scheduler", reana_ready=Mock(return_value=True), current_rwc_api_client=mock_rwc_api_client, current_workflow_submission_publisher=in_memory_wsp, ): consume_queue(scheduler, limit=1) assert (not in_memory_queue_connection.channel(). queues["workflow-submission"].empty())
def test_response_and_message_and_swagger_result(response_500): incoming_response = RequestsResponseAdapter(response_500) actual = str( HTTPError(incoming_response, message="Holy moly!", swagger_result={'msg': 'Kaboom'})) assert actual == "500 Server Error: Holy moly!: {'msg': 'Kaboom'}"
def response_callback(incoming_response, operation): """ So the http_client is finished with its part of processing the response. This hands the response over to bravado_core for validation and unmarshalling. :type incoming_response: :class:`bravado_core.response.IncomingResponse` :type operation: :class:`bravado_core.operation.Operation` :return: Response spec's return value. :raises: HTTPError - On 5XX status code, the HTTPError has minimal information. - On non-2XX status code with no matching response, the HTTPError contains a detailed error message. - On non-2XX status code with a matching response, the HTTPError contains the return value. """ raise_on_unexpected(incoming_response) try: swagger_return_value = unmarshal_response(incoming_response, operation) except MatchingResponseNotFound as e: six.reraise(HTTPError, HTTPError(response=incoming_response, message=str(e)), sys.exc_info()[2]) raise_on_expected(incoming_response, swagger_return_value) return swagger_return_value
def result(self, timeout=None): """Blocking call to wait for the HTTP response. :param timeout: Number of seconds to wait for a response. Defaults to None which means wait indefinitely. :type timeout: float :return: Depends on the value of also_return_response sent in to the constructor. """ inner_response = self.future.result(timeout=timeout) incoming_response = self.response_adapter(inner_response) if self.operation is not None: unmarshal_response(incoming_response, self.operation, self.response_callbacks) swagger_result = incoming_response.swagger_result if self.also_return_response: return swagger_result, incoming_response return swagger_result if 200 <= incoming_response.status_code < 300: return incoming_response raise HTTPError(response=incoming_response)
def test_secrets_add_already_exist(): """Test adding secrets when they already exist.""" status_code = 409 reana_token = '000000' env = {'REANA_SERVER_URL': 'localhost'} message = 'One of the secrets already exists. No secrets were added.' mock_http_response = Mock( status_code=status_code, reason='Conflict', json=Mock(return_value={'message': 'Conflict'})) rs_api_client_mock = Mock() rs_api_client_mock.api.add_secrets = Mock( side_effect=HTTPError(mock_http_response)) runner = CliRunner(env=env) with runner.isolation(): with patch( "reana_client.api.client.current_rs_api_client", rs_api_client_mock): result = runner.invoke( cli, ['secrets-add', '-t', reana_token, '--from-literal', 'USER=reanauser'] ) assert message in result.output assert result.exit_code == 1
def test_get_task_from_instance(mock_client): mock_client.get_paasta_api_client.return_value = None with raises(utils.PaastaTaskNotFound): utils.get_task_from_instance('cluster1', 'my-service', 'main') mock_client.get_paasta_api_client.assert_called_with(cluster='cluster1') mock_api = mock.Mock() mock_client.get_paasta_api_client.return_value = mock_api mock_task_1 = mock.Mock() mock_task_2 = mock.Mock() mock_tasks = [mock_task_1, mock_task_2] mock_result = mock.Mock(return_value=mock_tasks) mock_task_result = mock.Mock(return_value=mock_task_2) mock_api.service.tasks_instance.return_value = mock.Mock(result=mock_result) mock_api.service.task_instance.return_value = mock.Mock(result=mock_task_result) ret = utils.get_task_from_instance('cluster1', 'my-service', 'main', task_id='123') assert ret == mock_task_2 mock_api.service.task_instance.assert_called_with( service='my-service', instance='main', verbose=True, task_id='123', ) ret = utils.get_task_from_instance('cluster1', 'my-service', 'main') assert ret == mock_task_1 mock_api.service.tasks_instance.assert_called_with( service='my-service', instance='main', verbose=True, slave_hostname=None, ) mock_result = mock.Mock(return_value=[]) mock_api.service.tasks_instance.return_value = mock.Mock(result=mock_result) with raises(utils.PaastaTaskNotFound): ret = utils.get_task_from_instance( 'cluster1', 'my-service', 'main', slave_hostname='test', ) mock_api.service.tasks_instance.side_effect = HTTPError(response=mock.Mock(status_code=500)) with raises(utils.PaastaTaskNotFound): ret = utils.get_task_from_instance( 'cluster1', 'my-service', 'main', slave_hostname='test', ) mock_api.service.tasks_instance.assert_called_with( service='my-service', instance='main', verbose=True, slave_hostname='test', ) mock_api.service.tasks_instance.side_effect = HTTPNotFound(response=mock.Mock(status_code=404)) with raises(utils.PaastaTaskNotFound): ret = utils.get_task_from_instance( 'cluster1', 'my-service', 'main', slave_hostname='test', )
def mock_http_err(): return HTTPError( mock.MagicMock( spec=IncomingResponse, status_code='503', text='nothing', ) )
def raise_on_unexpected(http_response): """Raise an HTTPError if the response is 5XX. :param http_response: :class:`bravado_core.response.IncomingResponse` :raises: HTTPError """ if 500 <= http_response.status_code <= 599: raise HTTPError(response=http_response)
def raise_on_expected(http_response): """Raise an HTTPError if the response is non-2XX and matches a response in the swagger spec. :param http_response: :class:`bravado_core.response.IncomingResponse` :raises: HTTPError """ if not 200 <= http_response.status_code < 300: raise HTTPError(response=http_response, swagger_result=http_response.swagger_result)
def raise_on_expected(http_response, swagger_return_value): """ Raise an HTTPError if the response is non-2XX and matches a response in the swagger spec. :param http_response: :class:`bravado_core.response.IncomingResponse` :param swagger_return_value: The return value of a swagger response if it has one, None otherwise. :raises: HTTPError """ if not 200 <= http_response.status_code < 300: raise HTTPError(response=http_response, swagger_result=swagger_return_value)
def test_http_error(mock_get_paasta_api_client): args = mock.Mock() args.cluster = "westeros-prod" mock_response = mock.Mock(status_code=500, text="Internal Server Error") response_adapter = RequestsResponseAdapter(mock_response) mock_api_client = mock_get_paasta_api_client.return_value mock_api_client.deploy_queue.deploy_queue.return_value.result.side_effect = HTTPError( response_adapter ) assert list_deploy_queue(args) == 500
def test_400_service_call(mock_unmarshal_response): response_adapter_instance = Mock(spec=IncomingResponse, status_code=400, swagger_result={'error': 'Blah'}) mock_unmarshal_response.side_effect = HTTPError(response_adapter_instance) response_adapter_type = Mock(return_value=response_adapter_instance) http_future = HttpFuture(future=Mock(spec=FutureAdapter), response_adapter=response_adapter_type, operation=Mock(spec=Operation)) with pytest.raises(HTTPError) as excinfo: http_future.result() assert excinfo.value.response.status_code == 400
def test_paasta_status_exception(system_paasta_config): system_paasta_config = system_paasta_config with mock.patch('paasta_tools.cli.cmds.status.get_paasta_api_client', autospec=True) as mock_get_paasta_api_client: requests_response = mock.Mock(status_code=500, reason='Internal Server Error') incoming_response = RequestsResponseAdapter(requests_response) mock_swagger_client = mock.Mock() mock_swagger_client.service.status_instance.side_effect = HTTPError( incoming_response) mock_get_paasta_api_client.return_value = mock_swagger_client paasta_status_on_api_endpoint( 'fake_cluster', 'fake_service', 'fake_instance', system_paasta_config, verbose=False, )
def result(self, timeout=None): """Blocking call to wait for API response :param timeout: Number of seconds to wait for a response. Defaults to None which means wait indefinitely. :type timeout: float :return: swagger response return value when given a callback or the http_response otherwise. """ inner_response = self.future.result(timeout=timeout) incoming_response = self.response_adapter(inner_response) if self.response_callback: swagger_return_value = self.response_callback(incoming_response) return swagger_return_value if 200 <= incoming_response.status_code < 300: return incoming_response raise HTTPError(response=incoming_response)
def test_secrets_add_already_exist(): """Test adding secrets when they already exist.""" status_code = 409 reana_token = "000000" env = {"REANA_SERVER_URL": "localhost"} message = "One of the secrets already exists. No secrets were added." mock_http_response = Mock( status_code=status_code, reason="Conflict", json=Mock(return_value={"message": "Conflict"}), ) rs_api_client_mock = Mock() rs_api_client_mock.api.add_secrets = Mock(side_effect=HTTPError(mock_http_response)) runner = CliRunner(env=env) with runner.isolation(): with patch("reana_client.api.client.current_rs_api_client", rs_api_client_mock): result = runner.invoke( cli, ["secrets-add", "-t", reana_token, "--env", "USER=reanauser"] ) assert message in result.output assert result.exit_code == 1
def unmarshal_response(incoming_response, operation, response_callbacks=None): """So the http_client is finished with its part of processing the response. This hands the response over to bravado_core for validation and unmarshalling and then runs any response callbacks. On success, the swagger_result is available as ``incoming_response.swagger_result``. :type incoming_response: :class:`bravado_core.response.IncomingResponse` :type operation: :class:`bravado_core.operation.Operation` :type response_callbacks: list of callable. See bravado_core.client.REQUEST_OPTIONS_DEFAULTS. :raises: HTTPError - On 5XX status code, the HTTPError has minimal information. - On non-2XX status code with no matching response, the HTTPError contains a detailed error message. - On non-2XX status code with a matching response, the HTTPError contains the return value. """ response_callbacks = response_callbacks or [] try: raise_on_unexpected(incoming_response) incoming_response.swagger_result = \ bravado_core.response.unmarshal_response( incoming_response, operation) except MatchingResponseNotFound as e: six.reraise( HTTPError, HTTPError(response=incoming_response, message=str(e)), sys.exc_info()[2]) finally: # Always run the callbacks regardless of success/failure for response_callback in response_callbacks: response_callback(incoming_response, operation) raise_on_expected(incoming_response)
def test_response_and_message(response_500): incoming_response = RequestsResponseAdapter(response_500) actual = str(HTTPError(incoming_response, message="Kaboom")) assert actual == '500 Server Error: Kaboom'
def test_response_only(response_500): incoming_response = RequestsResponseAdapter(response_500) assert str(HTTPError(incoming_response)) == '500 Server Error'
def mock_status_instance_side_effect(service, instance, omit_smartstack, omit_mesos): if instance in ["instance1", "instance6", "notaninstance", "api_error"]: # valid completed instance mock_mstatus = Mock( app_count=1, deploy_status="Running", expected_instance_count=2, running_instance_count=2, ) if instance == "instance2": # too many marathon apps mock_mstatus = Mock( app_count=2, deploy_status="Running", expected_instance_count=2, running_instance_count=2, ) if instance == "instance3": # too many running instances mock_mstatus = Mock( app_count=1, deploy_status="Running", expected_instance_count=2, running_instance_count=4, ) if instance == "instance4": # still Deploying mock_mstatus = Mock( app_count=1, deploy_status="Deploying", expected_instance_count=2, running_instance_count=2, ) if instance == "instance4.1": # still Deploying mock_mstatus = Mock( app_count=1, deploy_status="Waiting", expected_instance_count=2, running_instance_count=2, ) if instance == "instance5": # not a marathon instance mock_mstatus = None if instance == "instance7": # paasta stop'd mock_mstatus = Mock( app_count=1, deploy_status="Stopped", expected_instance_count=0, running_instance_count=0, desired_state="stop", ) if instance == "instance8": # paasta has autoscaled to 0 mock_mstatus = Mock( app_count=1, deploy_status="Stopped", expected_instance_count=0, running_instance_count=0, ) mock_status = Mock() mock_status.git_sha = "somesha" if instance == "instance6": # running the wrong version mock_status.git_sha = "anothersha" mock_status.marathon = mock_mstatus mock_status.kubernetes = None mock_result = mock_status mock_status_instance = Mock() mock_status_instance.result.return_value = mock_result if instance == "notaninstance": # not an instance paasta can find mock_status_instance.result.side_effect = HTTPError(response=Mock( status_code=404)) if instance == "api_error": # not an instance paasta can find mock_status_instance.result.side_effect = HTTPError(response=Mock( status_code=500)) return mock_status_instance