neon-sprawl/server/NeonSprawl.Server.Tests/Game/Skills/SkillProgressionGrantPersis...

79 lines
2.8 KiB
C#

using System.Net.Http.Json;
using NeonSprawl.Server.Game.Skills;
using NeonSprawl.Server.Tests.Game.PositionState;
using Npgsql;
using Xunit;
namespace NeonSprawl.Server.Tests.Game.Skills;
[Collection("Postgres integration")]
public sealed class SkillProgressionGrantPersistenceIntegrationTests(PostgresIntegrationHarness harness)
{
private PostgresWebApplicationFactory Factory => harness.Factory;
[RequirePostgresFact]
public async Task PostGrantThenGetAcrossNewFactory_ShouldPersistSkillXp()
{
// Arrange
await ResetProgressionTableAsync();
var grant = new SkillProgressionGrantRequest
{
SchemaVersion = SkillProgressionGrantRequest.CurrentSchemaVersion,
SkillId = "salvage",
Amount = 50,
SourceKind = "activity",
};
HttpResponseMessage postResponse;
// Act — write grant through first host
using (var firstClient = Factory.CreateClient())
{
postResponse = await firstClient.PostAsJsonAsync(
"/game/players/dev-local-1/skill-progression",
grant);
}
// Act — read back through a fresh host (forces DB round-trip / new DI scope)
await using var secondFactory = new PostgresWebApplicationFactory();
using var secondClient = secondFactory.CreateClient();
var snapshot =
await secondClient.GetFromJsonAsync<SkillProgressionSnapshotResponse>(
"/game/players/dev-local-1/skill-progression");
// Assert
Assert.True(postResponse.IsSuccessStatusCode);
Assert.NotNull(snapshot);
var salvage = Assert.Single(snapshot!.Skills!, static s => s.Id == "salvage");
Assert.Equal(50, salvage.Xp);
Assert.Equal(1, salvage.Level);
}
private static async Task ResetProgressionTableAsync()
{
var cs = Environment.GetEnvironmentVariable("ConnectionStrings__NeonSprawl");
if (string.IsNullOrWhiteSpace(cs))
{
throw new InvalidOperationException("ConnectionStrings__NeonSprawl is not set.");
}
var ddlPath = Path.Combine(AppContext.BaseDirectory, "db", "migrations", "V003__player_skill_progression.sql");
if (!File.Exists(ddlPath))
{
throw new FileNotFoundException($"Test DDL not found at '{ddlPath}'.", ddlPath);
}
var ddl = await File.ReadAllTextAsync(ddlPath);
await using var conn = new NpgsqlConnection(cs);
await conn.OpenAsync();
await using (var apply = new NpgsqlCommand(ddl, conn))
{
await apply.ExecuteNonQueryAsync();
}
await using (var truncate = new NpgsqlCommand("TRUNCATE player_skill_progression;", conn))
{
await truncate.ExecuteNonQueryAsync();
}
}
}