From 521229e709a6dc3dbbdfafb1ac4e2d617e8eb85e Mon Sep 17 00:00:00 2001 From: ColonistOne Date: Thu, 18 Jun 2026 06:06:24 +0100 Subject: [PATCH] Add self-cleaning integration tests for legacy + two-step registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Exercises the full registration surface against the live API and cleans up after itself with the new delete_account(), so a run leaves no orphan accounts (the reason the old register integration test was gated as "won't be cleaned up"). - test_legacy_register_then_self_delete: register() -> key works -> delete_account() -> released key no longer authenticates. - test_two_step_register_then_self_delete: register_begin() -> register_confirm(last-6) -> active -> key works -> delete_account(). Both verified live (2 passed) against thecolony.cc. Also: - Fix ruff format on tests/test_async_client.py (left unformatted by #78, which made main red on the non-required lint check). - Cover MockColonyClient.delete_account() in the mock smoke test (restores 100% coverage; #78 added the mock method untested). No version bump — stays under Unreleased for the next cut. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01TRn9SBFGaxRwZbwRsKNJ7b --- tests/integration/test_auth.py | 74 +++++++++++++++++++++++++++------- tests/test_async_client.py | 3 +- tests/test_testing.py | 1 + 3 files changed, 61 insertions(+), 17 deletions(-) diff --git a/tests/integration/test_auth.py b/tests/integration/test_auth.py index c8b49b3..73e5aba 100644 --- a/tests/integration/test_auth.py +++ b/tests/integration/test_auth.py @@ -8,13 +8,14 @@ from __future__ import annotations +import contextlib import os import pytest -from colony_sdk import ColonyClient +from colony_sdk import ColonyAuthError, ColonyClient -from .conftest import unique_suffix +from .conftest import NO_RETRY, unique_suffix class TestAuth: @@ -68,28 +69,71 @@ def test_refresh_token_clears_cache(self, client: ColonyClient) -> None: @pytest.mark.skipif( not os.environ.get("COLONY_TEST_REGISTER"), - reason="set COLONY_TEST_REGISTER=1 to run register tests (creates real accounts)", + reason="set COLONY_TEST_REGISTER=1 to run registration tests (creates real accounts)", ) -class TestRegisterDestructive: - """Destructive: each run creates a real account that won't be cleaned up.""" +class TestRegistrationLifecycle: + """Register a real account, verify the key works, then self-delete to clean up. - def test_register_returns_api_key(self) -> None: - suffix = unique_suffix() - username = f"sdk-it-{suffix}" + Both flows mint a real account on thecolony.cc, so they stay opt-in behind + ``COLONY_TEST_REGISTER=1``. Unlike a bare ``register``, each test cleans up + after itself with ``delete_account()`` — a fresh, zero-activity account can + be scrapped inside its 15-minute window — so a run leaves no orphans behind. + """ + + def test_legacy_register_then_self_delete(self) -> None: + """One-step ``register`` → key works → ``delete_account`` releases it.""" + username = f"sdk-it-{unique_suffix()}" result = ColonyClient.register( username=username, display_name="SDK integration test", - bio="Created by colony-sdk integration tests. Safe to delete.", + bio="Created by colony-sdk integration tests. Auto-deleted.", capabilities={"skills": ["testing"]}, ) - assert isinstance(result, dict) - assert "api_key" in result assert result["api_key"].startswith("col_") - # The new key should be usable immediately. - new_client = ColonyClient(result["api_key"]) - me = new_client.get_me() - assert me["username"] == username + client = ColonyClient(result["api_key"], retry=NO_RETRY) + try: + assert client.get_me()["username"] == username + # delete_account is part of what we're verifying: 204 → {}. + assert client.delete_account() == {} + finally: + # Best-effort cleanup if an assertion above failed before delete ran. + with contextlib.suppress(Exception): + client.delete_account() + + # The released key no longer authenticates. + with pytest.raises(ColonyAuthError): + ColonyClient(result["api_key"], retry=NO_RETRY).get_me() + + def test_two_step_register_then_self_delete(self) -> None: + """``register_begin`` → ``register_confirm`` (last-6) → key works → ``delete_account``.""" + username = f"sdk-it2-{unique_suffix()}" + begun = ColonyClient.register_begin( + username=username, + display_name="SDK integration test (two-step)", + bio="Created by colony-sdk integration tests. Auto-deleted.", + capabilities={"skills": ["testing"]}, + ) + assert begun["status"] == "pending" + api_key = begun["api_key"] + assert api_key.startswith("col_") + assert begun["claim_token"] + + # Activate by proving we still hold the key (its last 6 chars). + confirmed = ColonyClient.register_confirm(begun["claim_token"], api_key[-6:]) + assert confirmed["status"] == "active" + assert confirmed["username"] == username + + client = ColonyClient(api_key, retry=NO_RETRY) + try: + assert client.get_me()["username"] == username + assert client.delete_account() == {} + finally: + with contextlib.suppress(Exception): + client.delete_account() + + with pytest.raises(ColonyAuthError): + ColonyClient(api_key, retry=NO_RETRY).get_me() @pytest.mark.skipif( diff --git a/tests/test_async_client.py b/tests/test_async_client.py index 04a7a65..7524f7b 100644 --- a/tests/test_async_client.py +++ b/tests/test_async_client.py @@ -3732,8 +3732,7 @@ async def test_delete_account_has_activity(self) -> None: def handler(request: httpx.Request) -> httpx.Response: return _json_response( - {"detail": {"message": "has activity", - "code": "ACCOUNT_DELETE_HAS_ACTIVITY"}}, + {"detail": {"message": "has activity", "code": "ACCOUNT_DELETE_HAS_ACTIVITY"}}, status=409, ) diff --git a/tests/test_testing.py b/tests/test_testing.py index b929fdd..cb90d79 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -140,6 +140,7 @@ def test_all_methods_work(self) -> None: client.delete_webhook("wh1") client.refresh_token() client.rotate_key() + client.delete_account() assert len(client.calls) > 30 def test_get_all_comments(self) -> None: