passerelle/tests/test_sivin.py

207 lines
7.1 KiB
Python

# Copyright (C) 2022 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 json
import mock
import pytest
from django.contrib.contenttypes.models import ContentType
from django.urls import reverse
from requests.exceptions import ReadTimeout
import tests.utils
from passerelle.apps.sivin.models import Resource
from passerelle.base.models import AccessRight, ApiUser
pytestmark = pytest.mark.django_db
VEHICLE_DETAILS = {
"carrosserie": "BERLINE",
"clEnvironPrf": "70/220 2001/100EURO3",
"codifVin": "VF7FCKFVB26857835",
"genreVCG": "VP",
"immatSiv": "FS032GM",
"genreVPrf": "VP",
"date1erCir": "2003-11-21",
"nSiren": "000000000",
}
VEHICLE_THEORICAL_FINITION = {
'carrosserie': 'COMBISPACE',
'clEnvironPrf': '2001/100A',
'codifVin': 'VF7GJRHYK93204774',
'genreVCG': 'VP',
'immatSiv': '01XT0747',
'genreVPrf': 'VP',
'date1erCir': '2004-11-19',
'nSiren': '000000000',
}
EXPIRED_TOKEN_MESSAGE = (
'<ams:fault xmlns:ams="http://wso2.org/apimanager/security">'
'<ams:code>900901</ams:code><ams:message>Invalid Credentials</ams:message>'
'<ams:description>Invalid Credentials. Make sure you have provided the correct security credentials</ams:description>'
'</ams:fault>'
)
TOKEN_401 = tests.utils.FakedResponse(
content='{"error_description": "Client Authentication failed.", "error": "invalid_client"}',
status_code=401,
headers={'Content-Type': 'application/json'},
)
TOKEN = tests.utils.FakedResponse(
content='{"access_token": "token_value", "scope": "default", "token_type": "Bearer", "expires_in": 3600}',
status_code=200,
headers={'Content-Type': 'application/json'},
)
EXPIRED_TOKEN = tests.utils.FakedResponse(
content=EXPIRED_TOKEN_MESSAGE,
status_code=500,
)
VIN = tests.utils.FakedResponse(
content=json.dumps(VEHICLE_DETAILS),
status_code=200,
headers={'Content-Type': 'application/json'},
)
VEHICLES = tests.utils.FakedResponse(
content='{"vins":["VF1FB30A511331122"]}', status_code=200, headers={'Content-Type': 'application/json'}
)
FINITION = tests.utils.FakedResponse(
content=json.dumps(VEHICLE_THEORICAL_FINITION),
status_code=200,
headers={'Content-Type': 'application/json'},
)
@pytest.fixture
def conn():
api_user = ApiUser.objects.create(username='sivin', keytype='API', key='sivinkey')
connector = Resource.objects.create(
title='Test', slug='test', consumer_key='key', consumer_secret='secret', environment='test'
)
obj_type = ContentType.objects.get_for_model(Resource)
AccessRight.objects.create(
codename='can_access', apiuser=api_user, resource_type=obj_type, resource_pk=connector.pk
)
return connector
@mock.patch('passerelle.utils.Request.post')
def test_no_api_key(mocked_post, app, conn):
url = reverse(
'generic-endpoint',
kwargs={'connector': 'sivin', 'endpoint': 'consultervehiculeparvin', 'slug': conn.slug},
)
app.get(url, params={'vin': 'vin'}, status=403)
assert mocked_post.call_count == 0
@mock.patch('passerelle.utils.Request.post')
def test_wrong_credentials(mocked_post, app, conn):
mocked_post.return_value = TOKEN_401
url = reverse(
'generic-endpoint',
kwargs={'connector': 'sivin', 'endpoint': 'consultervehiculeparvin', 'slug': conn.slug},
)
resp = app.get(url, params={'apikey': 'sivinkey', 'vin': 'VF1BA0E0514143067'}).json
assert mocked_post.call_count == 1
assert mocked_post.call_args[0][0] == 'https://api.rec.sivin.fr/token'
assert resp['err']
assert resp['err_desc'] == 'Failed to get token. Error: 401'
@mock.patch('passerelle.utils.Request.post')
def test_get_token(mocked_post, app, conn):
mocked_post.return_value = TOKEN
conn.get_token()
assert mocked_post.call_count == 1
assert mocked_post.call_args[0][0] == 'https://api.rec.sivin.fr/token'
# token is in cache so no more http hits
conn.get_token()
assert mocked_post.call_count == 1
@mock.patch('passerelle.utils.Request.post', side_effect=(TOKEN, VIN))
def test_get_details_by_vin(mocked_post, app, conn):
url = reverse(
'generic-endpoint',
kwargs={'connector': 'sivin', 'endpoint': 'consultervehiculeparvin', 'slug': conn.slug},
)
resp = app.get(url, params={'apikey': 'sivinkey', 'vin': 'VF1BA0E0514143067'}).json
assert mocked_post.call_count == 2
assert not resp['err']
assert resp['data'] == VEHICLE_DETAILS
@mock.patch('passerelle.utils.Request.post', side_effect=(TOKEN, VEHICLES))
def test_get_vehicles_by_siren(mocked_post, app, conn):
url = reverse(
'generic-endpoint',
kwargs={'connector': 'sivin', 'endpoint': 'consulterflotteparsiren', 'slug': conn.slug},
)
resp = app.get(url, params={'apikey': 'sivinkey', 'siren': '000399634'}).json
assert mocked_post.call_count == 2
assert not resp['err']
for item in resp['data']:
assert 'id' in item
assert 'text' in item
@mock.patch('passerelle.utils.Request.post', side_effect=(TOKEN, EXPIRED_TOKEN))
def test_get_with_expired_token(mocked_post, app, conn):
url = reverse(
'generic-endpoint',
kwargs={'connector': 'sivin', 'endpoint': 'consulterflotteparsiren', 'slug': conn.slug},
)
resp = app.get(url, params={'apikey': 'sivinkey', 'siren': '000399634'}).json
assert mocked_post.call_count == 2
assert resp['err']
assert resp['err_desc'] == EXPIRED_TOKEN_MESSAGE
@mock.patch('passerelle.utils.Request.post', side_effect=(TOKEN, FINITION))
def test_get_vehicle_theorical_finition(mocked_post, app, conn):
url = reverse(
'generic-endpoint',
kwargs={'connector': 'sivin', 'endpoint': 'consulterfinitiontheoriqueparimmat', 'slug': conn.slug},
)
resp = app.get(url, params={'apikey': 'sivinkey', 'immat': '01-xT0 747'}).json
assert mocked_post.call_count == 2
assert mocked_post.mock_calls[-1].kwargs['json'] == {'immat': '01XT0747'}
assert not resp['err']
assert resp['data'] == VEHICLE_THEORICAL_FINITION
@mock.patch('passerelle.utils.Request.post', side_effect=ReadTimeout('timeout'))
def test_connection_timeout(mocked_post, app, conn):
url = reverse(
'generic-endpoint',
kwargs={'connector': 'sivin', 'endpoint': 'consulterflotteparsiren', 'slug': conn.slug},
)
resp = app.get(url, params={'apikey': 'sivinkey', 'siren': '000399634'}).json
assert mocked_post.call_count == 1
assert resp['err']
assert (
resp['err_desc']
== 'failed to call https://api.rec.sivin.fr/sivin/v2/consulterflotteparsiren: timeout'
)