170 lines
5.0 KiB
Python
170 lines
5.0 KiB
Python
# passerelle - uniform access to multiple data sources and services
|
|
# Copyright (C) 2023 Entr'ouvert
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify it
|
|
# under the terms of the GNU Affero General Public License as published
|
|
# by the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program 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 Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import pytest
|
|
import responses
|
|
import responses.matchers
|
|
|
|
import tests.utils
|
|
from passerelle.apps.proxy.models import Resource
|
|
|
|
|
|
@pytest.fixture
|
|
def proxy(db):
|
|
return tests.utils.setup_access_rights(
|
|
Resource.objects.create(slug='echo', upstream_base_url='https://example.org/')
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def endpoint(proxy):
|
|
return tests.utils.generic_endpoint_url('proxy', 'request', slug=proxy.slug)
|
|
|
|
|
|
@pytest.fixture
|
|
def mocked_responses():
|
|
with responses.RequestsMock(assert_all_requests_are_fired=False) as rsp:
|
|
yield rsp
|
|
|
|
|
|
def test_get(mocked_responses, app, proxy, endpoint):
|
|
mocked_responses.get(
|
|
url='https://example.org/foo/bar',
|
|
body='ok',
|
|
match=[
|
|
responses.matchers.query_string_matcher(''),
|
|
],
|
|
)
|
|
|
|
resp = app.get(endpoint + '/foo/bar', status=200)
|
|
assert resp.text == 'ok'
|
|
|
|
|
|
def test_status(mocked_responses, app, proxy, endpoint):
|
|
mocked_responses.get(url='https://example.org/foo/bar', body='bad request', status=400)
|
|
resp = app.get(endpoint + '/foo/bar', status=400)
|
|
assert resp.text == 'bad request'
|
|
|
|
|
|
def test_post(mocked_responses, app, proxy, endpoint):
|
|
mocked_responses.post(
|
|
url='https://example.org/post',
|
|
body='ok',
|
|
match=[
|
|
responses.matchers.json_params_matcher({'foo': 'bar'}),
|
|
],
|
|
)
|
|
resp = app.post_json(endpoint + '/post', params={'foo': 'bar'}, status=200)
|
|
assert resp.text == 'ok'
|
|
|
|
|
|
def no_header_matcher(header_name):
|
|
def inner(request):
|
|
if header_name in request.headers:
|
|
return False, f'Found header "{header_name} in requests headers.'
|
|
return True, None
|
|
|
|
return inner
|
|
|
|
|
|
def test_headers(mocked_responses, app, proxy, endpoint):
|
|
mocked_responses.get(
|
|
url='https://example.org/foo/bar',
|
|
body='ok',
|
|
match=[
|
|
responses.matchers.header_matcher({'User-Agent': 'test-ua'}),
|
|
no_header_matcher('x-foo'),
|
|
no_header_matcher('dontpass'),
|
|
],
|
|
)
|
|
resp = app.get(endpoint + '/foo/bar', headers={'user-agent': 'test-ua', 'dontpass': 'x'}, status=200)
|
|
assert resp.text == 'ok'
|
|
|
|
|
|
def test_forced_headers(mocked_responses, app, proxy, endpoint):
|
|
proxy.forced_headers = '''
|
|
x-foo : bar
|
|
badentry
|
|
|
|
# comment: do not use me
|
|
'''
|
|
proxy.save()
|
|
|
|
mocked_responses.get(
|
|
url='https://example.org/foo/bar',
|
|
body='ok',
|
|
match=[
|
|
responses.matchers.header_matcher({'x-foo': 'bar'}),
|
|
no_header_matcher('dontpass'),
|
|
],
|
|
)
|
|
resp = app.get(endpoint + '/foo/bar', headers={'user-agent': 'test', 'dontpass': 'x'}, status=200)
|
|
assert resp.text == 'ok'
|
|
|
|
|
|
def test_query_parameters(mocked_responses, app, proxy, endpoint):
|
|
mocked_responses.get(
|
|
url='https://example.org/foo/bar',
|
|
body='ok',
|
|
match=[
|
|
responses.matchers.query_param_matcher({'param1': '1', 'param2': '2'}, strict_match=True),
|
|
],
|
|
)
|
|
|
|
resp = app.get(endpoint + '/foo/bar?param1=1¶m2=2', status=200)
|
|
assert resp.text == 'ok'
|
|
|
|
|
|
def test_publik_signature_is_removed(mocked_responses, app, proxy, endpoint):
|
|
mocked_responses.get(
|
|
url='https://example.org/foo/bar',
|
|
body='ok',
|
|
match=[
|
|
responses.matchers.query_param_matcher({'param1': '1', 'param2': '2'}, strict_match=True),
|
|
],
|
|
)
|
|
resp = app.get(
|
|
endpoint + '/foo/bar?param1=1¶m2=2&orig=coucou&algo=foo&nonce=bar×tamp=xxx&signature=okok',
|
|
status=200,
|
|
)
|
|
assert resp.text == 'ok'
|
|
|
|
|
|
def test_auth(mocked_responses, app, proxy, endpoint):
|
|
proxy.basic_auth_username = 'test-login'
|
|
proxy.basic_auth_password = 'test-pass'
|
|
proxy.save()
|
|
|
|
mocked_responses.get(
|
|
url='https://example.org/foo/bar',
|
|
body='ok',
|
|
match=[responses.matchers.header_matcher({'Authorization': 'Basic dGVzdC1sb2dpbjp0ZXN0LXBhc3M='})],
|
|
)
|
|
resp = app.get(endpoint + '/foo/bar', status=200)
|
|
assert resp.text == 'ok'
|
|
|
|
|
|
def test_timeout(mocked_responses, app, proxy, endpoint):
|
|
proxy.http_timeout = 5
|
|
proxy.save()
|
|
mocked_responses.get(
|
|
url='https://example.org/foo/bar',
|
|
body='ok',
|
|
match=[responses.matchers.request_kwargs_matcher({'timeout': 5})],
|
|
)
|
|
resp = app.get(endpoint + '/foo/bar', status=200)
|
|
assert resp.text == 'ok'
|