PR #26 (squash-merged via Gitea API)
Some checks failed
CI / Frontend Lint (push) Has been cancelled
CI / Frontend Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Frontend E2E Tests (push) Has been cancelled
CI / Orchestrator Build (push) Has been cancelled
CI / Orchestrator Unit Tests (push) Has been cancelled
CI / Orchestrator E2E (Testcontainers) (push) Has been cancelled
CI / Contracts Compile (push) Has been cancelled
CI / Contracts Test (push) Has been cancelled
Security Scan / Dependency Vulnerability Scan (push) Has been cancelled
Security Scan / OWASP ZAP Scan (push) Has been cancelled
Some checks failed
CI / Frontend Lint (push) Has been cancelled
CI / Frontend Type Check (push) Has been cancelled
CI / Frontend Build (push) Has been cancelled
CI / Frontend E2E Tests (push) Has been cancelled
CI / Orchestrator Build (push) Has been cancelled
CI / Orchestrator Unit Tests (push) Has been cancelled
CI / Orchestrator E2E (Testcontainers) (push) Has been cancelled
CI / Contracts Compile (push) Has been cancelled
CI / Contracts Test (push) Has been cancelled
Security Scan / Dependency Vulnerability Scan (push) Has been cancelled
Security Scan / OWASP ZAP Scan (push) Has been cancelled
This commit was merged in pull request #26.
This commit is contained in:
198
orchestrator/tests/services/dbisCoreClient.test.ts
Normal file
198
orchestrator/tests/services/dbisCoreClient.test.ts
Normal file
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* Unit tests for the dbis_core HTTP client adapter.
|
||||
*
|
||||
* Covers both provider-switch legs:
|
||||
* - `createDbisCoreClient()` with DBIS_CORE_URL unset → mock mode.
|
||||
* - `createDbisCoreClient({ baseUrl, fetchImpl })` → live mode, with
|
||||
* a stub `fetch` so tests never hit the network.
|
||||
*/
|
||||
|
||||
import {
|
||||
createDbisCoreClient,
|
||||
type DbisCoreClient,
|
||||
} from "../../src/services/dbisCore";
|
||||
|
||||
describe("dbisCore.createDbisCoreClient() — mock mode", () => {
|
||||
let client: DbisCoreClient;
|
||||
|
||||
beforeAll(() => {
|
||||
delete process.env.DBIS_CORE_URL;
|
||||
delete process.env.DBIS_CORE_API_KEY;
|
||||
client = createDbisCoreClient();
|
||||
});
|
||||
|
||||
it("reports mock mode", () => {
|
||||
expect(client.mode).toBe("mock");
|
||||
});
|
||||
|
||||
it("returns a balance shaped like upstream", async () => {
|
||||
const b = await client.getAccountBalance("acct-1");
|
||||
expect(b.accountId).toBe("acct-1");
|
||||
expect(typeof b.available).toBe("string");
|
||||
expect(typeof b.held).toBe("string");
|
||||
expect(b.currency).toBeDefined();
|
||||
});
|
||||
|
||||
it("returns a plausible route", async () => {
|
||||
const r = await client.findSettlementRoute({
|
||||
sourceBankId: "src",
|
||||
destinationBankId: "dst",
|
||||
amount: "100",
|
||||
currencyCode: "USD",
|
||||
});
|
||||
expect(r.routeId).toContain("src");
|
||||
expect(r.hops.length).toBeGreaterThan(0);
|
||||
expect(r.estimatedFeeBps).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
it("settles atomically with a deterministic id", async () => {
|
||||
const s = await client.atomicSettle({
|
||||
routeId: "r1",
|
||||
sourceAccountId: "a",
|
||||
destinationAccountId: "b",
|
||||
amount: "1",
|
||||
currencyCode: "USD",
|
||||
reference: "ref-1",
|
||||
});
|
||||
expect(s.status).toBe("settled");
|
||||
expect(s.settlementId).toContain("ref-1");
|
||||
expect(s.completedAt).toBeDefined();
|
||||
});
|
||||
|
||||
it("returns an allow decision by default from ARI", async () => {
|
||||
const d = await client.requestAriDecision({
|
||||
txId: "tx-1",
|
||||
amount: "1",
|
||||
currencyCode: "USD",
|
||||
creator: "0xdead",
|
||||
});
|
||||
expect(d.outcome).toBe("allow");
|
||||
expect(d.txId).toBe("tx-1");
|
||||
expect(d.riskScore).toBeLessThan(1);
|
||||
});
|
||||
|
||||
it("accepts a pacs008 dispatch and echoes the messageId", async () => {
|
||||
const r = await client.dispatchPacs008({
|
||||
messageId: "msg-1",
|
||||
creationDateTime: "2026-01-01T00:00:00Z",
|
||||
debtor: { name: "Acme", bic: "ACMEUS33", account: "1" },
|
||||
creditor: { name: "Widget", bic: "WDGTGB22", account: "2" },
|
||||
amount: "100",
|
||||
currencyCode: "USD",
|
||||
});
|
||||
expect(r.status).toBe("accepted");
|
||||
expect(r.messageId).toBe("msg-1");
|
||||
});
|
||||
|
||||
it("returns a settled status from a synthetic settlementId", async () => {
|
||||
const s = await client.getSettlementStatus("stlm-99");
|
||||
expect(s.status).toBe("settled");
|
||||
expect(s.legs.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("dbisCore.createDbisCoreClient() — live mode (stubbed fetch)", () => {
|
||||
function makeFetch(
|
||||
record: (url: string, init: RequestInit) => void,
|
||||
responseBody: unknown,
|
||||
status = 200,
|
||||
): typeof fetch {
|
||||
return (async (input: string | URL | Request, init?: RequestInit) => {
|
||||
record(String(input), init ?? {});
|
||||
return new Response(JSON.stringify(responseBody), {
|
||||
status,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
}) as typeof fetch;
|
||||
}
|
||||
|
||||
it("reports live mode when baseUrl is set", () => {
|
||||
const client = createDbisCoreClient({
|
||||
baseUrl: "http://dbis.example.test",
|
||||
fetchImpl: makeFetch(
|
||||
() => undefined,
|
||||
{ accountId: "a", currency: "USD", available: "0", held: "0", asOf: "" },
|
||||
),
|
||||
});
|
||||
expect(client.mode).toBe("live");
|
||||
});
|
||||
|
||||
it("hits GET /api/accounts/:id/balance with the API key header", async () => {
|
||||
const calls: { url: string; headers: Record<string, string>; method?: string }[] = [];
|
||||
const client = createDbisCoreClient({
|
||||
baseUrl: "http://dbis.example.test",
|
||||
apiKey: "k-secret",
|
||||
fetchImpl: makeFetch(
|
||||
(url, init) => {
|
||||
calls.push({
|
||||
url,
|
||||
method: init.method,
|
||||
headers: (init.headers ?? {}) as Record<string, string>,
|
||||
});
|
||||
},
|
||||
{
|
||||
accountId: "a42",
|
||||
currency: "USD",
|
||||
available: "500",
|
||||
held: "10",
|
||||
asOf: "2026-01-01T00:00:00Z",
|
||||
},
|
||||
),
|
||||
});
|
||||
|
||||
const b = await client.getAccountBalance("a42");
|
||||
expect(b.available).toBe("500");
|
||||
expect(calls).toHaveLength(1);
|
||||
expect(calls[0].url).toBe("http://dbis.example.test/api/accounts/a42/balance");
|
||||
expect(calls[0].method).toBe("GET");
|
||||
expect(calls[0].headers["X-API-Key"]).toBe("k-secret");
|
||||
});
|
||||
|
||||
it("posts a route request and parses the structured response", async () => {
|
||||
const client = createDbisCoreClient({
|
||||
baseUrl: "http://dbis.example.test/",
|
||||
fetchImpl: makeFetch(
|
||||
() => undefined,
|
||||
{
|
||||
routeId: "R1",
|
||||
hops: [{ bankId: "A", latencyMs: 1, feeBps: 2 }],
|
||||
estimatedLatencyMs: 10,
|
||||
estimatedFeeBps: 2,
|
||||
},
|
||||
),
|
||||
});
|
||||
const r = await client.findSettlementRoute({
|
||||
sourceBankId: "A",
|
||||
destinationBankId: "B",
|
||||
amount: "1",
|
||||
currencyCode: "USD",
|
||||
});
|
||||
expect(r.routeId).toBe("R1");
|
||||
expect(r.estimatedFeeBps).toBe(2);
|
||||
});
|
||||
|
||||
it("throws a descriptive error on non-2xx", async () => {
|
||||
const client = createDbisCoreClient({
|
||||
baseUrl: "http://dbis.example.test",
|
||||
fetchImpl: makeFetch(() => undefined, { error: "denied" }, 403),
|
||||
});
|
||||
await expect(client.getAccountBalance("a1")).rejects.toThrow(/HTTP 403/);
|
||||
});
|
||||
|
||||
it("encodes path parameters safely", async () => {
|
||||
const calls: string[] = [];
|
||||
const client = createDbisCoreClient({
|
||||
baseUrl: "http://dbis.example.test",
|
||||
fetchImpl: makeFetch(
|
||||
(url) => {
|
||||
calls.push(url);
|
||||
},
|
||||
{ settlementId: "x", status: "settled", legs: [], lastUpdated: "" },
|
||||
),
|
||||
});
|
||||
await client.getSettlementStatus("weird/id with space");
|
||||
expect(calls[0]).toBe(
|
||||
"http://dbis.example.test/api/isn/settlements/weird%2Fid%20with%20space",
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user