This commit is contained in:
parent
84e33024a7
commit
d58eb67764
2 changed files with 58 additions and 4 deletions
|
|
@ -340,7 +340,7 @@ async def save_credential(
|
||||||
async with pool.acquire() as conn:
|
async with pool.acquire() as conn:
|
||||||
row = await conn.fetchrow(
|
row = await conn.fetchrow(
|
||||||
"""
|
"""
|
||||||
INSERT INTO app.admin_provider_credential (
|
INSERT INTO app.admin_provider_credential AS existing (
|
||||||
provider, token_encrypted, token_hint, auth_kind, updated_by, updated_at,
|
provider, token_encrypted, token_hint, auth_kind, updated_by, updated_at,
|
||||||
refresh_token_encrypted, extra
|
refresh_token_encrypted, extra
|
||||||
)
|
)
|
||||||
|
|
@ -351,8 +351,14 @@ async def save_credential(
|
||||||
auth_kind = EXCLUDED.auth_kind,
|
auth_kind = EXCLUDED.auth_kind,
|
||||||
updated_by = EXCLUDED.updated_by,
|
updated_by = EXCLUDED.updated_by,
|
||||||
updated_at = now(),
|
updated_at = now(),
|
||||||
refresh_token_encrypted = COALESCE(EXCLUDED.refresh_token_encrypted, refresh_token_encrypted),
|
refresh_token_encrypted = COALESCE(
|
||||||
extra = CASE WHEN EXCLUDED.extra::text = '{}'::jsonb THEN extra ELSE EXCLUDED.extra END,
|
EXCLUDED.refresh_token_encrypted,
|
||||||
|
existing.refresh_token_encrypted
|
||||||
|
),
|
||||||
|
extra = CASE
|
||||||
|
WHEN EXCLUDED.extra = '{}'::jsonb THEN existing.extra
|
||||||
|
ELSE EXCLUDED.extra
|
||||||
|
END,
|
||||||
last_verified_at = NULL,
|
last_verified_at = NULL,
|
||||||
last_verify_ok = NULL,
|
last_verify_ok = NULL,
|
||||||
last_verify_error = NULL
|
last_verify_error = NULL
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""provider 자격증명 서비스(암호화·카탈로그) 단위 테스트."""
|
"""provider 자격증명 서비스(암호화·카탈로그) 단위 테스트."""
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import patch
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
from pydantic import SecretStr
|
from pydantic import SecretStr
|
||||||
|
|
||||||
|
|
@ -73,5 +73,53 @@ class CatalogTest(unittest.TestCase):
|
||||||
self.assertIn("codex", codes)
|
self.assertIn("codex", codes)
|
||||||
|
|
||||||
|
|
||||||
|
class SaveCredentialQueryTest(unittest.IsolatedAsyncioTestCase):
|
||||||
|
async def test_upsert_preserves_omitted_refresh_and_extra(self):
|
||||||
|
row = {
|
||||||
|
"provider": "openrouter",
|
||||||
|
"token_hint": "…next",
|
||||||
|
"auth_kind": "oauth_token",
|
||||||
|
"updated_by": "admin@example.com",
|
||||||
|
"updated_at": None,
|
||||||
|
"last_verified_at": None,
|
||||||
|
"last_verify_ok": None,
|
||||||
|
"last_verify_error": None,
|
||||||
|
"refresh_token_encrypted": None,
|
||||||
|
"extra": {},
|
||||||
|
}
|
||||||
|
conn = AsyncMock()
|
||||||
|
conn.fetchrow.return_value = row
|
||||||
|
|
||||||
|
class _Acquire:
|
||||||
|
async def __aenter__(self):
|
||||||
|
return conn
|
||||||
|
|
||||||
|
async def __aexit__(self, exc_type, exc, traceback):
|
||||||
|
return False
|
||||||
|
|
||||||
|
class _Pool:
|
||||||
|
def acquire(self):
|
||||||
|
return _Acquire()
|
||||||
|
|
||||||
|
with (
|
||||||
|
patch.object(svc, "ensure_table", AsyncMock()),
|
||||||
|
patch.object(svc, "get_pool", return_value=_Pool()),
|
||||||
|
patch.object(svc.settings, "provider_credential_secret", SecretStr("unit-test-master-secret-0123456789")),
|
||||||
|
):
|
||||||
|
await svc.save_credential(
|
||||||
|
provider="openrouter",
|
||||||
|
token="new-access-token",
|
||||||
|
auth_kind="oauth_token",
|
||||||
|
updated_by="admin@example.com",
|
||||||
|
)
|
||||||
|
|
||||||
|
query = conn.fetchrow.await_args.args[0]
|
||||||
|
self.assertIn("INSERT INTO app.admin_provider_credential AS existing", query)
|
||||||
|
self.assertIn("EXCLUDED.refresh_token_encrypted,\n existing.refresh_token_encrypted", query)
|
||||||
|
self.assertIn("WHEN EXCLUDED.extra = '{}'::jsonb THEN existing.extra", query)
|
||||||
|
self.assertEqual(conn.fetchrow.await_args.args[6], None)
|
||||||
|
self.assertEqual(conn.fetchrow.await_args.args[7], "{}")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue