Initial
This commit is contained in:
84
tests/ClaudeMailbox.Tests/TestHost.cs
Normal file
84
tests/ClaudeMailbox.Tests/TestHost.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using ClaudeMailbox;
|
||||
using ClaudeMailbox.Config;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace ClaudeMailbox.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Spins up a full ClaudeMailbox WebApplication on an ephemeral port against a temp SQLite file.
|
||||
/// Disposable — removes the DB and stops the host on dispose.
|
||||
/// </summary>
|
||||
public sealed class TestHost : IAsyncDisposable
|
||||
{
|
||||
private readonly WebApplication _app;
|
||||
private readonly string _dbPath;
|
||||
|
||||
public HttpClient Client { get; }
|
||||
public string BaseUrl { get; }
|
||||
public string DbPath => _dbPath;
|
||||
|
||||
private TestHost(WebApplication app, string dbPath, string baseUrl)
|
||||
{
|
||||
_app = app;
|
||||
_dbPath = dbPath;
|
||||
BaseUrl = baseUrl;
|
||||
Client = new HttpClient { BaseAddress = new Uri(baseUrl) };
|
||||
}
|
||||
|
||||
public static async Task<TestHost> StartAsync()
|
||||
{
|
||||
var dbPath = Path.Combine(Path.GetTempPath(), $"claude-mailbox-test-{Guid.NewGuid():N}.db");
|
||||
var cfg = new DaemonConfig
|
||||
{
|
||||
Port = 0,
|
||||
BindAddress = "127.0.0.1",
|
||||
DbPath = dbPath,
|
||||
};
|
||||
|
||||
var builder = ServerHost.CreateBuilder(cfg);
|
||||
builder.WebHost.UseUrls("http://127.0.0.1:0");
|
||||
|
||||
var app = builder.Build();
|
||||
ServerHost.ConfigurePipeline(app);
|
||||
|
||||
await app.StartAsync();
|
||||
|
||||
// Discover the port Kestrel picked.
|
||||
var server = app.Services.GetRequiredService<Microsoft.AspNetCore.Hosting.Server.IServer>();
|
||||
var feature = server.Features.Get<Microsoft.AspNetCore.Hosting.Server.Features.IServerAddressesFeature>();
|
||||
var url = feature?.Addresses.FirstOrDefault()
|
||||
?? throw new InvalidOperationException("No bound URL after start.");
|
||||
|
||||
return new TestHost(app, dbPath, url);
|
||||
}
|
||||
|
||||
public HttpClient NewClientFor(string mailboxName)
|
||||
{
|
||||
var c = new HttpClient { BaseAddress = new Uri(BaseUrl) };
|
||||
c.DefaultRequestHeaders.Add("X-Mailbox", mailboxName);
|
||||
return c;
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
Client.Dispose();
|
||||
await _app.StopAsync();
|
||||
await _app.DisposeAsync();
|
||||
|
||||
// Allow SQLite handle to release before deleting.
|
||||
GC.Collect();
|
||||
GC.WaitForPendingFinalizers();
|
||||
|
||||
foreach (var ext in new[] { "", "-wal", "-shm" })
|
||||
{
|
||||
var path = _dbPath + ext;
|
||||
if (File.Exists(path))
|
||||
{
|
||||
try { File.Delete(path); } catch { /* best-effort cleanup */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user