fix(config): DraftSnapshotFactory loads only active (unreleased) reservations
Filter ExternalIdReservations to WHERE ReleasedAt IS NULL so DraftSnapshot.ActiveReservations matches its documented semantics and ValidateReservationPreflight cannot emit spurious BadDuplicateExternalIdentifier errors from already-released rows. Adds a focused unit test seeding one active and one released reservation and asserting only the active row is returned.
This commit is contained in:
@@ -43,6 +43,9 @@ public static class DraftSnapshotFactory
|
|||||||
VirtualTags = await db.VirtualTags.AsNoTracking().ToListAsync(ct),
|
VirtualTags = await db.VirtualTags.AsNoTracking().ToListAsync(ct),
|
||||||
PollGroups = await db.PollGroups.AsNoTracking().ToListAsync(ct),
|
PollGroups = await db.PollGroups.AsNoTracking().ToListAsync(ct),
|
||||||
PriorEquipment = [],
|
PriorEquipment = [],
|
||||||
ActiveReservations = await db.ExternalIdReservations.AsNoTracking().ToListAsync(ct),
|
ActiveReservations = await db.ExternalIdReservations
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(r => r.ReleasedAt == null) // active only — matches DraftSnapshot.ActiveReservations semantics
|
||||||
|
.ToListAsync(ct),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,44 @@ public sealed class DraftSnapshotFactoryTests : IDisposable
|
|||||||
DraftValidator.Validate(snapshot).ShouldNotContain(e => e.Code == "EquipmentSignalNameCollision");
|
DraftValidator.Validate(snapshot).ShouldNotContain(e => e.Code == "EquipmentSignalNameCollision");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Seeds one active and one released reservation for the same equipment context;
|
||||||
|
/// only the active row (ReleasedAt == null) should appear in the snapshot.</summary>
|
||||||
|
[Fact]
|
||||||
|
public async Task FromConfigDb_ActiveReservations_excludes_released_rows()
|
||||||
|
{
|
||||||
|
var equipmentUuid = Guid.NewGuid();
|
||||||
|
|
||||||
|
_db.ExternalIdReservations.Add(new ExternalIdReservation
|
||||||
|
{
|
||||||
|
ReservationId = Guid.NewGuid(),
|
||||||
|
Kind = ReservationKind.ZTag,
|
||||||
|
Value = "ZT-001",
|
||||||
|
EquipmentUuid = equipmentUuid,
|
||||||
|
ClusterId = "cluster-a",
|
||||||
|
FirstPublishedBy = "test",
|
||||||
|
ReleasedAt = null, // active
|
||||||
|
});
|
||||||
|
_db.ExternalIdReservations.Add(new ExternalIdReservation
|
||||||
|
{
|
||||||
|
ReservationId = Guid.NewGuid(),
|
||||||
|
Kind = ReservationKind.ZTag,
|
||||||
|
Value = "ZT-002",
|
||||||
|
EquipmentUuid = equipmentUuid,
|
||||||
|
ClusterId = "cluster-a",
|
||||||
|
FirstPublishedBy = "test",
|
||||||
|
ReleasedAt = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc), // released
|
||||||
|
ReleasedBy = "test",
|
||||||
|
ReleaseReason = "retired",
|
||||||
|
});
|
||||||
|
await _db.SaveChangesAsync();
|
||||||
|
|
||||||
|
var snapshot = await DraftSnapshotFactory.FromConfigDbAsync(_db);
|
||||||
|
|
||||||
|
snapshot.ActiveReservations.Count.ShouldBe(1);
|
||||||
|
snapshot.ActiveReservations[0].Value.ShouldBe("ZT-001");
|
||||||
|
snapshot.ActiveReservations[0].ReleasedAt.ShouldBeNull();
|
||||||
|
}
|
||||||
|
|
||||||
private void SeedEquipment(string equipmentId)
|
private void SeedEquipment(string equipmentId)
|
||||||
{
|
{
|
||||||
var uuid = Guid.NewGuid();
|
var uuid = Guid.NewGuid();
|
||||||
|
|||||||
Reference in New Issue
Block a user