mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
2253d05618
Remove the nested v3/ subdirectory by moving all active source code, tests, configs, and assets directly to the project root. Archive v2/ (dead code, 847MB) to v2-archive.tar.gz. Key changes: - Move v3/src/ → src/, v3/tests/ → tests/, v3/packages/ → packages/ - Move v3/tsconfig.json, v3/vitest.config.ts to root - Merge v3/package.json into root package.json (ESM, scripts, deps, exports) - Merge v3/scripts/ into scripts/, v3/implementation/ into docs/implementation/ - Update all CI workflows to remove "cd v3 &&" and v3/ path prefixes - Fix all init installer path resolution (3-level-up → 2-level-up) - Fix hooks to use "node ./dist/cli/bundle.js" instead of bare "aqe" - Update settings.json ADR/DDD directories to docs/implementation/ - Fix helper scripts (statusline, adr-compliance, ddd-tracker, guidance-hooks) - Update 58 agent definitions: aqe/v3/ → aqe/ memory namespaces - Update 15 guidance shards: v3/src/ → src/ path references - Fix sync interfaces: remove v3/ and v2/ path references - Fix test path calculations (process.cwd() + '..' no longer needed) - Fix flaky perf test threshold (500ms → 1000ms for CI environments) - Fix complexity-analyzer test to match ADR-051 keyword-based eligibility Build passes, 17,901 tests pass, CLI and MCP bundles verified. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
196 lines
6.1 KiB
TypeScript
196 lines
6.1 KiB
TypeScript
/**
|
|
* PostgreSQL Integration Tests
|
|
*
|
|
* Requires a real Postgres instance. Skipped when POSTGRES_URL is not set.
|
|
*
|
|
* Local:
|
|
* docker compose -f v3/tests/docker-compose.test.yml up -d
|
|
* POSTGRES_URL=postgresql://aqe_test:aqe_test@localhost:15432/aqe_test npx vitest run tests/integration/sync/
|
|
*
|
|
* CI: GitHub Actions `services:` provides the Postgres instance automatically.
|
|
*/
|
|
|
|
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
|
|
|
const POSTGRES_URL = process.env.POSTGRES_URL;
|
|
|
|
// Graceful skip when no Postgres is available
|
|
const describeWithPg = POSTGRES_URL ? describe : describe.skip;
|
|
|
|
/** Dynamically load pg so the test file itself can be imported without pg present */
|
|
async function loadPg() {
|
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
const pg = await import('pg');
|
|
const Client = pg.default?.Client ?? pg.Client;
|
|
return Client as typeof import('pg').Client;
|
|
}
|
|
|
|
describeWithPg('PostgreSQL Integration (real DB)', () => {
|
|
let Client: typeof import('pg').Client;
|
|
let client: InstanceType<typeof import('pg').Client>;
|
|
|
|
beforeAll(async () => {
|
|
Client = await loadPg();
|
|
client = new Client({ connectionString: POSTGRES_URL });
|
|
await client.connect();
|
|
|
|
// Create a test table
|
|
await client.query(`
|
|
CREATE TABLE IF NOT EXISTS integration_test (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
score DOUBLE PRECISION,
|
|
metadata JSONB,
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
)
|
|
`);
|
|
|
|
// Clean slate
|
|
await client.query('TRUNCATE integration_test');
|
|
});
|
|
|
|
afterAll(async () => {
|
|
if (client) {
|
|
await client.query('DROP TABLE IF EXISTS integration_test');
|
|
await client.end();
|
|
}
|
|
});
|
|
|
|
it('should connect and run a basic query', async () => {
|
|
const result = await client.query('SELECT 1 AS val');
|
|
expect(result.rows[0].val).toBe(1);
|
|
});
|
|
|
|
it('should insert and retrieve records', async () => {
|
|
await client.query(
|
|
`INSERT INTO integration_test (id, name, score) VALUES ($1, $2, $3)`,
|
|
['rec-1', 'Test Record', 0.95]
|
|
);
|
|
|
|
const result = await client.query(
|
|
'SELECT * FROM integration_test WHERE id = $1',
|
|
['rec-1']
|
|
);
|
|
|
|
expect(result.rows.length).toBe(1);
|
|
expect(result.rows[0].name).toBe('Test Record');
|
|
expect(result.rows[0].score).toBeCloseTo(0.95);
|
|
});
|
|
|
|
it('should handle upsert via ON CONFLICT', async () => {
|
|
// Insert initial
|
|
await client.query(
|
|
`INSERT INTO integration_test (id, name, score)
|
|
VALUES ($1, $2, $3)
|
|
ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, score = EXCLUDED.score`,
|
|
['rec-upsert', 'Original', 0.5]
|
|
);
|
|
|
|
// Upsert with updated values
|
|
await client.query(
|
|
`INSERT INTO integration_test (id, name, score)
|
|
VALUES ($1, $2, $3)
|
|
ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, score = EXCLUDED.score`,
|
|
['rec-upsert', 'Updated', 0.99]
|
|
);
|
|
|
|
const result = await client.query(
|
|
'SELECT * FROM integration_test WHERE id = $1',
|
|
['rec-upsert']
|
|
);
|
|
|
|
expect(result.rows[0].name).toBe('Updated');
|
|
expect(result.rows[0].score).toBeCloseTo(0.99);
|
|
});
|
|
|
|
it('should handle transactions (commit)', async () => {
|
|
await client.query('BEGIN');
|
|
await client.query(
|
|
`INSERT INTO integration_test (id, name, score) VALUES ($1, $2, $3)`,
|
|
['rec-tx-commit', 'Committed', 1.0]
|
|
);
|
|
await client.query('COMMIT');
|
|
|
|
const result = await client.query(
|
|
'SELECT * FROM integration_test WHERE id = $1',
|
|
['rec-tx-commit']
|
|
);
|
|
expect(result.rows.length).toBe(1);
|
|
});
|
|
|
|
it('should handle transactions (rollback)', async () => {
|
|
await client.query('BEGIN');
|
|
await client.query(
|
|
`INSERT INTO integration_test (id, name, score) VALUES ($1, $2, $3)`,
|
|
['rec-tx-rollback', 'Should Not Exist', 0.0]
|
|
);
|
|
await client.query('ROLLBACK');
|
|
|
|
const result = await client.query(
|
|
'SELECT * FROM integration_test WHERE id = $1',
|
|
['rec-tx-rollback']
|
|
);
|
|
expect(result.rows.length).toBe(0);
|
|
});
|
|
|
|
it('should store and retrieve JSONB metadata', async () => {
|
|
const metadata = { tags: ['test', 'integration'], nested: { key: 'value' } };
|
|
|
|
await client.query(
|
|
`INSERT INTO integration_test (id, name, metadata)
|
|
VALUES ($1, $2, $3::jsonb)`,
|
|
['rec-jsonb', 'JSONB Test', JSON.stringify(metadata)]
|
|
);
|
|
|
|
const result = await client.query(
|
|
'SELECT metadata FROM integration_test WHERE id = $1',
|
|
['rec-jsonb']
|
|
);
|
|
|
|
expect(result.rows[0].metadata).toEqual(metadata);
|
|
});
|
|
|
|
it('should handle batch inserts', async () => {
|
|
const values: string[] = [];
|
|
const params: unknown[] = [];
|
|
const batchSize = 50;
|
|
|
|
for (let i = 0; i < batchSize; i++) {
|
|
const offset = i * 3;
|
|
values.push(`($${offset + 1}, $${offset + 2}, $${offset + 3})`);
|
|
params.push(`batch-${i}`, `Batch Record ${i}`, i / batchSize);
|
|
}
|
|
|
|
await client.query(
|
|
`INSERT INTO integration_test (id, name, score) VALUES ${values.join(', ')}
|
|
ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, score = EXCLUDED.score`,
|
|
params
|
|
);
|
|
|
|
const result = await client.query(
|
|
`SELECT COUNT(*) AS cnt FROM integration_test WHERE id LIKE 'batch-%'`
|
|
);
|
|
expect(Number(result.rows[0].cnt)).toBe(batchSize);
|
|
});
|
|
|
|
it('should handle TIMESTAMPTZ serialization', async () => {
|
|
const now = new Date();
|
|
|
|
await client.query(
|
|
`INSERT INTO integration_test (id, name, created_at)
|
|
VALUES ($1, $2, $3)
|
|
ON CONFLICT (id) DO UPDATE SET created_at = EXCLUDED.created_at`,
|
|
['rec-ts', 'Timestamp Test', now.toISOString()]
|
|
);
|
|
|
|
const result = await client.query(
|
|
'SELECT created_at FROM integration_test WHERE id = $1',
|
|
['rec-ts']
|
|
);
|
|
|
|
const stored = new Date(result.rows[0].created_at);
|
|
// Allow 1 second tolerance for rounding
|
|
expect(Math.abs(stored.getTime() - now.getTime())).toBeLessThan(1000);
|
|
});
|
|
});
|