@@ -797,14 +797,45 @@ async def test_checkin_dedupes_same_upstream_account(repo):
797797 assert provider .checkin_calls == 1
798798
799799
800- async def test_checkin_skips_disabled_and_unsupported (repo ):
800+ async def test_checkin_skips_disabled (repo ):
801801 credentials , _db = repo
802802 credential_id = credentials .add (provider = "codebuddy" , credential_data = {"bearer_token" : "a" })
803803 credentials .save_error (credential_id , _disabled_outcome ())
804- credentials .add (provider = "trae" , credential_data = {"accessToken" : "t" })
805- task = CheckinTask (credentials , {"codebuddy" : ProbeProvider (), "trae" : TraeProvider ()})
804+ task = CheckinTask (credentials , {"codebuddy" : ProbeProvider ()})
806805 report = await task .run_once ()
807806 assert report .attempted == 0
807+ assert report .skipped == 1
808+
809+
810+ async def test_checkin_supports_both_providers (repo ):
811+ """TRAE 与 CodeBuddy 都实现签到后,任务要能覆盖两个上游。"""
812+ credentials , _db = repo
813+ credentials .add (provider = "codebuddy" , credential_data = {"bearer_token" : "a" ,
814+ "account_uid" : "cb" })
815+ credentials .add (provider = "trae" , credential_data = {"accessToken" : "t" , "uid" : "tr" })
816+
817+ class TraeCheckinProvider :
818+ id = "trae"
819+
820+ def __init__ (self ) -> None :
821+ self .calls = 0
822+
823+ async def checkin (self , _data ):
824+ self .calls += 1
825+ from src .provider .base import CheckinResult
826+
827+ return CheckinResult (ok = True , credit = None , message = "今天已签到" ,
828+ already_checked_in = True )
829+
830+ def checkin_scope (self , data ):
831+ return f"trae|{ data .get ('uid' , '' )} "
832+
833+ trae = TraeCheckinProvider ()
834+ task = CheckinTask (credentials , {"codebuddy" : ProbeProvider (), "trae" : trae })
835+ report = await task .run_once ()
836+ assert report .attempted == 2
837+ assert report .succeeded == 2
838+ assert trae .calls == 1
808839
809840
810841def _disabled_outcome ():
@@ -2079,7 +2110,6 @@ def test_schedule_probe_returns_early_when_credential_unreadable(admin_client):
20792110
20802111def test_trae_start_auth_builds_login_url_with_public_callback ():
20812112 from src .main import resolve_public_callback_url
2082- from src .provider .trae .client import TraeProvider
20832113
20842114 settings = Settings (_env_file = None , APP_SECRET = "s" , PUBLIC_BASE_URL = "https://gw.example" )
20852115 provider = TraeProvider ()
@@ -2096,7 +2126,7 @@ async def test_trae_complete_callback_exchanges_token():
20962126 """回调链接必须真的换 token,而不是只存 refreshToken。"""
20972127 import httpx as _httpx
20982128
2099- from src .provider .trae .client import TraeClient , TraeProvider
2129+ from src .provider .trae .client import TraeClient
21002130
21012131 def handler (request : _httpx .Request ) -> _httpx .Response :
21022132 if request .url .path .endswith ("ExchangeToken" ):
@@ -2123,7 +2153,6 @@ def handler(request: _httpx.Request) -> _httpx.Response:
21232153
21242154
21252155async def test_trae_complete_callback_rejects_bad_state ():
2126- from src .provider .trae .client import TraeProvider
21272156 from src .provider .trae .events import UpstreamProtocolViolation
21282157
21292158 provider = TraeProvider ()
@@ -2135,7 +2164,7 @@ def test_authorize_completes_trae_login_end_to_end(tmp_path):
21352164 """完整闭环:start → 浏览器回调 → 凭证入库 → 立即探测。"""
21362165 import httpx as _httpx
21372166
2138- from src .provider .trae .client import TraeClient , TraeProvider
2167+ from src .provider .trae .client import TraeClient
21392168
21402169 def handler (request : _httpx .Request ) -> _httpx .Response :
21412170 if request .url .path .endswith ("ExchangeToken" ):
@@ -2214,7 +2243,7 @@ async def test_complete_callback_does_not_use_refresh_token_as_access_token():
22142243 """ExchangeToken 失败时不得把 refreshToken 当 accessToken 塞进池子。"""
22152244 import httpx as _httpx
22162245
2217- from src .provider .trae .client import TraeClient , TraeProvider
2246+ from src .provider .trae .client import TraeClient
22182247 from src .provider .trae .events import UpstreamProtocolViolation
22192248
22202249 def handler (request : _httpx .Request ) -> _httpx .Response :
@@ -2236,7 +2265,7 @@ def handler(request: _httpx.Request) -> _httpx.Response:
22362265async def test_complete_callback_raises_when_no_token_available ():
22372266 import httpx as _httpx
22382267
2239- from src .provider .trae .client import TraeClient , TraeProvider
2268+ from src .provider .trae .client import TraeClient
22402269 from src .provider .trae .events import UpstreamProtocolViolation
22412270
22422271 def handler (_request : _httpx .Request ) -> _httpx .Response :
@@ -2398,7 +2427,7 @@ def test_authorize_accepts_real_trae_callback_without_state(tmp_path):
23982427 """
23992428 import httpx as _httpx
24002429
2401- from src .provider .trae .client import TraeClient , TraeProvider
2430+ from src .provider .trae .client import TraeClient
24022431
24032432 def handler (request : _httpx .Request ) -> _httpx .Response :
24042433 if request .url .path .endswith ("ExchangeToken" ):
0 commit comments