mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-19 08:28:06 +02:00
132 lines
4 KiB
TypeScript
132 lines
4 KiB
TypeScript
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { initKtxProject, loadKtxProject } from '../src/context/project/project.js';
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { createKtxCliScanConnector } from '../src/local-scan-connectors.js';
|
|
|
|
const bigQueryMock = vi.hoisted(() => ({
|
|
constructorInputs: [] as Array<{
|
|
connectionId: string;
|
|
connection: unknown;
|
|
}>,
|
|
}));
|
|
|
|
vi.mock('../src/connectors/bigquery/connector.js', () => ({
|
|
isKtxBigQueryConnectionConfig: (connection: { driver?: unknown } | undefined) =>
|
|
String(connection?.driver ?? '').toLowerCase() === 'bigquery',
|
|
KtxBigQueryScanConnector: class {
|
|
readonly id: string;
|
|
readonly driver = 'bigquery';
|
|
|
|
constructor(options: { connectionId: string; connection: unknown }) {
|
|
bigQueryMock.constructorInputs.push(options);
|
|
this.id = `bigquery:${options.connectionId}`;
|
|
}
|
|
},
|
|
}));
|
|
|
|
describe('createKtxCliScanConnector', () => {
|
|
let tempDir: string;
|
|
|
|
beforeEach(async () => {
|
|
bigQueryMock.constructorInputs.length = 0;
|
|
tempDir = await mkdtemp(join(tmpdir(), 'ktx-cli-scan-connector-'));
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await rm(tempDir, { recursive: true, force: true });
|
|
});
|
|
|
|
it('creates a native sqlite connector from standalone config', async () => {
|
|
await initKtxProject({ projectDir: tempDir });
|
|
await writeFile(
|
|
join(tempDir, 'ktx.yaml'),
|
|
[
|
|
'connections:',
|
|
' warehouse:',
|
|
' driver: sqlite',
|
|
' path: warehouse.db',
|
|
'',
|
|
].join('\n'),
|
|
'utf-8',
|
|
);
|
|
const project = await loadKtxProject({ projectDir: tempDir });
|
|
|
|
const connector = await createKtxCliScanConnector(project, 'warehouse');
|
|
|
|
expect(connector.id).toBe('sqlite:warehouse');
|
|
expect(connector.driver).toBe('sqlite');
|
|
});
|
|
|
|
it('passes canonical BigQuery YAML scan limits through to the connector', async () => {
|
|
await initKtxProject({ projectDir: tempDir });
|
|
await writeFile(
|
|
join(tempDir, 'ktx.yaml'),
|
|
[
|
|
'connections:',
|
|
' warehouse:',
|
|
' driver: bigquery',
|
|
' dataset_id: analytics',
|
|
' max_bytes_billed: "987654321"',
|
|
' job_timeout_ms: 30000',
|
|
'',
|
|
].join('\n'),
|
|
'utf-8',
|
|
);
|
|
const project = await loadKtxProject({ projectDir: tempDir });
|
|
|
|
const connector = await createKtxCliScanConnector(project, 'warehouse');
|
|
|
|
expect(connector.id).toBe('bigquery:warehouse');
|
|
expect(connector.driver).toBe('bigquery');
|
|
expect(bigQueryMock.constructorInputs).toEqual([
|
|
expect.objectContaining({
|
|
connectionId: 'warehouse',
|
|
connection: expect.objectContaining({
|
|
max_bytes_billed: '987654321',
|
|
job_timeout_ms: 30000,
|
|
}),
|
|
}),
|
|
]);
|
|
expect(bigQueryMock.constructorInputs[0]).not.toHaveProperty('maxBytesBilled');
|
|
});
|
|
|
|
it('rejects daemon-only fallback driver configs at config parse time', async () => {
|
|
await initKtxProject({ projectDir: tempDir });
|
|
await writeFile(
|
|
join(tempDir, 'ktx.yaml'),
|
|
[
|
|
'connections:',
|
|
' warehouse:',
|
|
' driver: duckdb',
|
|
' path: warehouse.duckdb',
|
|
'',
|
|
].join('\n'),
|
|
'utf-8',
|
|
);
|
|
|
|
await expect(loadKtxProject({ projectDir: tempDir })).rejects.toThrow(
|
|
/connections\.warehouse\.driver:.*Invalid discriminator value/,
|
|
);
|
|
});
|
|
|
|
it('rejects connection blocks with no driver field at config parse time', async () => {
|
|
await initKtxProject({ projectDir: tempDir });
|
|
await writeFile(
|
|
join(tempDir, 'ktx.yaml'),
|
|
[
|
|
'connections:',
|
|
' warehouse:',
|
|
' type: postgres',
|
|
' url: postgresql://example/db',
|
|
'',
|
|
].join('\n'),
|
|
'utf-8',
|
|
);
|
|
|
|
await expect(loadKtxProject({ projectDir: tempDir })).rejects.toThrow(
|
|
/connections\.warehouse\.driver:.*Invalid discriminator value/,
|
|
);
|
|
});
|
|
});
|