using Data.SeaHavenIndustries; using Data.SeaHavenIndustries.Enums; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; using SeaHaven.DataServices.Implementation; using SeaHaven.Services.DTOs; using SeaHaven.Services.Helpers; using SeaHaven.Services.Implementation; using SeaHaven.Services.Interfaces; using SeaHaven.Services.Validation; namespace SeaHavenIndustries.Tests; public class WorkOrderPhase7CoexistenceTests { [Fact] public void IngestFieldMapper_MapsDynamoStatus() { Assert.Equal("Open", WorkOrderIngestFieldMapper.MapStatus("new")); Assert.Equal("In Progress", WorkOrderIngestFieldMapper.MapStatus("in_progress")); Assert.Equal("Done", WorkOrderIngestFieldMapper.MapStatus("completed")); } [Fact] public async Task IngestService_CreatesThenUpdates_IdempotentByExternalId() { var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(Guid.NewGuid().ToString()) .Options; await using var context = new ApplicationDbContext(options); var fieldLocks = new WorkOrderFieldLockService(context); var audit = new WorkOrderAuditService(context, fieldLocks); var ingest = new WorkOrderIngestService(context, new SyncFieldMergePolicy(fieldLocks, audit), fieldLocks, audit); var payload = new WorkOrderIngestPayloadDto { ExternalWorkOrderId = "ext-100", Description = "Initial", WoStatus = "new", Severity = "2", SiteCode = "BK1" }; var create = await ingest.UpsertBatchAsync(new[] { payload }); Assert.Equal(1, create.Created); Assert.Equal(0, create.Updated); payload.Description = "Updated via ingest"; var update = await ingest.UpsertBatchAsync(new[] { payload }); Assert.Equal(0, update.Created); Assert.Equal(1, update.Updated); var wo = await context.workOrders.SingleAsync(); Assert.Equal("Updated via ingest", wo.Description); Assert.Equal("ext-100", wo.ExternalWorkOrderId); } [Fact] public async Task IngestRespectsFieldLock_AfterShocBoardCreate() { var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(Guid.NewGuid().ToString()) .Options; await using var context = new ApplicationDbContext(options); var boardData = new WorkOrderBoardDataService(context); var boardService = new WorkOrderBoardService(boardData); var fieldLocks = new WorkOrderFieldLockService(context); var audit = new WorkOrderAuditService(context, fieldLocks); var createService = new WorkOrderBoardCreateService( context, boardData, boardService, audit, new WorkOrderBoardCreateValidation()); var policy = new SyncFieldMergePolicy(fieldLocks, audit); var ingest = new WorkOrderIngestService(context, policy, fieldLocks, audit); await createService.CreateAsync(new WorkOrderBoardCreateRequestDto { WorkOrderType = WorkOrderType.PM, SiteCode = "BK5" }, "dispatcher-1"); var wo = await context.workOrders.SingleAsync(); wo.ExternalWorkOrderId = "ext-shoc-1"; await context.SaveChangesAsync(); await ingest.UpsertBatchAsync(new[] { new WorkOrderIngestPayloadDto { ExternalWorkOrderId = "ext-shoc-1", SiteCode = "SYNC-SITE" } }); Assert.Equal("BK5", wo.SiteCode); Assert.True(await context.WorkOrderAuditLogs.AnyAsync(l => l.Action == "SyncRejected")); } [Fact] public async Task OpsHealth_ReturnsCoexistenceMetrics() { var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(Guid.NewGuid().ToString()) .Options; await using var context = new ApplicationDbContext(options); context.WorkOrderFieldLocks.Add(new WorkOrderFieldLock { WorkOrderId = 1, FieldName = "SiteCode", LockedAt = DateTime.UtcNow, LockedByUserId = "u1" }); context.WorkOrderAuditLogs.Add(new WorkOrderAuditLog { WorkOrderId = 1, Action = "SyncRejected", FieldName = "Description", CreatedAt = DateTime.UtcNow.AddHours(-1) }); await context.SaveChangesAsync(); var runState = new WorkOrderJobRunStateAccessor { State = { LastWeekRolledRunUtc = DateTime.UtcNow.AddDays(-1) } }; var healthOptions = Options.Create(new WorkOrderOpsHealthOptions { SyncEnabled = true, IngestEnabled = true, LegacyDeprecationEnabled = true, LegacySunsetDate = "2026-12-31" }); var service = new WorkOrderOpsHealthService(context, runState, healthOptions); var health = await service.GetHealthAsync(); Assert.Equal(1, health.FieldLockCount); Assert.Equal(1, health.SyncRejectedLast24h); Assert.True(health.SyncEnabled); Assert.True(health.IngestEnabled); Assert.Equal("2026-12-31", health.LegacySunsetDate); } [Fact] public async Task BoardAndLegacyEndpoints_CanCoexist_InSameDatabase() { var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(Guid.NewGuid().ToString()) .Options; await using var context = new ApplicationDbContext(options); context.workOrders.Add(new WorkOrder { WorkerOrderTitle = "Legacy row", Status = "Open", InternalWONumber = "10000001", istemplate = false }); await context.SaveChangesAsync(); var boardData = new WorkOrderBoardDataService(context); var boardService = new WorkOrderBoardService(boardData); var count = await context.workOrders.CountAsync(); Assert.Equal(1, count); Assert.NotNull(boardService); } }