import test from 'node:test'; import assert from 'node:assert/strict'; import { billingAdminConfigInternals, createBillingAdminConfigService, toComputeBillingConfig, toCostEstimateConfig, } from './billing-admin-config.mjs'; function createMemoryPool(initialRows = []) { const rows = new Map( initialRows.map((row) => [row.config_scope, { ...row }]), ); return { async query(sql, params = []) { if (/CREATE TABLE/i.test(sql)) return [{}, undefined]; if (/SELECT/i.test(sql)) { const scope = params[0]; const row = rows.get(scope); return [row ? [row] : [], undefined]; } if (/INSERT INTO/i.test(sql)) { const [scope, configJson, updatedBy, updatedAt] = params; rows.set(scope, { config_scope: scope, config_json: configJson, updated_by: updatedBy, updated_at: updatedAt, }); return [{ affectedRows: 1 }, undefined]; } return [{}, undefined]; }, _rows: rows, }; } test('mergePatch validates margin and FX', () => { const next = billingAdminConfigInternals.mergePatch( billingAdminConfigInternals.defaultConfigShape({}), { marginMultiplier: 1.5, usdCnyRate: 7.1, useBackendCost: true, }, {}, ); assert.equal(next.marginMultiplier, 1.5); assert.equal(next.usdCnyRate, 7.1); assert.equal(next.useBackendCost, true); }); test('toComputeBillingConfig maps admin shape', () => { const compute = toComputeBillingConfig({ useBackendCost: true, usdCnyRate: 7.2, marginMultiplier: 1.2, inputCentsPer1k: 2, outputCentsPer1k: 6, minBillCents: 1, }); assert.deepEqual(compute, { useBackendCost: true, usdCnyRate: 7.2, marginMultiplier: 1.2, inputCentsPer1k: 2, outputCentsPer1k: 6, minBillCents: 1, }); }); test('toCostEstimateConfig disables when cost mode off', () => { const estimate = toCostEstimateConfig({ useBackendCost: false, costEstimateFromTokens: true, costEstimateInputUsdPer1M: 0.27, costEstimateOutputUsdPer1M: 1.1, }); assert.equal(estimate.enabled, false); }); test('admin-db config wins over env for effective billing', async () => { const pool = createMemoryPool(); const env = { H5_USE_BACKEND_COST: '1', H5_USD_CNY_RATE: '7.2', H5_MARGIN_MULTIPLIER: '1.2', }; const service = createBillingAdminConfigService(pool, { env, cacheTtlMs: 0 }); await service.updateAdminConfig( { marginMultiplier: 2, usdCnyRate: 7.5, useBackendCost: true }, { updatedBy: 'admin-1' }, ); const effective = await service.getEffectiveBillingConfig(); assert.equal(effective.marginMultiplier, 2); assert.equal(effective.usdCnyRate, 7.5); const admin = await service.getAdminConfig(); assert.equal(admin.source, 'admin-db'); assert.equal(admin.updatedBy, 'admin-1'); }); test('H5_BILLING_CONFIG_SOURCE=env locks admin writes', async () => { const pool = createMemoryPool(); const service = createBillingAdminConfigService(pool, { env: { H5_BILLING_CONFIG_SOURCE: 'env', H5_MARGIN_MULTIPLIER: '1.2' }, cacheTtlMs: 0, }); await assert.rejects( () => service.updateAdminConfig({ marginMultiplier: 9 }), /H5_BILLING_CONFIG_SOURCE=env/, ); const admin = await service.getAdminConfig(); assert.equal(admin.source, 'env-override'); assert.equal(admin.config.marginMultiplier, 1.2); }); test('env fallback used when no admin row', async () => { const pool = createMemoryPool(); const service = createBillingAdminConfigService(pool, { env: { H5_USE_BACKEND_COST: '1', H5_MARGIN_MULTIPLIER: '1.2', H5_USD_CNY_RATE: '7.2', }, cacheTtlMs: 0, }); const admin = await service.getAdminConfig(); assert.equal(admin.source, 'env'); assert.equal(admin.config.marginMultiplier, 1.2); assert.equal(admin.config.useBackendCost, true); });