Add explicit write transactions and deterministic ordering tests

This commit is contained in:
2026-02-07 01:16:07 +01:00
parent 0d60108036
commit 35d842d6ee
4 changed files with 26 additions and 25 deletions

View File

@@ -13,6 +13,8 @@ internal sealed class AdminWorkflowService(AppDbContext db)
state.ResultsOpen = request.ResultsOpen;
state.UpdatedAt = DateTimeOffset.UtcNow;
await using var tx = await db.Database.BeginTransactionAsync();
if (request.ResultsOpen)
{
await db.Players.ExecuteUpdateAsync(p => p.SetProperty(x => x.CurrentPhase, Phase.Results));
@@ -23,6 +25,7 @@ internal sealed class AdminWorkflowService(AppDbContext db)
}
await db.SaveChangesAsync();
await tx.CommitAsync();
var currentState = await db.AppState.AsNoTracking().FirstAsync();
return Results.Ok(new
{
@@ -207,6 +210,8 @@ internal sealed class AdminWorkflowService(AppDbContext db)
public async Task<IResult> ResetAsync()
{
await using var tx = await db.Database.BeginTransactionAsync();
await db.Votes.ExecuteDeleteAsync();
await db.Suggestions.ExecuteDeleteAsync();
@@ -215,6 +220,7 @@ internal sealed class AdminWorkflowService(AppDbContext db)
state.ResultsOpen = false;
state.UpdatedAt = DateTimeOffset.UtcNow;
await db.SaveChangesAsync();
await tx.CommitAsync();
return Results.Ok(new
{

View File

@@ -67,6 +67,8 @@ internal sealed class SuggestionWorkflowService(AppDbContext db, IHttpClientFact
MaxPlayers = request.MaxPlayers
};
await using var tx = await db.Database.BeginTransactionAsync();
db.Suggestions.Add(suggestion);
if (usingJoker)
@@ -76,6 +78,7 @@ internal sealed class SuggestionWorkflowService(AppDbContext db, IHttpClientFact
}
await db.SaveChangesAsync();
await tx.CommitAsync();
return Results.Created($"/api/suggestions/{suggestion.Id}", new { suggestion.Id });
}
@@ -95,6 +98,8 @@ internal sealed class SuggestionWorkflowService(AppDbContext db, IHttpClientFact
if (suggestion == null)
return Results.NotFound(new { error = "Suggestion not found." });
await using var tx = await db.Database.BeginTransactionAsync();
await db.Suggestions
.Where(s => s.ParentSuggestionId == suggestion.Id)
.ExecuteUpdateAsync(s => s.SetProperty(x => x.ParentSuggestionId, (int?)null));
@@ -103,6 +108,7 @@ internal sealed class SuggestionWorkflowService(AppDbContext db, IHttpClientFact
db.Suggestions.Remove(suggestion);
await db.SaveChangesAsync();
await tx.CommitAsync();
return Results.NoContent();
}

View File

@@ -244,11 +244,11 @@ public class AdminTests
{
var p = await db.Players.FirstAsync(x => !x.IsAdmin);
p.VotesFinal = true;
var state = await db.AppState.FirstAsync();
state.UpdatedAt = DateTimeOffset.UnixEpoch;
await db.SaveChangesAsync();
});
var beforeState = await factory.WithDbContextAsync(async db => await db.AppState.AsNoTracking().FirstAsync());
await Task.Delay(5);
var close = await admin.PostAsJsonAsync("/api/admin/results", new { resultsOpen = false });
close.EnsureSuccessStatusCode();
@@ -259,7 +259,7 @@ public class AdminTests
Assert.False(p.VotesFinal);
var state = await db.AppState.AsNoTracking().FirstAsync();
Assert.False(state.ResultsOpen);
Assert.True(state.UpdatedAt > beforeState.UpdatedAt);
Assert.True(state.UpdatedAt > DateTimeOffset.UnixEpoch);
});
}

View File

@@ -365,28 +365,15 @@ public class SuggestionTests
var client = factory.CreateClientWithCookies();
await client.RegisterAsync("mine");
await client.PostAsJsonAsync("/api/suggestions", new
var secondId = await client.CreateSuggestionAsync("Second");
var thirdId = await client.CreateSuggestionAsync("Third");
await factory.WithDbContextAsync(async db =>
{
Name = "Second",
Genre = (string?)null,
Description = (string?)null,
ScreenshotUrl = (string?)null,
YoutubeUrl = (string?)null,
GameUrl = (string?)null,
MinPlayers = (int?)null,
MaxPlayers = (int?)null
});
await Task.Delay(10);
await client.PostAsJsonAsync("/api/suggestions", new
{
Name = "Third",
Genre = (string?)null,
Description = (string?)null,
ScreenshotUrl = (string?)null,
YoutubeUrl = (string?)null,
GameUrl = (string?)null,
MinPlayers = (int?)null,
MaxPlayers = (int?)null
var second = await db.Suggestions.FindAsync(secondId);
var third = await db.Suggestions.FindAsync(thirdId);
second!.CreatedAt = DateTimeOffset.UtcNow.AddMinutes(-1);
third!.CreatedAt = DateTimeOffset.UtcNow;
await db.SaveChangesAsync();
});
var mine = await client.GetFromJsonAsync<List<JsonElement>>("/api/suggestions/mine");
@@ -572,11 +559,13 @@ public class SuggestionTests
await client.RegisterAsync("owner");
var id1 = await client.CreateSuggestionAsync("Alpha");
await Task.Delay(10);
var id2 = await client.CreateSuggestionAsync("Beta");
await factory.WithDbContextAsync(async db =>
{
var alpha = await db.Suggestions.FindAsync(id1);
var beta = await db.Suggestions.FindAsync(id2);
alpha!.CreatedAt = DateTimeOffset.UtcNow.AddMinutes(-1);
beta!.CreatedAt = DateTimeOffset.UtcNow;
beta!.ParentSuggestionId = id1;
await db.SaveChangesAsync();
});