refactor(bootstrap): migrate practice opponents to seed file
Move /practice/info handling out of GlobalsImporter into a dedicated PracticeOpponentImporter that reads a normalized JSON seed file generated by data_dumps/extract/extract-practice-opponents.ps1.
This commit is contained in:
41
SVSim.UnitTests/Importers/PracticeOpponentImporterTests.cs
Normal file
41
SVSim.UnitTests/Importers/PracticeOpponentImporterTests.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using SVSim.Bootstrap.Importers;
|
||||
using SVSim.Database;
|
||||
using SVSim.UnitTests.Infrastructure;
|
||||
|
||||
namespace SVSim.UnitTests.Importers;
|
||||
|
||||
public class PracticeOpponentImporterTests
|
||||
{
|
||||
private static string SeedDir => Path.Combine(AppContext.BaseDirectory, "Data", "seeds");
|
||||
|
||||
[Test]
|
||||
public async Task Imports_opponents_from_seed_file()
|
||||
{
|
||||
using var factory = new SVSimTestFactory();
|
||||
using var scope = factory.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
|
||||
|
||||
await new PracticeOpponentImporter().ImportAsync(db, SeedDir);
|
||||
|
||||
var opponents = await db.PracticeOpponents.OrderBy(p => p.Id).ToListAsync();
|
||||
Assert.That(opponents.Count, Is.GreaterThan(0), "seed file must contain opponents");
|
||||
Assert.That(opponents.All(o => o.ClassId >= 0), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Is_idempotent_on_rerun()
|
||||
{
|
||||
using var factory = new SVSimTestFactory();
|
||||
using var scope = factory.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
|
||||
|
||||
await new PracticeOpponentImporter().ImportAsync(db, SeedDir);
|
||||
int before = await db.PracticeOpponents.CountAsync();
|
||||
await new PracticeOpponentImporter().ImportAsync(db, SeedDir);
|
||||
int after = await db.PracticeOpponents.CountAsync();
|
||||
|
||||
Assert.That(after, Is.EqualTo(before));
|
||||
}
|
||||
}
|
||||
@@ -185,9 +185,14 @@ internal sealed class SVSimTestFactory : WebApplicationFactory<Program>
|
||||
public async Task SeedGlobalsAsync(string? capturesDir = null)
|
||||
{
|
||||
capturesDir ??= Path.Combine(AppContext.BaseDirectory, "Data", "prod-captures");
|
||||
string seedDir = Path.Combine(AppContext.BaseDirectory, "Data", "seeds");
|
||||
using var scope = Services.CreateScope();
|
||||
var ctx = scope.ServiceProvider.GetRequiredService<SVSimDbContext>();
|
||||
await new GlobalsImporter().ImportAllAsync(ctx, capturesDir);
|
||||
// Per-importer seed pipeline runs alongside GlobalsImporter during the migration.
|
||||
// Wired here so SeedGlobalsAsync callers (e.g. PracticeControllerTests) still see
|
||||
// practice-opponent rows after the corresponding block was lifted out of GlobalsImporter.
|
||||
await new PracticeOpponentImporter().ImportAsync(ctx, seedDir);
|
||||
}
|
||||
|
||||
/// <summary>Convenience: bake the X-Test-Viewer-Id header into a fresh client.</summary>
|
||||
|
||||
@@ -42,6 +42,11 @@
|
||||
<Content Include="..\SVSim.Bootstrap\Data\prod-captures\*.json" Link="Data\prod-captures\%(Filename)%(Extension)">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<!-- Seed JSON files for the per-importer pipeline (replaces prod-captures during migration).
|
||||
Both globs coexist while individual endpoints are still being converted. -->
|
||||
<Content Include="..\SVSim.Bootstrap\Data\seeds\**\*.json" Link="Data\seeds\%(RecursiveDir)%(Filename)%(Extension)">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<!-- Test-only fixtures live outside prod-captures so the production bootstrap glob doesn't
|
||||
pick them up (a fixture-named file would win the importer's reverse-alphabetical sort
|
||||
against a dated capture). Linked into the same test output dir so SeedGlobalsAsync sees
|
||||
|
||||
Reference in New Issue
Block a user