passerelle/tests/test_isere_esrh.py

283 lines
9.8 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 urllib.parse
import httmock
import pytest
from requests import ConnectionError, RequestException, Timeout
from passerelle.contrib.isere_esrh.models import IsereESRH
from tests.utils import setup_access_rights
@pytest.fixture()
def connector(db):
return setup_access_rights(IsereESRH.objects.create(slug='test', base_url='http://esrh.net'))
def test_connection_error_handling(app, connector):
def connection_error(url, request):
raise ConnectionError('oops')
def timeout(url, request):
raise Timeout('oops')
def request_error(url, request):
raise RequestException('oops')
for handler in [connection_error, timeout, request_error]:
with httmock.HTTMock(handler):
response = app.get('/isere-esrh/test/official?number=004242&authority=CG38', status=200)
assert response.json['err_desc'] == 'HTTP request failed'
assert response.json['data'] == {'exception': 'oops'}
def invalid_json(url, request):
return httmock.response(200, 'bad_json')
with httmock.HTTMock(invalid_json):
response = app.get('/isere-esrh/test/official?number=004242&authority=CG38', status=200)
assert response.json['err_desc'] == 'ESRH returned invalid json'
assert 'Expecting value' in response.json['data']['exception']
def invalid_json_content(url, request):
return httmock.response(200, '[]')
with httmock.HTTMock(invalid_json_content):
response = app.get('/isere-esrh/test/official?number=004242&authority=CG38', status=200)
assert (
response.json['err_desc']
== 'ESRH returned malformed json : expecting a dictionary with a "values" key containing a list of objects.'
)
def test_official(app, connector, freezer):
freezer.move_to('1871-03-18 13:13:00')
@httmock.urlmatch()
def error_handler(url, request):
assert False, 'should not be reached'
@httmock.urlmatch(path=r'^/api/v2/Agent$', query='numero=004242&collectivite=CG38')
def mock_official_not_found(url, request):
return httmock.response(200, {'values': []})
with httmock.HTTMock(mock_official_not_found, error_handler):
response = app.get('/isere-esrh/test/official?number=004242&authority=CG38')
assert response.json['err'] == 0
assert response.json['data'] is None
@httmock.urlmatch(path=r'^/api/v2/Agent$', query='numero=004242&collectivite=CG38')
def mock_malformed_response(url, request):
return httmock.response(200, {'values': [{}]})
with httmock.HTTMock(mock_malformed_response, error_handler):
response = app.get('/isere-esrh/test/official?number=004242&authority=CG38')
assert response.json['err'] == 1
assert (
response.json['err_desc']
== 'Malformed response : values elements are expected to be objects with an "agentId" key'
)
@httmock.urlmatch(path=r'^/api/v2/Agent$', query='numero=004242&collectivite=CG38')
def mock_official(url, request):
return httmock.response(
200,
{
'values': [
{
'nom': 'Abitbol',
'agentId': 12,
'prenom': 'Georges',
'matricule': '004242',
'observation': 'Agent polyvalent en gestion de classe',
},
]
},
)
@httmock.urlmatch(
path=r'^/api/v2/Agent/12/DossiersStatutaire$',
query=f'aDate={urllib.parse.quote("1871-03-18T13:13:00+00:00")}',
)
def mock_empty_file(url, request):
return httmock.response(200, {'values': []})
with httmock.HTTMock(mock_official, mock_empty_file, error_handler):
response = app.get('/isere-esrh/test/official?number=004242&authority=CG38')
assert response.json['data'] == {
'agentId': 12,
'nom': 'Abitbol',
'prenom': 'Georges',
'matricule': '004242',
'observation': 'Agent polyvalent en gestion de classe',
'DossiersStatutaire': [],
}
@httmock.urlmatch(
path=r'^/api/v2/Agent/12/DossiersStatutaire$',
query=f'aDate={urllib.parse.quote("1871-03-18T13:13:00+00:00")}',
)
def mock_file(url, request):
return httmock.response(
200,
{
'values': [
{
'dossierStatutaireId': 1,
'grade': {
'gradeId': 2,
'code': 'T34',
'libelle': 'Adjoint du sherif',
'cadreEmploiId': 3,
},
}
]
},
)
with httmock.HTTMock(mock_official, mock_file, error_handler):
response = app.get('/isere-esrh/test/official?number=004242&authority=CG38')
assert response.json['data'] == {
'agentId': 12,
'nom': 'Abitbol',
'prenom': 'Georges',
'matricule': '004242',
'observation': 'Agent polyvalent en gestion de classe',
'DossiersStatutaire': [
{
'dossierStatutaireId': 1,
'grade': {
'gradeId': 2,
'code': 'T34',
'libelle': 'Adjoint du sherif',
'cadreEmploiId': 3,
},
}
],
}
def test_entities(app, connector, freezer):
freezer.move_to('1871-03-18 13:13:00')
@httmock.urlmatch()
def error_handler(url, request):
assert False, 'should not be reached'
@httmock.urlmatch(
path=r'^/api/v2/Entite$', query=f'aDate={urllib.parse.quote("1871-03-18T13:13:00+00:00")}'
)
def mock_entites(url, request):
return httmock.response(
200,
{
'values': [
{
'entiteId': 1,
'code': '6500',
'libelle': 'dir. de la classe internationale',
'region': 'ouest',
},
{'entiteId': 2, 'code': '650001', 'libelle': 'sce. des sapes', 'region': 'nord'},
{
'entiteId': 3,
'code': '6400',
'libelle': 'dir. des dinosaures de droite',
'region': 'sud',
},
]
},
)
entity_1 = {
'id': 1,
'text': 'dir. de la classe internationale',
'code': '6500',
'region': 'ouest',
'entiteId': 1,
'libelle': 'dir. de la classe internationale',
}
entity_2 = {
'id': 2,
'text': 'sce. des sapes',
'code': '650001',
'region': 'nord',
'entiteId': 2,
'libelle': 'sce. des sapes',
}
entity_3 = {
'id': 3,
'code': '6400',
'text': 'dir. des dinosaures de droite',
'region': 'sud',
'entiteId': 3,
'libelle': 'dir. des dinosaures de droite',
}
with httmock.HTTMock(mock_entites, error_handler):
response = app.get('/isere-esrh/test/entities')
assert response.json['data'] == [entity_1, entity_2, entity_3]
response = app.get('/isere-esrh/test/entities?label_pattern=^dir\\..*')
assert response.json['data'] == [entity_1, entity_3]
response = app.get('/isere-esrh/test/entities?code_pattern=^6500\\d%2B')
assert response.json['data'] == [entity_2]
response = app.get('/isere-esrh/test/entities?code_pattern=^6500&label_pattern=^dir\\..*')
assert response.json['data'] == [entity_1]
def test_job_types(app, connector, freezer):
freezer.move_to('1871-03-18 13:13:00')
now = urllib.parse.quote('1871-03-18T13:13:00+00:00')
@httmock.urlmatch()
def error_handler(url, request):
assert False, 'should not be reached'
@httmock.urlmatch(
path=r'^/api/v2/Poste$', query=f'codeCollectivite=CG38&avecLibellePoste=True&aDate={now}'
)
def mock_entites(url, request):
return httmock.response(
200,
{
'values': [
{'posteId': 1, 'libelles': [{'libelle': 'Patron de l\'auberge'}], 'ravioles': 'non'},
{'posteId': 2, 'libelles': [], 'ravioles': 'oui'},
{'posteId': 3, 'ravioles': 'non'},
]
},
)
with httmock.HTTMock(mock_entites, error_handler):
response = app.get('/isere-esrh/test/job-types?authority=CG38')
assert response.json['data'] == [
{
'id': 1,
'text': 'Patron de l\'auberge',
'ravioles': 'non',
'posteId': 1,
'libelles': [{'libelle': 'Patron de l\'auberge'}],
},
{'id': 2, 'text': 'N/A', 'ravioles': 'oui', 'posteId': 2, 'libelles': []},
{'id': 3, 'text': 'N/A', 'ravioles': 'non', 'posteId': 3},
]