@
R3 Slice 3: CongressTrading-Modul + Worker-Log + core_settings auf EF Core - Modul: CongressTradingDbContext (ct_congressMember/ct_trade) + Design-Time-Factory; CongressRepository von Dapper auf EF; CongressTrade.DetailsFetched ergaenzt; Dapper entfernt - Core: CoreSettingsService (core_settings via EF); WorkerBase-Log auf EF (core_worker_log); 7 Worker-Ctors DatabaseService -> IDbContextFactory<CoreDbContext> - CoreMigrations + CongressMigrations (Dapper) entfernt; core_-Schema nun rein EF - EF-Migration InitialCongressTrading; AddCorePersistence-Fallback fuer leeren Connection-String (App startet ohne DB); Connection aus appsettings.Local.json (gitignored) - Tests: +4 CongressRepository (EF-InMemory) -> 39/39 gruen; Build + smoke-ui + App-Start ok Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> @
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
using FluentAssertions;
|
||||
using IBKRTrader.Core.Logging;
|
||||
using IBKRTrader.Core.Persistence.Ef;
|
||||
using IBKRTrader.Core.Settings;
|
||||
using IBKRTrader.Modules.CongressTrading.Database;
|
||||
using IBKRTrader.Modules.CongressTrading.Models;
|
||||
using IBKRTrader.Modules.CongressTrading.Persistence.Ef;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace IBKRTrader.Tests.Modules;
|
||||
|
||||
/// <summary>EF-Repo des Moduls gegen EF-InMemory (deterministisch, kein externer DB-Zugriff).</summary>
|
||||
[Trait("cat", "unit")]
|
||||
public class CongressRepositoryTests
|
||||
{
|
||||
private sealed class Factory<T>(DbContextOptions<T> options) : IDbContextFactory<T> where T : DbContext
|
||||
{
|
||||
public T CreateDbContext() => (T)Activator.CreateInstance(typeof(T), options)!;
|
||||
}
|
||||
|
||||
private static CongressRepository CreateSut()
|
||||
{
|
||||
var ctOpts = new DbContextOptionsBuilder<CongressTradingDbContext>()
|
||||
.UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;
|
||||
var coreOpts = new DbContextOptionsBuilder<CoreDbContext>()
|
||||
.UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;
|
||||
|
||||
var settings = new CoreSettingsService(new Factory<CoreDbContext>(coreOpts));
|
||||
return new CongressRepository(new Factory<CongressTradingDbContext>(ctOpts), settings, new LoggingService());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpsertMember_IsIdempotent_ByBioId()
|
||||
{
|
||||
var repo = CreateSut();
|
||||
|
||||
await repo.UpsertMemberAsync(new CongressMember { BioId = "W1", Name = "Alice" });
|
||||
await repo.UpsertMemberAsync(new CongressMember { BioId = "W1", Name = "Alice B." });
|
||||
|
||||
(await repo.MemberExistsAsync("W1")).Should().BeTrue();
|
||||
(await repo.GetMemberCountAsync()).Should().Be(1);
|
||||
(await repo.GetAllMemberBioIdsAsync()).Should().Contain("W1");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InsertTrade_IgnoresDuplicateTradeId()
|
||||
{
|
||||
var repo = CreateSut();
|
||||
|
||||
await repo.InsertTradeAsync(new CongressTrade { TradeId = "T1", MemberBioId = "W1", Ticker = "AAPL", TradeType = "buy" });
|
||||
await repo.InsertTradeAsync(new CongressTrade { TradeId = "T1", MemberBioId = "W1", Ticker = "AAPL" });
|
||||
|
||||
(await repo.TradeExistsAsync("T1")).Should().BeTrue();
|
||||
(await repo.GetTradeCountAsync()).Should().Be(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DetailsFlow_MarksTradeComplete()
|
||||
{
|
||||
var repo = CreateSut();
|
||||
await repo.InsertTradeAsync(new CongressTrade { TradeId = "T2" }, detailsFetched: false);
|
||||
|
||||
(await repo.GetTradesWithoutDetailsAsync()).Should().Contain("T2");
|
||||
|
||||
await repo.UpdateTradeDetailsAsync(new CongressTrade { TradeId = "T2", Ticker = "MSFT", TradeType = "sell" });
|
||||
|
||||
(await repo.GetTradesWithoutDetailsAsync()).Should().NotContain("T2");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Settings_RoundTripThroughCoreSettings()
|
||||
{
|
||||
var repo = CreateSut();
|
||||
|
||||
await repo.SetSettingAsync("ct.history_import_page", "7");
|
||||
(await repo.GetSettingAsync("ct.history_import_page")).Should().Be("7");
|
||||
|
||||
await repo.DeleteSettingAsync("ct.history_import_page");
|
||||
(await repo.GetSettingAsync("ct.history_import_page")).Should().BeNull();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user