def test_base_service_process_request_scenario1(dispatcher, request): request_set_config = MITMRequest( method='POST', url='http://mitm-manager.local/config', body='{"active_scenario": "test_scenario1"}', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], })) request_service_1 = MITMRequest(method='GET', url='https://host_a.local/api', headers=MITMHeaders({ 'Host': ['host_a.local'], 'Accept': ['application/json'], })) request_service_2 = MITMRequest(method='GET', url='https://host_b.local/api', headers=MITMHeaders({ 'Host': ['host_b.local'], 'Accept': ['application/json'], })) response_set_config = dispatcher.process_request(request_set_config) assert response_set_config.status_code == 201 response_service_1 = dispatcher.process_request(request_service_1) assert response_service_1.body == b'test_scenario1/TestServiceA/0' response_service_2 = dispatcher.process_request(request_service_2) assert response_service_2.body == b'test_scenario1/TestServiceB/0'
def test_base_service_process_request_scenario_raise_if_no_interaction( dispatcher): request_set_config = MITMRequest( method='POST', url='http://mitm-manager.local/config', body='{"active_scenario": "test_scenario_raise_if_no_interaction"}', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], })) request_service_1 = MITMRequest(method='GET', body='correct body content', url='https://host_a.local/api', headers=MITMHeaders({ 'Host': ['host_a.local'], 'Accept': ['application/json'], })) request_service_2 = MITMRequest(method='GET', url='http://host_b.local/api', headers=MITMHeaders({ 'Host': ['host_b.local'], 'Accept': ['application/json'], })) response_set_config = dispatcher.process_request(request_set_config) assert response_set_config.status_code == 201 response_service_1 = dispatcher.process_request(request_service_1) assert response_service_1.body == b'test_scenario_raise_if_no_interaction/TestServiceA/0' with raises(ScenarioNotInService): dispatcher.process_request(request_service_2)
def test_base_service_process_request_picks_next_interaction_after_reaches_max_replays( dispatcher): request_set_config = MITMRequest( method='POST', url='http://mitm-manager.local/config', body='{"active_scenario": "test_scenario_replays_once_and_takes_next"}', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], })) same_request = MITMRequest(method='GET', url='https://host_a.local/api', headers=MITMHeaders({ 'Host': ['host_a.local'], 'Accept': ['application/json'], })) response_set_config = dispatcher.process_request(request_set_config) assert response_set_config.status_code == 201 response_1 = dispatcher.process_request(same_request) assert response_1.body == b'test_scenario_replays_ok/TestServiceA/0' response_2 = dispatcher.process_request(same_request) assert response_2.body == b'test_scenario_replays_ok/TestServiceA/1'
def test_management_service_get_scenarios(fake_scenarios_dir, dispatcher): result = dispatcher.process_request( MITMRequest(method='GET', url='http://mitm-manager.local/scenarios', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], }))) expected = { 'scenario1': { 'responses': { 'A': ['1.yaml', '2.yaml'], } }, 'scenario2': { 'responses': { 'A': ['1.yaml'], 'B': ['1.yaml', '2.yaml', '3.yaml'], } }, } assert result.status_code == 200 assert json_loads(result.body) == expected
def test_dispatcher_process_request(dispatcher, url, message): result = dispatcher.process_request( MITMRequest(url=url, headers=MITMHeaders({ 'Accept': ['text/plain'], }))) assert result.body == message
def test_base_service_handles_request(service: BaseService, request_: dict, handled: bool): request_ = MITMRequest( url=request_['url'], headers=MITMHeaders(request_['headers']), ) assert service.handles_request(request_) == handled
def test_management_service_get_services(dispatcher): result = dispatcher.process_request( MITMRequest(method='GET', url='http://mitm-manager.local/services', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], }))) expected = { 'services': [ { 'type': 'ManagementService', 'name': 'ManagementService', 'hosts_list': ['mitm-manager.local'], }, { 'type': 'BaseService', 'name': 'TestService', 'hosts_list': ['test-service.local'], }, ], } assert result.status_code == 200 assert json.loads(result.body) == expected
def test_dispatcher_process_request_fail_if_none_match(dispatcher): with raises(NoServicesForRequest): dispatcher.process_request( MITMRequest(url='http://test-service-z.local/does_not_exist', headers=MITMHeaders({ 'Accept': ['text/plain'], })))
def test_base_service_get_interactions_for_active_scenario(service: BaseService, scenarios_dir): expected_request_1 = MITMRequest( headers=MITMHeaders({ 'Accept': ['application/json'], 'Accept-Encoding': ['gzip, deflate'], 'Connection': ['keep-alive'], 'User-Agent': ['python-requests/2.18.4'] }), method='GET', url='https://host_a.local/api', ) expected_response_1 = MITMResponse( body='{"value": "response1"}', headers=MITMHeaders({ 'content-type': ['application/json; charset=UTF-8'] }), status_code=200, ) expected_request_2 = MITMRequest( body='{"value": "response2"}', headers=MITMHeaders({ 'Accept': ['application/json'], 'Accept-Encoding': ['gzip, deflate'], 'Connection': ['keep-alive'], 'User-Agent': ['python-requests/2.18.4'] }), method='POST', url='https://host_a.local/api', ) expected_response_2 = MITMResponse( headers=MITMHeaders({ 'content-type': ['application/json; charset=UTF-8'] }), status_code=201, ) interactions = service.get_interactions_for_active_scenario() assert len(interactions) == 2 assert interactions[0].request == expected_request_1 assert interactions[0].response == expected_response_1 assert interactions[1].request == expected_request_2 assert interactions[1].response == expected_response_2
def test_whitelist_service_raises(dispatcher): with raises(DoNotIntercept): dispatcher.process_request( MITMRequest(method='GET', url='http://test-indexer:9200/records-hep/fake', body="{}", headers=MITMHeaders({ 'Host': ['test-indexer:9200'], 'Accept': ['application/json'], })))
def sample_request(request) -> MITMRequest: return MITMRequest( body='body content', headers=MITMHeaders({ 'Accept': ['text/plain'], 'Connection': ['keep-alive'], 'User-Agent': ['python-requests/2.18.4'] }), method='GET', url='https://domain.local/path;param?query=value', )
def test_management_service_post_and_put_config(dispatcher): post_config_request = MITMRequest( method='POST', url='http://mitm-manager.local/config', body='{"active_scenario": "a scenario", "another": "value"}', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], })) put_config_request = MITMRequest( method='PUT', url='http://mitm-manager.local/config', body='{"active_scenario": "another scenario"}', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], })) get_config_request = MITMRequest(method='GET', url='http://mitm-manager.local/config', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], })) expected_config = { 'active_scenario': 'another scenario', 'another': 'value', } post_req = dispatcher.process_request(post_config_request) assert post_req.status_code == 201 put_req = dispatcher.process_request(put_config_request) assert put_req.status_code == 204 result = dispatcher.process_request(get_config_request) assert result.status_code == 200 assert json_loads(result.body) == expected_config
def test_process_request_fails_on_unknown_request(service: BaseService, scenarios_dir): request = MITMRequest( body='{"value": "whatever"}', headers=MITMHeaders({ 'Accept': ['application/json'], }), method='PUT', url='https://host_a.local/this/path/is/not/handled', ) with raises(NoMatchingRecording): service.process_request(request)
def test_get_service_interactions_raises(dispatcher: Dispatcher): request_set_config = MITMRequest( method='POST', url='http://mitm-manager.local/config', body='{"active_scenario": "test_scenario_replays_ok"}', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], })) request_inexistent_service_interactions = MITMRequest( method='GET', url='http://mitm-manager.local/service/InexistentService/interactions', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], })) response_set_config = dispatcher.process_request(request_set_config) assert response_set_config.status_code == 201 with raises(ServiceNotFound): dispatcher.process_request(request_inexistent_service_interactions)
def test_base_service_process_request_scenario2_and_raise(dispatcher, request): request_set_config = MITMRequest( method='POST', url='http://mitm-manager.local/config', body='{"active_scenario": "test_scenario2"}', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], })) request_service_1 = MITMRequest(method='GET', body='correct body content', url='https://host_a.local/api', headers=MITMHeaders({ 'Host': ['host_a.local'], 'Accept': ['application/json'], })) request_service_2 = MITMRequest(method='GET', url='http://host_b.local/api', headers=MITMHeaders({ 'Host': ['host_b.local'], 'Accept': ['application/json'], })) with patch('requests.request') as request_func: response_set_config = dispatcher.process_request(request_set_config) assert response_set_config.status_code == 201 sleep(1) request_func.assert_called_once() response_service_1 = dispatcher.process_request(request_service_1) assert response_service_1.body == b'test_scenario2/TestServiceA/0' with raises(ScenarioNotFound): dispatcher.process_request(request_service_2)
def test_base_service_process_request_test_scenario_replays_ok(dispatcher): request_set_config = MITMRequest( method='POST', url='http://mitm-manager.local/config', body='{"active_scenario": "test_scenario_replays_ok"}', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], })) request_service_1 = MITMRequest(method='GET', url='https://host_a.local/api', headers=MITMHeaders({ 'Host': ['host_a.local'], 'Accept': ['application/json'], })) request_service_2 = MITMRequest(method='GET', url='https://host_b.local/api', headers=MITMHeaders({ 'Host': ['host_b.local'], 'Accept': ['application/json'], })) response_set_config = dispatcher.process_request(request_set_config) assert response_set_config.status_code == 201 with patch('requests.request') as request: response_service_1 = dispatcher.process_request(request_service_1) assert response_service_1.body == b'test_scenario_replays_ok/TestServiceA/0' sleep(1) # Wait for the callback request.assert_called_once() response_service_2 = dispatcher.process_request(request_service_2) assert response_service_2.body == b'test_scenario_replays_ok/TestServiceB/0'
def test_management_service_get_config(dispatcher): result = dispatcher.process_request( MITMRequest(method='GET', url='http://mitm-manager.local/config', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], }))) expected = { 'active_scenario': 'default', } assert result.status_code == 200 assert json_loads(result.body) == expected
def test_should_replay_only_once(service: BaseService, scenarios_dir): interaction = service.get_interactions_for_active_scenario()[0] interaction.max_replays = 1 assert service.should_replay(interaction) request_1 = MITMRequest( headers=MITMHeaders({ 'Accept': ['application/json'], 'Accept-Encoding': ['gzip, deflate'], 'Connection': ['keep-alive'], 'User-Agent': ['python-requests/2.18.4'] }), method='GET', url='https://host_a.local/api', ) service.process_request(request_1) assert not service.should_replay(interaction)
def test_management_service_build_response_empty_object_body(management_service): with patch( 'inspire_mitmproxy.services.management_service.get_current_version', return_value='0.0.1', ): result = management_service.build_response(200, json_message={}) expected = MITMResponse( body='{}', headers=MITMHeaders({ 'Content-Type': ['application/json; encoding=UTF-8'], 'Server': ['inspire-mitmproxy/0.0.1'], }), status_code=200, ) assert expected == result
def test_management_service_set_services(method, dispatcher): result = dispatcher.process_request( MITMRequest(method=method, url='http://mitm-manager.local/services', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], }), body=json.dumps({ 'services': [{ 'type': 'BaseService', 'name': 'ExternalService', 'hosts_list': ['external_service.local'], }, { 'type': 'WhitelistService', 'name': 'WhitelistService', 'hosts_list': ['let_me_pass.local'], }] }))) expected = { 'services': [{ 'type': 'ManagementService', 'name': 'ManagementService', 'hosts_list': ['mitm-manager.local'], }, { 'type': 'BaseService', 'name': 'ExternalService', 'hosts_list': ['external_service.local'], }, { 'type': 'WhitelistService', 'name': 'WhitelistService', 'hosts_list': ['let_me_pass.local'], }] } assert result.status_code == 201 assert json.loads(result.body) == expected
def process_request(self, request: dict): return MITMResponse(body=message, headers=MITMHeaders({ 'Content-Type': ['text/plain'], }))
def test_headers_from_mitmproxy(): expected = TEST_HEADERS result = MITMHeaders.from_mitmproxy(TEST_MITM_HEADERS) assert expected == result
interactions = service.get_interactions_for_active_scenario() assert len(interactions) == 2 assert interactions[0].request == expected_request_1 assert interactions[0].response == expected_response_1 assert interactions[1].request == expected_request_2 assert interactions[1].response == expected_response_2 @mark.parametrize( 'request_, response', [ ( MITMRequest( headers=MITMHeaders({ 'Accept': ['application/json'], }), method='GET', url='https://host_a.local/api', ), MITMResponse( body='{"value": "response1"}', headers=MITMHeaders({ 'content-type': ['application/json; charset=UTF-8'], }), status_code=200, ), ), ( MITMRequest( body='{"value": "response2"}',
# # 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. from inspire_mitmproxy.http import MITMHeaders, encoding_by_header TEST_HEADERS = MITMHeaders({ 'Content-Type': ['text/plain; charset=ASCII'], 'Access-Control-Expose-Headers': [ 'Content-Type, ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, ' 'X-Multiple-Values', ], 'X-Multiple-Values': [ 'Value1', 'Value2', ] }) TEST_HEADERS_NO_CHARSET = MITMHeaders({ 'Content-Type': ['text/plain'], 'Access-Control-Expose-Headers': [ 'Content-Type, ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, ' 'X-Multiple-Values', ], 'X-Multiple-Values': [ 'Value1', 'Value2',
def test_get_service_interactions(dispatcher: Dispatcher): request_set_config = MITMRequest( method='POST', url='http://mitm-manager.local/config', body='{"active_scenario": "test_scenario_replays_ok"}', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], })) request_service_a = MITMRequest(method='GET', url='https://host_a.local/api', headers=MITMHeaders({ 'Host': ['host_a.local'], 'Accept': ['application/json'], })) request_service_b = MITMRequest(method='GET', url='https://host_b.local/api', headers=MITMHeaders({ 'Host': ['host_b.local'], 'Accept': ['application/json'], })) request_service_a_interactions = MITMRequest( method='GET', url='http://mitm-manager.local/service/TestServiceA/interactions', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], })) request_service_b_interactions = MITMRequest( method='GET', url='http://mitm-manager.local/service/TestServiceB/interactions', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], })) response_set_config = dispatcher.process_request(request_set_config) assert response_set_config.status_code == 201 with patch('requests.request') as request: response_service_a_1 = dispatcher.process_request(request_service_a) assert response_service_a_1.status_code == 200 response_service_a_2 = dispatcher.process_request(request_service_a) assert response_service_a_2.status_code == 200 sleep(1) # Wait for the callback assert request.call_count == 2 response_service_b = dispatcher.process_request(request_service_b) assert response_service_b.status_code == 200 response_service_a_interactions = dispatcher.process_request( request_service_a_interactions) response_service_b_interactions = dispatcher.process_request( request_service_b_interactions) assert json_loads(response_service_a_interactions.body) == { 'interaction_0': { 'num_calls': 2 } } assert json_loads(response_service_b_interactions.body) == { 'interaction_0': { 'num_calls': 1 } }
# 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. from mitmproxy.http import HTTPRequest from inspire_mitmproxy.http import MITMHeaders, MITMRequest TEST_REQUEST = MITMRequest( body='{"message": "Witaj, świecie!"}', headers=MITMHeaders({ 'Content-Type': ['application/json; charset=UTF-8'], 'Accept-Encoding': ['gzip, deflate'], 'Connection': ['keep-alive'], 'User-Agent': ['python-requests/2.18.4'], }), method='GET', url='http://127.0.0.1/test' ) TEST_REQUEST_GZIP = MITMRequest( # gzipped utf-8-encoded "Hello, world!" body=b'x\x9c\xf3H\xcd\xc9\xc9\xd7Q(\xcf/\xcaIQ\x04\x00 ^\x04\x8a', headers=MITMHeaders({ 'Content-Type': ['text/plain; charset=UTF-8'], 'Content-Encoding': ['gzip'], 'Accept-Encoding': ['gzip, deflate'], 'Connection': ['keep-alive'],
(b'Content-Type', b'text/plain; charset=UTF-8'), (b'Date', b'Wed, 21 Mar 2018 12:47:18 GMT'), (b'Server', b'nginx/1.12.2'), (b'Content-Encoding', b'gzip'), ]), # gzipped utf-8-encoded "Hello, world!" content=b'x\x9c\xf3H\xcd\xc9\xc9\xd7Q(\xcf/\xcaIQ\x04\x00 ^\x04\x8a', ) TEST_RESPONSE = MITMResponse( status_code=200, status_message='OK', body="Witaj, świecie!", headers=MITMHeaders({ 'Content-Type': ['text/plain; charset=ISO-8859-2'], 'Date': ['Wed, 21 Mar 2018 12:47:18 GMT'], 'Server': ['nginx/1.12.2'], }), original_encoding='ISO-8859-2', http_version='HTTP/1.1', ) TEST_RESPONSE_WITH_BYTES_BODY = MITMResponse( status_code=200, status_message='OK', body=b"Witaj, \xb6wiecie!", headers=MITMHeaders({ 'Content-Type': ['text/plain; charset=ISO-8859-2'], 'Date': ['Wed, 21 Mar 2018 12:47:18 GMT'], 'Server': ['nginx/1.12.2'], }),
# # 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. from pathlib import Path from re import compile from pytest import fixture, mark from inspire_mitmproxy.http import MITMHeaders, MITMRequest, MITMResponse from inspire_mitmproxy.interaction import Interaction TEST_REQUEST = MITMRequest( body=None, headers=MITMHeaders({'Host': ['test.local']}), method='GET', url='https://test.local/path', ) TEST_RESPONSE = MITMResponse( body='{"key": "value"}', headers=MITMHeaders({'Content-Type': ['application/json; charset=UTF-8']}), status_code=200, ) def _get_headers(good=True): if good: return MITMHeaders({})
def test_base_service_process_response_record_when_dir_exists_and_has_some_interactions_already( dispatcher: Dispatcher, temporary_scenarios_dir, ): expected_replayed_response = b'test_scenario_record_not_empty/TestServiceA/0' expected_recording = { 'request': { 'url': 'https://host_a.local/recordme', 'method': 'GET', 'body': '', 'headers': { 'Accept': ['text/plain'], 'Host': ['host_a.local'], }, }, 'response': { 'body': 'Hello, world!', 'headers': {}, 'status': { 'code': 200, 'message': 'OK', }, }, 'match': {}, 'callbacks': [], 'max_replays': -1, } request_set_scenario = MITMRequest( method='POST', url='http://mitm-manager.local/config', body='{"active_scenario": "test_scenario_record_not_empty"}', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], })) request_enable_recording = MITMRequest( method='POST', url='http://mitm-manager.local/record', body='{"enable": true}', headers=MITMHeaders({ 'Host': ['mitm-manager.local'], 'Accept': ['application/json'], })) request_to_be_replayed = MITMRequest(method='GET', url='https://host_a.local/replayme', headers=MITMHeaders({ 'Host': ['host_a.local'], 'Accept': ['text/plain'], })) request_to_be_recorded = MITMRequest(method='GET', url='https://host_a.local/recordme', headers=MITMHeaders({ 'Host': ['host_a.local'], 'Accept': ['text/plain'], })) response_to_be_recorded = MITMResponse(status_code=200, body='Hello, world!') response_set_scenario = dispatcher.process_request(request_set_scenario) assert response_set_scenario.status_code == 201 response_enable_recording = dispatcher.process_request( request_enable_recording) assert response_enable_recording.status_code == 201 response_to_be_replayed = dispatcher.process_request( request_to_be_replayed) assert expected_replayed_response == response_to_be_replayed.body with raises(DoNotIntercept): dispatcher.process_request(request_to_be_recorded) dispatcher.process_response(request_to_be_recorded, response_to_be_recorded) service_interactions_dir = temporary_scenarios_dir.join( 'test_scenario_record_not_empty') assert service_interactions_dir.exists() assert len(service_interactions_dir.listdir()) == 1 assert len(service_interactions_dir.join('TestServiceA').listdir()) == 2 out_file = service_interactions_dir.join('TestServiceA').join( 'interaction_1.yaml').read() result_recording = yaml_load(out_file) assert expected_recording == result_recording
def _get_headers(good=True): if good: return MITMHeaders({}) else: return MITMHeaders({'X-Wrong-Header': ["Headers don't matter"]})