Add Rolemaster payload budget coverage
This commit is contained in:
@@ -138,7 +138,7 @@ dotnet dotnet-ef migrations add <MigrationName> --project RpgRoller/RpgRoller.cs
|
|||||||
```powershell
|
```powershell
|
||||||
dotnet test RpgRoller.Tests/RpgRoller.Tests.csproj --collect:"XPlat Code Coverage" --settings RpgRoller.Tests/coverlet.runsettings
|
dotnet test RpgRoller.Tests/RpgRoller.Tests.csproj --collect:"XPlat Code Coverage" --settings RpgRoller.Tests/coverlet.runsettings
|
||||||
```
|
```
|
||||||
- Regression tests enforce payload budgets for the hottest contracts: character sheet reads, initial log page loads, incremental log updates, and roll mutation responses.
|
- Regression tests enforce payload budgets for the hottest contracts: character sheet reads, initial log page loads, incremental log updates, roll mutation responses, and lazy-loaded Rolemaster roll detail payloads.
|
||||||
- Coverage gate:
|
- Coverage gate:
|
||||||
```powershell
|
```powershell
|
||||||
pwsh ./scripts/check-coverage.ps1 -MinLineRate 0.90 -MinBranchRate 0.70
|
pwsh ./scripts/check-coverage.ps1 -MinLineRate 0.90 -MinBranchRate 0.70
|
||||||
|
|||||||
@@ -87,6 +87,29 @@ public sealed class PayloadBudgetTests
|
|||||||
AssertPayloadWithinBudget(incrementalPage, 2 * 1024, "incremental log update");
|
AssertPayloadWithinBudget(incrementalPage, 2 * 1024, "incremental log update");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RolemasterCampaignLogInitialPagePayload_StaysWithinBudget()
|
||||||
|
{
|
||||||
|
using var harness = ServiceTestSupport.CreateHarness(CreateRolemasterOpenEndedRolls(90));
|
||||||
|
var service = harness.Service;
|
||||||
|
|
||||||
|
service.Register("gm-rm-log-budget", "Password123", "GM");
|
||||||
|
service.Register("owner-rm-log-budget", "Password123", "Owner");
|
||||||
|
|
||||||
|
var gmSession = ServiceTestSupport.GetValue(service.Login("gm-rm-log-budget", "Password123")).SessionToken;
|
||||||
|
var ownerSession = ServiceTestSupport.GetValue(service.Login("owner-rm-log-budget", "Password123")).SessionToken;
|
||||||
|
|
||||||
|
var campaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Rolemaster Payload Log", "rolemaster"));
|
||||||
|
var character = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Open Hero", campaign.Id));
|
||||||
|
var skill = ServiceTestSupport.GetValue(service.CreateSkill(ownerSession, character.Id, "Awareness", "d100!+85", 0, false, null, 5));
|
||||||
|
|
||||||
|
for (var i = 0; i < 25; i++)
|
||||||
|
_ = ServiceTestSupport.GetValue(service.RollSkill(ownerSession, skill.Id, "public"));
|
||||||
|
|
||||||
|
var page = ServiceTestSupport.GetValue(service.GetCampaignLogPage(gmSession, campaign.Id, limit: 25));
|
||||||
|
AssertPayloadWithinBudget(page, 8 * 1024, "initial rolemaster log page");
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void RollResultPayload_StaysWithinJsInteropBudget()
|
public void RollResultPayload_StaysWithinJsInteropBudget()
|
||||||
{
|
{
|
||||||
@@ -107,6 +130,41 @@ public sealed class PayloadBudgetTests
|
|||||||
AssertPayloadWithinBudget(roll, 16 * 1024, "roll mutation response");
|
AssertPayloadWithinBudget(roll, 16 * 1024, "roll mutation response");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RolemasterRollDetailPayload_StaysWithinBudget_AndRolemasterMetadataRemainsLazy()
|
||||||
|
{
|
||||||
|
using var harness = ServiceTestSupport.CreateHarness([96, 100, 100, 100, 100, 97, 12]);
|
||||||
|
var service = harness.Service;
|
||||||
|
|
||||||
|
service.Register("gm-rm-detail-budget", "Password123", "GM");
|
||||||
|
service.Register("owner-rm-detail-budget", "Password123", "Owner");
|
||||||
|
|
||||||
|
var gmSession = ServiceTestSupport.GetValue(service.Login("gm-rm-detail-budget", "Password123")).SessionToken;
|
||||||
|
var ownerSession = ServiceTestSupport.GetValue(service.Login("owner-rm-detail-budget", "Password123")).SessionToken;
|
||||||
|
|
||||||
|
var campaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Rolemaster Payload Detail", "rolemaster"));
|
||||||
|
var character = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Detail Hero", campaign.Id));
|
||||||
|
var skill = ServiceTestSupport.GetValue(service.CreateSkill(ownerSession, character.Id, "Sense", "d100!+85", 0, false, null, 5));
|
||||||
|
|
||||||
|
var roll = ServiceTestSupport.GetValue(service.RollSkill(ownerSession, skill.Id, "public"));
|
||||||
|
var logPage = ServiceTestSupport.GetValue(service.GetCampaignLogPage(gmSession, campaign.Id, limit: 5));
|
||||||
|
var detail = ServiceTestSupport.GetValue(service.GetRollDetail(gmSession, roll.RollId));
|
||||||
|
|
||||||
|
AssertPayloadWithinBudget(detail, 4 * 1024, "rolemaster roll detail");
|
||||||
|
|
||||||
|
var rollJson = JsonSerializer.Serialize(roll, SerializerOptions);
|
||||||
|
var logPageJson = JsonSerializer.Serialize(logPage, SerializerOptions);
|
||||||
|
var detailJson = JsonSerializer.Serialize(detail, SerializerOptions);
|
||||||
|
|
||||||
|
Assert.DoesNotContain("\"signedContribution\":null", rollJson, StringComparison.Ordinal);
|
||||||
|
Assert.DoesNotContain("\"signedContribution\"", logPageJson, StringComparison.Ordinal);
|
||||||
|
Assert.DoesNotContain("\"sequence\"", logPageJson, StringComparison.Ordinal);
|
||||||
|
Assert.DoesNotContain("\"breakdown\"", logPageJson, StringComparison.Ordinal);
|
||||||
|
Assert.Contains("\"kind\":\"rolemaster-open-ended-initial\"", detailJson, StringComparison.Ordinal);
|
||||||
|
Assert.Contains("\"signedContribution\":96", detailJson, StringComparison.Ordinal);
|
||||||
|
Assert.Contains("\"sequence\":6", detailJson, StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
private static void AssertPayloadWithinBudget<T>(T payload, int maxBytes, string label)
|
private static void AssertPayloadWithinBudget<T>(T payload, int maxBytes, string label)
|
||||||
{
|
{
|
||||||
var byteCount = JsonSerializer.SerializeToUtf8Bytes(payload, SerializerOptions).Length;
|
var byteCount = JsonSerializer.SerializeToUtf8Bytes(payload, SerializerOptions).Length;
|
||||||
@@ -123,5 +181,15 @@ public sealed class PayloadBudgetTests
|
|||||||
return scriptedRolls;
|
return scriptedRolls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int[] CreateRolemasterOpenEndedRolls(int count)
|
||||||
|
{
|
||||||
|
var values = new[] { 96, 100, 12 };
|
||||||
|
var scriptedRolls = new int[count];
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
scriptedRolls[i] = values[i % values.Length];
|
||||||
|
|
||||||
|
return scriptedRolls;
|
||||||
|
}
|
||||||
|
|
||||||
private static readonly JsonSerializerOptions SerializerOptions = RpgRollerJson.CreateSerializerOptions();
|
private static readonly JsonSerializerOptions SerializerOptions = RpgRollerJson.CreateSerializerOptions();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user