// Ported from apps/server/test (CR-014 Step 14.5): now runs on the engine. import { content } from "@deadhead/content"; import { describe, expect, it } from "vitest"; import { useTestApp, signUp, call, getState, setCredits, testContract, putBoard, makeOwner, signUpOwner, } from "../support"; const testApp = useTestApp(); describe("concurrency and money safety", () => { it("lets only one of two simultaneous purchases through when only one is affordable", async () => { const { app } = testApp(); const guest = await signUpOwner(app); const price = content.shipModel("courier")!.price; await setCredits(testApp().app, price + price / 2); const responses = await Promise.all([ call(app, guest, "POST", "/api/ships", { modelId: "courier", bayId: guest.earthBayId }), call(app, guest, "POST", "/api/ships", { modelId: "courier", bayId: guest.earthBayId }), ]); expect(responses.map((r) => r.statusCode).sort()).toEqual([200, 409]); const state = await getState(app, guest); // The owner already had one ship. expect(state.ships).toHaveLength(2); expect(state.company.credits).toBe(price / 2); }); it("never goes negative under many simultaneous purchases", async () => { const { app } = testApp(); const guest = await signUpOwner(app); const price = content.shipModel("courier")!.price; await setCredits(testApp().app, price * 3); const responses = await Promise.all( Array.from({ length: 8 }, () => call(app, guest, "POST", "/api/ships", { modelId: "courier", bayId: guest.earthBayId }), ), ); expect(responses.filter((r) => r.statusCode === 200)).toHaveLength(3); const state = await getState(app, guest); expect(state.ships).toHaveLength(1 + 3); expect(state.company.credits).toBe(0); }); it("accepts a contract only once when dispatched twice at the same moment", async () => { const { app } = testApp(); const guest = await signUp(app); const { shipId } = await makeOwner(app, guest.avatarId); await setCredits(app, 10_000); const contract = testContract(); await putBoard(app, [contract]); const body = { kind: "contract", contractId: contract.id, shipId, pilotId: guest.avatarId }; const responses = await Promise.all([ call(app, guest, "POST", "/api/dispatches", body), call(app, guest, "POST", "/api/dispatches", body), ]); expect(responses.map((r) => r.statusCode).sort()).toEqual([200, 409]); const state = await getState(app, guest); expect(state.activeDispatches).toHaveLength(1); // One leg's fuel left the tank, once; no credits were charged (CR-015). expect(state.company.credits).toBe(10_000); expect(state.ships[0]!.fuelFu).toBeCloseTo( state.ships[0]!.stats.tankCapacityFu - state.activeDispatches[0]!.fuelBurnedFu, ); }); it("leases one bay when the same lease is sent twice at once", async () => { const { app } = testApp(); const guest = await signUpOwner(app); await setCredits(testApp().app, 100_000); const responses = await Promise.all([ call(app, guest, "POST", "/api/bays", { locationId: "moon" }), call(app, guest, "POST", "/api/bays", { locationId: "moon" }), ]); expect(responses.map((r) => r.statusCode).sort()).toEqual([200, 409]); const state = await getState(app, guest); expect(state.bays.map((b) => b.locationId).sort()).toEqual(["earth", "moon"]); expect(state.company.credits).toBe(100_000 - content.location("moon")!.bayLeasePrice); }); });