Resolve all 46 low-severity architecture review findings
This commit is contained in:
+73
@@ -0,0 +1,73 @@
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Repositories;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests.Repositories;
|
||||
|
||||
public class AuditPurgeBudgetTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task BackloggedChannel_StopsAtBudgetIncludingPartialFinalBatch()
|
||||
{
|
||||
using var connection = new BackloggedConnection();
|
||||
await using var context = new ScadaBridgeDbContext(new DbContextOptionsBuilder<ScadaBridgeDbContext>()
|
||||
.UseSqlServer(connection).Options);
|
||||
var deleted = await new AuditLogRepository(context).PurgeChannelOlderThanAsync(
|
||||
"ScriptTrace", DateTime.UtcNow, batchSize: 3, maxRows: 5);
|
||||
Assert.Equal(5, deleted);
|
||||
Assert.Equal(new[] { 3, 2 }, connection.RequestedBatches);
|
||||
Assert.Equal(ConnectionState.Closed, connection.State);
|
||||
}
|
||||
|
||||
private sealed class BackloggedConnection : DbConnection
|
||||
{
|
||||
public List<int> RequestedBatches { get; } = new();
|
||||
private ConnectionState _state;
|
||||
[AllowNull] public override string ConnectionString { get; set; } = "Server=localhost;Database=test";
|
||||
public override string Database => "test";
|
||||
public override string DataSource => "localhost";
|
||||
public override string ServerVersion => "16.0";
|
||||
public override ConnectionState State => _state;
|
||||
public override void Open() => _state = ConnectionState.Open;
|
||||
public override void Close() => _state = ConnectionState.Closed;
|
||||
public override void ChangeDatabase(string databaseName) => throw new NotSupportedException();
|
||||
protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) => throw new NotSupportedException();
|
||||
protected override DbCommand CreateDbCommand() => new BackloggedCommand(this);
|
||||
}
|
||||
|
||||
private sealed class BackloggedCommand(BackloggedConnection owner) : DbCommand
|
||||
{
|
||||
private readonly SqlCommand _parameters = new();
|
||||
[AllowNull] public override string CommandText { get; set; } = "";
|
||||
public override int CommandTimeout { get; set; }
|
||||
public override CommandType CommandType { get; set; }
|
||||
public override bool DesignTimeVisible { get; set; }
|
||||
public override UpdateRowSource UpdatedRowSource { get; set; }
|
||||
protected override DbConnection? DbConnection { get; set; }
|
||||
protected override DbTransaction? DbTransaction { get; set; }
|
||||
protected override DbParameterCollection DbParameterCollection => _parameters.Parameters;
|
||||
protected override DbParameter CreateDbParameter() => new SqlParameter();
|
||||
public override int ExecuteNonQuery()
|
||||
{
|
||||
// A server with more eligible rows than any tick is allowed to delete.
|
||||
// Fail rapidly if the repository loops indefinitely, without a timer-based test.
|
||||
if (owner.RequestedBatches.Count >= 10)
|
||||
throw new InvalidOperationException("Purge did not yield despite exhausting its row budget.");
|
||||
var requested = (int)_parameters.Parameters["@batch"].Value;
|
||||
owner.RequestedBatches.Add(requested);
|
||||
return requested;
|
||||
}
|
||||
public override object? ExecuteScalar() => throw new NotSupportedException();
|
||||
protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior) => throw new NotSupportedException();
|
||||
public override void Cancel() { }
|
||||
public override void Prepare() { }
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing) _parameters.Dispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
@@ -29,6 +29,30 @@ public class TemplateEngineRepositoryTests : IDisposable
|
||||
_context.Dispose();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TopologyPage_IsBoundedFilteredAndUntracked()
|
||||
{
|
||||
var site = new ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites.Site("PageSite", "page-site");
|
||||
var other = new ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites.Site("OtherPageSite", "other-page-site");
|
||||
var template = new Template("PageTemplate");
|
||||
_context.Sites.AddRange(site, other);
|
||||
_context.Templates.Add(template);
|
||||
await _context.SaveChangesAsync();
|
||||
_context.Instances.AddRange(Enumerable.Range(0, 101).Select(id =>
|
||||
new ZB.MOM.WW.ScadaBridge.Commons.Entities.Instances.Instance($"Paged-{id:D3}") { SiteId = site.Id, TemplateId = template.Id }));
|
||||
_context.Instances.Add(new ZB.MOM.WW.ScadaBridge.Commons.Entities.Instances.Instance("Other") { SiteId = other.Id, TemplateId = template.Id });
|
||||
await _context.SaveChangesAsync();
|
||||
_context.ChangeTracker.Clear();
|
||||
var first = await _repository.GetTopologyInstancesAsync(site.Id, null, 0, 50);
|
||||
var second = await _repository.GetTopologyInstancesAsync(site.Id, null, 50, 50);
|
||||
Assert.Equal(50, first.Count);
|
||||
Assert.Equal(50, second.Count);
|
||||
Assert.All(first.Concat(second), i => Assert.Equal(site.Id, i.SiteId));
|
||||
Assert.Empty(first.Select(i => i.Id).Intersect(second.Select(i => i.Id)));
|
||||
Assert.Empty(_context.ChangeTracker.Entries());
|
||||
await Assert.ThrowsAsync<ArgumentOutOfRangeException>(() => _repository.GetTopologyInstancesAsync(site.Id, null, 0, 51));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetTemplateWithChildrenAsync_ReturnsTemplateWithAllMemberCollectionsPopulated()
|
||||
{
|
||||
|
||||
+2
-8
@@ -10,14 +10,8 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" />
|
||||
<!--
|
||||
Bundle C migration integration tests need Microsoft.Data.SqlClient. EF
|
||||
SqlServer 10.0.7 pulls in SqlClient >= 6.1.1, but the central package
|
||||
version is pinned at 6.0.2 (the version the production
|
||||
ExternalSystemGateway uses). Override the version locally for the test
|
||||
project only; production assemblies are unaffected.
|
||||
-->
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" VersionOverride="6.1.1" />
|
||||
<!-- Use the central SqlClient pin, matching the production EF dependency floor. -->
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" />
|
||||
<!-- Security pin: GHSA-2m69-gcr7-jv3q. Microsoft.Data.Sqlite pulls the
|
||||
vulnerable native 2.1.11; 2.1.12 patches it. Bumping Sqlite does not help. -->
|
||||
|
||||
Reference in New Issue
Block a user