src/orders/resting.test.ts
v0.2.1 · 3.5 KB
import { describe, expect, it } from 'vitest';
import { placeKey } from '../pending/memory.js';
import { ORDER_ID_A, ORDER_ID_B } from '../testing/fixtures.js';
import { resolveResting, sendClassOf, sortForSending, waitForOrderKeyInBook } from './resting.js';
const noSleep = async () => {};
function clock(start = 0) {
let t = start;
return { now: () => t, tick: (ms: number) => (t += ms) };
}
describe('resolveResting', () => {
it('finds the order by client_order_index and market after the rollup catches up', async () => {
const c = clock();
let reads = 0;
const r = await resolveResting({
readOpenOrders: async () => {
reads++;
return reads < 3 ? [] : [{ orderId: ORDER_ID_A, clientOrderIndex: 42, marketIndex: 32 }];
},
clientOrderIndex: 42,
marketIndex: 32,
timeoutMs: 5000,
intervalMs: 700,
sleep: async (ms) => {
c.tick(ms);
},
now: c.now,
});
expect(r).toMatchObject({ found: true, orderId: ORDER_ID_A, reads: 3 });
});
it('does not match the same index on another market or a null index', async () => {
const c = clock();
const r = await resolveResting({
readOpenOrders: async () => [
{ orderId: ORDER_ID_A, clientOrderIndex: 42, marketIndex: 41 },
{ orderId: ORDER_ID_B, clientOrderIndex: null, marketIndex: 32 },
],
clientOrderIndex: 42,
marketIndex: 32,
timeoutMs: 1000,
intervalMs: 500,
sleep: async (ms) => {
c.tick(ms);
},
now: c.now,
});
expect(r).toEqual({ found: false, reads: 3 }); // t=0, 500, 1000 -> deadline reached
});
it('reads at least once even with a zero timeout', async () => {
const r = await resolveResting({
readOpenOrders: async () => [],
clientOrderIndex: 1,
marketIndex: 1,
timeoutMs: 0,
sleep: noSleep,
});
expect(r).toEqual({ found: false, reads: 1 });
});
});
describe('waitForOrderKeyInBook', () => {
it('returns true and calls onFound when the key appears, false on timeout', async () => {
const key = placeKey('ETH', true, '1650.00');
const c = clock();
let n = 0;
const found: string[] = [];
const ok = await waitForOrderKeyInBook({
readKeys: async () => new Set(++n >= 2 ? [key] : []),
key,
timeoutMs: 5000,
intervalMs: 700,
sleep: async (ms) => {
c.tick(ms);
},
now: c.now,
onFound: (k) => found.push(k),
});
expect(ok).toBe(true);
expect(found).toEqual([key]);
const c2 = clock();
const missing = await waitForOrderKeyInBook({
readKeys: async () => new Set<string>(),
key,
timeoutMs: 1400,
intervalMs: 700,
sleep: async (ms) => {
c2.tick(ms);
},
now: c2.now,
});
expect(missing).toBe(false);
});
});
describe('sortForSending', () => {
it('orders cancels, IoC, reduceOnly GTC, ordinary GTC; stable within a class', () => {
type A = { kind: 'cancel'; id: string } | { kind: 'place'; tif: 'Gtc' | 'Ioc'; reduceOnly: boolean; id: string };
const actions: A[] = [
{ kind: 'place', tif: 'Gtc', reduceOnly: false, id: 'g1' },
{ kind: 'place', tif: 'Gtc', reduceOnly: true, id: 'r1' },
{ kind: 'cancel', id: 'c1' },
{ kind: 'place', tif: 'Ioc', reduceOnly: false, id: 'i1' },
{ kind: 'place', tif: 'Gtc', reduceOnly: false, id: 'g2' },
{ kind: 'cancel', id: 'c2' },
];
expect(sortForSending(actions, sendClassOf).map((a) => a.id)).toEqual(['c1', 'c2', 'i1', 'r1', 'g1', 'g2']);
});
});