test(rules): verify failed save preserves committed owner settings
This commit is contained in:
@@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
@@ -15,6 +16,43 @@ namespace JobTrackerApi.Tests;
|
||||
|
||||
public sealed class RuleSettingsFreshnessTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task Failed_owner_save_preserves_committed_rules_and_a_later_success_refreshes_existing_readers()
|
||||
{
|
||||
await using var fixture = await Fixture.CreateAsync();
|
||||
await using var readA = fixture.Context("owner-a");
|
||||
await using var readB = fixture.Context("owner-b");
|
||||
var ownerA = fixture.Controller(readA);
|
||||
var ownerB = fixture.Controller(readB);
|
||||
Assert.False(await FollowUp(ownerA, fixture.JobA, "list"));
|
||||
Assert.False(await FollowUp(ownerB, fixture.JobB, "list"));
|
||||
|
||||
var failure = new SaveFailureInterceptor();
|
||||
await using var write = fixture.Context("owner-a", failure);
|
||||
await Assert.ThrowsAsync<DbUpdateException>(() => new RulesController(write).Update(Settings(1), default));
|
||||
Assert.Equal(1, write.UserRuleSettings.Local.Single().AppliedFollowUpDays);
|
||||
Assert.Equal(30, (await RulesEngine.GetSettings(write, default)).AppliedFollowUpDays);
|
||||
Assert.False(await FollowUp(ownerA, fixture.JobA, "list"));
|
||||
Assert.False(await FollowUp(ownerB, fixture.JobB, "list"));
|
||||
|
||||
failure.RejectWrites = false;
|
||||
Assert.IsType<NoContentResult>(await new RulesController(write).Update(Settings(1), default));
|
||||
Assert.True(await FollowUp(ownerA, fixture.JobA, "list"));
|
||||
Assert.False(await FollowUp(ownerB, fixture.JobB, "list"));
|
||||
}
|
||||
|
||||
private sealed class SaveFailureInterceptor : SaveChangesInterceptor
|
||||
{
|
||||
public bool RejectWrites { get; set; } = true;
|
||||
|
||||
public override ValueTask<InterceptionResult<int>> SavingChangesAsync(
|
||||
DbContextEventData eventData, InterceptionResult<int> result, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (RejectWrites) throw new DbUpdateException("Synthetic settings storage failure");
|
||||
return base.SavingChangesAsync(eventData, result, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("list")]
|
||||
[InlineData("board")]
|
||||
@@ -158,11 +196,13 @@ public sealed class RuleSettingsFreshnessTests
|
||||
public int JobA { get; private set; }
|
||||
public int JobB { get; private set; }
|
||||
|
||||
public JobTrackerContext Context(string? owner)
|
||||
public JobTrackerContext Context(string? owner, IInterceptor? interceptor = null)
|
||||
{
|
||||
var user = new Mock<ICurrentUserService>();
|
||||
user.SetupGet(x => x.UserId).Returns(owner);
|
||||
return new JobTrackerContext(new DbContextOptionsBuilder<JobTrackerContext>().UseSqlite(_connection).Options, user.Object);
|
||||
var options = new DbContextOptionsBuilder<JobTrackerContext>().UseSqlite(_connection);
|
||||
if (interceptor is not null) options.AddInterceptors(interceptor);
|
||||
return new JobTrackerContext(options.Options, user.Object);
|
||||
}
|
||||
|
||||
public JobApplicationsController Controller(JobTrackerContext db) =>
|
||||
|
||||
Reference in New Issue
Block a user