passerelle/tests/test_api_entreprise.py

549 lines
20 KiB
Python

# -*- coding: utf-8 -*-
# tests/test_api_entreprise.py
# Copyright (C) 2019 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 mock
import requests
from httmock import urlmatch, HTTMock, response
from django.utils import timezone
from passerelle.apps.api_entreprise.models import APIEntreprise
from utils import make_resource, FakedResponse
ETABLISSEMENTS_RESPONSE = {
"etablissement": {
"siege_social": True,
"siret": "41816609600051",
"naf": "6202A",
"libelle_naf": "Conseil en systèmes et logiciels informatiques",
"date_mise_a_jour": 1449183600,
"tranche_effectif_salarie_etablissement": {
"de": 200,
"a": 249,
"code": "31",
"date_reference": "2014",
"intitule": "200 à 249 salariés"
},
"date_creation_etablissement": 1108594800,
"region_implantation": {
"code": "11",
"value": "Île-de-France"
},
"commune_implantation": {
"code": "75108",
"value": "PARIS 8"
},
"adresse": {
"l1": "OCTO TECHNOLOGY",
"l4": "50 AVENUE DES CHAMPS ELYSEES",
"l6": "75008 PARIS",
"l7": "FRANCE",
"numero_voie": "50",
"type_voie": "AV",
"nom_voie": "DES CHAMPS ELYSEES",
"code_postal": "75008",
"localite": "PARIS 8",
"code_insee_localite": "75108",
},
"etat_administratif": {
"value": "F",
"date_fermeture": 1315173600
}
},
"gateway_error": False
}
ENTREPRISES_RESPONSE = {
"entreprise": {
"siren": "418166096",
"capital_social": 459356,
"numero_tva_intracommunautaire": "FR16418166096",
"forme_juridique": "SA à directoire (s.a.i.)",
"forme_juridique_code": "5699",
"nom_commercial": "OCTO-TECHNOLOGY",
"procedure_collective": False,
"naf_entreprise": "6202A",
"libelle_naf_entreprise": "Conseil en systèmes et logiciels informatiques",
"raison_sociale": "OCTO-TECHNOLOGY",
"siret_siege_social": "41816609600051",
"code_effectif_entreprise": "31",
"date_creation": 891381600,
"categorie_entreprise": "PME",
"tranche_effectif_salarie_entreprise": {
"de": 200,
"a": 249,
"code": "31",
"date_reference": "2014",
"intitule": "200 à 249 salariés"
},
"mandataires_sociaux": [{
"nom": "HISQUIN",
"prenom": "FRANCOIS",
"fonction": "PRESIDENT DU DIRECTOIRE",
"dirigeant": True,
"date_naissance": "1965-01-27",
"raison_sociale": "",
"identifiant": "",
"type": "PP"
}, {
"nom": "",
"prenom": "",
"fonction": "COMMISSAIRE AUX COMPTES SUPPLEANT",
"dirigeant": True,
"date_naissance": "",
"date_naissance_timestamp": 0,
"raison_sociale": "BCRH & ASSOCIES - SOCIETE A RESPONSABILITE LIMITEE A ASSOCIE UNIQUE",
"identifiant": "490092574",
"type": "PM"
}
],
"etat_administratif": {
"value": "C", # A (actif) ou C (cessé)
"date_cessation": 1315173600 # null quand actif (A), un timestamp (un entier) quand cessé (C )
}
},
"etablissement_siege": {
"siege_social": True,
"siret": "41816609600051",
"naf": "6202A",
"libelle_naf": "Conseil en systèmes et logiciels informatiques",
"date_mise_a_jour": 1449183600,
"tranche_effectif_salarie_etablissement": {
"de": 200,
"a": 249,
"code": "31",
"date_reference": "2014",
"intitule": "200 à 249 salariés"
},
"date_creation_etablissement": 1108594800,
"region_implantation": {
"code": "11",
"value": "Île-de-France"
},
"commune_implantation": {
"code": "75108",
"value": "PARIS 8"
},
"adresse": {
"l1": "OCTO TECHNOLOGY",
"l4": "50 AVENUE DES CHAMPS ELYSEES",
"l6": "75008 PARIS",
"l7": "FRANCE",
"numero_voie": "50",
"type_voie": "AV",
"nom_voie": "DES CHAMPS ELYSEES",
"code_postal": "75008",
"localite": "PARIS 8",
"code_insee_localite": "75108",
},
"etat_administratif": {
"value": "F",
"date_fermeture": 1315173600
}
},
"gateway_error": False
}
EXTRAITS_RCS_RESPONSE = {
"siren": "418166096",
"date_immatriculation": "1998-03-27",
"date_immatriculation_timestamp": 890953200,
"date_extrait": "21 AVRIL 2017",
"observations": [
{
"date": "2000-02-23",
"date_timestamp": 951260400,
"numero": "12197",
"libelle": " LA SOCIETE NE CONSERVE AUCUNE ACTIVITE A SON ANCIEN SIEGE "
}
]
}
ASSOCIATIONS_RESPONSE = {
"association" : {
"id": "W751135389",
"titre": "ALLIANCE DU COEUR: UNION NATIONALE DES FEDERATIONS ET ASSOCIATIONS DE MALADES CARDIOVASCULAIRES",
"objet": "information, soutien, solidarité et accompagnement psycho médico social des personnes malades cardiovasculaires et de leurs proches...",
"siret": "42135938100025",
"siret_siege_social": "42135938100033",
"date_creation": "1993-02-11",
"date_declaration": "2013-06-28",
"date_publication": "1993-03-03",
"adresse_siege": {
"numero_voie": "10",
"type_voie": "RUE",
"libelle_voie": "Lebouis",
"code_insee": "75120",
"code_postal": "75014",
"commune": "Paris"
},
"groupement": "Simple",
"mise_a_jour": "2013-06-28"
}
}
DOCUMENTS_ASSOCIATION_RESPONSE = {
"nombre_documents": 2,
"documents": [
{
"type": "Statuts",
"url": "https://apientreprise.fr/attestations/40ab0b07d434d0417e8997ce7c5afbef/attestation_document_association.pdf",
"timestamp": "1500660325"
},
{
"type": "Récépissé",
"url": "https://apientreprise.fr/attestations/40ab0b07d434d0417e8997ce7c5afbef/recepisse_association.pdf",
"timestamp": "1500667325"
},
{
"timestamp": "1337158058",
"url": "https://apientreprise.fr/attestations/40ab0b07d434d0417e8997ce7c5afbef/attestation_document_association.pdf",
"type": "Statuts"
},
]
}
EFFECTIFS_ANNUELS_ACOSS_COVID = {
"siren": "418166096",
"annee": "2019",
"effectifs_annuels": 100.5
}
ENTREPRISE_EFFECTIFS_MENSUELS_ACOSS_COVID = {
"siren": "418166096",
"annee": "2019",
"mois": "02",
"effectifs_mensuels": 100.5
}
ETABLISSEMENT_EFFECTIFS_MENSUELS_ACOSS_COVID = {
"siret": "41816609600051",
"annee": "2019",
"mois": "02",
"effectifs_mensuels": 100.5
}
DOCUMENT_ASSOCIATION_RESPONSE = "binary content"
REQUEST_PARAMS = {'context': 'MSP', 'object': 'demand', 'recipient': 'siret'}
@urlmatch(netloc='^entreprise.api.gouv.fr$',
path='^/v2/etablissements/')
def api_entreprise_etablissements(url, request):
return response(200, ETABLISSEMENTS_RESPONSE, request=request)
@urlmatch(netloc='^entreprise.api.gouv.fr$',
path='^/v2/entreprises/')
def api_entreprise_entreprises(url, request):
return response(200, ENTREPRISES_RESPONSE, request=request)
@urlmatch(netloc='^entreprise.api.gouv.fr$',
path='^/v2/associations/')
def api_entreprise_associations(url, request):
return response(200, ASSOCIATIONS_RESPONSE, request=request)
@urlmatch(netloc='^entreprise.api.gouv.fr$',
path='^/v2/extraits_rcs_infogreffe/')
def api_entreprise_extraits_rcs(url, request):
return response(200, EXTRAITS_RCS_RESPONSE, request=request)
@urlmatch(netloc='^entreprise.api.gouv.fr$',
path='^/v2/documents_associations/')
def api_entreprise_documents_associations(url, request):
return response(200, DOCUMENTS_ASSOCIATION_RESPONSE, request=request)
@urlmatch(netloc='^apientreprise.fr$',
path='^/attestations/')
def api_entreprise_document_association(url, request):
return response(200, DOCUMENT_ASSOCIATION_RESPONSE, request=request)
@urlmatch(netloc='^entreprise.api.gouv.fr$',
path='^/v2/effectifs_annuels_acoss_covid/')
def effectifs_annuels_acoss_covid(url, request):
return response(200, EFFECTIFS_ANNUELS_ACOSS_COVID, request=request)
@urlmatch(netloc='^entreprise.api.gouv.fr$',
path='^/v2/effectifs_mensuels_acoss_covid/.*/entreprise')
def entreprise_effectifs_mensuels_acoss_covid(url, request):
return response(200, ENTREPRISE_EFFECTIFS_MENSUELS_ACOSS_COVID, request=request)
@urlmatch(netloc='^entreprise.api.gouv.fr$',
path='^/v2/effectifs_mensuels_acoss_covid/.*/etablissement')
def etablisssment_effectifs_mensuels_acoss_covid(url, request):
return response(200, ETABLISSEMENT_EFFECTIFS_MENSUELS_ACOSS_COVID, request=request)
@urlmatch(netloc='^entreprise.api.gouv.fr$')
def api_entreprise_error_500(url, request):
return response(500, 'bad error happened', request=request)
@urlmatch(netloc='^entreprise.api.gouv.fr$')
def api_entreprise_connection_error(url, request):
raise requests.RequestException('connection timed-out')
@urlmatch(netloc='^entreprise.api.gouv.fr$')
def api_entreprise_error_not_json(url, request):
return response(200, 'simple text', request=request)
@urlmatch(netloc='^entreprise.api.gouv.fr$')
def api_entreprise_error_not_found(url, request):
return response(404, {
'error': 'not_found',
'message': u'Page not found'
}, request=request)
@pytest.yield_fixture
def mock_api_entreprise():
with HTTMock(
api_entreprise_etablissements, api_entreprise_entreprises, api_entreprise_associations,
api_entreprise_extraits_rcs, api_entreprise_associations, api_entreprise_documents_associations,
api_entreprise_document_association, effectifs_annuels_acoss_covid,
entreprise_effectifs_mensuels_acoss_covid, etablisssment_effectifs_mensuels_acoss_covid):
yield None
@pytest.fixture
def resource(db):
return make_resource(
APIEntreprise,
slug='test',
title='API Entreprise',
description='API Entreprise',
token='83c68bf0b6013c4daf3f8213f7212aa5',
recipient='recipient')
@mock.patch('passerelle.utils.Request.get')
def test_endpoint_with_no_params(mocked_get, app, resource):
mocked_get.return_value = FakedResponse(content='{}', status_code=200)
response = app.get('/api-entreprise/test/documents_associations/443170139/', status=400)
assert response.json['err_class'] == 'passerelle.views.WrongParameter'
assert response.json['err_desc'] == "missing parameters: 'context'."
params = {'context': 'Custom context', 'object': 'Custom object'}
response = app.get('/api-entreprise/test/documents_associations/443170139/', params=params)
assert mocked_get.call_args[1]['data']['context'] == 'Custom context'
assert mocked_get.call_args[1]['data']['object'] == 'Custom object'
assert mocked_get.call_args[1]['data']['recipient'] == 'recipient'
params['recipient'] = 'Custom recipient'
response = app.get('/api-entreprise/test/documents_associations/443170139/', params=params)
assert mocked_get.call_args[1]['data']['recipient'] == 'Custom recipient'
def test_entreprises_endpoint(app, resource, mock_api_entreprise):
response = app.get('/api-entreprise/test/entreprises/443170139/',
params=REQUEST_PARAMS)
data = response.json['data']
assert data['entreprise']['categorie_entreprise'] == 'PME'
assert data['entreprise']['numero_tva_intracommunautaire'] == 'FR16418166096'
assert data['entreprise']['siret_siege_social'] == '41816609600051'
assert data['entreprise']['forme_juridique_code'] == '5699'
assert data['entreprise']['siren'] == '418166096'
assert data['entreprise']['date_creation'] == '1998-03-31'
assert data['entreprise']['mandataires_sociaux'][0]['date_naissance'] == '1965-01-27'
assert 'etablissement_siege' in data
assert data['etablissement_siege']['siret'] == '41816609600051'
assert data['etablissement_siege']['adresse']['numero_voie'] == '50'
assert data['etablissement_siege']['adresse']['type_voie'] == 'AV'
assert data['etablissement_siege']['adresse']['nom_voie'] == 'DES CHAMPS ELYSEES'
assert data['etablissement_siege']['adresse']['code_postal'] == '75008'
assert data['etablissement_siege']['adresse']['localite'] == 'PARIS 8'
assert data['etablissement_siege']['adresse']['code_insee_localite'] == '75108'
assert data['etablissement_siege']['date_mise_a_jour'] == '2015-12-03'
def test_etablissements_endpoint(app, resource, mock_api_entreprise):
response = app.get('/api-entreprise/test/etablissements/44317013900036/',
params=REQUEST_PARAMS)
assert 'data' in response.json
data = response.json['data']
assert 'etablissement' in data
assert data['etablissement']['siret'] == '41816609600051'
assert data['etablissement']['naf'] == '6202A'
assert data['etablissement']['date_mise_a_jour'] == '2015-12-03'
assert data['etablissement']['date_creation_etablissement'] == '2005-02-16'
assert 'adresse' in data['etablissement']
assert data['etablissement']['adresse']['code_postal'] == '75008'
assert data['etablissement']['adresse']['localite'] == 'PARIS 8'
assert data['etablissement']['adresse']['code_insee_localite'] == '75108'
def test_associations_endpoint(app, resource, mock_api_entreprise):
response = app.get('/api-entreprise/test/associations/443170139/',
params=REQUEST_PARAMS)
assert 'data' in response.json
data = response.json['data']
assert 'association' in data
assert data['association']['id'] == 'W751135389'
assert data['association']['siret'] == '42135938100025'
assert data['association']['date_creation'] == '1993-02-11'
assert data['association']['date_declaration'] == '2013-06-28'
assert data['association']['date_publication'] == '1993-03-03'
assert 'adresse_siege' in data['association']
assert data['association']['adresse_siege']['code_postal'] == '75014'
assert data['association']['adresse_siege']['code_insee'] == '75120'
def test_documents_associations_endpoint(app, resource, mock_api_entreprise):
response = app.get('/api-entreprise/test/documents_associations/443170139/',
params=REQUEST_PARAMS)
assert 'data' in response.json
data = response.json['data']
assert len(data) == 3
for document in data:
assert 'id' in document
assert 'text' in document
assert 'url' in document
assert 'type' in document
assert 'datetime' in document
def test_associations_last_document_of_type_endpoint(app, resource, mock_api_entreprise):
params = REQUEST_PARAMS
params['document_type'] = 'Statuts'
response = app.get('/api-entreprise/test/document_association/443170139/get-last/',
params=params)
assert 'data' in response.json
data = response.json['data']
assert data['timestamp'] == '1500660325'
params['document_type'] = 'Liste des dirigeants'
response = app.get('/api-entreprise/test/document_association/443170139/get-last/',
params=params)
assert not response.json['data']
def test_extraits_rcs(app, resource, mock_api_entreprise, freezer):
response = app.get('/api-entreprise/test/extraits_rcs/443170139/',
params=REQUEST_PARAMS)
assert 'data' in response.json
data = response.json['data']
assert data['siren'] == '418166096'
assert data['date_extrait'] == '21 AVRIL 2017'
assert data['date_immatriculation_timestamp'] == 890953200
assert data['date_immatriculation'] == '1998-03-27'
assert data['date_immatriculation_datetime'] == '1998-03-26T23:00:00Z'
def test_document_association(app, resource, mock_api_entreprise, freezer):
response = app.get('/api-entreprise/test/documents_associations/443170139/',
params=REQUEST_PARAMS)
assert 'data' in response.json
data = response.json['data']
assert len(data) == 3
document = data[0]
assert 'url' in document
resp = app.get(document['url'],
params={'context': 'MSP', 'object': 'demand', 'recipient': 'siret'},
status=200)
# try to get document with wrong signature
url = document['url']
wrong_url = document['url'] + "wrong/"
resp = app.get(wrong_url, status=404)
# try expired url
freezer.move_to(timezone.now() + timezone.timedelta(days=8))
resp = app.get(document['url'], status=404)
def test_effectifs_annuels_acoss_covid(app, resource, mock_api_entreprise, freezer):
response = app.get('/api-entreprise/test/effectifs_annuels_acoss_covid/418166096/',
params=REQUEST_PARAMS)
data = response.json['data']
assert data['siren'] == '418166096'
assert data['annee'] == '2019'
assert data['effectifs_annuels'] == 100.5
def test_entreprise_effectifs_mensuels_acoss_covid(app, resource, mock_api_entreprise, freezer):
response = app.get('/api-entreprise/test/entreprise_effectifs_mensuels_acoss_covid/2019/02/418166096/',
params=REQUEST_PARAMS)
data = response.json['data']
assert data['siren'] == '418166096'
assert data['annee'] == '2019'
assert data['mois'] == '02'
assert data['effectifs_mensuels'] == 100.5
def test_etablissment_effectifs_mensuels_acoss_covid(app, resource, mock_api_entreprise, freezer):
response = app.get('/api-entreprise/test/etablissement_effectifs_mensuels_acoss_covid/2019/02/418166096/',
params=REQUEST_PARAMS)
data = response.json['data']
assert data['siret'] == '41816609600051'
assert data['annee'] == '2019'
assert data['mois'] == '02'
assert data['effectifs_mensuels'] == 100.5
def test_error_500(app, resource, mock_api_entreprise):
with HTTMock(api_entreprise_error_500):
response = app.get('/api-entreprise/test/entreprises/443170139/',
params=REQUEST_PARAMS)
assert response.status_code == 200
assert response.json['err'] == 1
assert response.json['data']['status_code'] == 500
assert 'error happened' in response.json['err_desc']
def test_no_json_error(app, resource, mock_api_entreprise):
with HTTMock(api_entreprise_error_not_json):
response = app.get('/api-entreprise/test/entreprises/443170139/',
params=REQUEST_PARAMS)
assert response.status_code == 200
assert response.json['err'] == 1
assert response.json['err_desc'] == "API-entreprise returned non-JSON content with status 200: simple text"
def test_error_404(app, resource, mock_api_entreprise):
with HTTMock(api_entreprise_error_not_found):
response = app.get('/api-entreprise/test/entreprises/443170139/',
params=REQUEST_PARAMS)
assert response.status_code == 200
assert response.json['err'] == 1
assert response.json['err_desc'] == 'Page not found'
def test_connection_error(app, resource, mock_api_entreprise):
with HTTMock(api_entreprise_connection_error):
response = app.get('/api-entreprise/test/entreprises/443170139/',
params=REQUEST_PARAMS)
assert response.status_code == 200
assert response.json['err'] == 1
assert response.json['err_desc'] == 'API-entreprise connection error: connection timed-out'
assert response.json['data'] == []