feat(migration): implement offline-resolved database-ready ingestion, fix circular FKs, duplicate contacts and parser scanning bugs
This commit is contained in:
181
GerbilManager.Tests/IngestResolvedServiceTests.cs
Normal file
181
GerbilManager.Tests/IngestResolvedServiceTests.cs
Normal file
@@ -0,0 +1,181 @@
|
||||
using GerbilManagerWebAPI.Import;
|
||||
using GerbilManagerWebAPI.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace GerbilManager.Tests
|
||||
{
|
||||
public class IngestResolvedServiceTests : IDisposable
|
||||
{
|
||||
private readonly string _dir;
|
||||
private readonly string _resolvedJsonPath;
|
||||
|
||||
public IngestResolvedServiceTests()
|
||||
{
|
||||
_dir = Path.Combine(Path.GetTempPath(), "ingest-resolved-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(_dir);
|
||||
_resolvedJsonPath = Path.Combine(_dir, "resolved_import.json");
|
||||
|
||||
var contactId = Guid.NewGuid();
|
||||
var fatherId = Guid.NewGuid();
|
||||
var motherId = Guid.NewGuid();
|
||||
var litterId = Guid.NewGuid();
|
||||
var photoId = Guid.NewGuid();
|
||||
|
||||
var data = new
|
||||
{
|
||||
Contacts = new[]
|
||||
{
|
||||
new
|
||||
{
|
||||
Id = contactId,
|
||||
Name = "Test Breeder",
|
||||
ZuchtName = "Test Zucht",
|
||||
City = "Test City",
|
||||
Email = "test@example.com",
|
||||
Homepage = "",
|
||||
Phone = "",
|
||||
Address = ""
|
||||
}
|
||||
},
|
||||
Litters = new[]
|
||||
{
|
||||
new
|
||||
{
|
||||
Id = litterId,
|
||||
Name = "Wurf A",
|
||||
Date = "2026-01-01",
|
||||
TotalBorn = 5,
|
||||
DeathsWithin8Weeks = 0,
|
||||
FatherId = fatherId,
|
||||
MotherId = motherId,
|
||||
ExpectedGoHomeDate = (string?)null,
|
||||
Notes = "Test litter notes",
|
||||
PairingCode = "PC01",
|
||||
ExternalRef = "ext-litter-1",
|
||||
LitterLetter = "A"
|
||||
}
|
||||
},
|
||||
Gerbils = new[]
|
||||
{
|
||||
new
|
||||
{
|
||||
Id = fatherId,
|
||||
Name = "Papa",
|
||||
Gender = "male",
|
||||
Status = "Breeding",
|
||||
LitterId = (Guid?)null,
|
||||
OriginContactId = contactId,
|
||||
ReceiverContactId = (Guid?)null,
|
||||
EnclosureId = (Guid?)null,
|
||||
ColorVarietyId = new Guid("00000000-0000-0000-0000-000000000006"), // Schwarz
|
||||
DateOfBirth = "2025-01-01",
|
||||
DateOfDeath = (string?)null,
|
||||
CauseOfDeath = (string?)null,
|
||||
GoHomeDate = (string?)null,
|
||||
Genotype = "aa CC DD EE GG PP spsp rere",
|
||||
Notes = "",
|
||||
ImportSource = "docx-export",
|
||||
ExternalRef = "ext-papa",
|
||||
RawImportData = "{}",
|
||||
OriginBreeder = "Test Zucht",
|
||||
NameSearch = "papa",
|
||||
CharacterTraits = new string[] {},
|
||||
CharacterNote = (string?)null,
|
||||
IsDeaf = false,
|
||||
IsResident = true
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = motherId,
|
||||
Name = "Mama",
|
||||
Gender = "female",
|
||||
Status = "Breeding",
|
||||
LitterId = (Guid?)null,
|
||||
OriginContactId = contactId,
|
||||
ReceiverContactId = (Guid?)null,
|
||||
EnclosureId = (Guid?)null,
|
||||
ColorVarietyId = new Guid("00000000-0000-0000-0000-000000000006"), // Schwarz
|
||||
DateOfBirth = "2025-01-01",
|
||||
DateOfDeath = (string?)null,
|
||||
CauseOfDeath = (string?)null,
|
||||
GoHomeDate = (string?)null,
|
||||
Genotype = "aa CC DD EE GG PP spsp rere",
|
||||
Notes = "",
|
||||
ImportSource = "docx-export",
|
||||
ExternalRef = "ext-mama",
|
||||
RawImportData = "{}",
|
||||
OriginBreeder = "Test Zucht",
|
||||
NameSearch = "mama",
|
||||
CharacterTraits = new string[] {},
|
||||
CharacterNote = (string?)null,
|
||||
IsDeaf = false,
|
||||
IsResident = true
|
||||
}
|
||||
},
|
||||
GerbilPhotos = new[]
|
||||
{
|
||||
new
|
||||
{
|
||||
Id = photoId,
|
||||
GerbilId = fatherId,
|
||||
FileName = "photo1.jpg",
|
||||
SortOrder = 0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
File.WriteAllText(_resolvedJsonPath, JsonSerializer.Serialize(data));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
try { Directory.Delete(_dir, recursive: true); } catch { }
|
||||
}
|
||||
|
||||
private ApplicationContext NewDb()
|
||||
{
|
||||
var opts = new DbContextOptionsBuilder<ApplicationContext>()
|
||||
.UseInMemoryDatabase("ingest-resolved-" + Guid.NewGuid().ToString("N"))
|
||||
.Options;
|
||||
var db = new ApplicationContext(opts);
|
||||
db.Database.EnsureCreated();
|
||||
return db;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task IngestResolved_loads_data_and_resolves_all_relations()
|
||||
{
|
||||
using var db = NewDb();
|
||||
var config = new ConfigurationBuilder()
|
||||
.AddInMemoryCollection(new Dictionary<string, string?>
|
||||
{
|
||||
{ "Import:SourcePath", _dir }
|
||||
})
|
||||
.Build();
|
||||
|
||||
var service = new IngestResolvedService(db, config, null!);
|
||||
var result = await service.RunAsync();
|
||||
|
||||
Assert.Contains("Ingestion successful!", result);
|
||||
|
||||
// Verify counts
|
||||
Assert.Equal(1, await db.Contacts.CountAsync());
|
||||
Assert.Equal(1, await db.Litters.CountAsync());
|
||||
Assert.Equal(2, await db.Gerbils.CountAsync());
|
||||
Assert.Equal(1, await db.GerbilPhotos.CountAsync());
|
||||
|
||||
// Verify relations
|
||||
var litter = await db.Litters.SingleAsync();
|
||||
var father = await db.Gerbils.SingleAsync(g => g.Name == "Papa");
|
||||
var mother = await db.Gerbils.SingleAsync(g => g.Name == "Mama");
|
||||
var photo = await db.GerbilPhotos.SingleAsync();
|
||||
|
||||
Assert.Equal(father.Id, litter.FatherId);
|
||||
Assert.Equal(mother.Id, litter.MotherId);
|
||||
Assert.Equal(father.Id, photo.GerbilId);
|
||||
Assert.Equal(father.OriginContactId, mother.OriginContactId);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user