Initial Commit
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { SurrealAdapter } from "@suaveplan/surrealdb";
|
||||
import {
|
||||
afterAll,
|
||||
beforeAll,
|
||||
describe,
|
||||
expect,
|
||||
it,
|
||||
} from "@suaveplan/testing/runner";
|
||||
import { SurrealDBFixture } from "@suaveplan/testing-integration-surrealdb";
|
||||
import { SurrealImportStore } from "../../src/store/surreal/surreal-import-store.js";
|
||||
import type { ImportJobRecord } from "../../src/types/types.js";
|
||||
|
||||
let fixture: SurrealDBFixture | null = null;
|
||||
let adapter: SurrealAdapter | null = null;
|
||||
|
||||
function makeRecord(
|
||||
id: string,
|
||||
overrides: Partial<ImportJobRecord> = {}
|
||||
): ImportJobRecord {
|
||||
const now = new Date().toISOString();
|
||||
return {
|
||||
id,
|
||||
ownerId: "alice",
|
||||
status: "created",
|
||||
totalRows: 0,
|
||||
processedRows: 0,
|
||||
successCount: 0,
|
||||
errorCount: 0,
|
||||
errors: [],
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
fixture = new SurrealDBFixture();
|
||||
const cfg = await fixture.start();
|
||||
adapter = new SurrealAdapter({
|
||||
url: cfg.url,
|
||||
namespace: cfg.namespace,
|
||||
database: cfg.database,
|
||||
username: cfg.username,
|
||||
password: cfg.password,
|
||||
});
|
||||
await adapter.connect();
|
||||
const surql = await readFile(
|
||||
join(__dirname, "..", "..", "surql", "tables", "import_job.surql"),
|
||||
"utf8"
|
||||
);
|
||||
await adapter.query(surql);
|
||||
}, 180_000);
|
||||
|
||||
afterAll(async () => {
|
||||
if (adapter !== null) {
|
||||
await adapter.disconnect();
|
||||
adapter = null;
|
||||
}
|
||||
if (fixture !== null) {
|
||||
await fixture.stop();
|
||||
fixture = null;
|
||||
}
|
||||
}, 60_000);
|
||||
|
||||
describe("@suaveplan/api-plugin-import — SurrealImportStore integration", () => {
|
||||
it("round-trips a record through the real SurrealDB instance", {
|
||||
timeout: 180_000,
|
||||
}, async () => {
|
||||
if (adapter === null) throw new Error("fixture not ready");
|
||||
const store = new SurrealImportStore({ db: adapter });
|
||||
|
||||
const record = makeRecord("rt1", {
|
||||
metadata: { source: "integration" },
|
||||
errors: [{ row: 1, message: "preflight" }],
|
||||
});
|
||||
await store.create(record);
|
||||
|
||||
const fetched = await store.get("rt1");
|
||||
expect(fetched).toBeDefined();
|
||||
expect(fetched?.ownerId).toBe("alice");
|
||||
expect(fetched?.metadata).toEqual({ source: "integration" });
|
||||
expect(fetched?.errors).toEqual([{ row: 1, message: "preflight" }]);
|
||||
|
||||
await store.update("rt1", {
|
||||
status: "completed",
|
||||
successCount: 1,
|
||||
completedAt: new Date().toISOString(),
|
||||
});
|
||||
const updated = await store.get("rt1");
|
||||
expect(updated?.status).toBe("completed");
|
||||
expect(updated?.successCount).toBe(1);
|
||||
expect(updated?.completedAt).toBeDefined();
|
||||
|
||||
const owned = await store.list({ ownerId: "alice" });
|
||||
expect(owned.some((r) => r.id === "rt1")).toBe(true);
|
||||
|
||||
const completed = await store.list({ status: "completed", limit: 5 });
|
||||
expect(completed.some((r) => r.id === "rt1")).toBe(true);
|
||||
|
||||
expect(await store.delete("rt1")).toBe(true);
|
||||
expect(await store.get("rt1")).toBeUndefined();
|
||||
expect(await store.delete("rt1")).toBe(false);
|
||||
});
|
||||
|
||||
it("update on missing id surfaces the canonical message against a real instance", {
|
||||
timeout: 60_000,
|
||||
}, async () => {
|
||||
if (adapter === null) throw new Error("fixture not ready");
|
||||
const store = new SurrealImportStore({ db: adapter });
|
||||
await expect(
|
||||
store.update("never-existed", { status: "completed" })
|
||||
).rejects.toThrow(/Job "never-existed" not found/);
|
||||
});
|
||||
|
||||
it("migration enables canonical writes and rejects invalid status", {
|
||||
timeout: 60_000,
|
||||
}, async () => {
|
||||
if (adapter === null) throw new Error("fixture not ready");
|
||||
const store = new SurrealImportStore({ db: adapter });
|
||||
// Canonical write succeeds.
|
||||
await store.create(makeRecord("mig-canon"));
|
||||
expect((await store.get("mig-canon"))?.status).toBe("created");
|
||||
|
||||
// Direct SurQL with a bogus status MUST be rejected by the
|
||||
// SCHEMAFULL constraint — this proves the migration is in
|
||||
// effect.
|
||||
await expect(
|
||||
adapter.query(
|
||||
`CREATE import_job:mig-bogus SET owner_id = 'alice', status = 'bogus', total_rows = 0, processed_rows = 0, success_count = 0, error_count = 0, errors = [], created_at = time::now(), updated_at = time::now()`
|
||||
)
|
||||
).rejects.toBeDefined();
|
||||
|
||||
await store.delete("mig-canon");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user