fix pre-commit
Some checks failed
CI/CD Pipeline / Telegram Notify Success (push) Has been cancelled
CI/CD Pipeline / Run Tests (push) Has been cancelled
CI/CD Pipeline / Code Quality Checks (push) Has been cancelled
CI/CD Pipeline / Code Quality Checks (pull_request) Successful in 1m42s
CI/CD Pipeline / Run Tests (pull_request) Successful in 2m25s
CI/CD Pipeline / Telegram Notify Success (pull_request) Successful in 1m34s

This commit is contained in:
2026-03-17 13:55:34 +01:00
parent 3d298ce352
commit 25176f31b4
31 changed files with 653 additions and 553 deletions

View File

@@ -5,12 +5,19 @@ from types import SimpleNamespace
from unittest.mock import MagicMock, patch
from apps.exchange.services import ExchangeConnectionService, ExchangeServiceError
from apps.parsers.models import IndustrialCertificateRecord, ManufacturerRecord, ParserLoadLog
from apps.parsers.models import (
ManufacturerRecord,
ParserLoadLog,
)
from django.test import TestCase
from tests.apps.exchange.factories import ExchangeConnectionFactory
def _db_secret() -> str:
return "secret"
class _FakeModel:
_meta = SimpleNamespace(
app_label="tests",
@@ -45,19 +52,18 @@ class ExchangeConnectionServiceUnitTest(TestCase):
ExchangeConnectionService,
"test_connection",
return_value="target_alias",
) as test_connection_mock:
with patch.object(
ExchangeConnectionService,
"validate_target_structure",
) as validate_mock:
connection = ExchangeConnectionService.create_active_connection_and_prepare(
server="127.0.0.1",
port=5432,
username="postgres",
password="secret",
database_name="target_db",
schema_name="public",
)
) as test_connection_mock, patch.object(
ExchangeConnectionService,
"validate_target_structure",
) as validate_mock:
connection = ExchangeConnectionService.create_active_connection_and_prepare(
server="127.0.0.1",
port=5432,
username="postgres",
password=_db_secret(),
database_name="target_db",
schema_name="public",
)
self.assertTrue(connection.is_active)
self.assertIsNotNone(connection.last_checked_at)
@@ -88,9 +94,8 @@ class ExchangeConnectionServiceUnitTest(TestCase):
ExchangeConnectionService,
"_configure_alias",
return_value="exchange_target_1",
):
with patch("apps.exchange.services.connections", connections_mock):
alias = ExchangeConnectionService.test_connection(connection)
), patch("apps.exchange.services.connections", connections_mock):
alias = ExchangeConnectionService.test_connection(connection)
self.assertEqual(alias, "exchange_target_1")
db_connection.ensure_connection.assert_called_once_with()
@@ -107,13 +112,13 @@ class ExchangeConnectionServiceUnitTest(TestCase):
ExchangeConnectionService,
"_configure_alias",
return_value="exchange_target_1",
), patch(
"apps.exchange.services.connections", connections_mock
), self.assertRaisesMessage(
ExchangeServiceError,
"Ошибка подключения к целевой БД: boom",
):
with patch("apps.exchange.services.connections", connections_mock):
with self.assertRaisesMessage(
ExchangeServiceError,
"Ошибка подключения к целевой БД: boom",
):
ExchangeConnectionService.test_connection(connection)
ExchangeConnectionService.test_connection(connection)
connection.refresh_from_db()
self.assertEqual(connection.last_error, "boom")
@@ -125,34 +130,31 @@ class ExchangeConnectionServiceUnitTest(TestCase):
connections_mock = MagicMock()
connections_mock.__getitem__.return_value = db_connection
with patch("apps.exchange.services.connections", connections_mock):
with patch.object(
ExchangeConnectionService,
"_extend_models_with_dependencies",
return_value=[_FakeModel],
) as extend_mock:
with patch.object(
ExchangeConnectionService,
"_get_parser_models",
return_value=[_FakeModel],
):
with patch.object(
ExchangeConnectionService,
"_validate_schema_exists",
) as schema_mock:
with patch.object(
ExchangeConnectionService,
"_validate_tables_exist",
) as tables_mock:
with patch.object(
ExchangeConnectionService,
"_validate_columns_exist",
) as columns_mock:
ExchangeConnectionService.validate_target_structure(
connection=connection,
alias="target_alias",
schema_name="public",
)
with patch(
"apps.exchange.services.connections", connections_mock
), patch.object(
ExchangeConnectionService,
"_extend_models_with_dependencies",
return_value=[_FakeModel],
) as extend_mock, patch.object(
ExchangeConnectionService,
"_get_parser_models",
return_value=[_FakeModel],
), patch.object(
ExchangeConnectionService,
"_validate_schema_exists",
) as schema_mock, patch.object(
ExchangeConnectionService,
"_validate_tables_exist",
) as tables_mock, patch.object(
ExchangeConnectionService,
"_validate_columns_exist",
) as columns_mock:
ExchangeConnectionService.validate_target_structure(
connection=connection,
alias="target_alias",
schema_name="public",
)
db_connection.ensure_connection.assert_called_once_with()
extend_mock.assert_called_once()
@@ -174,19 +176,19 @@ class ExchangeConnectionServiceUnitTest(TestCase):
connections_mock = MagicMock()
connections_mock.__getitem__.return_value = db_connection
with patch("apps.exchange.services.connections", connections_mock):
with patch.object(
ExchangeConnectionService,
"_validate_schema_exists",
side_effect=ExchangeServiceError("bad schema"),
):
with self.assertRaisesMessage(ExchangeServiceError, "bad schema"):
ExchangeConnectionService.validate_target_structure(
connection=connection,
alias="target_alias",
schema_name="public",
models_to_copy=[_FakeModel],
)
with patch(
"apps.exchange.services.connections", connections_mock
), patch.object(
ExchangeConnectionService,
"_validate_schema_exists",
side_effect=ExchangeServiceError("bad schema"),
), self.assertRaisesMessage(ExchangeServiceError, "bad schema"):
ExchangeConnectionService.validate_target_structure(
connection=connection,
alias="target_alias",
schema_name="public",
models_to_copy=[_FakeModel],
)
connection.refresh_from_db()
self.assertEqual(connection.last_error, "bad schema")
@@ -197,22 +199,22 @@ class ExchangeConnectionServiceUnitTest(TestCase):
connections_mock = MagicMock()
connections_mock.__getitem__.return_value = db_connection
with patch("apps.exchange.services.connections", connections_mock):
with patch.object(
ExchangeConnectionService,
"_validate_schema_exists",
side_effect=RuntimeError("unexpected"),
):
with self.assertRaisesMessage(
ExchangeServiceError,
"Ошибка проверки структуры целевой БД: unexpected",
):
ExchangeConnectionService.validate_target_structure(
connection=connection,
alias="target_alias",
schema_name="public",
models_to_copy=[_FakeModel],
)
with patch(
"apps.exchange.services.connections", connections_mock
), patch.object(
ExchangeConnectionService,
"_validate_schema_exists",
side_effect=RuntimeError("unexpected"),
), self.assertRaisesMessage(
ExchangeServiceError,
"Ошибка проверки структуры целевой БД: unexpected",
):
ExchangeConnectionService.validate_target_structure(
connection=connection,
alias="target_alias",
schema_name="public",
models_to_copy=[_FakeModel],
)
connection.refresh_from_db()
self.assertEqual(connection.last_error, "unexpected")
@@ -223,37 +225,34 @@ class ExchangeConnectionServiceUnitTest(TestCase):
connections_mock = MagicMock()
connections_mock.__getitem__.return_value = db_connection
with patch("apps.exchange.services.connections", connections_mock):
with patch.object(
ExchangeConnectionService,
"_configure_alias",
return_value="target_alias",
):
with patch.object(
ExchangeConnectionService,
"_resolve_models",
return_value=[_FakeModel, _AnotherFakeModel],
):
with patch.object(
ExchangeConnectionService,
"_extend_models_with_dependencies",
return_value=[_FakeModel, _AnotherFakeModel],
):
with patch.object(
ExchangeConnectionService,
"validate_target_structure",
) as validate_mock:
with patch.object(
ExchangeConnectionService,
"_copy_model_data",
side_effect=[2, 3],
) as copy_mock:
result = ExchangeConnectionService.copy_parsers_data(
connection=connection,
mode="selected",
tables=["fake_table", "another_table"],
truncate_before_copy=False,
)
with patch(
"apps.exchange.services.connections", connections_mock
), patch.object(
ExchangeConnectionService,
"_configure_alias",
return_value="target_alias",
), patch.object(
ExchangeConnectionService,
"_resolve_models",
return_value=[_FakeModel, _AnotherFakeModel],
), patch.object(
ExchangeConnectionService,
"_extend_models_with_dependencies",
return_value=[_FakeModel, _AnotherFakeModel],
), patch.object(
ExchangeConnectionService,
"validate_target_structure",
) as validate_mock, patch.object(
ExchangeConnectionService,
"_copy_model_data",
side_effect=[2, 3],
) as copy_mock:
result = ExchangeConnectionService.copy_parsers_data(
connection=connection,
mode="selected",
tables=["fake_table", "another_table"],
truncate_before_copy=False,
)
self.assertEqual(result["mode"], "selected")
self.assertEqual(result["tables"], ["fake_table", "another_table"])
@@ -278,36 +277,34 @@ class ExchangeConnectionServiceUnitTest(TestCase):
connections_mock = MagicMock()
connections_mock.__getitem__.return_value = db_connection
with patch("apps.exchange.services.connections", connections_mock):
with patch.object(
ExchangeConnectionService,
"_configure_alias",
return_value="target_alias",
):
with patch.object(
ExchangeConnectionService,
"_resolve_models",
return_value=[_FakeModel],
):
with patch.object(
ExchangeConnectionService,
"_extend_models_with_dependencies",
return_value=[_FakeModel],
):
with self.assertRaisesMessage(
ExchangeServiceError,
"Ошибка подключения к целевой БД: target unavailable",
):
ExchangeConnectionService.copy_parsers_data(
connection=connection,
mode="all",
)
with patch(
"apps.exchange.services.connections", connections_mock
), patch.object(
ExchangeConnectionService,
"_configure_alias",
return_value="target_alias",
), patch.object(
ExchangeConnectionService,
"_resolve_models",
return_value=[_FakeModel],
), patch.object(
ExchangeConnectionService,
"_extend_models_with_dependencies",
return_value=[_FakeModel],
), self.assertRaisesMessage(
ExchangeServiceError,
"Ошибка подключения к целевой БД: target unavailable",
):
ExchangeConnectionService.copy_parsers_data(
connection=connection,
mode="all",
)
connection.refresh_from_db()
self.assertEqual(connection.last_error, "target unavailable")
def test_configure_alias_closes_existing_connection_and_clears_cache(self):
connection = ExchangeConnectionFactory(password="secret")
connection = ExchangeConnectionFactory(password=_db_secret())
alias = f"exchange_target_{connection.id}"
existing_db_connection = MagicMock()
storage = SimpleNamespace(**{alias: "stale"})
@@ -321,7 +318,9 @@ class ExchangeConnectionServiceUnitTest(TestCase):
self.assertEqual(configured_alias, alias)
existing_db_connection.close.assert_called_once_with()
self.assertEqual(connections_mock.databases[alias]["NAME"], connection.database_name)
self.assertEqual(
connections_mock.databases[alias]["NAME"], connection.database_name
)
self.assertEqual(connections_mock.databases[alias]["PASSWORD"], "secret")
self.assertNotIn(alias, storage.__dict__)
@@ -333,15 +332,16 @@ class ExchangeConnectionServiceUnitTest(TestCase):
connections_mock = MagicMock()
connections_mock.__getitem__.return_value = db_connection
with patch("apps.exchange.services.connections", connections_mock):
with self.assertRaisesMessage(
ExchangeServiceError,
"Схема 'public' отсутствует в целевой БД",
):
ExchangeConnectionService._validate_schema_exists(
alias="target_alias",
schema_name="public",
)
with patch(
"apps.exchange.services.connections", connections_mock
), self.assertRaisesMessage(
ExchangeServiceError,
"Схема 'public' отсутствует в целевой БД",
):
ExchangeConnectionService._validate_schema_exists(
alias="target_alias",
schema_name="public",
)
def test_validate_tables_exist_raises_when_tables_missing(self):
cursor = MagicMock()
@@ -351,16 +351,17 @@ class ExchangeConnectionServiceUnitTest(TestCase):
connections_mock = MagicMock()
connections_mock.__getitem__.return_value = db_connection
with patch("apps.exchange.services.connections", connections_mock):
with self.assertRaisesMessage(
ExchangeServiceError,
"В целевой БД отсутствуют таблицы: another_table",
):
ExchangeConnectionService._validate_tables_exist(
alias="target_alias",
schema_name="public",
models_to_copy=[_FakeModel, _AnotherFakeModel],
)
with patch(
"apps.exchange.services.connections", connections_mock
), self.assertRaisesMessage(
ExchangeServiceError,
"В целевой БД отсутствуют таблицы: another_table",
):
ExchangeConnectionService._validate_tables_exist(
alias="target_alias",
schema_name="public",
models_to_copy=[_FakeModel, _AnotherFakeModel],
)
def test_validate_columns_exist_raises_when_columns_missing(self):
cursor_context = MagicMock()
@@ -372,19 +373,22 @@ class ExchangeConnectionServiceUnitTest(TestCase):
connections_mock = MagicMock()
connections_mock.__getitem__.return_value = db_connection
with patch("apps.exchange.services.connections", connections_mock):
with self.assertRaisesMessage(
ExchangeServiceError,
"В таблице 'fake_table' отсутствуют колонки: name",
):
ExchangeConnectionService._validate_columns_exist(
alias="target_alias",
schema_name="public",
models_to_copy=[_FakeModel],
)
with patch(
"apps.exchange.services.connections", connections_mock
), self.assertRaisesMessage(
ExchangeServiceError,
"В таблице 'fake_table' отсутствуют колонки: name",
):
ExchangeConnectionService._validate_columns_exist(
alias="target_alias",
schema_name="public",
models_to_copy=[_FakeModel],
)
def test_get_parser_models_uses_configured_labels(self):
resolved_models = [_FakeModel for _ in ExchangeConnectionService.PARSER_MODEL_LABELS]
resolved_models = [
_FakeModel for _ in ExchangeConnectionService.PARSER_MODEL_LABELS
]
with patch(
"apps.exchange.services.django_apps.get_model",
@@ -417,13 +421,12 @@ class ExchangeConnectionServiceUnitTest(TestCase):
ExchangeConnectionService,
"_get_parser_models",
return_value=[ParserLoadLog],
):
with self.assertRaisesMessage(ExchangeServiceError, "Неизвестная таблица"):
ExchangeConnectionService._resolve_models(
mode="single",
table="unknown_table",
tables=None,
)
), self.assertRaisesMessage(ExchangeServiceError, "Неизвестная таблица"):
ExchangeConnectionService._resolve_models(
mode="single",
table="unknown_table",
tables=None,
)
def test_truncate_tables_executes_in_reverse_order(self):
cursor = MagicMock()