From 09e8a7c881a50c8d1f8b1620d0824e16b225c4e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=84=B1=EA=B2=BD?= Date: Fri, 18 Sep 2026 13:38:44 +0900 Subject: [PATCH] =?UTF-8?q?[feat]=20=EC=97=B0=EB=8F=99=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- solution/backend/tests/test_social.py | 73 +++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/solution/backend/tests/test_social.py b/solution/backend/tests/test_social.py index 5d7be8b..a46c42c 100644 --- a/solution/backend/tests/test_social.py +++ b/solution/backend/tests/test_social.py @@ -347,6 +347,79 @@ async def test_post_claim_prevents_second_external_write( ).scalar_one() == ("UNKNOWN" if unknown else "POSTED") +async def test_test_post_requires_connected_account(client, auth_headers): + h = await auth_headers("social-test-owner") + res = await client.post("/v1/social/test-post", headers=h, json={"text": "연동 확인"}) + assert ( + res.status_code == 409 and res.json()["detail"] == "ACCOUNT_CONNECTION_REQUIRED" + ) + + +async def test_test_post_requires_reauth_when_expired(client, auth_headers, db_engine, monkeypatch): + from cryptography.fernet import Fernet + + monkeypatch.setenv("SOCIAL_TOKEN_SECRET", Fernet.generate_key().decode()) + h = await auth_headers("social-reauth-owner") + async with db_engine.begin() as c: + uid = ( + await c.execute( + text("SELECT user_id FROM users WHERE id=:i"), {"i": "social-reauth-owner"} + ) + ).scalar_one() + await c.execute( + text( + "INSERT INTO owner_social_accounts(account_id,user_id,provider,provider_user_id,handle,profile_url,status) " + "VALUES (:a,:u,2,'22','host','https://www.threads.com/@host','needs_reauth')" + ), + {"a": uuid.uuid4(), "u": uid}, + ) + res = await client.post("/v1/social/test-post", headers=h, json={"text": "연동 확인"}) + assert ( + res.status_code == 409 and res.json()["detail"] == "ACCOUNT_NEEDS_REAUTH" + ) + + +async def test_test_post_publishes_immediately_bypassing_approval( + client, auth_headers, db_engine, monkeypatch +): + """연동 확인용 게시는 posting_enabled 게이트·승인 절차 없이 바로 나간다.""" + from cryptography.fernet import Fernet + from services import social_account_service as accounts + + monkeypatch.setenv("SOCIAL_TOKEN_SECRET", Fernet.generate_key().decode()) + monkeypatch.setattr(service, "posting_enabled", lambda: False) + h = await auth_headers("social-verify-owner") + async with db_engine.begin() as c: + uid = ( + await c.execute( + text("SELECT user_id FROM users WHERE id=:i"), {"i": "social-verify-owner"} + ) + ).scalar_one() + await c.execute( + text( + "INSERT INTO owner_social_accounts(account_id,user_id,provider,provider_user_id,handle,profile_url,status,access_token,access_expires_at) " + "VALUES (:a,:u,2,'22','host','https://www.threads.com/@host','linked',:t,now()+interval '1 day')" + ), + {"a": uuid.uuid4(), "u": uid, "t": accounts.encrypt("secret-token")}, + ) + + calls = [] + + class Adapter: + @staticmethod + async def publish(text_, token, *, client): + calls.append((text_, token)) + return {"id": "99", "permalink": "https://www.threads.com/@host/post/99"} + + monkeypatch.setattr(service, "adapter", lambda provider: Adapter) + res = await client.post( + "/v1/social/test-post", headers=h, json={"text": "연동 확인용 테스트"} + ) + assert res.status_code == 200, res.text + assert res.json() == {"id": "99", "permalink": "https://www.threads.com/@host/post/99"} + assert calls == [("연동 확인용 테스트", "secret-token")] + + async def test_oauth_roundtrip_saves_encrypted_account(db_engine, monkeypatch): """검증: 인가 코드를 받아 계정을 연결하고, 해제까지 한 바퀴 돈다.