feat(rank-battle): RankBattleController shell + DTOs + routing smoke tests

Stands up the controller with all 13 rank-battle URL routes wired via
explicit absolute [HttpPost] attributes (multi-prefix family — can't ride
[Route(\"[controller]\")]). Real DoMatching / AiStart logic arrives in
later tasks; finish + telemetry + force-finish are returnable stubs as
of this task.

DTOs cover the request + response shapes per the spec. Note the
camelCase wire keys on AiBattlePlayerInfo (sleeveId, emblemId, ...) —
the AI battle subsystem uses camelCase, not the project-default
snake_case, per AIBattleStartTask.Parse's literal Keys.Contains lookups.

DoMatchingResponseDto.NodeServerUrl is non-nullable + always-emit (with
[JsonIgnore(Never)]) — matches Phase 2's TK2 fix because the client's
DoMatchingBase parser calls .ToString() without a Keys.Contains guard.

13 routing smoke tests confirm each URL resolves to the controller.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-02 01:19:02 -04:00
parent a55187e10e
commit 7c4aa89d45
7 changed files with 410 additions and 0 deletions

View File

@@ -112,6 +112,19 @@ public class RoutingSmokeTests
[TestCase("/arena/get_challenge_info")]
[TestCase("/arena/get_challenge_ranking_history")]
[TestCase("/check/check_time_slip_card_master_hash")]
[TestCase("/rotation_rank_battle/do_matching")]
[TestCase("/unlimited_rank_battle/do_matching")]
[TestCase("/ai_rotation_rank_battle/start")]
[TestCase("/ai_unlimited_rank_battle/start")]
[TestCase("/rotation_rank_battle/finish")]
[TestCase("/unlimited_rank_battle/finish")]
[TestCase("/ai_rotation_rank_battle/finish")]
[TestCase("/ai_unlimited_rank_battle/finish")]
[TestCase("/rank_battle/force_finish")]
[TestCase("/rank_battle/add_client_log")]
[TestCase("/rank_battle/add_all_client_log")]
[TestCase("/rank_battle/add_last_turn_log")]
[TestCase("/rank_battle/get_latest_master_point")]
public async Task Authenticated_route_resolves(string path)
{
using var factory = new TestFactory();