mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-01 20:23:13 +00:00
271 lines
11 KiB
C#
271 lines
11 KiB
C#
using Data.SeaHavenIndustries;
|
|
using Data.SeaHavenIndustries.Enums;
|
|
using Microsoft.Data.Sqlite;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using SeaHaven.DataServices.Helpers;
|
|
using SeaHaven.Services.Implementation;
|
|
|
|
namespace SeaHavenIndustries.Tests;
|
|
|
|
public sealed class WorkOrderServiceRegistryFilterRelationalTests
|
|
{
|
|
[Fact]
|
|
public async Task ServiceDisplayAndFilter_RespectCompletedSnapshotsAndKeepCurrentAliases()
|
|
{
|
|
await using var connection = new SqliteConnection("Data Source=:memory:;Foreign Keys=True");
|
|
await connection.OpenAsync();
|
|
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
|
|
.UseSqlite(connection)
|
|
.Options;
|
|
|
|
await using var context = new SqliteServiceRegistryTestDbContext(options);
|
|
await context.Database.EnsureCreatedAsync();
|
|
|
|
context.Services.AddRange(
|
|
new Service
|
|
{
|
|
Id = 10,
|
|
Name = "Current Active Name",
|
|
NormalizedName = "CURRENT ACTIVE NAME",
|
|
Trade = "Electrical",
|
|
IconKey = "electrical",
|
|
IsActive = true
|
|
},
|
|
new Service
|
|
{
|
|
Id = 20,
|
|
Name = "Original Inactive Name",
|
|
NormalizedName = "ORIGINAL INACTIVE NAME",
|
|
Trade = "Electrical",
|
|
IconKey = "electrical",
|
|
IsActive = true
|
|
},
|
|
new Service
|
|
{
|
|
Id = 30,
|
|
Name = "QA Service",
|
|
NormalizedName = "QA SERVICE",
|
|
Trade = "Electrical",
|
|
IconKey = "electrical",
|
|
IsActive = true
|
|
},
|
|
new Service
|
|
{
|
|
Id = 31,
|
|
Name = "QA Service Extended",
|
|
NormalizedName = "QA SERVICE EXTENDED",
|
|
Trade = "Electrical",
|
|
IconKey = "electrical",
|
|
IsActive = true
|
|
});
|
|
context.workOrders.AddRange(
|
|
new WorkOrder
|
|
{
|
|
Id = 1,
|
|
ServiceId = 10,
|
|
ServiceNameSnapshot = "Original Active Name",
|
|
Trade = "Original Active Name"
|
|
},
|
|
new WorkOrder
|
|
{
|
|
Id = 2,
|
|
ServiceId = 20,
|
|
ServiceNameSnapshot = "Historical Inactive Name",
|
|
Trade = "Historical Inactive Name"
|
|
},
|
|
new WorkOrder
|
|
{
|
|
Id = 3,
|
|
Trade = "Legacy Cooling",
|
|
Problem = "Legacy Leak"
|
|
},
|
|
new WorkOrder
|
|
{
|
|
Id = 4,
|
|
ServiceId = 10,
|
|
ServiceNameSnapshot = "Completed Archive Alpha",
|
|
Trade = "Completed Archive Alpha",
|
|
LifecycleStatus = LifecycleStatus.Completed
|
|
},
|
|
new WorkOrder
|
|
{
|
|
Id = 5,
|
|
ServiceId = 10,
|
|
ServiceNameSnapshot = "Completed Archive Beta",
|
|
Trade = "Completed Archive Beta",
|
|
Status = "Done"
|
|
},
|
|
new WorkOrder
|
|
{
|
|
Id = 6,
|
|
ServiceId = 30,
|
|
ServiceNameSnapshot = "QA Service",
|
|
Trade = "QA Service",
|
|
LifecycleStatus = LifecycleStatus.Scheduled
|
|
},
|
|
new WorkOrder
|
|
{
|
|
Id = 7,
|
|
ServiceId = 31,
|
|
ServiceNameSnapshot = "QA Service Extended",
|
|
Trade = "QA Service Extended",
|
|
LifecycleStatus = LifecycleStatus.Scheduled
|
|
});
|
|
await context.SaveChangesAsync();
|
|
|
|
var renamedService = await context.Services.SingleAsync(service => service.Id == 20);
|
|
renamedService.Name = "Current Inactive Name";
|
|
renamedService.NormalizedName = "CURRENT INACTIVE NAME";
|
|
await context.SaveChangesAsync();
|
|
renamedService.IsActive = false;
|
|
await context.SaveChangesAsync();
|
|
|
|
var activeRows = await WorkOrderBoardProjection.ProjectRowsAsync(
|
|
context,
|
|
context.workOrders.AsNoTracking().Where(w => w.Id == 1),
|
|
isUnscheduled: true);
|
|
var activeDisplay = WorkOrderBoardService.MapRawRow(Assert.Single(activeRows), DateTime.UtcNow);
|
|
|
|
var inactiveRows = await WorkOrderBoardProjection.ProjectRowsAsync(
|
|
context,
|
|
context.workOrders.AsNoTracking().Where(w => w.Id == 2),
|
|
isUnscheduled: true);
|
|
var inactiveDisplay = WorkOrderBoardService.MapRawRow(Assert.Single(inactiveRows), DateTime.UtcNow);
|
|
|
|
var legacyRows = await WorkOrderBoardProjection.ProjectRowsAsync(
|
|
context,
|
|
context.workOrders.AsNoTracking().Where(w => w.Id == 3),
|
|
isUnscheduled: true);
|
|
var legacyDisplay = WorkOrderBoardService.MapRawRow(Assert.Single(legacyRows), DateTime.UtcNow);
|
|
|
|
var completedRows = await WorkOrderBoardProjection.ProjectRowsAsync(
|
|
context,
|
|
context.workOrders.AsNoTracking().Where(w => w.Id == 4),
|
|
isUnscheduled: true);
|
|
var completedDisplay = WorkOrderBoardService.MapRawRow(Assert.Single(completedRows), DateTime.UtcNow);
|
|
|
|
var legacyCompletedRows = await WorkOrderBoardProjection.ProjectRowsAsync(
|
|
context,
|
|
context.workOrders.AsNoTracking().Where(w => w.Id == 5),
|
|
isUnscheduled: true);
|
|
var legacyCompletedDisplay = WorkOrderBoardService.MapRawRow(Assert.Single(legacyCompletedRows), DateTime.UtcNow);
|
|
|
|
var currentActiveNameMatches = await WorkOrderBoardQueryFilters
|
|
.ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "Current Active Name" })
|
|
.Select(w => w.Id)
|
|
.ToListAsync();
|
|
|
|
var historicalInactiveNameMatches = await WorkOrderBoardQueryFilters
|
|
.ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "Historical Inactive Name" })
|
|
.Select(w => w.Id)
|
|
.ToListAsync();
|
|
|
|
var inactiveRegistryNameMatches = await WorkOrderBoardQueryFilters
|
|
.ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "Current Inactive Name" })
|
|
.Select(w => w.Id)
|
|
.ToListAsync();
|
|
|
|
var completedSnapshotMatches = await WorkOrderBoardQueryFilters
|
|
.ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "Completed Archive Alpha" })
|
|
.Select(w => w.Id)
|
|
.ToListAsync();
|
|
|
|
var legacyCompletedSnapshotMatches = await WorkOrderBoardQueryFilters
|
|
.ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "Completed Archive Beta" })
|
|
.Select(w => w.Id)
|
|
.ToListAsync();
|
|
|
|
var currentNameAliasMatches = await WorkOrderBoardQueryFilters
|
|
.ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "Current Active Name" })
|
|
.Select(w => w.Id)
|
|
.OrderBy(id => id)
|
|
.ToListAsync();
|
|
|
|
var exactRegistryNameMatches = await WorkOrderBoardQueryFilters
|
|
.ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "QA Service" })
|
|
.Select(w => w.Id)
|
|
.OrderBy(id => id)
|
|
.ToListAsync();
|
|
|
|
var multipleRegistryNameMatches = await WorkOrderBoardQueryFilters
|
|
.ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "QA Service", "QA Service Extended" })
|
|
.Select(w => w.Id)
|
|
.OrderBy(id => id)
|
|
.ToListAsync();
|
|
|
|
var legacyTradeMatches = await WorkOrderBoardQueryFilters
|
|
.ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "Legacy Cooling" })
|
|
.Select(w => w.Id)
|
|
.ToListAsync();
|
|
|
|
var legacyProblemMatches = await WorkOrderBoardQueryFilters
|
|
.ApplyPmTypeFilter(context.workOrders.AsNoTracking(), new[] { "Legacy Leak" })
|
|
.Select(w => w.Id)
|
|
.ToListAsync();
|
|
|
|
var actual = string.Join("\n", new[]
|
|
{
|
|
$"active-display={activeDisplay.Pm}",
|
|
$"inactive-display={inactiveDisplay.Pm}",
|
|
$"legacy-display={legacyDisplay.Pm}",
|
|
$"completed-display={completedDisplay.Pm}",
|
|
$"legacy-completed-display={legacyCompletedDisplay.Pm}",
|
|
$"active-filter={string.Join(',', currentActiveNameMatches)}",
|
|
$"inactive-snapshot-filter={string.Join(',', historicalInactiveNameMatches)}",
|
|
$"inactive-current-name-filter={string.Join(',', inactiveRegistryNameMatches)}",
|
|
$"completed-snapshot-filter={string.Join(',', completedSnapshotMatches)}",
|
|
$"legacy-completed-snapshot-filter={string.Join(',', legacyCompletedSnapshotMatches)}",
|
|
$"current-name-alias-filter={string.Join(',', currentNameAliasMatches)}",
|
|
$"exact-registry-filter={string.Join(',', exactRegistryNameMatches)}",
|
|
$"multiple-registry-filter={string.Join(',', multipleRegistryNameMatches)}",
|
|
$"legacy-trade-filter={string.Join(',', legacyTradeMatches)}",
|
|
$"legacy-problem-filter={string.Join(',', legacyProblemMatches)}"
|
|
});
|
|
var expected = string.Join("\n", new[]
|
|
{
|
|
"active-display=Current Active Name",
|
|
"inactive-display=Historical Inactive Name",
|
|
"legacy-display=Legacy Cooling",
|
|
"completed-display=Completed Archive Alpha",
|
|
"legacy-completed-display=Completed Archive Beta",
|
|
"active-filter=1,4,5",
|
|
"inactive-snapshot-filter=2",
|
|
"inactive-current-name-filter=2",
|
|
"completed-snapshot-filter=4",
|
|
"legacy-completed-snapshot-filter=5",
|
|
"current-name-alias-filter=1,4,5",
|
|
"exact-registry-filter=6",
|
|
"multiple-registry-filter=6,7",
|
|
"legacy-trade-filter=3",
|
|
"legacy-problem-filter=3"
|
|
});
|
|
Assert.True(expected == actual, $"Expected:\n{expected}\nActual:\n{actual}");
|
|
}
|
|
|
|
private sealed class SqliteServiceRegistryTestDbContext : ApplicationDbContext
|
|
{
|
|
public SqliteServiceRegistryTestDbContext(DbContextOptions<ApplicationDbContext> options)
|
|
: base(options)
|
|
{
|
|
}
|
|
|
|
protected override void OnModelCreating(ModelBuilder builder)
|
|
{
|
|
base.OnModelCreating(builder);
|
|
|
|
// SQL Server filtered indexes and rowversion semantics are not supported by SQLite.
|
|
foreach (var index in builder.Model.GetEntityTypes().SelectMany(entity => entity.GetIndexes()))
|
|
{
|
|
if (index.GetFilter() != null)
|
|
index.SetFilter(null);
|
|
}
|
|
|
|
foreach (var entityType in new[] { typeof(WorkOrder), typeof(Dispatch) })
|
|
{
|
|
var property = builder.Entity(entityType).Property("RowVersion").Metadata;
|
|
property.ValueGenerated = Microsoft.EntityFrameworkCore.Metadata.ValueGenerated.Never;
|
|
property.IsConcurrencyToken = false;
|
|
}
|
|
}
|
|
}
|
|
}
|