98 lines
4.2 KiB
C#
98 lines
4.2 KiB
C#
using Microsoft.Extensions.DependencyInjection;
|
|
using NeonSprawl.Server.Game.Gathering;
|
|
using NeonSprawl.Server.Tests.Game.PositionState;
|
|
using Npgsql;
|
|
using Xunit;
|
|
|
|
namespace NeonSprawl.Server.Tests.Game.Gathering;
|
|
|
|
[Collection("Postgres integration")]
|
|
public sealed class ResourceNodeInstancePersistenceIntegrationTests(PostgresIntegrationHarness harness)
|
|
{
|
|
private PostgresWebApplicationFactory Factory => harness.Factory;
|
|
|
|
private const string AlphaId = "prototype_resource_node_alpha";
|
|
|
|
[RequirePostgresFact]
|
|
public async Task TryCommitSuccessfulGatherDecrementAcrossNewFactory_ShouldPersistRemainingGathers()
|
|
{
|
|
// Arrange
|
|
await ResetInstanceTableAsync();
|
|
ResourceNodeInstanceMutationOutcome firstOutcome;
|
|
|
|
// Act — write through first host
|
|
using (var firstScope = Factory.Services.CreateScope())
|
|
{
|
|
var registry = firstScope.ServiceProvider.GetRequiredService<IResourceNodeDefinitionRegistry>();
|
|
var store = firstScope.ServiceProvider.GetRequiredService<IResourceNodeInstanceStore>();
|
|
firstOutcome = ResourceNodeInstanceOperations.TryCommitSuccessfulGatherDecrement(AlphaId, registry, store);
|
|
}
|
|
|
|
// Act — read back through a fresh host
|
|
await using var secondFactory = new PostgresWebApplicationFactory();
|
|
using var secondScope = secondFactory.Services.CreateScope();
|
|
var readStore = secondScope.ServiceProvider.GetRequiredService<IResourceNodeInstanceStore>();
|
|
var readBack = readStore.TryGetRemainingGathers(AlphaId, out var snapshot);
|
|
|
|
// Assert
|
|
Assert.Equal(ResourceNodeInstanceMutationKind.Applied, firstOutcome.Kind);
|
|
Assert.Equal(9, firstOutcome.Snapshot!.Value.RemainingGathers);
|
|
Assert.True(readBack);
|
|
Assert.Equal(9, snapshot.RemainingGathers);
|
|
}
|
|
|
|
[RequirePostgresFact]
|
|
public async Task TryCommitSuccessfulGatherDecrement_WhenDepleted_ShouldPersistZeroRow()
|
|
{
|
|
// Arrange
|
|
await ResetInstanceTableAsync();
|
|
using (var seedScope = Factory.Services.CreateScope())
|
|
{
|
|
var seedRegistry = seedScope.ServiceProvider.GetRequiredService<IResourceNodeDefinitionRegistry>();
|
|
var seedStore = seedScope.ServiceProvider.GetRequiredService<IResourceNodeInstanceStore>();
|
|
for (var i = 0; i < 10; i++)
|
|
{
|
|
_ = ResourceNodeInstanceOperations.TryCommitSuccessfulGatherDecrement(AlphaId, seedRegistry, seedStore);
|
|
}
|
|
}
|
|
|
|
// Act
|
|
await using var secondFactory = new PostgresWebApplicationFactory();
|
|
using var actScope = secondFactory.Services.CreateScope();
|
|
var actRegistry = actScope.ServiceProvider.GetRequiredService<IResourceNodeDefinitionRegistry>();
|
|
var actStore = actScope.ServiceProvider.GetRequiredService<IResourceNodeInstanceStore>();
|
|
var denyOutcome = ResourceNodeInstanceOperations.TryCommitSuccessfulGatherDecrement(AlphaId, actRegistry, actStore);
|
|
actStore.TryGetRemainingGathers(AlphaId, out var persisted);
|
|
|
|
// Assert
|
|
Assert.Equal(ResourceNodeInstanceMutationKind.Denied, denyOutcome.Kind);
|
|
Assert.Equal(ResourceNodeInstanceReasonCodes.NodeDepleted, denyOutcome.ReasonCode);
|
|
Assert.Equal(0, persisted.RemainingGathers);
|
|
}
|
|
|
|
private async Task ResetInstanceTableAsync()
|
|
{
|
|
var cs = Environment.GetEnvironmentVariable("ConnectionStrings__NeonSprawl");
|
|
if (string.IsNullOrWhiteSpace(cs))
|
|
{
|
|
throw new InvalidOperationException("ConnectionStrings__NeonSprawl is not set.");
|
|
}
|
|
|
|
_ = Factory.Services;
|
|
var ddlPath = Path.Combine(AppContext.BaseDirectory, "db", "migrations", "V006__resource_node_instance.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 resource_node_instance;", conn);
|
|
await truncate.ExecuteNonQueryAsync();
|
|
}
|
|
}
|