""" E2E тесты для Checko API клиента. Тесты выполняются через локальный HTTP сервер (без внешних API). """ from __future__ import annotations import json from urllib.parse import parse_qs from apps.parsers.clients.checko import ( CheckoAPIError, CheckoClient, CheckoNotFoundError, CompanyRequest, ContractLaw, ContractsRequest, EnforcementsRequest, FinancesRequest, InspectionsRequest, LegalCasesRequest, ObjectType, SearchRequest, SearchType, ) from apps.parsers.clients.checko.datasets import ( OKFS, OKOPF, OKVED2, AccountCodes, ) from django.test import TestCase from tests.utils import Response, TestHTTPServer from tests.utils.fixtures import fake def _digits(length: int) -> str: return "".join(str(fake.random_int(0, 9)) for _ in range(length)) def _meta_ok() -> dict: return { "status": "ok", "today_request_count": fake.random_int(min=1, max=10), "balance": float(fake.pydecimal(left_digits=2, right_digits=2, positive=True)), } def _client_for(server: TestHTTPServer, api_key: str = "test_key") -> CheckoClient: return CheckoClient( api_key=api_key, base_url=f"{server.base_url}/v2", http_adapter=server.adapter, ) def _json_response(payload: dict) -> Response: return Response( status=200, body=json.dumps(payload, ensure_ascii=False).encode("utf-8"), headers={"Content-Type": "application/json; charset=utf-8"}, ) class CheckoClientE2ETestCase(TestCase): """E2E тесты клиента CheckoClient через локальный HTTP сервер.""" def test_get_company_by_inn(self): inn = _digits(10) ogrn = _digits(13) short_name = fake.company() with TestHTTPServer() as server: server.add_json( "/v2/company", { "data": { "ogrn": ogrn, "inn": inn, "short_name": short_name, "full_name": fake.company(), "status": {"code": "100", "name": "Действующее"}, "legal_address": { "full_address": fake.address().replace("\n", ", "), "postal_code": _digits(6), }, }, "meta": _meta_ok(), }, ) client = _client_for(server) response = client.get_company(CompanyRequest(inn=inn)) self.assertEqual(response.meta.status, "ok") self.assertEqual(response.data.inn, inn) self.assertEqual(response.data.ogrn, ogrn) self.assertEqual(response.data.short_name, short_name) self.assertIsNotNone(response.data.legal_address) def test_get_company_by_ogrn(self): inn = _digits(10) ogrn = _digits(13) with TestHTTPServer() as server: server.add_json( "/v2/company", { "data": { "ogrn": ogrn, "inn": inn, "short_name": fake.company(), "status": {"code": "100", "name": "Действующее"}, }, "meta": _meta_ok(), }, ) client = _client_for(server) response = client.get_company(CompanyRequest(ogrn=ogrn)) self.assertEqual(response.meta.status, "ok") self.assertEqual(response.data.ogrn, ogrn) self.assertEqual(response.data.inn, inn) def test_get_company_with_source(self): inn = _digits(10) source_data = {"raw": fake.text(max_nb_chars=50)} with TestHTTPServer() as server: server.add_json( "/v2/company", { "data": { "inn": inn, "ogrn": _digits(13), "short_name": fake.company(), "status": {"code": "100", "name": "Действующее"}, }, "meta": _meta_ok(), "source_data": source_data, }, ) client = _client_for(server) response = client.get_company(CompanyRequest(inn=inn, source=True)) self.assertEqual(response.meta.status, "ok") self.assertIsNotNone(response.source_data) def test_search_by_name(self): inn = _digits(10) ogrn = _digits(13) name = fake.company() with TestHTTPServer() as server: server.add_json( "/v2/search", { "data": { "records": [ {"inn": inn, "ogrn": ogrn, "short_name": name}, ], "total_records": 1, "total_pages": 1, "current_page": 1, }, "meta": _meta_ok(), }, ) client = _client_for(server) response = client.search( SearchRequest( by=SearchType.NAME, obj=ObjectType.ORGANIZATION, query=f"{name} {fake.word()}", limit=10, ) ) self.assertEqual(response.meta.status, "ok") self.assertIsNotNone(response.data) self.assertGreater(len(response.data.organizations), 0) def test_search_active_only(self): inn = _digits(10) with TestHTTPServer() as server: server.add_json( "/v2/search", { "data": { "records": [ { "inn": inn, "status": {"code": "100", "name": "Действующее"}, }, ], "total_records": 1, "total_pages": 1, "current_page": 1, }, "meta": _meta_ok(), }, ) client = _client_for(server) response = client.search( SearchRequest( by=SearchType.NAME, obj=ObjectType.ORGANIZATION, query=fake.company(), active=True, limit=5, ) ) self.assertEqual(response.meta.status, "ok") self.assertIsNotNone(response.data) def test_get_finances(self): inn = _digits(10) ogrn = _digits(13) with TestHTTPServer() as server: server.add_json( "/v2/finances", { "data": { "inn": inn, "ogrn": ogrn, "reports": [ { "year": fake.random_int(min=2020, max=2025), "period": 12, "lines": [ { "code": _digits(4), "value": fake.random_int(10, 9999), } ], } ], }, "meta": _meta_ok(), }, ) client = _client_for(server) response = client.get_finances(FinancesRequest(inn=inn)) self.assertEqual(response.meta.status, "ok") self.assertIsNotNone(response.data) self.assertEqual(response.data.inn, inn) def test_get_contracts_fz44(self): inn = _digits(10) registry_number = _digits(12) with TestHTTPServer() as server: server.add_json( "/v2/contracts", { "data": { "contracts": [ {"registry_number": registry_number, "law": "44-FZ"}, ], "pagination": { "total_records": 1, "total_pages": 1, "current_page": 1, }, }, "meta": _meta_ok(), }, ) client = _client_for(server) response = client.get_contracts( ContractsRequest(inn=inn, law=ContractLaw.FZ44, limit=10) ) self.assertEqual(response.meta.status, "ok") self.assertIsNotNone(response.data) self.assertGreater(len(response.data.contracts), 0) def test_get_contracts_fz223(self): inn = _digits(10) with TestHTTPServer() as server: server.add_json( "/v2/contracts", { "data": { "contracts": [ {"registry_number": _digits(12), "law": "223-FZ"}, ], "pagination": { "total_records": 1, "total_pages": 1, "current_page": 1, }, }, "meta": _meta_ok(), }, ) client = _client_for(server) response = client.get_contracts( ContractsRequest(inn=inn, law=ContractLaw.FZ223, limit=10) ) self.assertEqual(response.meta.status, "ok") self.assertIsNotNone(response.data) def test_get_inspections(self): inn = _digits(10) with TestHTTPServer() as server: server.add_json( "/v2/inspections", { "data": { "inspections": [ { "id": fake.uuid4(), "status": fake.word(), "authority_name": fake.company(), "subject": fake.word(), } ], "pagination": { "total_records": 1, "total_pages": 1, "current_page": 1, }, }, "meta": _meta_ok(), }, ) client = _client_for(server) response = client.get_inspections(InspectionsRequest(inn=inn, limit=10)) self.assertEqual(response.meta.status, "ok") self.assertIsNotNone(response.data) self.assertGreater(len(response.data.inspections), 0) def test_get_enforcements(self): inn = _digits(10) with TestHTTPServer() as server: server.add_json( "/v2/enforcements", { "data": { "enforcements": [ { "number": _digits(12), "status": fake.word(), "debt_amount": fake.random_int(1_000, 10_000), } ], "pagination": { "total_records": 1, "total_pages": 1, "current_page": 1, }, "total_debt": fake.random_int(1_000, 100_000), }, "meta": _meta_ok(), }, ) client = _client_for(server) response = client.get_enforcements(EnforcementsRequest(inn=inn, limit=10)) self.assertEqual(response.meta.status, "ok") self.assertIsNotNone(response.data) self.assertGreater(len(response.data.enforcements), 0) def test_get_legal_cases(self): inn = _digits(10) with TestHTTPServer() as server: server.add_json( "/v2/legal-cases", { "data": { "cases": [ { "case_number": fake.bothify(text="A-####/##"), "status": fake.word(), }, ], "pagination": { "total_records": 1, "total_pages": 1, "current_page": 1, }, "total_claim_amount": fake.random_int(1000, 10000), }, "meta": _meta_ok(), }, ) client = _client_for(server) response = client.get_legal_cases(LegalCasesRequest(inn=inn, limit=10)) self.assertEqual(response.meta.status, "ok") self.assertIsNotNone(response.data) self.assertGreater(len(response.data.cases), 0) def test_get_legal_cases_filtered(self): inn = _digits(10) with TestHTTPServer() as server: server.add_json( "/v2/legal-cases", { "data": { "cases": [ { "case_number": fake.bothify(text="A-####/##"), "status": fake.word(), }, ], "pagination": { "total_records": 1, "total_pages": 1, "current_page": 1, }, }, "meta": _meta_ok(), }, ) client = _client_for(server) response = client.get_legal_cases( LegalCasesRequest(inn=inn, actual=True, active=True, limit=5) ) self.assertEqual(response.meta.status, "ok") self.assertIsNotNone(response.data) class CheckoClientIteratorsE2ETestCase(TestCase): """E2E тесты итераторов с автопагинацией.""" def test_iter_contracts_pagination(self): inn = _digits(10) def contracts_handler(request, _body): page = int(parse_qs(request.query).get("page", ["1"])[0]) total_pages = 3 contracts = [ {"registry_number": f"{page}-{_digits(10)}", "law": "44-FZ"}, ] return _json_response( { "data": { "contracts": contracts, "pagination": { "total_records": total_pages, "total_pages": total_pages, "current_page": page, }, }, "meta": _meta_ok(), } ) with TestHTTPServer() as server: server.add_route("GET", "/v2/contracts", contracts_handler) client = _client_for(server) contracts = list( client.iter_contracts( ContractsRequest(inn=inn, law=ContractLaw.FZ44, limit=1) ) ) self.assertGreater(len(contracts), 1) def test_iter_legal_cases_pagination(self): inn = _digits(10) def cases_handler(request, _body): page = int(parse_qs(request.query).get("page", ["1"])[0]) total_pages = 2 cases = [ {"case_number": f"A-{page}-{_digits(5)}", "status": fake.word()}, ] return _json_response( { "data": { "cases": cases, "pagination": { "total_records": total_pages, "total_pages": total_pages, "current_page": page, }, }, "meta": _meta_ok(), } ) with TestHTTPServer() as server: server.add_route("GET", "/v2/legal-cases", cases_handler) client = _client_for(server) cases = list(client.iter_legal_cases(LegalCasesRequest(inn=inn, limit=1))) self.assertGreater(len(cases), 1) class CheckoClientErrorE2ETestCase(TestCase): """E2E тесты обработки ошибок.""" def test_company_not_found(self): with TestHTTPServer() as server: server.add_json( "/v2/company", { "data": None, "meta": {"status": "error", "message": "не найден"}, }, ) client = _client_for(server) with self.assertRaises(CheckoNotFoundError): client.get_company(CompanyRequest(inn=_digits(10))) def test_invalid_api_key(self): with TestHTTPServer() as server: server.add_json( "/v2/company", { "data": None, "meta": {"status": "error", "message": "Invalid API key"}, }, ) client = _client_for(server, api_key="invalid_key") with self.assertRaises(CheckoAPIError): client.get_company(CompanyRequest(inn=_digits(10))) class CheckoDatasetsE2ETestCase(TestCase): """E2E тесты справочников (локальные JSON данные).""" def test_okved2_load_and_search(self): items = OKVED2.all() self.assertGreater(len(items), 0) sample = items[0] self.assertIsNotNone(OKVED2.get(sample.code)) search_term = sample.name.split(" ")[0] results = OKVED2.search(search_term) self.assertGreater(len(results), 0) def test_okfs_load(self): items = OKFS.all() self.assertGreater(len(items), 0) def test_okopf_load(self): items = OKOPF.all() self.assertGreater(len(items), 0) def test_account_codes_load(self): items = AccountCodes.all() self.assertGreater(len(items), 0) sample = items[0] self.assertIsNotNone(AccountCodes.get(sample.code))