Files
memind/billing.test.mjs
T
john 6f48cad4c2
Memind CI / Test, build, and release guards (push) Successful in 5m1s
fix(billing): apply margin multiplier to subscription quota consumption
Subscription plans now deduct period_tokens_used as upstream tokens ×
marginMultiplier, aligning package quota burn with wallet cost-mode pricing.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 20:31:38 +08:00

94 lines
3.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import test from 'node:test';
import assert from 'node:assert/strict';
import {
computeDeltaCostCents,
computeSubscriptionQuotaTokens,
normalizeTokenState,
} from './billing.mjs';
const config = {
useBackendCost: false,
usdCnyRate: 7.2,
inputCentsPer1k: 2,
outputCentsPer1k: 6,
minBillCents: 1,
};
test('normalizeTokenState reads camelCase fields', () => {
const state = normalizeTokenState({
inputTokens: 10,
outputTokens: 20,
accumulatedInputTokens: 100,
accumulatedOutputTokens: 200,
});
assert.equal(state.accumulatedInputTokens, 100);
assert.equal(state.accumulatedOutputTokens, 200);
});
test('computeDeltaCostCents bills token deltas', () => {
const previous = { lastInputTokens: 1000, lastOutputTokens: 500 };
const current = normalizeTokenState({
accumulatedInputTokens: 2000,
accumulatedOutputTokens: 1500,
});
const cost = computeDeltaCostCents(previous, current, config);
assert.equal(cost, 8);
});
test('computeDeltaCostCents returns zero when no usage delta', () => {
const previous = { lastInputTokens: 1000, lastOutputTokens: 500 };
const current = normalizeTokenState({
accumulatedInputTokens: 1000,
accumulatedOutputTokens: 500,
});
assert.equal(computeDeltaCostCents(previous, current, config), 0);
});
test('computeDeltaCostCents ignores backend USD cost unless explicitly enabled', () => {
const previous = { lastInputTokens: 0, lastOutputTokens: 0, lastAccumulatedCost: 0.01 };
const current = normalizeTokenState({
accumulatedInputTokens: 1000,
accumulatedOutputTokens: 500,
accumulatedCost: 0.02,
});
const rmbConfig = { ...config, useBackendCost: false };
assert.equal(computeDeltaCostCents(previous, current, rmbConfig), 5);
// 成本模式默认 margin=1deltaUsd 0.01 × 7.2 × 100 = 7.2 → ceil = 8
const usdConfig = { ...config, useBackendCost: true, marginMultiplier: 1 };
assert.equal(computeDeltaCostCents(previous, current, usdConfig), 8);
});
test('computeDeltaCostCents applies margin multiplier in cost mode', () => {
const previous = { lastInputTokens: 0, lastOutputTokens: 0, lastAccumulatedCost: 0 };
const current = normalizeTokenState({
accumulatedInputTokens: 1_000_000,
accumulatedOutputTokens: 10_000,
accumulatedCost: 0.25,
});
// deltaUsd 0.25 × 7.2 × 100 × 3 = 540 分(而非 flat token 的 2060 分)
const costConfig = { ...config, useBackendCost: true, marginMultiplier: 3 };
assert.equal(computeDeltaCostCents(previous, current, costConfig), 540);
});
test('computeDeltaCostCents falls back to token path when accumulatedCost missing', () => {
const previous = { lastInputTokens: 0, lastOutputTokens: 0 };
const current = normalizeTokenState({
accumulatedInputTokens: 1000,
accumulatedOutputTokens: 500,
// 上游未回传 accumulatedCost → 即便开启成本模式也回退 token 计费
});
const costConfig = { ...config, useBackendCost: true, marginMultiplier: 3 };
assert.equal(computeDeltaCostCents(previous, current, costConfig), 5);
});
test('computeSubscriptionQuotaTokens scales subscription quota by marginMultiplier', () => {
const billing = { ...config, marginMultiplier: 6 };
assert.equal(computeSubscriptionQuotaTokens(8000, 2000, billing), 60_000);
assert.equal(computeSubscriptionQuotaTokens(100, 0, billing), 600);
});
test('computeSubscriptionQuotaTokens leaves raw tokens when margin is 1', () => {
assert.equal(computeSubscriptionQuotaTokens(8000, 2000, config), 10_000);
assert.equal(computeSubscriptionQuotaTokens(0, 0, config), 0);
});