Use in-memory runtime state with SQLite write-through
This commit is contained in:
@@ -238,26 +238,41 @@ public sealed class GameServiceTests
|
|||||||
Assert.False(service.CreateSkill(ownerSession, Guid.NewGuid(), new CreateSkillRequest("Stealth", "2D+1")).Succeeded);
|
Assert.False(service.CreateSkill(ownerSession, Guid.NewGuid(), new CreateSkillRequest("Stealth", "2D+1")).Succeeded);
|
||||||
Assert.False(service.CreateSkill(otherSession, ownerCharacter.Id, new CreateSkillRequest("Stealth", "2D+1")).Succeeded);
|
Assert.False(service.CreateSkill(otherSession, ownerCharacter.Id, new CreateSkillRequest("Stealth", "2D+1")).Succeeded);
|
||||||
|
|
||||||
var ownerUser = harness.Db.Users.Single(u => u.UsernameNormalized == "OWNER");
|
using (var db = harness.CreateDbContext())
|
||||||
ownerUser.ActiveCharacterId = Guid.NewGuid();
|
{
|
||||||
harness.Db.SaveChanges();
|
var ownerUser = db.Users.Single(u => u.UsernameNormalized == "OWNER");
|
||||||
|
ownerUser.ActiveCharacterId = Guid.NewGuid();
|
||||||
|
db.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
var staleMe = GetValue(service.GetMe(ownerSession));
|
using var staleMeHarness = CreateHarnessFromPath(harness.DbPath, 2, 3, 4);
|
||||||
|
var staleMeService = staleMeHarness.Service;
|
||||||
|
|
||||||
|
var staleMe = GetValue(staleMeService.GetMe(ownerSession));
|
||||||
Assert.Null(staleMe.ActiveCharacterId);
|
Assert.Null(staleMe.ActiveCharacterId);
|
||||||
Assert.Null(staleMe.CurrentCampaignId);
|
Assert.Null(staleMe.CurrentCampaignId);
|
||||||
|
|
||||||
Assert.True(service.ActivateCharacter(ownerSession, ownerCharacter.Id).Succeeded);
|
Assert.True(staleMeService.ActivateCharacter(ownerSession, ownerCharacter.Id).Succeeded);
|
||||||
var activeMe = GetValue(service.GetMe(ownerSession));
|
var activeMe = GetValue(staleMeService.GetMe(ownerSession));
|
||||||
Assert.Equal(ownerCharacter.Id, activeMe.ActiveCharacterId);
|
Assert.Equal(ownerCharacter.Id, activeMe.ActiveCharacterId);
|
||||||
Assert.Equal(campaign.Id, activeMe.CurrentCampaignId);
|
Assert.Equal(campaign.Id, activeMe.CurrentCampaignId);
|
||||||
|
|
||||||
var staleOwner = harness.Db.Users.Single(u => u.Id == ownerUser.Id);
|
using (var db = harness.CreateDbContext())
|
||||||
staleOwner.ActiveCharacterId = Guid.NewGuid();
|
{
|
||||||
harness.Db.SaveChanges();
|
var staleOwner = db.Users.Single(u => u.UsernameNormalized == "OWNER");
|
||||||
|
staleOwner.ActiveCharacterId = Guid.NewGuid();
|
||||||
|
db.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
var staleCurrentCampaign = service.GetCurrentCampaignCharacters(ownerSession);
|
using var staleCurrentHarness = CreateHarnessFromPath(harness.DbPath, 2, 3, 4);
|
||||||
|
var staleCurrentService = staleCurrentHarness.Service;
|
||||||
|
|
||||||
|
var staleCurrentCampaign = staleCurrentService.GetCurrentCampaignCharacters(ownerSession);
|
||||||
Assert.False(staleCurrentCampaign.Succeeded);
|
Assert.False(staleCurrentCampaign.Succeeded);
|
||||||
Assert.Null(harness.Db.Users.Single(u => u.Id == ownerUser.Id).ActiveCharacterId);
|
using (var db = harness.CreateDbContext())
|
||||||
|
{
|
||||||
|
Assert.Null(db.Users.Single(u => u.UsernameNormalized == "OWNER").ActiveCharacterId);
|
||||||
|
}
|
||||||
|
|
||||||
var skill = GetValue(service.CreateSkill(ownerSession, ownerCharacter.Id, new CreateSkillRequest("Stealth", "2D+1")));
|
var skill = GetValue(service.CreateSkill(ownerSession, ownerCharacter.Id, new CreateSkillRequest("Stealth", "2D+1")));
|
||||||
Assert.False(service.UpdateSkill(ownerSession, skill.Id, new UpdateSkillRequest("", "2D+1")).Succeeded);
|
Assert.False(service.UpdateSkill(ownerSession, skill.Id, new UpdateSkillRequest("", "2D+1")).Succeeded);
|
||||||
@@ -265,11 +280,15 @@ public sealed class GameServiceTests
|
|||||||
Assert.False(service.UpdateSkill(ownerSession, skill.Id, new UpdateSkillRequest("Stealth", "bad")).Succeeded);
|
Assert.False(service.UpdateSkill(ownerSession, skill.Id, new UpdateSkillRequest("Stealth", "bad")).Succeeded);
|
||||||
Assert.False(service.RollSkill(string.Empty, skill.Id, new RollSkillRequest("public")).Succeeded);
|
Assert.False(service.RollSkill(string.Empty, skill.Id, new RollSkillRequest("public")).Succeeded);
|
||||||
|
|
||||||
var mutableSkill = harness.Db.Skills.Single(s => s.Id == skill.Id);
|
using (var db = harness.CreateDbContext())
|
||||||
mutableSkill.DiceRollDefinition = "bad";
|
{
|
||||||
harness.Db.SaveChanges();
|
var mutableSkill = db.Skills.Single(s => s.Id == skill.Id);
|
||||||
|
mutableSkill.DiceRollDefinition = "bad";
|
||||||
|
db.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
Assert.False(service.RollSkill(ownerSession, skill.Id, new RollSkillRequest("public")).Succeeded);
|
using var invalidExpressionHarness = CreateHarnessFromPath(harness.DbPath, 2, 3, 4);
|
||||||
|
Assert.False(invalidExpressionHarness.Service.RollSkill(ownerSession, skill.Id, new RollSkillRequest("public")).Succeeded);
|
||||||
Assert.False(service.GetCampaignLog(string.Empty, campaign.Id).Succeeded);
|
Assert.False(service.GetCampaignLog(string.Empty, campaign.Id).Succeeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,15 +365,28 @@ public sealed class GameServiceTests
|
|||||||
private static ServiceHarness CreateHarness(IPasswordHasher<UserAccount> passwordHasher, params int[] rollValues)
|
private static ServiceHarness CreateHarness(IPasswordHasher<UserAccount> passwordHasher, params int[] rollValues)
|
||||||
{
|
{
|
||||||
var dbPath = Path.Combine(Path.GetTempPath(), $"rpgroller-servicetests-{Guid.NewGuid():N}.db");
|
var dbPath = Path.Combine(Path.GetTempPath(), $"rpgroller-servicetests-{Guid.NewGuid():N}.db");
|
||||||
|
return CreateHarnessFromPath(dbPath, passwordHasher, rollValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ServiceHarness CreateHarnessFromPath(string dbPath, params int[] rollValues)
|
||||||
|
{
|
||||||
|
return CreateHarnessFromPath(dbPath, new PasswordHasher<UserAccount>(), rollValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ServiceHarness CreateHarnessFromPath(string dbPath, IPasswordHasher<UserAccount> passwordHasher, params int[] rollValues)
|
||||||
|
{
|
||||||
var options = new DbContextOptionsBuilder<RpgRollerDbContext>()
|
var options = new DbContextOptionsBuilder<RpgRollerDbContext>()
|
||||||
.UseSqlite($"Data Source={dbPath}")
|
.UseSqlite($"Data Source={dbPath}")
|
||||||
.Options;
|
.Options;
|
||||||
|
|
||||||
var db = new RpgRollerDbContext(options);
|
using (var db = new RpgRollerDbContext(options))
|
||||||
db.Database.EnsureCreated();
|
{
|
||||||
|
db.Database.EnsureCreated();
|
||||||
|
}
|
||||||
|
|
||||||
var service = new GameService(db, passwordHasher, new FixedDiceRoller(rollValues));
|
var factory = new SqliteDbContextFactory(dbPath);
|
||||||
return new ServiceHarness(service, db);
|
var service = new GameService(factory, passwordHasher, new FixedDiceRoller(rollValues));
|
||||||
|
return new ServiceHarness(service, factory, dbPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static T GetValue<T>(ServiceResult<T> result)
|
private static T GetValue<T>(ServiceResult<T> result)
|
||||||
@@ -382,20 +414,47 @@ public sealed class GameServiceTests
|
|||||||
|
|
||||||
private sealed class ServiceHarness : IDisposable
|
private sealed class ServiceHarness : IDisposable
|
||||||
{
|
{
|
||||||
private readonly RpgRollerDbContext m_Db;
|
private readonly SqliteDbContextFactory m_Factory;
|
||||||
|
|
||||||
public ServiceHarness(GameService service, RpgRollerDbContext db)
|
public ServiceHarness(GameService service, SqliteDbContextFactory factory, string dbPath)
|
||||||
{
|
{
|
||||||
Service = service;
|
Service = service;
|
||||||
m_Db = db;
|
m_Factory = factory;
|
||||||
|
DbPath = dbPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameService Service { get; }
|
public GameService Service { get; }
|
||||||
public RpgRollerDbContext Db => m_Db;
|
public string DbPath { get; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
m_Factory.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RpgRollerDbContext CreateDbContext()
|
||||||
|
{
|
||||||
|
return m_Factory.CreateDbContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class SqliteDbContextFactory : IDbContextFactory<RpgRollerDbContext>, IDisposable
|
||||||
|
{
|
||||||
|
private readonly DbContextOptions<RpgRollerDbContext> m_Options;
|
||||||
|
|
||||||
|
public SqliteDbContextFactory(string dbPath)
|
||||||
|
{
|
||||||
|
m_Options = new DbContextOptionsBuilder<RpgRollerDbContext>()
|
||||||
|
.UseSqlite($"Data Source={dbPath}")
|
||||||
|
.Options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RpgRollerDbContext CreateDbContext()
|
||||||
|
{
|
||||||
|
return new RpgRollerDbContext(m_Options);
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
m_Db.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -205,10 +205,11 @@ public sealed class UnitTest1 : IClassFixture<WebApplicationFactory<Program>>
|
|||||||
services.AddSingleton<IDiceRoller>(new FixedDiceRoller(rollValues));
|
services.AddSingleton<IDiceRoller>(new FixedDiceRoller(rollValues));
|
||||||
|
|
||||||
services.RemoveAll<DbContextOptions<RpgRollerDbContext>>();
|
services.RemoveAll<DbContextOptions<RpgRollerDbContext>>();
|
||||||
|
services.RemoveAll<IDbContextFactory<RpgRollerDbContext>>();
|
||||||
services.RemoveAll<RpgRollerDbContext>();
|
services.RemoveAll<RpgRollerDbContext>();
|
||||||
|
|
||||||
var dbPath = Path.Combine(Path.GetTempPath(), $"rpgroller-tests-{Guid.NewGuid():N}.db");
|
var dbPath = Path.Combine(Path.GetTempPath(), $"rpgroller-tests-{Guid.NewGuid():N}.db");
|
||||||
services.AddDbContext<RpgRollerDbContext>(options => options.UseSqlite($"Data Source={dbPath}"));
|
services.AddDbContextFactory<RpgRollerDbContext>(options => options.UseSqlite($"Data Source={dbPath}"));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,16 +14,18 @@ var sqliteConnectionString = builder.Configuration.GetConnectionString("RpgRolle
|
|||||||
EnsureSqliteDataDirectory(sqliteConnectionString, builder.Environment.ContentRootPath);
|
EnsureSqliteDataDirectory(sqliteConnectionString, builder.Environment.ContentRootPath);
|
||||||
|
|
||||||
builder.Services.AddSingleton<IPasswordHasher<UserAccount>, PasswordHasher<UserAccount>>();
|
builder.Services.AddSingleton<IPasswordHasher<UserAccount>, PasswordHasher<UserAccount>>();
|
||||||
builder.Services.AddDbContext<RpgRollerDbContext>(options => options.UseSqlite(sqliteConnectionString));
|
builder.Services.AddDbContextFactory<RpgRollerDbContext>(options => options.UseSqlite(sqliteConnectionString));
|
||||||
builder.Services.AddSingleton<IDiceRoller, RandomDiceRoller>();
|
builder.Services.AddSingleton<IDiceRoller, RandomDiceRoller>();
|
||||||
builder.Services.AddScoped<IGameService, GameService>();
|
builder.Services.AddSingleton<IGameService, GameService>();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
using (var scope = app.Services.CreateScope())
|
using (var scope = app.Services.CreateScope())
|
||||||
{
|
{
|
||||||
var db = scope.ServiceProvider.GetRequiredService<RpgRollerDbContext>();
|
var dbFactory = scope.ServiceProvider.GetRequiredService<IDbContextFactory<RpgRollerDbContext>>();
|
||||||
|
using var db = dbFactory.CreateDbContext();
|
||||||
db.Database.EnsureCreated();
|
db.Database.EnsureCreated();
|
||||||
|
_ = scope.ServiceProvider.GetRequiredService<IGameService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseDefaultFiles();
|
app.UseDefaultFiles();
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user