Files
umami/src/lib/db.test.ts
T

119 lines
4.1 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
// db.ts imports none of these directly, but the mocks keep the test isolated
// from real database clients if that ever changes.
vi.mock('@/lib/prisma', () => ({}));
vi.mock('@/lib/clickhouse', () => ({}));
vi.mock('@/lib/kafka', () => ({}));
let db!: typeof import('./db');
beforeEach(async () => {
vi.resetModules();
db = await import('./db');
});
afterEach(() => {
vi.unstubAllEnvs();
});
describe('getDatabaseType', () => {
test('maps a postgres:// url to postgresql', () => {
expect(db.getDatabaseType('postgres://user:pass@localhost:5432/umami')).toBe('postgresql');
});
test('returns postgresql for a postgresql:// url', () => {
expect(db.getDatabaseType('postgresql://user:pass@localhost:5432/umami')).toBe('postgresql');
});
test('returns the raw scheme for other databases', () => {
expect(db.getDatabaseType('mysql://user:pass@localhost:3306/umami')).toBe('mysql');
});
test('reads process.env.DATABASE_URL by default', () => {
vi.stubEnv('DATABASE_URL', 'postgres://user:pass@localhost:5432/umami');
expect(db.getDatabaseType()).toBe('postgresql');
});
test('falls back to the DATABASE_URL default when called with undefined', () => {
vi.stubEnv('DATABASE_URL', 'postgres://user:pass@localhost:5432/umami');
expect(db.getDatabaseType(undefined)).toBe('postgresql');
});
});
describe('runQuery', () => {
test('runs the clickhouse query when CLICKHOUSE_URL is set', async () => {
vi.stubEnv('CLICKHOUSE_URL', 'http://localhost:8123');
const clickhouse = vi.fn().mockResolvedValue('clickhouse-result');
const prisma = vi.fn();
await expect(db.runQuery({ clickhouse, prisma })).resolves.toBe('clickhouse-result');
expect(clickhouse).toHaveBeenCalledTimes(1);
expect(prisma).not.toHaveBeenCalled();
});
test('prefers the kafka query over clickhouse when both are provided', async () => {
vi.stubEnv('CLICKHOUSE_URL', 'http://localhost:8123');
const kafka = vi.fn().mockResolvedValue('kafka-result');
const clickhouse = vi.fn();
await expect(db.runQuery({ kafka, clickhouse })).resolves.toBe('kafka-result');
expect(kafka).toHaveBeenCalledTimes(1);
expect(clickhouse).not.toHaveBeenCalled();
});
test('runs the prisma query for a postgresql database', async () => {
vi.stubEnv('CLICKHOUSE_URL', '');
vi.stubEnv('DATABASE_URL', 'postgresql://user:pass@localhost:5432/umami');
const prisma = vi.fn().mockResolvedValue('prisma-result');
await expect(db.runQuery({ prisma })).resolves.toBe('prisma-result');
expect(prisma).toHaveBeenCalledTimes(1);
});
test('returns undefined for an unsupported database with no clickhouse', async () => {
vi.stubEnv('CLICKHOUSE_URL', '');
vi.stubEnv('DATABASE_URL', 'mysql://user:pass@localhost:3306/umami');
const prisma = vi.fn();
await expect(db.runQuery({ prisma })).resolves.toBeUndefined();
expect(prisma).not.toHaveBeenCalled();
});
});
describe('isRelationalOnly', () => {
test('returns true for a postgresql database without clickhouse', () => {
vi.stubEnv('CLICKHOUSE_URL', '');
vi.stubEnv('DATABASE_URL', 'postgresql://user:pass@localhost:5432/umami');
expect(db.isRelationalOnly()).toBe(true);
});
test('returns false when clickhouse is enabled', () => {
vi.stubEnv('CLICKHOUSE_URL', 'http://localhost:8123');
vi.stubEnv('DATABASE_URL', 'postgresql://user:pass@localhost:5432/umami');
expect(db.isRelationalOnly()).toBe(false);
});
test('returns false for unsupported non-relational databases', () => {
vi.stubEnv('CLICKHOUSE_URL', '');
vi.stubEnv('DATABASE_URL', 'mysql://user:pass@localhost:3306/umami');
expect(db.isRelationalOnly()).toBe(false);
});
});
describe('BigInt.prototype.toJSON', () => {
test('serializes bigint values as numbers', () => {
expect((BigInt(123) as any).toJSON()).toBe(123);
expect(JSON.stringify({ count: BigInt(42) })).toBe('{"count":42}');
});
});
describe('notImplemented', () => {
test('throws a Not implemented error', () => {
expect(() => db.notImplemented()).toThrow('Not implemented.');
});
});