166f07fa68
LocalDb 0.1.1 creates the parent directory of LocalDb:Path itself, so the SiteLocalDbDirectory shim this repo carried through Phase 2 is deleted along with its call site. The gap was found here but was never ScadaBridge's alone — every LocalDb consumer had it — so the fix moved to the library. SiteLocalDbDirectoryTests is RETAINED and retargeted rather than deleted with the shim. It was already written against the site registration path, not the mechanism, so it needed only its Ensure() call removed: what a site node requires is that resolving ILocalDb not fail on a fresh machine, regardless of who provides that. Verified it still earns its place — pinned back to LocalDb 0.1.0 it fails inside SqliteLocalDb..ctor -> SqliteConnection.Open(), so it genuinely depends on the library behaviour and not on a coincidence. Also corrects the coverage-split note in StoreAndForwardStorageTests, which asserted that directory creation is "NOT LocalDb's" — true when written, wrong as of 0.1.1. Build 0 warnings; Host 330, StoreAndForward 130, LocalDb integration 20 pass. Claude-Session: https://claude.ai/code/session_01BL2Vu1ESDQ9SCN4gVKkdts
73 lines
3.0 KiB
C#
73 lines
3.0 KiB
C#
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using ZB.MOM.WW.LocalDb;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.Host.Tests;
|
|
|
|
/// <summary>
|
|
/// Pins that a site node creates the directory holding <c>LocalDb:Path</c> before the
|
|
/// database is opened.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// The guarantee has now had three owners: <c>StoreAndForwardStorage</c> created the
|
|
/// directory for its own SQLite file, LocalDb Phase 2 folded that file into the
|
|
/// consolidated database and the Host took it over as a <c>SiteLocalDbDirectory</c> shim,
|
|
/// and LocalDb 0.1.1 took it into the library itself. This test survived all three moves
|
|
/// unchanged in intent, because what a site node needs is the OUTCOME — resolving
|
|
/// <c>ILocalDb</c> from the site registration must not fail on a fresh machine — not any
|
|
/// particular implementer of it. It is deliberately written against the registration path
|
|
/// rather than the mechanism, so a future move costs nothing here.
|
|
/// </para>
|
|
/// <para>
|
|
/// This is not hypothetical: the default site configuration points at the <i>relative</i>
|
|
/// path <c>./data/site-localdb.db</c>, so any site node whose working directory has no
|
|
/// <c>data/</c> subdirectory hits it. The docker rig escapes only because its volume mount
|
|
/// creates <c>/app/data</c> — which is exactly the kind of coincidence that hides a defect
|
|
/// until a bare-metal or fresh deployment.
|
|
/// </para>
|
|
/// </remarks>
|
|
public class SiteLocalDbDirectoryTests
|
|
{
|
|
[Fact]
|
|
public void SiteRegistration_CreatesTheLocalDbDirectory_WhenItDoesNotExist()
|
|
{
|
|
var root = Path.Combine(Path.GetTempPath(), "localdb-dir-test-" + Guid.NewGuid().ToString("N"));
|
|
var dbPath = Path.Combine(root, "nested", "site-localdb.db");
|
|
Assert.False(Directory.Exists(root));
|
|
|
|
try
|
|
{
|
|
var config = new ConfigurationBuilder()
|
|
.AddInMemoryCollection(new Dictionary<string, string?>
|
|
{
|
|
["LocalDb:Path"] = dbPath,
|
|
})
|
|
.Build();
|
|
|
|
// The registration path under test. Resolving ILocalDb is what actually opens
|
|
// the file, so this fails with SQLite Error 14 if the directory step regresses
|
|
// — wherever it lives.
|
|
var services = new ServiceCollection();
|
|
services.AddZbLocalDb(config);
|
|
|
|
using var provider = services.BuildServiceProvider();
|
|
using var scope = provider.CreateScope();
|
|
var db = scope.ServiceProvider.GetRequiredService<ILocalDb>();
|
|
|
|
Assert.NotNull(db);
|
|
Assert.True(Directory.Exists(Path.GetDirectoryName(dbPath)!));
|
|
Assert.True(File.Exists(dbPath));
|
|
}
|
|
finally
|
|
{
|
|
SqliteConnectionPoolCleanup();
|
|
if (Directory.Exists(root))
|
|
Directory.Delete(root, recursive: true);
|
|
}
|
|
}
|
|
|
|
private static void SqliteConnectionPoolCleanup() =>
|
|
Microsoft.Data.Sqlite.SqliteConnection.ClearAllPools();
|
|
}
|