feat(ranking): stub /ranking/* (6 endpoints)
Rankings menu opens. Period picker shows deterministic monthly schedule.
Every leaderboard returns { period, ranking: [] }.
Endpoints:
- /ranking/get_viewable_ranking_period_list
- /ranking/master_point_{rotation,unlimited}_info
- /ranking/rank_match_class_win_{rotation,unlimited}_info
- /ranking/two_pick_win_info
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
86
SVSim.EmulatedEntrypoint/Controllers/RankingController.cs
Normal file
86
SVSim.EmulatedEntrypoint/Controllers/RankingController.cs
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using SVSim.EmulatedEntrypoint.Models.Dtos.Ranking;
|
||||||
|
using SVSim.EmulatedEntrypoint.Models.Dtos.Requests;
|
||||||
|
using SVSim.EmulatedEntrypoint.Services;
|
||||||
|
|
||||||
|
namespace SVSim.EmulatedEntrypoint.Controllers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// /ranking/* — Rankings menu. Stub: the period picker renders a real
|
||||||
|
/// deterministic monthly schedule, but every leaderboard returns an empty
|
||||||
|
/// `ranking: []`. See docs/superpowers/specs/2026-06-10-ranking-stubs-design.md.
|
||||||
|
/// </summary>
|
||||||
|
[Route("ranking")]
|
||||||
|
public sealed class RankingController : SVSimController
|
||||||
|
{
|
||||||
|
[HttpPost("get_viewable_ranking_period_list")]
|
||||||
|
public IActionResult GetViewablePeriodList([FromBody] BaseRequest req)
|
||||||
|
{
|
||||||
|
if (!TryGetViewerId(out _)) return Unauthorized();
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
return Ok(new PeriodListResponseDto
|
||||||
|
{
|
||||||
|
RankMatch = ToBase(RankingPeriodSchedule.GenerateFor(RankingPeriodSchedule.Family.RankMatch, now)),
|
||||||
|
MasterPoint = ToMasterPoint(RankingPeriodSchedule.GenerateFor(RankingPeriodSchedule.Family.MasterPoint, now)),
|
||||||
|
TwoPick = ToTwoPick(RankingPeriodSchedule.GenerateFor(RankingPeriodSchedule.Family.TwoPick, now)),
|
||||||
|
Sealed = ToBase(RankingPeriodSchedule.GenerateFor(RankingPeriodSchedule.Family.Sealed, now)),
|
||||||
|
// Crossover arrays stay empty — captured prod returned [] for both.
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("master_point_rotation_info")]
|
||||||
|
public IActionResult MasterPointRotation([FromBody] MasterPointInfoRequestDto req)
|
||||||
|
=> RankingFor(RankingPeriodSchedule.Family.MasterPoint, req.PeriodId);
|
||||||
|
|
||||||
|
[HttpPost("master_point_unlimited_info")]
|
||||||
|
public IActionResult MasterPointUnlimited([FromBody] MasterPointInfoRequestDto req)
|
||||||
|
=> RankingFor(RankingPeriodSchedule.Family.MasterPoint, req.PeriodId);
|
||||||
|
|
||||||
|
[HttpPost("rank_match_class_win_rotation_info")]
|
||||||
|
public IActionResult RankMatchClassWinRotation([FromBody] ClassWinInfoRequestDto req)
|
||||||
|
=> RankingFor(RankingPeriodSchedule.Family.RankMatch, req.PeriodId);
|
||||||
|
|
||||||
|
[HttpPost("rank_match_class_win_unlimited_info")]
|
||||||
|
public IActionResult RankMatchClassWinUnlimited([FromBody] ClassWinInfoRequestDto req)
|
||||||
|
=> RankingFor(RankingPeriodSchedule.Family.RankMatch, req.PeriodId);
|
||||||
|
|
||||||
|
[HttpPost("two_pick_win_info")]
|
||||||
|
public IActionResult TwoPickWin([FromBody] TwoPickWinInfoRequestDto req)
|
||||||
|
=> RankingFor(RankingPeriodSchedule.Family.TwoPick, req.PeriodId);
|
||||||
|
|
||||||
|
private IActionResult RankingFor(RankingPeriodSchedule.Family family, int periodId)
|
||||||
|
{
|
||||||
|
if (!TryGetViewerId(out _)) return Unauthorized();
|
||||||
|
var entry = RankingPeriodSchedule.TryFindById(family, periodId, DateTime.UtcNow);
|
||||||
|
var periodDto = entry is null
|
||||||
|
? new PeriodEntryDto { Id = periodId.ToString() }
|
||||||
|
: new PeriodEntryDto
|
||||||
|
{
|
||||||
|
Id = entry.Id,
|
||||||
|
PeriodNum = entry.PeriodNum,
|
||||||
|
BeginTime = entry.BeginTime,
|
||||||
|
EndTime = entry.EndTime,
|
||||||
|
};
|
||||||
|
return Ok(new MonthlyRankingResponseDto { Period = periodDto, Ranking = new() });
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<PeriodEntryDto> ToBase(IReadOnlyList<PeriodEntry> src)
|
||||||
|
=> src.Select(e => new PeriodEntryDto
|
||||||
|
{
|
||||||
|
Id = e.Id, PeriodNum = e.PeriodNum, BeginTime = e.BeginTime, EndTime = e.EndTime,
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
private static List<MasterPointPeriodEntryDto> ToMasterPoint(IReadOnlyList<PeriodEntry> src)
|
||||||
|
=> src.Select(e => new MasterPointPeriodEntryDto
|
||||||
|
{
|
||||||
|
Id = e.Id, PeriodNum = e.PeriodNum, BeginTime = e.BeginTime, EndTime = e.EndTime,
|
||||||
|
NecessaryScore = "0",
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
private static List<TwoPickPeriodEntryDto> ToTwoPick(IReadOnlyList<PeriodEntry> src)
|
||||||
|
=> src.Select(e => new TwoPickPeriodEntryDto
|
||||||
|
{
|
||||||
|
Id = e.Id, PeriodNum = e.PeriodNum, BeginTime = e.BeginTime, EndTime = e.EndTime,
|
||||||
|
Type = "2", Over460 = "1",
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using MessagePack;
|
||||||
|
using SVSim.EmulatedEntrypoint.Models.Dtos.Requests;
|
||||||
|
|
||||||
|
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Ranking;
|
||||||
|
|
||||||
|
[MessagePackObject]
|
||||||
|
public sealed class ClassWinInfoRequestDto : BaseRequest
|
||||||
|
{
|
||||||
|
[JsonPropertyName("period_id"), Key("period_id")]
|
||||||
|
public int PeriodId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("class_id"), Key("class_id")]
|
||||||
|
public int ClassId { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using MessagePack;
|
||||||
|
using SVSim.EmulatedEntrypoint.Models.Dtos.Requests;
|
||||||
|
|
||||||
|
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Ranking;
|
||||||
|
|
||||||
|
[MessagePackObject]
|
||||||
|
public sealed class MasterPointInfoRequestDto : BaseRequest
|
||||||
|
{
|
||||||
|
[JsonPropertyName("period_id"), Key("period_id")]
|
||||||
|
public int PeriodId { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using MessagePack;
|
||||||
|
|
||||||
|
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Ranking;
|
||||||
|
|
||||||
|
[MessagePackObject]
|
||||||
|
public sealed class MasterPointPeriodEntryDto : PeriodEntryDto
|
||||||
|
{
|
||||||
|
[JsonPropertyName("necessary_score"), Key("necessary_score")]
|
||||||
|
public string NecessaryScore { get; set; } = "0";
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using MessagePack;
|
||||||
|
|
||||||
|
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Ranking;
|
||||||
|
|
||||||
|
[MessagePackObject]
|
||||||
|
public sealed class MonthlyRankingResponseDto
|
||||||
|
{
|
||||||
|
[JsonPropertyName("period"), Key("period")]
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public PeriodEntryDto Period { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonPropertyName("ranking"), Key("ranking")]
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public List<RankingEntryDto> Ranking { get; set; } = new();
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using MessagePack;
|
||||||
|
|
||||||
|
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Ranking;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base period-entry shape used by /ranking/get_viewable_ranking_period_list's
|
||||||
|
/// rank_match[] and crossover_* arrays. Master-point and two-pick variants
|
||||||
|
/// add fields — see <see cref="MasterPointPeriodEntryDto"/> and
|
||||||
|
/// <see cref="TwoPickPeriodEntryDto"/>.
|
||||||
|
/// </summary>
|
||||||
|
[MessagePackObject]
|
||||||
|
public class PeriodEntryDto
|
||||||
|
{
|
||||||
|
[JsonPropertyName("id"), Key("id")]
|
||||||
|
public string Id { get; set; } = "0";
|
||||||
|
|
||||||
|
[JsonPropertyName("period_num"), Key("period_num")]
|
||||||
|
public string PeriodNum { get; set; } = "0";
|
||||||
|
|
||||||
|
[JsonPropertyName("begin_time"), Key("begin_time")]
|
||||||
|
public string BeginTime { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonPropertyName("end_time"), Key("end_time")]
|
||||||
|
public string EndTime { get; set; } = "";
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using MessagePack;
|
||||||
|
|
||||||
|
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Ranking;
|
||||||
|
|
||||||
|
[MessagePackObject]
|
||||||
|
public sealed class PeriodListResponseDto
|
||||||
|
{
|
||||||
|
// All required per spec; emit empty list, never null.
|
||||||
|
[JsonPropertyName("rank_match"), Key("rank_match")]
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public List<PeriodEntryDto> RankMatch { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonPropertyName("master_point"), Key("master_point")]
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public List<MasterPointPeriodEntryDto> MasterPoint { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonPropertyName("two_pick"), Key("two_pick")]
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public List<TwoPickPeriodEntryDto> TwoPick { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonPropertyName("sealed"), Key("sealed")]
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public List<PeriodEntryDto> Sealed { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonPropertyName("crossover_rank_match"), Key("crossover_rank_match")]
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public List<PeriodEntryDto> CrossoverRankMatch { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonPropertyName("crossover_master_point"), Key("crossover_master_point")]
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.Never)]
|
||||||
|
public List<PeriodEntryDto> CrossoverMasterPoint { get; set; } = new();
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using MessagePack;
|
||||||
|
|
||||||
|
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Ranking;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// One row in a /ranking/* leaderboard's `ranking[]` array. Stub server never
|
||||||
|
/// emits these; the type exists so the DTO compiles and so wire-shape tests can
|
||||||
|
/// parse captured prod frames into it. Wire-type quirks (per capture frame 65):
|
||||||
|
/// viewer_id/score/ranking_rank are STRINGS; rank/emblem_id/degree_id are NUMBERS.
|
||||||
|
/// </summary>
|
||||||
|
[MessagePackObject]
|
||||||
|
public sealed class RankingEntryDto
|
||||||
|
{
|
||||||
|
[JsonPropertyName("viewer_id"), Key("viewer_id")]
|
||||||
|
public string ViewerId { get; set; } = "0";
|
||||||
|
|
||||||
|
[JsonPropertyName("score"), Key("score")]
|
||||||
|
public string Score { get; set; } = "0";
|
||||||
|
|
||||||
|
[JsonPropertyName("ranking_rank"), Key("ranking_rank")]
|
||||||
|
public string RankingRank { get; set; } = "0";
|
||||||
|
|
||||||
|
[JsonPropertyName("name"), Key("name")]
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonPropertyName("country_code"), Key("country_code")]
|
||||||
|
public string CountryCode { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonPropertyName("rank"), Key("rank")]
|
||||||
|
public int Rank { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("emblem_id"), Key("emblem_id")]
|
||||||
|
public long EmblemId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("degree_id"), Key("degree_id")]
|
||||||
|
public long DegreeId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("last_play_time"), Key("last_play_time")]
|
||||||
|
public string LastPlayTime { get; set; } = "";
|
||||||
|
|
||||||
|
[JsonPropertyName("guild_name"), Key("guild_name")]
|
||||||
|
public string GuildName { get; set; } = "";
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using MessagePack;
|
||||||
|
|
||||||
|
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Ranking;
|
||||||
|
|
||||||
|
[MessagePackObject]
|
||||||
|
public sealed class TwoPickPeriodEntryDto : PeriodEntryDto
|
||||||
|
{
|
||||||
|
[JsonPropertyName("type"), Key("type")]
|
||||||
|
public string Type { get; set; } = "2";
|
||||||
|
|
||||||
|
[JsonPropertyName("over_460"), Key("over_460")]
|
||||||
|
public string Over460 { get; set; } = "1";
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using MessagePack;
|
||||||
|
using SVSim.EmulatedEntrypoint.Models.Dtos.Requests;
|
||||||
|
|
||||||
|
namespace SVSim.EmulatedEntrypoint.Models.Dtos.Ranking;
|
||||||
|
|
||||||
|
[MessagePackObject]
|
||||||
|
public sealed class TwoPickWinInfoRequestDto : BaseRequest
|
||||||
|
{
|
||||||
|
[JsonPropertyName("period_id"), Key("period_id")]
|
||||||
|
public int PeriodId { get; set; }
|
||||||
|
}
|
||||||
146
SVSim.UnitTests/Controllers/RankingControllerTests.cs
Normal file
146
SVSim.UnitTests/Controllers/RankingControllerTests.cs
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
using System.Net;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using SVSim.UnitTests.Infrastructure;
|
||||||
|
|
||||||
|
namespace SVSim.UnitTests.Controllers;
|
||||||
|
|
||||||
|
public class RankingControllerTests
|
||||||
|
{
|
||||||
|
private static StringContent JsonBody(string json) => new(json, Encoding.UTF8, "application/json");
|
||||||
|
|
||||||
|
private const string EmptyBody = """{"viewer_id":"0","steam_id":0,"steam_session_ticket":""}""";
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GetViewablePeriodList_returns_six_family_arrays()
|
||||||
|
{
|
||||||
|
using var factory = new SVSimTestFactory();
|
||||||
|
long viewerId = await factory.SeedViewerAsync(steamId: 76_561_198_000_030_001UL);
|
||||||
|
using var client = factory.CreateAuthenticatedClient(viewerId);
|
||||||
|
|
||||||
|
var resp = await client.PostAsync("/ranking/get_viewable_ranking_period_list", JsonBody(EmptyBody));
|
||||||
|
Assert.That(resp.StatusCode, Is.EqualTo(HttpStatusCode.OK));
|
||||||
|
|
||||||
|
var raw = await resp.Content.ReadAsStringAsync();
|
||||||
|
using var doc = JsonDocument.Parse(raw);
|
||||||
|
var data = doc.RootElement;
|
||||||
|
|
||||||
|
foreach (var key in new[] { "rank_match", "master_point", "two_pick", "sealed",
|
||||||
|
"crossover_rank_match", "crossover_master_point" })
|
||||||
|
{
|
||||||
|
Assert.That(data.TryGetProperty(key, out _), Is.True, $"missing key {key}");
|
||||||
|
}
|
||||||
|
Assert.That(data.GetProperty("rank_match").GetArrayLength(), Is.GreaterThan(0));
|
||||||
|
Assert.That(data.GetProperty("crossover_rank_match").GetArrayLength(), Is.EqualTo(0));
|
||||||
|
Assert.That(data.GetProperty("crossover_master_point").GetArrayLength(), Is.EqualTo(0));
|
||||||
|
|
||||||
|
// Master-point entries carry the extra "necessary_score" field per capture.
|
||||||
|
var mp0 = data.GetProperty("master_point")[0];
|
||||||
|
Assert.That(mp0.GetProperty("necessary_score").GetString(), Is.EqualTo("0"));
|
||||||
|
|
||||||
|
// Two-pick entries carry "type" and "over_460".
|
||||||
|
var tp0 = data.GetProperty("two_pick")[0];
|
||||||
|
Assert.That(tp0.GetProperty("type").GetString(), Is.EqualTo("2"));
|
||||||
|
Assert.That(tp0.GetProperty("over_460").GetString(), Is.EqualTo("1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task MasterPointRotationInfo_returns_empty_ranking_with_period_echoed()
|
||||||
|
{
|
||||||
|
using var factory = new SVSimTestFactory();
|
||||||
|
long viewerId = await factory.SeedViewerAsync(steamId: 76_561_198_000_030_001UL);
|
||||||
|
using var client = factory.CreateAuthenticatedClient(viewerId);
|
||||||
|
|
||||||
|
var resp = await client.PostAsync("/ranking/master_point_rotation_info",
|
||||||
|
JsonBody("""{"viewer_id":"0","steam_id":0,"steam_session_ticket":"","period_id":1}"""));
|
||||||
|
Assert.That(resp.StatusCode, Is.EqualTo(HttpStatusCode.OK));
|
||||||
|
|
||||||
|
var raw = await resp.Content.ReadAsStringAsync();
|
||||||
|
using var doc = JsonDocument.Parse(raw);
|
||||||
|
Assert.That(doc.RootElement.GetProperty("ranking").GetArrayLength(), Is.EqualTo(0));
|
||||||
|
Assert.That(doc.RootElement.GetProperty("period").GetProperty("id").GetString(), Is.EqualTo("1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task MasterPointUnlimitedInfo_returns_empty_ranking()
|
||||||
|
{
|
||||||
|
using var factory = new SVSimTestFactory();
|
||||||
|
long viewerId = await factory.SeedViewerAsync(steamId: 76_561_198_000_030_001UL);
|
||||||
|
using var client = factory.CreateAuthenticatedClient(viewerId);
|
||||||
|
|
||||||
|
var resp = await client.PostAsync("/ranking/master_point_unlimited_info",
|
||||||
|
JsonBody("""{"viewer_id":"0","steam_id":0,"steam_session_ticket":"","period_id":1}"""));
|
||||||
|
Assert.That(resp.StatusCode, Is.EqualTo(HttpStatusCode.OK));
|
||||||
|
var raw = await resp.Content.ReadAsStringAsync();
|
||||||
|
using var doc = JsonDocument.Parse(raw);
|
||||||
|
Assert.That(doc.RootElement.GetProperty("ranking").GetArrayLength(), Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task RankMatchClassWinRotationInfo_accepts_class_id_and_returns_empty()
|
||||||
|
{
|
||||||
|
using var factory = new SVSimTestFactory();
|
||||||
|
long viewerId = await factory.SeedViewerAsync(steamId: 76_561_198_000_030_001UL);
|
||||||
|
using var client = factory.CreateAuthenticatedClient(viewerId);
|
||||||
|
|
||||||
|
var resp = await client.PostAsync("/ranking/rank_match_class_win_rotation_info",
|
||||||
|
JsonBody("""{"viewer_id":"0","steam_id":0,"steam_session_ticket":"","period_id":1,"class_id":3}"""));
|
||||||
|
Assert.That(resp.StatusCode, Is.EqualTo(HttpStatusCode.OK));
|
||||||
|
var raw = await resp.Content.ReadAsStringAsync();
|
||||||
|
using var doc = JsonDocument.Parse(raw);
|
||||||
|
Assert.That(doc.RootElement.GetProperty("ranking").GetArrayLength(), Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task RankMatchClassWinUnlimitedInfo_returns_empty()
|
||||||
|
{
|
||||||
|
using var factory = new SVSimTestFactory();
|
||||||
|
long viewerId = await factory.SeedViewerAsync(steamId: 76_561_198_000_030_001UL);
|
||||||
|
using var client = factory.CreateAuthenticatedClient(viewerId);
|
||||||
|
|
||||||
|
var resp = await client.PostAsync("/ranking/rank_match_class_win_unlimited_info",
|
||||||
|
JsonBody("""{"viewer_id":"0","steam_id":0,"steam_session_ticket":"","period_id":1,"class_id":1}"""));
|
||||||
|
Assert.That(resp.StatusCode, Is.EqualTo(HttpStatusCode.OK));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TwoPickWinInfo_returns_empty_ranking()
|
||||||
|
{
|
||||||
|
using var factory = new SVSimTestFactory();
|
||||||
|
long viewerId = await factory.SeedViewerAsync(steamId: 76_561_198_000_030_001UL);
|
||||||
|
using var client = factory.CreateAuthenticatedClient(viewerId);
|
||||||
|
|
||||||
|
var resp = await client.PostAsync("/ranking/two_pick_win_info",
|
||||||
|
JsonBody("""{"viewer_id":"0","steam_id":0,"steam_session_ticket":"","period_id":1}"""));
|
||||||
|
Assert.That(resp.StatusCode, Is.EqualTo(HttpStatusCode.OK));
|
||||||
|
var raw = await resp.Content.ReadAsStringAsync();
|
||||||
|
using var doc = JsonDocument.Parse(raw);
|
||||||
|
Assert.That(doc.RootElement.GetProperty("ranking").GetArrayLength(), Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task MasterPointRotationInfo_unknown_period_returns_empty_period()
|
||||||
|
{
|
||||||
|
using var factory = new SVSimTestFactory();
|
||||||
|
long viewerId = await factory.SeedViewerAsync(steamId: 76_561_198_000_030_001UL);
|
||||||
|
using var client = factory.CreateAuthenticatedClient(viewerId);
|
||||||
|
|
||||||
|
var resp = await client.PostAsync("/ranking/master_point_rotation_info",
|
||||||
|
JsonBody("""{"viewer_id":"0","steam_id":0,"steam_session_ticket":"","period_id":99999}"""));
|
||||||
|
Assert.That(resp.StatusCode, Is.EqualTo(HttpStatusCode.OK));
|
||||||
|
var raw = await resp.Content.ReadAsStringAsync();
|
||||||
|
using var doc = JsonDocument.Parse(raw);
|
||||||
|
Assert.That(doc.RootElement.GetProperty("ranking").GetArrayLength(), Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Unauthenticated_get_viewable_period_list_returns_401()
|
||||||
|
{
|
||||||
|
using var factory = new SVSimTestFactory();
|
||||||
|
var client = factory.CreateClient();
|
||||||
|
|
||||||
|
var resp = await client.PostAsync("/ranking/get_viewable_ranking_period_list", JsonBody(EmptyBody));
|
||||||
|
Assert.That(resp.StatusCode, Is.EqualTo(HttpStatusCode.Unauthorized));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user