diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaColosseum/GetFeeInfoRequest.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaColosseum/GetFeeInfoRequest.cs index 4e7bb3c..f13ba63 100644 --- a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaColosseum/GetFeeInfoRequest.cs +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaColosseum/GetFeeInfoRequest.cs @@ -3,4 +3,4 @@ using MessagePack; namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.ArenaColosseum; [MessagePackObject] -public class GetFeeInfoRequest { } +public class GetFeeInfoRequest : BaseRequest { } diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/BattleFinishRequest.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/BattleFinishRequest.cs index eb0ff6b..5ab53d9 100644 --- a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/BattleFinishRequest.cs +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/BattleFinishRequest.cs @@ -4,7 +4,7 @@ using MessagePack; namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.ArenaTwoPick; [MessagePackObject] -public class BattleFinishRequest +public class BattleFinishRequest : BaseRequest { [JsonPropertyName("class_id")] [Key("class_id")] public int ClassId { get; set; } [JsonPropertyName("total_turn")] [Key("total_turn")] public int TotalTurn { get; set; } diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/CardChooseRequest.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/CardChooseRequest.cs index f31def4..c6389ff 100644 --- a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/CardChooseRequest.cs +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/CardChooseRequest.cs @@ -4,7 +4,7 @@ using MessagePack; namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.ArenaTwoPick; [MessagePackObject] -public class CardChooseRequest +public class CardChooseRequest : BaseRequest { [JsonPropertyName("selected_id")] [Key("selected_id")] public long SelectedId { get; set; } } diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/ClassChooseRequest.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/ClassChooseRequest.cs index 03a3650..6dbd3d7 100644 --- a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/ClassChooseRequest.cs +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/ClassChooseRequest.cs @@ -4,7 +4,7 @@ using MessagePack; namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.ArenaTwoPick; [MessagePackObject] -public class ClassChooseRequest +public class ClassChooseRequest : BaseRequest { [JsonPropertyName("class_id")] [Key("class_id")] public int ClassId { get; set; } } diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/DoMatchingRequest.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/DoMatchingRequest.cs index 6526931..93fbaa4 100644 --- a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/DoMatchingRequest.cs +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/DoMatchingRequest.cs @@ -4,7 +4,7 @@ using MessagePack; namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.ArenaTwoPick; [MessagePackObject] -public class DoMatchingRequest +public class DoMatchingRequest : BaseRequest { [JsonPropertyName("card_master_hash")] [Key("card_master_hash")] public string? CardMasterHash { get; set; } [JsonPropertyName("deck_no")] [Key("deck_no")] public long DeckNo { get; set; } diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/EntryRequest.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/EntryRequest.cs index 86ef614..4639bc7 100644 --- a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/EntryRequest.cs +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/EntryRequest.cs @@ -4,7 +4,7 @@ using MessagePack; namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.ArenaTwoPick; [MessagePackObject] -public class EntryRequest +public class EntryRequest : BaseRequest { [JsonPropertyName("consume_item_type")] [Key("consume_item_type")] public int ConsumeItemType { get; set; } } diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/FinishRequest.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/FinishRequest.cs index eb8b528..18f6fce 100644 --- a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/FinishRequest.cs +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/FinishRequest.cs @@ -3,4 +3,4 @@ using MessagePack; namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.ArenaTwoPick; [MessagePackObject] -public class FinishRequest { } +public class FinishRequest : BaseRequest { } diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/RetireRequest.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/RetireRequest.cs index c808a9f..63fb699 100644 --- a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/RetireRequest.cs +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/RetireRequest.cs @@ -3,4 +3,4 @@ using MessagePack; namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.ArenaTwoPick; [MessagePackObject] -public class RetireRequest { } +public class RetireRequest : BaseRequest { } diff --git a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/TopRequest.cs b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/TopRequest.cs index adc13be..caa1ef4 100644 --- a/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/TopRequest.cs +++ b/SVSim.EmulatedEntrypoint/Models/Dtos/Requests/ArenaTwoPick/TopRequest.cs @@ -4,7 +4,7 @@ using MessagePack; namespace SVSim.EmulatedEntrypoint.Models.Dtos.Requests.ArenaTwoPick; [MessagePackObject] -public class TopRequest +public class TopRequest : BaseRequest { [JsonPropertyName("mode")] [Key("mode")] public int Mode { get; set; } } diff --git a/SVSim.UnitTests/Controllers/ArenaTwoPickBattleControllerTests.cs b/SVSim.UnitTests/Controllers/ArenaTwoPickBattleControllerTests.cs index e0537d3..40582b4 100644 --- a/SVSim.UnitTests/Controllers/ArenaTwoPickBattleControllerTests.cs +++ b/SVSim.UnitTests/Controllers/ArenaTwoPickBattleControllerTests.cs @@ -12,7 +12,10 @@ public class ArenaTwoPickBattleControllerTests using var factory = new SVSimTestFactory(); var viewerId = await factory.SeedViewerAsync(); using var client = factory.CreateAuthenticatedClient(viewerId); - var req = new { deck_no = 1L, need_init = 1, log = 1, excluded_field_id_list = new long[] { }, use_stage_select = 1, is_default_skin = 0 }; + var req = new { + deck_no = 1L, need_init = 1, log = 1, excluded_field_id_list = new long[] { }, use_stage_select = 1, is_default_skin = 0, + viewer_id = "0", steam_id = 0, steam_session_ticket = "", + }; var resp = await client.PostAsync("/arena_two_pick_battle/do_matching", JsonContent.Create(req)); Assert.That(resp.StatusCode, Is.EqualTo(HttpStatusCode.OK)); diff --git a/SVSim.UnitTests/Controllers/ArenaTwoPickControllerTests.cs b/SVSim.UnitTests/Controllers/ArenaTwoPickControllerTests.cs index 2e33383..5c3d8c8 100644 --- a/SVSim.UnitTests/Controllers/ArenaTwoPickControllerTests.cs +++ b/SVSim.UnitTests/Controllers/ArenaTwoPickControllerTests.cs @@ -6,12 +6,18 @@ namespace SVSim.UnitTests.Controllers; public class ArenaTwoPickControllerTests { + // Every request DTO inherits BaseRequest; the [ApiController] auto-400 path rejects + // bodies missing the envelope fields. Spread this into JSON bodies in addition to per- + // endpoint payload. + private static readonly object Envelope = new { viewer_id = "0", steam_id = 0, steam_session_ticket = "" }; + [Test] public async Task Top_unauthenticated_returns_401() { using var factory = new SVSimTestFactory(); using var client = factory.CreateClient(); - var resp = await client.PostAsync("/arena_two_pick/top", JsonContent.Create(new { mode = 0 })); + var resp = await client.PostAsync("/arena_two_pick/top", + JsonContent.Create(new { mode = 0, viewer_id = "0", steam_id = 0, steam_session_ticket = "" })); Assert.That(resp.StatusCode, Is.EqualTo(HttpStatusCode.Unauthorized)); } @@ -21,7 +27,8 @@ public class ArenaTwoPickControllerTests using var factory = new SVSimTestFactory(); var viewerId = await factory.SeedViewerAsync(); using var client = factory.CreateAuthenticatedClient(viewerId); - var resp = await client.PostAsync("/arena_two_pick/top", JsonContent.Create(new { mode = 0 })); + var resp = await client.PostAsync("/arena_two_pick/top", + JsonContent.Create(new { mode = 0, viewer_id = "0", steam_id = 0, steam_session_ticket = "" })); Assert.That(resp.StatusCode, Is.EqualTo(HttpStatusCode.OK)); var body = await resp.Content.ReadAsStringAsync(); StringAssert.Contains("\"entry_info\":null", body); diff --git a/SVSim.UnitTests/Integration/ArenaTwoPickEndToEndTests.cs b/SVSim.UnitTests/Integration/ArenaTwoPickEndToEndTests.cs index c98db03..76c19b0 100644 --- a/SVSim.UnitTests/Integration/ArenaTwoPickEndToEndTests.cs +++ b/SVSim.UnitTests/Integration/ArenaTwoPickEndToEndTests.cs @@ -79,14 +79,21 @@ public class ArenaTwoPickEndToEndTests using var client = factory.CreateAuthenticatedClient(viewerId); + // Every TK2 request DTO inherits BaseRequest; the [ApiController] auto-400 path + // rejects bodies missing the envelope fields. Each PostAsync below carries them. + const string Vid = "0"; + const int Sid = 0; + const string Stk = ""; + // 1) /top → entry_info:null (no active run). - var top = await client.PostAsync("/arena_two_pick/top", JsonContent.Create(new { mode = 0 })); + var top = await client.PostAsync("/arena_two_pick/top", + JsonContent.Create(new { mode = 0, viewer_id = Vid, steam_id = Sid, steam_session_ticket = Stk })); Assert.That(top.StatusCode, Is.EqualTo(HttpStatusCode.OK)); StringAssert.Contains("\"entry_info\":null", await top.Content.ReadAsStringAsync()); // 2) /entry → deducts 1 ticket (post-state = 4), returns 3 candidate class ids. var entry = await client.PostAsync("/arena_two_pick/entry", - JsonContent.Create(new { consume_item_type = 3 })); + JsonContent.Create(new { consume_item_type = 3, viewer_id = Vid, steam_id = Sid, steam_session_ticket = Stk })); Assert.That(entry.StatusCode, Is.EqualTo(HttpStatusCode.OK), $"/entry failed: {await entry.Content.ReadAsStringAsync()}"); using var entryDoc = JsonDocument.Parse(await entry.Content.ReadAsStringAsync()); @@ -96,7 +103,7 @@ public class ArenaTwoPickEndToEndTests // 3) /class_choose with first candidate → returns candidate_card_list. var classChoose = await client.PostAsync("/arena_two_pick/class_choose", - JsonContent.Create(new { class_id = candidates[0] })); + JsonContent.Create(new { class_id = candidates[0], viewer_id = Vid, steam_id = Sid, steam_session_ticket = Stk })); Assert.That(classChoose.StatusCode, Is.EqualTo(HttpStatusCode.OK), $"/class_choose failed: {await classChoose.Content.ReadAsStringAsync()}"); using var classDoc = JsonDocument.Parse(await classChoose.Content.ReadAsStringAsync()); @@ -109,7 +116,7 @@ public class ArenaTwoPickEndToEndTests for (int turn = 1; turn <= 15; turn++) { var cc = await client.PostAsync("/arena_two_pick/card_choose", - JsonContent.Create(new { selected_id = pickId })); + JsonContent.Create(new { selected_id = pickId, viewer_id = Vid, steam_id = Sid, steam_session_ticket = Stk })); Assert.That(cc.StatusCode, Is.EqualTo(HttpStatusCode.OK), $"turn {turn} /card_choose failed: {await cc.Content.ReadAsStringAsync()}"); @@ -124,7 +131,8 @@ public class ArenaTwoPickEndToEndTests // 5) /retire at 0 wins → 1 ticket + 100 rupies from the seed table. // Post-state: ticket = 4 (after debit) + 1 (grant) = 5; rupies = 0 + 100 = 100. - var retire = await client.PostAsync("/arena_two_pick/retire", JsonContent.Create(new { })); + var retire = await client.PostAsync("/arena_two_pick/retire", + JsonContent.Create(new { viewer_id = Vid, steam_id = Sid, steam_session_ticket = Stk })); Assert.That(retire.StatusCode, Is.EqualTo(HttpStatusCode.OK), $"/retire failed: {await retire.Content.ReadAsStringAsync()}"); using var retDoc = JsonDocument.Parse(await retire.Content.ReadAsStringAsync()); @@ -146,7 +154,8 @@ public class ArenaTwoPickEndToEndTests "post-state ticket = 4 (after debit) + 1 (grant) = 5"); // 6) /top → entry_info:null again (run was deleted by /retire). - var topAgain = await client.PostAsync("/arena_two_pick/top", JsonContent.Create(new { mode = 0 })); + var topAgain = await client.PostAsync("/arena_two_pick/top", + JsonContent.Create(new { mode = 0, viewer_id = Vid, steam_id = Sid, steam_session_ticket = Stk })); Assert.That(topAgain.StatusCode, Is.EqualTo(HttpStatusCode.OK)); StringAssert.Contains("\"entry_info\":null", await topAgain.Content.ReadAsStringAsync()); }