fix(store-and-forward): create the SQLite database directory on init (StoreAndForward-014)

StoreAndForwardStorage.InitializeAsync opened a SqliteConnection against the
configured SqliteDbPath (default ./data/store-and-forward.db) without ensuring
the parent directory exists. SQLite creates the database file but not its
directory, so when data/ was absent the connection failed with
"SQLite Error 14: unable to open database file" — aborting the site host's
RegisterSiteActors at StoreAndForwardService.StartAsync.

This was the root cause of the six failing SiteActorPathTests. Production
masked it because the Docker image / deployment creates data/.

InitializeAsync now calls EnsureDatabaseDirectoryExists, which parses the
connection string and creates the parent directory of a file-backed database
(in-memory databases and bare filenames are skipped).

Regression test InitializeAsync_FileInMissingDirectory_CreatesDirectory fails
against the pre-fix code. Host suite now 155/155 green (was 149/155).
This commit is contained in:
Joseph Doherty
2026-05-16 19:13:00 -04:00
parent 61253e3269
commit 91438dcc1b
4 changed files with 96 additions and 2 deletions

View File

@@ -25,6 +25,8 @@ public class StoreAndForwardStorage
/// </summary>
public async Task InitializeAsync()
{
EnsureDatabaseDirectoryExists();
await using var connection = new SqliteConnection(_connectionString);
await connection.OpenAsync();
@@ -53,6 +55,32 @@ public class StoreAndForwardStorage
_logger.LogInformation("Store-and-forward SQLite storage initialized");
}
/// <summary>
/// Ensures the directory for a file-backed SQLite database exists. SQLite creates
/// the database file on demand but not its parent directory, so a configured path
/// such as "./data/store-and-forward.db" fails to open ("unable to open database
/// file") when the "data" directory does not yet exist. In-memory databases and
/// bare filenames in the working directory have no directory to create and are
/// skipped.
/// </summary>
private void EnsureDatabaseDirectoryExists()
{
var builder = new SqliteConnectionStringBuilder(_connectionString);
if (builder.Mode == SqliteOpenMode.Memory)
return;
var dataSource = builder.DataSource;
if (string.IsNullOrEmpty(dataSource) || dataSource == ":memory:")
return;
var directory = System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(dataSource));
if (!string.IsNullOrEmpty(directory) && !System.IO.Directory.Exists(directory))
{
System.IO.Directory.CreateDirectory(directory);
_logger.LogInformation("Created store-and-forward database directory: {Directory}", directory);
}
}
/// <summary>
/// WP-9: Enqueues a new message with Pending status.
/// </summary>