Server: start a retried write transaction from the database, not from the attempt that failed

This commit is contained in:
jaap-jan committed 2026-10-02 14:15:52 +02:00
1 parent 36fb0817a4
commit b2516ca7fb
8 files changed
+173 -21

No files matched your search

@@ -647,6 +647,38 @@ public sealed class TeamEndpointTests(ApiFixture fixture)
.Role.ShouldBe(TeamMemberRole.Owner);
}
/// <remarks>
/// The commit lost on its way to the database, which the execution strategy answers by running the
/// transaction again on the same context. That context still held the two memberships as the failed
/// attempt left them — already owner, already admin, and marked unchanged — so the retry saved nothing,
/// committed, and answered 204 over a team whose roles had not moved. See <c>FreshAttempts</c>.
/// </remarks>
[Fact]
public async Task ATransferWhoseCommitIsLost_IsRetriedFromTheDatabase_AndStillLands()
{
var owner = await EnrolledClientAsync("retry-owner", "rowner@example.com");
await EnrolledClientAsync("retry-successor", "rsuccessor@example.com");
var team = await CreateTeamAsync(owner, "Retried handover");
var entry = await LookupAsync(owner, "rsuccessor@example.com");
await AddMemberAsync(owner, team.TeamId, entry.UserId, TeamMemberRole.Member);
var failedBefore = fixture.Commits.Failed;
fixture.Commits.FailNextCommit();
var response = await owner.PostContractAsync(
OwnerUrl(team.TeamId), new TransferTeamOwnershipRequest(entry.UserId));
response.StatusCode.ShouldBe(HttpStatusCode.NoContent);
fixture.Commits.Failed.ShouldBe(failedBefore + 1, "the first commit has to have been lost for this to mean anything");
var members = await ReadAsync<IReadOnlyList<TeamMemberSummary>>(owner, MembersUrl(team.TeamId));
members.Where(row => row.UserId == entry.UserId).ShouldHaveSingleItem().Role.ShouldBe(TeamMemberRole.Owner);
members.Count(row => row.Role == TeamMemberRole.Owner).ShouldBe(1);
}
/// <remarks>
/// The thing that was impossible before this endpoint existed. An owner could not be removed and
/// could not be demoted, so somebody who left the company owning a team left it owned by them for