Files
deb-python-dcos/tests/test_marathon.py
2016-12-02 12:50:46 -08:00

842 lines
29 KiB
Python

import re
import jsonschema
import mock
import pytest
import requests
from requests.structures import CaseInsensitiveDict
from dcos import http, marathon, rpcclient
from dcos.errors import DCOSException, DCOSHTTPException
def test_add_pod_puts_json_in_request_body():
_assert_add_pod_puts_json_in_request_body(pod_json={"some": "json"})
_assert_add_pod_puts_json_in_request_body(
pod_json=["another", {"json": "value"}])
def test_add_pod_returns_parsed_response_body():
_assert_add_pod_returns_parsed_response_body({"id": "i-am-a-pod"})
_assert_add_pod_returns_parsed_response_body(["another", "pod", "json"])
def test_remove_pod_has_default_force_value():
marathon_client, rpc_client = _create_fixtures()
marathon_client.remove_pod('foo')
rpc_client.http_req.assert_called_with(
http.delete, 'v2/pods/foo', params=None)
def test_remove_pod_builds_rpc_correctly():
_assert_remove_pod_builds_rpc_correctly(
pod_id='foo', force=False, path='v2/pods/foo', params=None)
_assert_remove_pod_builds_rpc_correctly(
pod_id='foo', force=True, path='v2/pods/foo', params={'force': 'true'})
_assert_remove_pod_builds_rpc_correctly(
pod_id='/foo bar/', force=False, path='v2/pods/foo%20bar', params=None)
def test_remove_pod_propagates_dcos_exception():
_assert_method_propagates_rpc_dcos_exception(
lambda marathon_client: marathon_client.remove_pod('bad'))
def test_show_pod_builds_rpc_correctly():
_assert_show_pod_builds_rpc_correctly(
pod_id='foo', path='v2/pods/foo::status')
_assert_show_pod_builds_rpc_correctly(
pod_id='/bar', path='v2/pods/bar::status')
_assert_show_pod_builds_rpc_correctly(
pod_id='baz/', path='v2/pods/baz::status')
_assert_show_pod_builds_rpc_correctly(
pod_id='foo bar', path='v2/pods/foo%20bar::status')
def test_show_pod_returns_response_json():
_assert_show_pod_returns_response_json({'some': 'json'})
_assert_show_pod_returns_response_json(['another', 'json', 'value'])
def test_show_pod_propagates_dcos_exception():
_assert_method_propagates_rpc_dcos_exception(
lambda marathon_client: marathon_client.show_pod('bad-req'))
def test_show_pod_raises_dcos_exception_for_json_parse_errors():
_assert_method_raises_dcos_exception_for_json_parse_errors(
lambda marathon_client: marathon_client.show_pod('bad-json'))
def test_list_pod_builds_rpc_correctly():
marathon_client, rpc_client = _create_fixtures()
marathon_client.list_pod()
rpc_client.http_req.assert_called_with(http.get, 'v2/pods/::status')
def test_list_pod_returns_success_response_json():
_assert_list_pod_returns_success_response_json(body_json={'some': 'json'})
_assert_list_pod_returns_success_response_json(body_json=['a', 'b', 'c'])
def test_list_pod_propagates_rpc_dcos_exception():
_assert_method_propagates_rpc_dcos_exception(
lambda marathon_client: marathon_client.list_pod())
def test_list_pod_raises_dcos_exception_for_json_parse_errors():
_assert_method_raises_dcos_exception_for_json_parse_errors(
lambda marathon_client: marathon_client.list_pod())
def test_update_pod_executes_successfully():
_assert_update_pod_executes_successfully(
pod_id='foo',
pod_json={'some', 'json'},
force=False,
path='v2/pods/foo',
params=None,
deployment_id='pod-deployment-id')
_assert_update_pod_executes_successfully(
pod_id='/foo bar/',
pod_json={'some', 'json'},
force=False,
path='v2/pods/foo%20bar',
params=None,
deployment_id='pod-deployment-id')
_assert_update_pod_executes_successfully(
pod_id='foo',
pod_json={'some', 'json'},
force=True,
path='v2/pods/foo',
params={'force': 'true'},
deployment_id='pod-deployment-id')
_assert_update_pod_executes_successfully(
pod_id='foo',
pod_json={'something', 'different'},
force=False,
path='v2/pods/foo',
params=None,
deployment_id='pod-deployment-id')
_assert_update_pod_executes_successfully(
pod_id='foo',
pod_json={'some', 'json'},
force=False,
path='v2/pods/foo',
params=None,
deployment_id='an-arbitrary-value')
def test_update_pod_has_default_force_value():
marathon_client, rpc_client = _create_fixtures()
marathon_client.update_pod('foo', {'some': 'json'})
rpc_client.http_req.assert_called_with(
http.put, 'v2/pods/foo', params=None, json={'some': 'json'})
def test_update_pod_propagates_rpc_dcos_exception():
_assert_method_propagates_rpc_dcos_exception(
lambda marathon_client:
marathon_client.update_pod('foo', {'some': 'json'}))
def test_add_pod_raises_dcos_exception_if_deployment_id_missing():
_assert_add_pod_raises_dcos_exception_if_deployment_id_missing(
headers={'foo': 'bar'})
_assert_add_pod_raises_dcos_exception_if_deployment_id_missing(
headers={'marathon-deployment_ID': 'misspelled-field', 'zzz': 'aaa'})
def test_update_pod_raises_dcos_exception_if_deployment_id_missing():
_assert_update_pod_raises_dcos_exception_if_deployment_id_missing(
headers={'foo': 'bar'})
_assert_update_pod_raises_dcos_exception_if_deployment_id_missing(
headers={'marathon-deployment_ID': 'misspelled-field', 'zzz': 'aaa'})
def test_kill_pod_instances_executes_successfully():
pod_id = 'foo'
instance_ids = ['instance1', 'instance2']
path = 'v2/pods/foo::instances'
response_json = {'some': ['instance', 'status']}
mock_response = mock.create_autospec(requests.Response)
mock_response.json.return_value = response_json
marathon_client, rpc_client = _create_fixtures()
rpc_client.http_req.return_value = mock_response
path_format_method_name = 'dcos.marathon.Client._marathon_id_path_format'
path_format = mock.MagicMock()
path_format.return_value = path
with mock.patch(path_format_method_name, new=path_format):
actual_json = marathon_client.kill_pod_instances(pod_id, instance_ids)
path_format.assert_called_with('v2/pods/{}::instances', pod_id)
rpc_client.http_req.assert_called_with(
http.delete, path, json=instance_ids)
assert actual_json == response_json
def test_kill_pod_instances_propagates_rpc_dcos_exception():
_assert_method_propagates_rpc_dcos_exception(
lambda marathon_client:
marathon_client.kill_pod_instances('foo', ['inst1', 'inst2']))
def test_kill_pod_instances_raises_dcos_exception_for_json_parse_errors():
_assert_method_raises_dcos_exception_for_json_parse_errors(
lambda marathon_client: marathon_client.kill_pod_instances(
'foo', ['bar', 'baz']))
@mock.patch('dcos.http.head')
def test_pod_feature_supported_gets_success_response(head_fn):
def invoke_test_case(status_code):
mock_response = mock.create_autospec(requests.Response)
mock_response.status_code = status_code
head_fn.return_value = mock_response
rpc_client = rpcclient.RpcClient('http://base/url', timeout=42)
marathon_client = marathon.Client(rpc_client)
is_supported = marathon_client.pod_feature_supported()
head_fn.assert_called_with('http://base/url/v2/pods', timeout=42)
return is_supported
assert invoke_test_case(status_code=200)
assert invoke_test_case(status_code=204)
assert not invoke_test_case(status_code=100)
assert not invoke_test_case(status_code=302)
@mock.patch('dcos.http.head')
def test_pod_feature_supported_gets_404_response(head_fn):
mock_response = mock.create_autospec(requests.Response)
mock_response.status_code = 404
head_fn.side_effect = DCOSHTTPException(mock_response)
rpc_client = rpcclient.RpcClient('http://base/url', timeout=24)
marathon_client = marathon.Client(rpc_client)
assert not marathon_client.pod_feature_supported()
head_fn.assert_called_with('http://base/url/v2/pods', timeout=24)
def test_pod_feature_supported_converts_http_exceptions_to_dcos_exceptions():
@mock.patch('dcos.http.head')
def test_case(head_fn, status_code):
request = requests.Request(method='ANY', url='http://arbitrary/url')
mock_response = mock.create_autospec(requests.Response)
mock_response.status_code = status_code
mock_response.reason = 'Arbitrary Reason'
mock_response.request = request
mock_response.json.side_effect = ValueError('empty body')
head_fn.side_effect = DCOSHTTPException(mock_response)
rpc_client = rpcclient.RpcClient('http://does/not/matter')
marathon_client = marathon.Client(rpc_client)
with pytest.raises(DCOSException) as exception_info:
marathon_client.pod_feature_supported()
message = rpcclient.RpcClient.response_error_message(
status_code,
reason='Arbitrary Reason',
request_method='ANY',
request_url='http://arbitrary/url',
json_body=None)
assert str(exception_info.value).endswith(message)
test_case(status_code=400)
test_case(status_code=401)
test_case(status_code=403)
test_case(status_code=409)
test_case(status_code=422)
test_case(status_code=500)
def test_pod_feature_supported_propagates_other_exceptions():
_assert_pod_feature_supported_raises_exception(
exception=DCOSException("BOOM!"))
_assert_pod_feature_supported_raises_exception(
exception=Exception("Uh oh"))
def test_rpc_client_http_req_calls_method_fn():
def test_case(base_url, path, full_url):
method_fn = mock.Mock()
rpc_client = rpcclient.RpcClient(base_url)
rpc_client.http_req(method_fn, path)
method_fn.assert_called_with(full_url,
timeout=http.DEFAULT_TIMEOUT)
test_case(
base_url='http://base/url',
path='some/path',
full_url='http://base/url/some/path')
test_case(
base_url='http://base/url',
path='different/thing',
full_url='http://base/url/different/thing')
test_case(
base_url='gopher://different/thing',
path='some/path',
full_url='gopher://different/thing/some/path')
test_case(
base_url='http://base/without/slash',
path='/path/with/slash',
full_url='http://base/without/slash/path/with/slash')
test_case(
base_url='http://base/with/slash/',
path='path/without/slash',
full_url='http://base/with/slash/path/without/slash')
test_case(
base_url='http://base/with/slash/',
path='/path/with/slash',
full_url='http://base/with/slash/path/with/slash')
def test_rpc_client_http_req_passes_args_to_method_fn():
method_fn = mock.Mock()
rpc_client = rpcclient.RpcClient('http://base/url')
rpc_client.http_req(method_fn, 'some/path', 'foo', 42)
method_fn.assert_called_with('http://base/url/some/path',
'foo',
42,
timeout=http.DEFAULT_TIMEOUT)
def test_rpc_client_http_req_passes_kwargs_to_method_fn():
method_fn = mock.Mock()
rpc_client = rpcclient.RpcClient('http://base/url')
rpc_client.http_req(method_fn, 'some/path', foo='bar', baz=42)
method_fn.assert_called_with('http://base/url/some/path',
foo='bar',
baz=42,
timeout=http.DEFAULT_TIMEOUT)
def test_rpc_client_http_req_kwarg_timeout_overrides_default():
method_fn = mock.Mock()
rpc_client = rpcclient.RpcClient('http://base/url')
rpc_client.http_req(method_fn, 'some/path', timeout=42)
method_fn.assert_called_with('http://base/url/some/path', timeout=42)
def test_rpc_client_http_req_set_timeout_in_constructor():
method_fn = mock.Mock()
rpc_client = rpcclient.RpcClient('http://base/url', 24)
rpc_client.http_req(method_fn, 'some/path')
method_fn.assert_called_with('http://base/url/some/path', timeout=24)
def test_rpc_client_http_req_returns_method_fn_result():
def test_case(expected):
def method_fn(*args, **kwargs):
return expected
rpc_client = rpcclient.RpcClient('http://base/url')
actual = rpc_client.http_req(method_fn, 'some/path')
assert actual == expected
test_case(['the', 'result'])
test_case({'another': 'result'})
def test_rpc_client_http_req_propagates_method_fn_exception_1():
request = requests.Request(method='ANY', url='http://arbitrary/url')
# Need the mock so that the `.json()` method can be overridden
response = mock.create_autospec(requests.Response)
response.status_code = 403
response.reason = 'Forbidden'
response.request = request
response.json.side_effect = Exception('not JSON')
def method_fn(*args, **kwargs):
raise DCOSHTTPException(response)
rpc_client = rpcclient.RpcClient('http://base/url')
with pytest.raises(DCOSException) as e:
rpc_client.http_req(method_fn, 'some/path')
expected_message = rpcclient.RpcClient.response_error_message(
status_code=403,
reason='Forbidden',
request_method='ANY',
request_url='http://arbitrary/url',
json_body=None)
assert str(e).endswith(expected_message)
def test_rpc_client_http_req_propagates_method_fn_exception_2():
request = requests.Request(method='NONE', url='http://host/path')
# Need the mock so that the `.json()` method can be overridden
response = mock.create_autospec(requests.Response)
response.status_code = 422
response.reason = 'Something Bad'
response.request = request
response.json.return_value = {'message': 'BOOM!'}
def method_fn(*args, **kwargs):
raise DCOSHTTPException(response)
rpc_client = rpcclient.RpcClient('http://base/url')
with pytest.raises(DCOSException) as e:
rpc_client.http_req(method_fn, 'some/path')
expected_message = rpcclient.RpcClient.response_error_message(
status_code=422,
reason='Something Bad',
request_method='None',
request_url='http://host/path',
json_body={'message': 'BOOM!'})
assert str(e).endswith(expected_message)
def test_error_json_schema_is_valid():
error_json_schema = rpcclient.load_error_json_schema()
jsonschema.Draft4Validator.check_schema(error_json_schema)
def test_response_error_message_with_400_status_no_json():
_assert_response_error_message_with_400_status_no_json(
reason=_REASON_1,
request_method=_METHOD_1,
request_url=_URL_1)
_assert_response_error_message_with_400_status_no_json(
reason=_REASON_2,
request_method=_METHOD_2,
request_url=_URL_2)
def test_response_error_message_with_400_status_json():
_assert_response_error_message_with_400_status_json(
_RESPONSE_JSON_1, _PRINTED_JSON_1)
_assert_response_error_message_with_400_status_json(
_RESPONSE_JSON_2, _PRINTED_JSON_2)
def test_res_err_msg_with_409_status():
def test_case(request_url, expected_resource):
actual = rpcclient.RpcClient.response_error_message(
status_code=409,
reason=_REASON_X,
request_method=_METHOD_X,
request_url=request_url,
json_body=None)
pattern = r'Changes blocked: deployment already in progress for (.*)\.'
_assert_matches_with_groups(pattern, actual, (expected_resource,))
test_case('http://marathon/v2/apps', 'app')
test_case('http://marathon/v2/groups/group-id', 'group')
test_case('http://marathon/v2/pods/', 'pod')
test_case('http://marathon/v2/thingies/foo', 'resource')
test_case('http://dcos/service/marathon/v2/apps/bar', 'app')
test_case('http://pods-app.com/service/marathon/v2/groups/baz', 'group')
def test_response_error_message_with_other_status_no_json():
_assert_response_error_message_with_other_status_no_json(
status_code=401,
reason=_REASON_1,
request_url=_URL_1)
_assert_response_error_message_with_other_status_no_json(
status_code=401,
reason=_REASON_2,
request_url=_URL_2)
_assert_response_error_message_with_other_status_no_json(
status_code=403,
reason=_REASON_X,
request_url=_URL_X)
_assert_response_error_message_with_other_status_no_json(
status_code=404,
reason=_REASON_X,
request_url=_URL_X)
_assert_response_error_message_with_other_status_no_json(
status_code=422,
reason=_REASON_X,
request_url=_URL_X)
def test_response_error_message_with_other_status_json_has_message():
_assert_response_error_message_with_other_status_json_has_message(
status_code=401,
json_message=_MESSAGE_1)
_assert_response_error_message_with_other_status_json_has_message(
status_code=401,
json_message=_MESSAGE_2)
_assert_response_error_message_with_other_status_json_has_message(
status_code=403,
json_message=_MESSAGE_X)
_assert_response_error_message_with_other_status_json_has_message(
status_code=404,
json_message=_MESSAGE_X)
_assert_response_error_message_with_other_status_json_has_message(
status_code=422,
json_message=_MESSAGE_X)
def test_res_err_msg_with_other_status_json_no_message_has_valid_errors():
_assert_res_err_msg_with_other_status_json_no_message_has_valid_errors(
status_code=401,
errors_json=[{'error': 'err1'}, {'error': 'err2'}],
errors_str='err1\nerr2')
_assert_res_err_msg_with_other_status_json_no_message_has_valid_errors(
status_code=401,
errors_json=[{'error': 'foo'}, {'error': 'bar'}, {'error': 'baz'}],
errors_str='foo\nbar\nbaz')
_assert_res_err_msg_with_other_status_json_no_message_has_valid_errors(
status_code=403,
errors_json=[{'error': 'foo'}, {'error': 'bar'}, {'error': 'baz'}],
errors_str='foo\nbar\nbaz')
_assert_res_err_msg_with_other_status_json_no_message_has_valid_errors(
status_code=404,
errors_json=[{'error': 'foo'}, {'error': 'bar'}, {'error': 'baz'}],
errors_str='foo\nbar\nbaz')
_assert_res_err_msg_with_other_status_json_no_message_has_valid_errors(
status_code=422,
errors_json=[{'error': 'foo'}, {'error': 'bar'}, {'error': 'baz'}],
errors_str='foo\nbar\nbaz')
def test_res_err_msg_with_other_status_invalid_error_json():
# Is not an object
_assert_res_err_msg_with_other_status_invalid_json(401, 'Error!')
_assert_res_err_msg_with_other_status_invalid_json(401, ['Error!'])
# Missing both message and errors fields
_assert_res_err_msg_with_other_status_invalid_json(401, {})
_assert_res_err_msg_with_other_status_invalid_json(
401, {'foo': 5, 'bar': 'x'})
# Has non-str message
_assert_res_err_msg_with_other_status_invalid_json(401, {'message': 42})
_assert_res_err_msg_with_other_status_invalid_json(
401, {'message': ['Oops!']})
# Has non-array errors
_assert_res_err_msg_with_other_status_invalid_json(401, {'errors': 42})
_assert_res_err_msg_with_other_status_invalid_json(
401, {'errors': {'error': 5}})
# Errors array has non-object elements
_assert_res_err_msg_with_other_status_invalid_json(
401, {'errors': [42, True]})
_assert_res_err_msg_with_other_status_invalid_json(
401, {'errors': [{'error': 'BOOM!'}, 'not_an_error']})
# Errors array has objects without `error` field
_assert_res_err_msg_with_other_status_invalid_json(
401, {'errors': [{'error': 'BOOM!'}, {'foo': 'bar'}]})
# Errors array has objects with non-str `error` field
_assert_res_err_msg_with_other_status_invalid_json(
401, {'errors': [{'error': 'BOOM!'}, {'error': 42}]})
# Other status codes
_assert_res_err_msg_with_other_status_invalid_json(
403, {'errors': [{'error': 'BOOM!'}, {'error': 42}]})
_assert_res_err_msg_with_other_status_invalid_json(
404, {'errors': [{'error': 'BOOM!'}, {'error': 42}]})
_assert_res_err_msg_with_other_status_invalid_json(
422, {'errors': [{'error': 'BOOM!'}, {'error': 42}]})
def _assert_add_pod_puts_json_in_request_body(pod_json):
rpc_client = mock.create_autospec(rpcclient.RpcClient)
client = marathon.Client(rpc_client)
client.add_pod(pod_json)
rpc_client.http_req.assert_called_with(http.post, 'v2/pods', json=pod_json)
def _assert_add_pod_returns_parsed_response_body(response_json):
headers = {'Marathon-Deployment-Id': "XYZ"}
mock_response = _pod_response_fixture(headers)
mock_response.json.return_value = response_json
marathon_client, rpc_client = _create_fixtures()
rpc_client.http_req.return_value = mock_response
assert marathon_client.add_pod({'some': 'json'}) == "XYZ"
def _assert_remove_pod_builds_rpc_correctly(pod_id, force, path, params):
marathon_client, rpc_client = _create_fixtures()
marathon_client.remove_pod(pod_id, force)
rpc_client.http_req.assert_called_with(http.delete, path, params=params)
def _assert_show_pod_builds_rpc_correctly(pod_id, path):
marathon_client, rpc_client = _create_fixtures()
marathon_client.show_pod(pod_id)
rpc_client.http_req.assert_called_with(http.get, path)
def _assert_show_pod_returns_response_json(expected):
marathon_client, rpc_client = _create_fixtures()
mock_response = mock.create_autospec(requests.Response)
mock_response.json.return_value = expected
rpc_client.http_req.return_value = mock_response
response_json = marathon_client.show_pod('arbitrary-id')
assert response_json == expected
def _assert_list_pod_returns_success_response_json(body_json):
marathon_client, rpc_client = _create_fixtures()
mock_response = mock.create_autospec(requests.Response)
mock_response.json.return_value = body_json
rpc_client.http_req.return_value = mock_response
assert marathon_client.list_pod() == body_json
def _assert_update_pod_executes_successfully(
pod_id, pod_json, force, path, params, deployment_id):
headers = {'Marathon-Deployment-Id': deployment_id}
mock_response = _pod_response_fixture(headers)
marathon_client, rpc_client = _create_fixtures()
rpc_client.http_req.return_value = mock_response
actual_return = marathon_client.update_pod(pod_id, pod_json, force)
rpc_client.http_req.assert_called_with(
http.put, path, params=params, json=pod_json)
assert actual_return == deployment_id
def _assert_method_raises_dcos_exception_for_json_parse_errors(invoke_method):
def assert_test_case(non_json):
mock_response = mock.create_autospec(requests.Response)
mock_response.json.side_effect = Exception()
mock_response.text = non_json
marathon_client, rpc_client = _create_fixtures()
rpc_client.http_req.return_value = mock_response
with pytest.raises(DCOSException) as exception_info:
invoke_method(marathon_client)
pattern = ('Error: Response from Marathon was not in expected JSON '
'format:\n(.*)')
actual_error = str(exception_info.value)
_assert_matches_with_groups(pattern, actual_error, (non_json,))
assert_test_case('not-json')
assert_test_case('{"oops"}')
def _assert_add_pod_raises_dcos_exception_if_deployment_id_missing(headers):
marathon_client, rpc_client = _create_fixtures()
rpc_client.http_req.return_value = _pod_response_fixture(headers)
result = marathon_client.add_pod({'some': 'json'})
assert result is None
def _assert_update_pod_raises_dcos_exception_if_deployment_id_missing(headers):
marathon_client, rpc_client = _create_fixtures()
rpc_client.http_req.return_value = _pod_response_fixture(headers)
with pytest.raises(DCOSException) as exception_info:
marathon_client.update_pod('foo', {'some': 'json'})
expected_error = ('Error: missing "Marathon-Deployment-Id" header from '
'Marathon response')
assert str(exception_info.value) == expected_error
def _assert_method_propagates_rpc_dcos_exception(invoke_method):
marathon_client, rpc_client = _create_fixtures()
rpc_client.http_req.side_effect = DCOSException('BOOM!')
with pytest.raises(DCOSException) as exception_info:
invoke_method(marathon_client)
assert str(exception_info.value) == 'BOOM!'
@mock.patch('dcos.http.head')
def _assert_pod_feature_supported_raises_exception(head_fn, exception):
rpc_client = rpcclient.RpcClient('http://base/url', timeout=22)
marathon_client = marathon.Client(rpc_client)
head_fn.side_effect = exception
with pytest.raises(exception.__class__) as exception_info:
marathon_client.pod_feature_supported()
assert exception_info.value == exception
def _assert_response_error_message_with_400_status_no_json(
reason, request_method, request_url):
message = rpcclient.RpcClient.response_error_message(
status_code=400,
reason=reason,
request_method=request_method,
request_url=request_url,
json_body=None)
pattern = r'Error on request \[(.*) (.*)\]: HTTP 400: (.*)'
groups = (request_method, request_url, reason)
_assert_matches_with_groups(pattern, message, groups)
def _assert_response_error_message_with_400_status_json(
response_json, printed_json):
message = rpcclient.RpcClient.response_error_message(
status_code=400,
reason=_REASON_X,
request_method=_METHOD_X,
request_url=_URL_X,
json_body=response_json)
error_line, json_lines = message.split('\n', 1)
pattern = r'Error on request \[(.*) (.*)\]: HTTP 400: (.*):'
groups = (_METHOD_X, _URL_X, _REASON_X)
_assert_matches_with_groups(pattern, error_line, groups)
assert json_lines == printed_json
def _assert_response_error_message_with_other_status_no_json(
status_code, reason, request_url):
message = rpcclient.RpcClient.response_error_message(
status_code=status_code,
reason=reason,
request_method=_METHOD_X,
request_url=request_url,
json_body=None)
pattern = r'Error decoding response from \[(.*)\]: HTTP (.*): (.*)'
groups = (request_url, str(status_code), reason)
_assert_matches_with_groups(pattern, message, groups)
def _assert_response_error_message_with_other_status_json_has_message(
status_code, json_message):
error_message = rpcclient.RpcClient.response_error_message(
status_code=status_code,
reason=_REASON_X,
request_method=_METHOD_X,
request_url=_URL_X,
json_body={'message': json_message})
pattern = r'Error: (.*)'
_assert_matches_with_groups(pattern, error_message, (json_message,))
def _assert_res_err_msg_with_other_status_json_no_message_has_valid_errors(
status_code, errors_json, errors_str):
message = rpcclient.RpcClient.response_error_message(
status_code=status_code,
reason=_REASON_X,
request_method=_METHOD_X,
request_url=_URL_X,
json_body={'errors': errors_json})
pattern = (r'Service likely misconfigured\. Please check your proxy or '
r'Service URL settings\. See dcos config --help\. (.*)')
_assert_matches_with_groups(pattern, message, (errors_str,))
def _assert_res_err_msg_with_other_status_invalid_json(status_code, json_body):
actual = rpcclient.RpcClient.response_error_message(
status_code=status_code,
reason=_REASON_X,
request_method=_METHOD_X,
request_url=_URL_X,
json_body=json_body)
expected = ('Service likely misconfigured. Please check your proxy or '
'Service URL settings. See dcos config --help. ')
assert actual == expected
def _assert_matches_with_groups(pattern, text, groups):
match = re.fullmatch(pattern, text, flags=re.DOTALL)
assert match
assert match.groups() == groups
def _create_fixtures():
rpc_client = mock.create_autospec(rpcclient.RpcClient)
marathon_client = marathon.Client(rpc_client)
return marathon_client, rpc_client
def _pod_response_fixture(headers=None):
mock_response = mock.create_autospec(requests.Response)
headers = CaseInsensitiveDict({} if headers is None else headers)
mock_response.headers = headers
return mock_response
_MESSAGE_1 = 'Oops!'
_MESSAGE_2 = 'Uh oh!'
_MESSAGE_X = "D'oh!"
_METHOD_1 = 'FOO'
_METHOD_2 = 'BAR'
_METHOD_X = 'ANY'
_PRINTED_JSON_1 = (
'{\n'
' "x": "err",\n'
' "y": 3.14,\n'
' "z": [\n'
' 1,\n'
' 2,\n'
' 3\n'
' ]\n'
'}')
_PRINTED_JSON_2 = (
'[\n'
' "something",\n'
' "completely",\n'
' "different"\n'
']')
_REASON_1 = 'Something Bad'
_REASON_2 = 'Another Reason'
_REASON_X = 'Arbitrary Reason'
_RESPONSE_JSON_1 = {"z": [1, 2, 3], "y": 3.14, "x": "err"}
_RESPONSE_JSON_2 = ["something", "completely", "different"]
_URL_1 = 'http://request/url'
_URL_2 = 'https://another/url'
_URL_X = 'http://does/not/matter'