Files
agent-bounty-protocol/test_idempotency.ts

129 lines
4.3 KiB
TypeScript

import { PrismaClient } from "./apps/web/prisma/generated/client/index.js";
import { TaskStatus, MCPToolName, SettlementPhase, TaskDifficulty } from "./packages/contracts/src/enums/index.js";
import { v4 as uuidv4 } from "uuid";
const prisma = new PrismaClient();
async function main() {
console.log("=== Idempotency and Payment Flow Test ===");
// 1. Create a mock task
const taskId = uuidv4();
await prisma.task.create({
data: {
id: taskId,
title: "Test Task",
difficulty: TaskDifficulty.COMPONENT,
status: TaskStatus.OPEN,
requirements: "Test requirements",
base_reward_cents: 500,
}
});
console.log(`[+] Created Task ${taskId}`);
// 2. Simulate Claim Task (Auth Hold)
console.log(`\n[+] Simulating MCP: claim_task`);
// First attempt (Should succeed and create Auth Hold)
const agentId = "agent-test-1";
const idempotencyKeyClaim = `${taskId}_${MCPToolName.CLAIM_TASK}`;
const claim1 = await prisma.$transaction(async (tx) => {
// authHold logic
const existing = await tx.ledgerEntry.findUnique({ where: { idempotency_key: idempotencyKeyClaim }});
if (existing) {
console.log("Idempotent hit for claim_task!");
return existing;
}
await tx.task.update({
where: { id: taskId },
data: { status: TaskStatus.EXECUTING, agent_id: agentId }
});
return await tx.ledgerEntry.create({
data: {
task_id: taskId,
phase: SettlementPhase.AUTH_HOLD,
amount_cents: 500,
currency: "USD",
stripe_object_id: "pi_mock_" + uuidv4(),
idempotency_key: idempotencyKeyClaim
}
});
});
console.log(`[1] First claim_task attempt created ledger entry: ${claim1.id}`);
// Second attempt (Should hit idempotency key and NOT duplicate)
const claim2 = await prisma.$transaction(async (tx) => {
const existing = await tx.ledgerEntry.findUnique({ where: { idempotency_key: idempotencyKeyClaim }});
if (existing) {
console.log("Idempotent hit for claim_task!");
return existing;
}
// Should not reach here
throw new Error("Idempotency failed!");
});
console.log(`[2] Second claim_task attempt returned same entry: ${claim2.id}`);
// 3. Simulate Submit Solution (Capture)
console.log(`\n[+] Simulating MCP: submit_solution`);
const idempotencyKeySubmit = `${taskId}_${MCPToolName.SUBMIT_SOLUTION}`;
const submit1 = await prisma.$transaction(async (tx) => {
const existing = await tx.ledgerEntry.findUnique({ where: { idempotency_key: idempotencyKeySubmit }});
if (existing) {
console.log("Idempotent hit for submit_solution!");
return existing;
}
await tx.task.update({
where: { id: taskId },
data: { status: TaskStatus.COMPLETED }
});
return await tx.ledgerEntry.create({
data: {
task_id: taskId,
phase: SettlementPhase.CAPTURE,
amount_cents: 500,
currency: "USD",
stripe_object_id: claim1.stripe_object_id,
idempotency_key: idempotencyKeySubmit
}
});
});
console.log(`[1] First submit_solution attempt created ledger entry: ${submit1.id}`);
const submit2 = await prisma.$transaction(async (tx) => {
const existing = await tx.ledgerEntry.findUnique({ where: { idempotency_key: idempotencyKeySubmit }});
if (existing) {
console.log("Idempotent hit for submit_solution!");
return existing;
}
throw new Error("Idempotency failed!");
});
console.log(`[2] Second submit_solution attempt returned same entry: ${submit2.id}`);
// Verify DB state
const finalTask = await prisma.task.findUnique({ where: { id: taskId }, include: { ledger_entries: true } });
console.log(`\n=== Final Verification ===`);
console.log(`Task Status: ${finalTask?.status}`);
console.log(`Ledger Entries: ${finalTask?.ledger_entries.length}`);
finalTask?.ledger_entries.forEach(entry => {
console.log(` - Phase: ${entry.phase}, Amount: ${entry.amount_cents}, Key: ${entry.idempotency_key}`);
});
if (finalTask?.status === TaskStatus.COMPLETED && finalTask.ledger_entries.length === 2) {
console.log("\n✅ End-to-End Simulation Passed! Idempotency and State transitions are correct.");
} else {
console.log("\n❌ Simulation Failed.");
}
}
main()
.catch(console.error)
.finally(async () => {
await prisma.$disconnect();
});