fix: serialize profile reset operations

This commit is contained in:
2026-07-31 13:19:27 +00:00
parent d959c9b06d
commit 26fbba39b4
17 changed files with 1715 additions and 378 deletions
+87 -3
View File
@@ -32,6 +32,7 @@ const buildCaller = async (
});
const session = await sessions.createSession({ ...admin, roles: adminRoles });
const createdInputs: GatewayOperationCreateInput[] = [];
const operationRecords = new Map<string, Awaited<ReturnType<GatewayProfileRepository['createOperation']>>>();
const createdRuntimeActions: Array<Record<string, unknown>> = [];
const flushes: Array<{ userId: string; reason?: string; iconRevision?: string }> = [];
const profile = {
@@ -59,10 +60,12 @@ const buildCaller = async (
updateWorkspaceUsage: async () => {},
clearWorkspaceUsage: async () => {},
listOperations: async () => [],
getOperation: async () => null,
getOperation: async (id) => operationRecords.get(id) ?? null,
createOperation: async (input) => {
createdInputs.push(input);
return createOperation(input);
const operation = await createOperation(input);
operationRecords.set(operation.id, operation);
return operation;
},
claimNextOperation: async () => null,
completeOperation: async () => {
@@ -103,7 +106,11 @@ const buildCaller = async (
reconcileNow: async () => {},
runScheduleNow: async () => {},
runBuildQueueNow: async () => {},
runOperationsNow: async () => {},
runOperationsNow: async () => {
for (const [id, operation] of operationRecords) {
operationRecords.set(id, { ...operation, status: 'SUCCEEDED' });
}
},
cleanupStaleWorkspaces: async () => ({ removed: [], skipped: [] }),
listRuntimeStates: async () => [],
},
@@ -180,6 +187,83 @@ describe('admin operation API', () => {
});
});
describe('legacy profile install API', () => {
const install = {
scenarioId: 1010,
turnTermMinutes: 60,
sync: false,
fiction: 1,
extend: false,
blockGeneralCreate: 0,
npcMode: 0,
showImgLevel: 0,
tournamentTrig: false,
joinMode: 'full' as const,
gitRef: 'HEAD',
};
const buildResetOperation = (input: GatewayOperationCreateInput) => ({
id: '22222222-2222-4222-8222-222222222222',
profileName: input.profileName,
type: 'RESET' as const,
status: 'QUEUED' as const,
sourceMode: input.sourceMode,
sourceRef: input.sourceRef,
payload: input.payload ?? {},
requestedBy: input.requestedBy,
createdAt: '2026-07-31T00:00:00.000Z',
updatedAt: '2026-07-31T00:00:00.000Z',
});
it('queues profiles.install instead of seeding the live database directly', async () => {
const harness = await buildCaller(async (input) => buildResetOperation(input));
await expect(
harness.caller.admin.profiles.install({
profileName: 'che:2',
install,
reason: 'durable install',
})
).resolves.toMatchObject({ ok: true, operationId: '22222222-2222-4222-8222-222222222222' });
expect(harness.createdInputs).toHaveLength(1);
expect(harness.createdInputs[0]).toMatchObject({
profileName: 'che:2',
type: 'RESET',
sourceMode: 'COMMIT',
reason: 'durable install',
});
expect(harness.createdInputs[0]?.payload).toMatchObject({
install: {
scenarioId: 1010,
adminUser: { id: harness.admin.id },
},
});
});
it('queues installNow through the same reset operation boundary', async () => {
const harness = await buildCaller(async (input) => buildResetOperation(input));
await expect(
harness.caller.admin.profiles.installNow({
profileName: 'che:2',
install,
reason: 'no direct seed',
})
).resolves.toEqual({ ok: true, operationId: '22222222-2222-4222-8222-222222222222' });
expect(harness.createdInputs[0]).toMatchObject({
type: 'RESET',
sourceMode: 'COMMIT',
reason: 'no direct seed',
payload: {
install: {
scenarioId: 1010,
adminUser: { id: harness.admin.id },
},
},
});
});
});
describe('admin runtime clock action API', () => {
const unusedCreateOperation: GatewayProfileRepository['createOperation'] = async () => {
throw new Error('not used');