fix(housekeeping): serialize set-rank intents
This commit is contained in:
1 parent
48096833ec
commit
2c5db2168b
2 files changed
+21
-2
No files matched your search
@@ -922,7 +922,7 @@ async function executeRconMutation(
|
|||||||
.select({ rank: User.rank })
|
.select({ rank: User.rank })
|
||||||
.from(User)
|
.from(User)
|
||||||
.where(eq(User.id, userId))
|
.where(eq(User.id, userId))
|
||||||
.limit(1);
|
.for("update");
|
||||||
if (!target) {
|
if (!target) {
|
||||||
throw new SystemMutationFailure(
|
throw new SystemMutationFailure(
|
||||||
"NOT_FOUND",
|
"NOT_FOUND",
|
||||||
|
|||||||
+20
-1
@@ -12,6 +12,7 @@ const doubles = vi.hoisted(() => ({
|
|||||||
createEmulatorRankInTransaction: vi.fn(),
|
createEmulatorRankInTransaction: vi.fn(),
|
||||||
dbDelete: vi.fn(),
|
dbDelete: vi.fn(),
|
||||||
dbExecute: vi.fn(),
|
dbExecute: vi.fn(),
|
||||||
|
dbForUpdate: vi.fn(),
|
||||||
dbInsert: vi.fn(),
|
dbInsert: vi.fn(),
|
||||||
dbSelect: vi.fn(),
|
dbSelect: vi.fn(),
|
||||||
dbTransaction: vi.fn(),
|
dbTransaction: vi.fn(),
|
||||||
@@ -117,10 +118,11 @@ function updateChain(result: Promise<unknown> = Promise.resolve(undefined)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function limitedSelection(rows: readonly unknown[]) {
|
function limitedSelection(rows: readonly unknown[]) {
|
||||||
|
doubles.dbForUpdate.mockResolvedValueOnce(rows);
|
||||||
return {
|
return {
|
||||||
from: () => ({
|
from: () => ({
|
||||||
where: () => ({
|
where: () => ({
|
||||||
for: () => Promise.resolve(rows),
|
for: doubles.dbForUpdate,
|
||||||
limit: () => Promise.resolve(rows),
|
limit: () => Promise.resolve(rows),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
@@ -310,6 +312,23 @@ describe("durable rank synchronization", () => {
|
|||||||
expect(doubles.rconSetRank).not.toHaveBeenCalled();
|
expect(doubles.rconSetRank).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("locks the user row before committing a set-rank intent", async () => {
|
||||||
|
doubles.dbSelect.mockImplementationOnce(() =>
|
||||||
|
limitedSelection([{ rank: 3 }]),
|
||||||
|
);
|
||||||
|
doubles.dbExecute.mockResolvedValue([[{ id: 4 }]]);
|
||||||
|
doubles.rconSetRank.mockResolvedValue(true);
|
||||||
|
|
||||||
|
const result = await systemMutationService.execute(
|
||||||
|
serviceContext(PERMS.RCON_EXECUTE),
|
||||||
|
"rcon.set-rank",
|
||||||
|
{ userId: 8, rank: 4 },
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result).toMatchObject({ ok: true });
|
||||||
|
expect(doubles.dbForUpdate).toHaveBeenCalledWith("update");
|
||||||
|
});
|
||||||
|
|
||||||
it("returns the durable recovery key when set-rank RCON fails after commit", async () => {
|
it("returns the durable recovery key when set-rank RCON fails after commit", async () => {
|
||||||
doubles.dbSelect.mockImplementationOnce(() =>
|
doubles.dbSelect.mockImplementationOnce(() =>
|
||||||
limitedSelection([{ rank: 3 }]),
|
limitedSelection([{ rank: 3 }]),
|
||||||
|
|||||||
Reference in new issue
Block a user