Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 51 additions & 28 deletions apps/web/src/routers/usage-analytics-router.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
jest.mock('@/lib/redis', () => ({ redisClient: {} }));

import { PgDialect } from 'drizzle-orm/pg-core';
import {
CostSourceSchema,
MAX_SCOPE_ORGANIZATION_IDS,
Expand All @@ -21,26 +22,38 @@ const PARENT_ORG = '11111111-1111-4111-8111-111111111111';
const CHILD_ORG_A = '22222222-2222-4222-8222-222222222222';
const CHILD_ORG_B = '33333333-3333-4333-8333-333333333333';

const dialect = new PgDialect();

function compile(builder: WhereBuilder) {
const sql = builder.toSQL();
if (!sql) return { sql: '', params: [] as unknown[] };
const compiled = dialect.sqlToQuery(sql);
return { sql: compiled.sql, params: compiled.params };
}

function scopeSql(rawFilters: Record<string, unknown>) {
const filters = UsageAnalyticsFiltersSchema.parse({ ...baseFilters, ...rawFilters });
const where = new WhereBuilder();
buildScopeConditions(where, filters, CTX_USER);
return { sql: where.sql(), bindings: where.bindings.map(b => b.value) };
return compile(where);
}

describe('usage analytics cost source', () => {
it('defaults to billable cost for existing clients', () => {
expect(UsageAnalyticsFiltersSchema.parse(baseFilters).costSource).toBe('cost');
expect(costColumnFor('cost')).toBe('total_cost_microdollars');
expect(costSumExprSql('cost')).toBe('COALESCE(SUM(total_cost_microdollars), 0)');
expect(dialect.sqlToQuery(costColumnFor('cost')).sql).toContain('cost');
expect(dialect.sqlToQuery(costSumExprSql('cost')).sql).toMatch(/COALESCE\(SUM\(/);
expect(dialect.sqlToQuery(costSumExprSql('cost')).sql).toContain('cost');
expect(dialect.sqlToQuery(costSumExprSql('cost')).sql).not.toContain('market_cost');
});

it('uses the estimated market cost rollup when selected', () => {
it('uses the estimated market cost when selected', () => {
expect(
UsageAnalyticsFiltersSchema.parse({ ...baseFilters, costSource: 'market' }).costSource
).toBe('market');
expect(costColumnFor('market')).toBe('total_market_cost_microdollars');
expect(costSumExprSql('market')).toBe('COALESCE(SUM(total_market_cost_microdollars), 0)');
expect(dialect.sqlToQuery(costColumnFor('market')).sql).toContain('market_cost');
expect(dialect.sqlToQuery(costSumExprSql('market')).sql).toMatch(/COALESCE\(SUM\(/);
expect(dialect.sqlToQuery(costSumExprSql('market')).sql).toContain('market_cost');
});

it('rejects arbitrary cost source values', () => {
Expand All @@ -52,53 +65,63 @@ describe('usage analytics cost source', () => {

describe('usage analytics scope conditions', () => {
it('pins a single org to the caller in self view', () => {
const { sql, bindings } = scopeSql({ organizationId: PARENT_ORG, viewAs: 'self' });
expect(sql).toContain('organization_id = ?');
expect(sql).toContain('kilo_user_id = ?');
expect(bindings).toEqual([PARENT_ORG, CTX_USER]);
const { sql, params } = scopeSql({ organizationId: PARENT_ORG, viewAs: 'self' });
expect(sql).toContain('organization_id');
expect(sql).toContain('kilo_user_id');
expect(sql).not.toContain('IS NULL');
Comment thread
chrarnoldus marked this conversation as resolved.
Outdated
expect(params).toEqual([PARENT_ORG, CTX_USER]);
});

it('does not pin to the caller in org-wide view', () => {
const { sql, bindings } = scopeSql({ organizationId: PARENT_ORG, viewAs: 'org-wide' });
expect(sql).toContain('organization_id = ?');
const { sql, params } = scopeSql({ organizationId: PARENT_ORG, viewAs: 'org-wide' });
expect(sql).toContain('organization_id');
expect(sql).not.toContain('kilo_user_id');
expect(bindings).toEqual([PARENT_ORG]);
expect(params).toEqual([PARENT_ORG]);
});

it('aggregates org-wide across all orgs when organizationIds is set', () => {
const { sql, bindings } = scopeSql({
const { sql, params } = scopeSql({
organizationIds: [PARENT_ORG, CHILD_ORG_A, CHILD_ORG_B],
});
expect(sql).toContain('organization_id IN (?, ?, ?)');
expect(sql).toContain('organization_id');
expect(sql).toMatch(/in/i);
expect(sql).not.toContain('kilo_user_id');
expect(bindings).toEqual([PARENT_ORG, CHILD_ORG_A, CHILD_ORG_B]);
expect(params).toEqual([PARENT_ORG, CHILD_ORG_A, CHILD_ORG_B]);
});

it('honors explicit user filters in the all-orgs aggregate', () => {
const { sql, bindings } = scopeSql({
const { sql, params } = scopeSql({
organizationIds: [PARENT_ORG, CHILD_ORG_A],
userIds: [CTX_USER],
});
expect(sql).toContain('organization_id IN (?, ?)');
expect(sql).toContain('kilo_user_id IN (?)');
expect(bindings).toEqual([PARENT_ORG, CHILD_ORG_A, CTX_USER]);
expect(sql).toContain('organization_id');
expect(sql).toContain('kilo_user_id');
expect(params).toEqual([PARENT_ORG, CHILD_ORG_A, CTX_USER]);
});

it('takes precedence over a single organizationId', () => {
const { sql, bindings } = scopeSql({
const { sql, params } = scopeSql({
organizationId: CHILD_ORG_B,
organizationIds: [PARENT_ORG, CHILD_ORG_A],
});
expect(sql).toContain('organization_id IN (?, ?)');
expect(bindings).toEqual([PARENT_ORG, CHILD_ORG_A]);
expect(sql).toContain('organization_id');
expect(params).toEqual([PARENT_ORG, CHILD_ORG_A]);
});

it('falls back to personal scope with no org', () => {
const { sql, bindings } = scopeSql({});
expect(sql).toContain('kilo_user_id = ?');
expect(sql).toContain('organization_id = ?');
// personal-only pins kilo_user_id to caller and org to the empty-string sentinel
expect(bindings).toEqual([CTX_USER, '']);
const { sql, params } = scopeSql({});
expect(sql).toContain('kilo_user_id');
expect(sql).toContain('organization_id');
// personal-only pins kilo_user_id to caller and organization_id IS NULL
expect(sql).toMatch(/is null/i);
expect(params).toEqual([CTX_USER]);
});

it('includes org-attributed rows when personalScope is include-orgs', () => {
const { sql, params } = scopeSql({ personalScope: 'include-orgs' });
expect(sql).toContain('kilo_user_id');
expect(sql).not.toContain('organization_id');
expect(params).toEqual([CTX_USER]);
});

it('caps organizationIds at the boundary to bound auth fan-out', () => {
Expand Down
Loading