Files
RpgRoller/RpgRoller.Tests/PayloadBudgetTests.cs
2026-04-05 01:32:52 +02:00

194 lines
10 KiB
C#

using System.Text.Json;
namespace RpgRoller.Tests;
public sealed class PayloadBudgetTests
{
[Fact]
public void CharacterSheetPayload_StaysWithinBudget()
{
using var harness = ServiceTestSupport.CreateHarness();
var service = harness.Service;
service.Register("gm-sheet", "Password123", "GM");
service.Register("owner-sheet", "Password123", "Owner");
var gmSession = ServiceTestSupport.GetValue(service.Login("gm-sheet", "Password123")).SessionToken;
var ownerSession = ServiceTestSupport.GetValue(service.Login("owner-sheet", "Password123")).SessionToken;
var campaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Payload Sheet", "d6"));
var character = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Payload Hero", campaign.Id));
var groupIds = new List<Guid>
{
ServiceTestSupport.GetValue(service.CreateSkillGroup(ownerSession, character.Id, "Combat", "2D+1", 1, true)).Id,
ServiceTestSupport.GetValue(service.CreateSkillGroup(ownerSession, character.Id, "Social", "2D+1", 1, true)).Id,
ServiceTestSupport.GetValue(service.CreateSkillGroup(ownerSession, character.Id, "Knowledge", "2D+1", 1, true)).Id,
ServiceTestSupport.GetValue(service.CreateSkillGroup(ownerSession, character.Id, "Survival", "2D+1", 1, true)).Id
};
for (var i = 0; i < 18; i++)
{
Guid? skillGroupId = i < 16 ? groupIds[i % groupIds.Count] : null;
_ = ServiceTestSupport.GetValue(service.CreateSkill(ownerSession, character.Id, $"Skill {i:D2}", "2D+1", 1, true, skillGroupId));
}
var sheet = ServiceTestSupport.GetValue(service.GetCharacterSheet(ownerSession, character.Id));
AssertPayloadWithinBudget(sheet, 12 * 1024, "initial character sheet");
}
[Fact]
public void CampaignLogInitialPagePayload_StaysWithinBudget()
{
using var harness = ServiceTestSupport.CreateHarness(CreateScriptedRolls(220));
var service = harness.Service;
service.Register("gm-log-budget", "Password123", "GM");
service.Register("owner-log-budget", "Password123", "Owner");
var gmSession = ServiceTestSupport.GetValue(service.Login("gm-log-budget", "Password123")).SessionToken;
var ownerSession = ServiceTestSupport.GetValue(service.Login("owner-log-budget", "Password123")).SessionToken;
var campaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Payload Log", "d6"));
var character = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Log Hero", campaign.Id));
var skill = ServiceTestSupport.GetValue(service.CreateSkill(ownerSession, character.Id, "Stealth", "2D+1", 1, true));
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 log page");
}
[Fact]
public void CampaignLogIncrementalPayload_StaysWithinBudget()
{
using var harness = ServiceTestSupport.CreateHarness(CreateScriptedRolls(240));
var service = harness.Service;
service.Register("gm-log-delta", "Password123", "GM");
service.Register("owner-log-delta", "Password123", "Owner");
var gmSession = ServiceTestSupport.GetValue(service.Login("gm-log-delta", "Password123")).SessionToken;
var ownerSession = ServiceTestSupport.GetValue(service.Login("owner-log-delta", "Password123")).SessionToken;
var campaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Payload Delta", "d6"));
var character = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Delta Hero", campaign.Id));
var skill = ServiceTestSupport.GetValue(service.CreateSkill(ownerSession, character.Id, "Stealth", "2D+1", 1, true));
for (var i = 0; i < 25; i++)
_ = ServiceTestSupport.GetValue(service.RollSkill(ownerSession, skill.Id, "public"));
var initialPage = ServiceTestSupport.GetValue(service.GetCampaignLogPage(gmSession, campaign.Id, limit: 25));
_ = ServiceTestSupport.GetValue(service.RollSkill(ownerSession, skill.Id, "public"));
var incrementalPage = ServiceTestSupport.GetValue(service.GetCampaignLogPage(gmSession, campaign.Id, initialPage.Cursor, 25));
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]
public void RollResultPayload_StaysWithinJsInteropBudget()
{
using var harness = ServiceTestSupport.CreateHarness(CreateScriptedRolls(40));
var service = harness.Service;
service.Register("gm-roll-budget", "Password123", "GM");
service.Register("owner-roll-budget", "Password123", "Owner");
var gmSession = ServiceTestSupport.GetValue(service.Login("gm-roll-budget", "Password123")).SessionToken;
var ownerSession = ServiceTestSupport.GetValue(service.Login("owner-roll-budget", "Password123")).SessionToken;
var campaign = ServiceTestSupport.GetValue(service.CreateCampaign(gmSession, "Payload Roll", "d6"));
var character = ServiceTestSupport.GetValue(service.CreateCharacter(ownerSession, "Roll Hero", campaign.Id));
var skill = ServiceTestSupport.GetValue(service.CreateSkill(ownerSession, character.Id, "Wild Roll", "6D+3", 3, true));
var roll = ServiceTestSupport.GetValue(service.RollSkill(ownerSession, skill.Id, "public"));
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)
{
var byteCount = JsonSerializer.SerializeToUtf8Bytes(payload, SerializerOptions).Length;
Assert.True(byteCount <= maxBytes, $"{label} payload was {byteCount} bytes, above the {maxBytes}-byte budget.");
}
private static int[] CreateScriptedRolls(int count)
{
var values = new[] { 6, 5, 4, 3, 2, 1 };
var scriptedRolls = new int[count];
for (var i = 0; i < count; i++)
scriptedRolls[i] = values[i % values.Length];
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();
}