Source code for inspirehep.testlib.api.mitm_client
# -*- coding: utf-8 -*-
#
# This file is part of INSPIRE.
# Copyright (C) 2018 CERN.
#
# INSPIRE is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# INSPIRE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with INSPIRE. If not, see <http://www.gnu.org/licenses/>.
#
# In applying this license, CERN does not waive the privileges and immunities
# granted to it by virtue of its status as an Intergovernmental Organization
# or submit itself to any jurisdiction.
"""Client interface for INSPIRE-MITMPROXY."""
from __future__ import absolute_import, division, print_function
from decorator import decorate
from os import environ
from . import Session
[docs]def with_mitmproxy(*args, **kwargs):
'''Decorator to abstract fixture recording and scenario setup for the E2E tests with mitmproxy.
Args:
scenario_name (Optional[str]): scenario name, by default test name without 'test_' prefix
should_record (Optional[bool]): is recording new interactions allowed during test run,
by default `False`
*args (List[Callable]): list of length of either zero or one: decorated function.
This is to allow the decorator to function both with and without calling it
with parameters: if args is present, we can deduce that the decorator was used
without parameters.
Returns:
Callable: a decorator the can be used both with and without calling brackets
(if all params should be default)
'''
scenario_name = kwargs.pop('scenario_name', None)
should_record = kwargs.pop('should_record', False)
if not args:
assert not kwargs, 'Parameters %s not expected' % kwargs
def _with_mitmproxy(func, *args, **kwargs):
def ommit_test_in_name(name):
if name.startswith('test_'):
return name[5:]
mitmproxy_url = environ.get('MITMPROXY_HOST', 'http://mitm-manager.local')
mitm_client = MITMClient(mitmproxy_url)
final_scenario_name = scenario_name or ommit_test_in_name(func.__name__)
try:
mitm_client.set_scenario(final_scenario_name)
if should_record:
mitm_client.start_recording()
func(*args, **kwargs)
except Exception:
raise
finally:
mitm_client.stop_recording()
mitm_client.set_scenario('default')
def _decorator(func):
return decorate(func, _with_mitmproxy)
if args:
return decorate(args[0], _with_mitmproxy)
return _decorator
[docs]class MITMClient(object):
def __init__(self, proxy_host='http://mitm-manager.local'):
self._client = Session(base_url=proxy_host)
[docs] def set_scenario(self, scenario_name):
resp = self._client.put('/config', json={'active_scenario': scenario_name})
resp.raise_for_status()
[docs] def get_interactions_for_service(self, service_name):
resp = self._client.get('/service/{}/interactions'.format(service_name))
resp.raise_for_status()
return resp.json()
[docs] def assert_interaction_used(self, service_name, interaction_name, times=None):
interactions = self.get_interactions_for_service(service_name)
num_calls = interactions.get(interaction_name, {}).get('num_calls', 0)
if times is None and not num_calls:
raise AssertionError(
'Interaction %s in %s was not used' % (interaction_name, service_name)
)
if times is not None and num_calls != times:
raise AssertionError(
'Interaction %s in %s wasn\'t used %d times (but %d times instead)'
% (interaction_name, service_name, times, num_calls)
)
[docs] def start_recording(self):
resp = self._client.post('/record', json={'enable': True})
resp.raise_for_status()
[docs] def stop_recording(self):
resp = self._client.post('/record', json={'enable': False})
resp.raise_for_status()