fix(exchange): isolate concurrent connection checks
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import uuid
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@@ -301,7 +302,10 @@ class ExchangeConnectionService:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _configure_alias(cls, connection: ExchangeConnection) -> str:
|
def _configure_alias(cls, connection: ExchangeConnection) -> str:
|
||||||
alias = f"exchange_target_{connection.id}"
|
connection_key = (
|
||||||
|
connection.pk if connection.pk is not None else uuid.uuid4().hex
|
||||||
|
)
|
||||||
|
alias = f"exchange_target_{connection_key}"
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
"ENGINE": "django.db.backends.postgresql",
|
"ENGINE": "django.db.backends.postgresql",
|
||||||
|
|||||||
@@ -90,8 +90,8 @@ class ExchangeConnectionTestView(APIView):
|
|||||||
tags=[EXCHANGE_TAG],
|
tags=[EXCHANGE_TAG],
|
||||||
operation_summary="Проверить подключение",
|
operation_summary="Проверить подключение",
|
||||||
operation_description=(
|
operation_description=(
|
||||||
"Проверяет подключение и структуру целевой БД без сохранения "
|
"Проверяет доступность PostgreSQL и учетные данные без сохранения "
|
||||||
"настроек подключения."
|
"настроек подключения. Проверка структуры выполняется при сохранении."
|
||||||
),
|
),
|
||||||
request_body=ExchangeConnectionCreateSerializer,
|
request_body=ExchangeConnectionCreateSerializer,
|
||||||
responses={
|
responses={
|
||||||
|
|||||||
@@ -505,6 +505,27 @@ class ExchangeConnectionServiceUnitTest(TestCase):
|
|||||||
self.assertEqual(connections_mock.databases[alias]["PASSWORD"], "secret")
|
self.assertEqual(connections_mock.databases[alias]["PASSWORD"], "secret")
|
||||||
self.assertNotIn(alias, storage.__dict__)
|
self.assertNotIn(alias, storage.__dict__)
|
||||||
|
|
||||||
|
def test_configure_alias_uses_unique_alias_for_unsaved_connection(self):
|
||||||
|
connection = ExchangeConnection(
|
||||||
|
server="127.0.0.1",
|
||||||
|
port=5432,
|
||||||
|
username="postgres",
|
||||||
|
password="secret", # noqa: S106
|
||||||
|
database_name="target_db",
|
||||||
|
schema_name="public",
|
||||||
|
)
|
||||||
|
|
||||||
|
first_alias = ExchangeConnectionService._configure_alias(connection)
|
||||||
|
second_alias = ExchangeConnectionService._configure_alias(connection)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.assertNotEqual(first_alias, second_alias)
|
||||||
|
self.assertTrue(first_alias.startswith("exchange_target_"))
|
||||||
|
self.assertTrue(second_alias.startswith("exchange_target_"))
|
||||||
|
finally:
|
||||||
|
ExchangeConnectionService._cleanup_alias(first_alias)
|
||||||
|
ExchangeConnectionService._cleanup_alias(second_alias)
|
||||||
|
|
||||||
def test_validate_schema_exists_raises_when_schema_missing(self):
|
def test_validate_schema_exists_raises_when_schema_missing(self):
|
||||||
cursor = MagicMock()
|
cursor = MagicMock()
|
||||||
cursor.fetchone.return_value = None
|
cursor.fetchone.return_value = None
|
||||||
|
|||||||
Reference in New Issue
Block a user