Ctrl K
ComunidadGuías…

test/dashboard-account-requests.test.js

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// Per-account request history: the ring in auth.js and its dashboard route.
//
// The feature exists because neither existing request log can attribute a call
// to an account: stats.recentRequests stores the upstream KEY at most chat call
// sites, and request-ring rows are keyed by a caller hash. These tests pin the
// ring's honesty rules — newest-first, bounded, per-account, billed-only — and
// the route contract (auth gate inherited, 404 unknown, no key material).

import { afterEach, beforeEach, describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { config } from '../src/config.js';
import {
  ACCOUNT_REQUEST_CAP,
  __resetAccountRequestsForTest,
  addAccountByKey,
  configureBindHost,
  forgetAccountRequests,
  getAccountRequests,
  recordAccountAttempt,
  recordAccountRequest,
  recordAccountSpend,
  removeAccount,
  _resetLockoutForTests,
} from '../src/auth.js';
import { finalizeConnectAccount } from '../src/handlers/chat.js';
import { handleDashboardApi } from '../src/dashboard/api.js';
import { _resetRuntimeConfigForTests } from '../src/runtime-config.js';

const originalDashboardPassword = config.dashboardPassword;
const originalApiKey = config.apiKey;
const created = new Set();

function fakeRes() {
  return {
    statusCode: 0,
    headers: {},
    body: '',
    writeHead(status, headers) { this.statusCode = status; this.headers = headers || {}; },
    end(chunk) { this.body += chunk ? String(chunk) : ''; },
    json() { return this.body ? JSON.parse(this.body) : null; },
  };
}

function req(path, headers = {}) {
  return { url: `/dashboard/api${path}`, headers, socket: { remoteAddress: '127.0.0.1' } };
}

function authed(path, extra = {}) {
  return req(path, { 'x-dashboard-password': 'dash-secret', ...extra });
}

function addAccount(label) {
  const account = addAccountByKey(`req-key-${label}-${Date.now()}-${Math.random().toString(16).slice(2)}`, label);
  created.add(account.id);
  return account;
}

beforeEach(() => {
  __resetAccountRequestsForTest();
});

afterEach(() => {
  for (const id of created) removeAccount(id);
  created.clear();
  __resetAccountRequestsForTest();
  _resetRuntimeConfigForTests();
  _resetLockoutForTests();
  configureBindHost('0.0.0.0');
  config.dashboardPassword = originalDashboardPassword;
  config.apiKey = originalApiKey;
});

describe('account request ring', () => {
  it('returns newest first and keeps the whole-window totals', () => {
    const acct = { id: 'ring-acct-1' };
    recordAccountRequest(acct, { model: 'a', usage: { prompt_tokens: 1, completion_tokens: 2 }, creditCost: 0.5, acuCost: 0.1, now: 100 });
    recordAccountRequest(acct, { model: 'b', usage: { prompt_tokens: 3, completion_tokens: 4 }, creditCost: 1, acuCost: 0.2, now: 200 });

    const page = getAccountRequests('ring-acct-1', { limit: 1 });
    assert.deepEqual(page.items.map((r) => r.model), ['b']);
    assert.equal(page.total, 2, 'total is the ring size, not the page size');
    assert.equal(page.billed, 2);
    assert.equal(page.failed, 0);
    assert.equal(page.items.length, 1);
    assert.equal(page.items[0].billed, true, 'recordAccountRequest is billed by default');
    assert.deepEqual(page.summary, {
      requests: 2,
      promptTokens: 4,
      completionTokens: 6,
      totalTokens: 10,
      credit: 1.5,
      acu: 0.30000000000000004,
      lastTs: 200,
    });
  });

  it('is bounded and drops the oldest row past the cap', () => {
    for (let i = 0; i < ACCOUNT_REQUEST_CAP + 3; i++) {
      recordAccountRequest({ id: 'ring-cap' }, { model: `m${i}`, now: i });
    }
    const page = getAccountRequests('ring-cap', { limit: ACCOUNT_REQUEST_CAP });
    assert.equal(page.total, ACCOUNT_REQUEST_CAP);
    assert.equal(page.items[0].model, `m${ACCOUNT_REQUEST_CAP + 2}`, 'newest row survives');
    assert.equal(page.items.at(-1).model, 'm3', 'the three oldest rows were evicted');
  });

  // P2 (wave-7 review): failed attempts and billed rows used to compete for the
  // same 100 slots, so a failure burst could evict every billed row and the
  // summary — recomputed from survivors — read as "this account served
  // nothing". Billed rows are the money truth: they are never evicted by a
  // failure.
  it('a failure burst cannot evict the billed window or zero its summary', () => {
    const acct = { id: 'ring-billed-reserve' };
    recordAccountRequest(acct, {
      model: 'claude-sonnet-4',
      usage: { prompt_tokens: 5, completion_tokens: 3 },
      creditCost: 2,
      acuCost: 1,
      now: 1,
    });
    const before = getAccountRequests(acct.id).summary;

    for (let i = 0; i < ACCOUNT_REQUEST_CAP; i++) {
      recordAccountAttempt(acct, { model: 'claude-sonnet-4', outcome: 'rate_limited', status: 429, now: 10 + i });
    }

    const page = getAccountRequests(acct.id, { limit: ACCOUNT_REQUEST_CAP });
    assert.equal(page.billed, 1, 'the billed row survives a full failure burst');
    assert.equal(page.failed, ACCOUNT_REQUEST_CAP - 1, 'failures share the window but stay bounded');
    assert.equal(page.total, ACCOUNT_REQUEST_CAP);
    assert.deepEqual(page.summary, before, 'the billed summary is byte-for-byte unchanged');
    assert.equal(page.items.filter((r) => r.billed === true).length, 1);
  });

  it('drops an incoming failure rather than evicting a billed row from a full billed window', () => {
    const acct = { id: 'ring-billed-full' };
    for (let i = 0; i < ACCOUNT_REQUEST_CAP; i++) {
      recordAccountRequest(acct, { model: `m${i}`, usage: { prompt_tokens: 1 }, now: i });
    }

    recordAccountAttempt(acct, { model: 'm0', outcome: 'rate_limited', status: 429, now: 1000 });

    const page = getAccountRequests(acct.id, { limit: ACCOUNT_REQUEST_CAP });
    assert.equal(page.billed, ACCOUNT_REQUEST_CAP);
    assert.equal(page.failed, 0, 'the failure had no slot it could take without evicting a billed row');
    assert.equal(page.total, ACCOUNT_REQUEST_CAP);
    assert.equal(page.items[0].model, `m${ACCOUNT_REQUEST_CAP - 1}`, 'the newest billed row is still newest');
    assert.equal(page.items.at(-1).model, 'm0', 'no billed row was evicted');
    assert.equal(page.summary.requests, ACCOUNT_REQUEST_CAP);
  });

  it('a newer billed row evicts the oldest failure before any billed row', () => {
    const acct = { id: 'ring-failure-first' };
    for (let i = 0; i < ACCOUNT_REQUEST_CAP - 1; i++) {
      recordAccountRequest(acct, { model: `m${i}`, now: i });
    }
    recordAccountAttempt(acct, { model: 'fail', outcome: 'upstream_error', status: 502, now: 500 });

    recordAccountRequest(acct, { model: 'newest', now: 600 });

    const page = getAccountRequests(acct.id, { limit: ACCOUNT_REQUEST_CAP });
    assert.equal(page.billed, ACCOUNT_REQUEST_CAP);
    assert.equal(page.failed, 0);
    assert.equal(page.items[0].model, 'newest');
    assert.ok(!page.items.some((r) => r.model === 'fail'), 'the failure was the row evicted');
    assert.equal(page.items.at(-1).model, 'm0', 'the oldest billed row was not displaced');
  });

  it('keeps accounts isolated and forgets a removed account', () => {
    recordAccountRequest({ id: 'iso-a' }, { model: 'a' });
    recordAccountRequest({ id: 'iso-b' }, { model: 'b' });
    assert.deepEqual(getAccountRequests('iso-a').items.map((r) => r.model), ['a']);
    assert.deepEqual(getAccountRequests('iso-b').items.map((r) => r.model), ['b']);
    forgetAccountRequests('iso-a');
    assert.equal(getAccountRequests('iso-a').total, 0);
    assert.equal(getAccountRequests('iso-b').total, 1);
  });

  it('clamps hostile usage instead of storing negatives', () => {
    recordAccountRequest({ id: 'clamp' }, {
      model: 42,
      usage: { prompt_tokens: -5, completion_tokens: 'x', total_tokens: -1 },
      creditCost: -3,
      acuCost: -1,
    });
    const row = getAccountRequests('clamp').items[0];
    assert.equal(row.model, '', 'a non-string model is not coerced into copy');
    assert.equal(row.promptTokens, 0);
    assert.equal(row.completionTokens, 0);
    assert.equal(row.totalTokens, 0);
    assert.equal(row.credit, 0);
    assert.equal(row.acu, 0);
  });

  it('only billed rows enter the billed summary; failures are counted separately', () => {
    const acct = addAccount('spend-attribution');
    recordAccountSpend(acct.apiKey, { prompt_tokens: 10, completion_tokens: 5 }, { creditCost: 2, acuCost: 0.25, model: 'claude-sonnet-4' });
    const before = getAccountRequests(acct.id);
    recordAccountAttempt({ id: acct.id }, { model: 'claude-sonnet-4', outcome: 'rate_limited', status: 429, attemptId: 'attempt-7' });
    // A request against a key that belongs to no account must not create a row,
    // and a failure with no account id belongs to nobody.
    recordAccountSpend('not-an-account-key', { prompt_tokens: 1 }, { model: 'x' });
    recordAccountAttempt(null, { model: 'x', outcome: 'upstream_error', status: 502 });

    const page = getAccountRequests(acct.id);
    assert.equal(page.total, 2, 'the failed attempt occupies a retained slot');
    assert.equal(page.billed, 1);
    assert.equal(page.failed, 1);
    // The billed summary is byte-for-byte what the success alone produced: the
    // failed row must not move a single counter or lastTs.
    assert.deepEqual(page.summary, before.summary, 'a failed row must not move the billed summary');
    assert.deepEqual(page.summary, {
      requests: 1,
      promptTokens: 10,
      completionTokens: 5,
      totalTokens: 15,
      credit: 2,
      acu: 0.25,
      lastTs: before.summary.lastTs,
    });
    const [failedRow, billedRow] = page.items;
    assert.equal(billedRow.model, 'claude-sonnet-4');
    assert.equal(billedRow.billed, true);
    assert.equal(failedRow.billed, false);
    assert.equal(failedRow.outcome, 'rate_limited');
    assert.equal(failedRow.status, 429);
    assert.equal(failedRow.attemptId, 'attempt-7');
    assert.equal(failedRow.totalTokens, 0);
    assert.equal(failedRow.promptTokens, 0);
    assert.equal(failedRow.completionTokens, 0);
    assert.equal(failedRow.credit, 0);
    assert.equal(failedRow.acu, 0);
  });

  it('refuses an unattributed failure instead of inventing an owner', () => {
    assert.equal(recordAccountAttempt(null, { model: 'x' }), null);
    assert.equal(recordAccountAttempt({}, { model: 'x' }), null);
    assert.equal(recordAccountAttempt({ id: '' }, { model: 'x' }), null);
    assert.equal(getAccountRequests('x').total, 0);
  });

  it('records CONNECT failure exits against the account that was attempted', () => {
    const acct = addAccount('connect-failures');
    acct.reservationTimestamp = 4242;
    const base = { model: 'swe-2', startTime: Date.now() };

    finalizeConnectAccount(acct, { ...base, err: Object.assign(new Error('rate limited'), { code: 'RATE_LIMITED' }) });
    finalizeConnectAccount(acct, { ...base, err: Object.assign(new Error('socket reset'), { code: 'ECONNRESET' }) });
    finalizeConnectAccount(acct, { ...base, err: Object.assign(new Error('client gone'), { name: 'AbortError' }), aborted: true });

    const page = getAccountRequests(acct.id);
    assert.equal(page.billed, 0);
    assert.equal(page.failed, 3);
    assert.deepEqual(page.items.map((r) => [r.outcome, r.status]), [
      ['client_abort', 499],
      ['connection_error', 502],
      ['rate_limited', 429],
    ]);
    assert.equal(page.items[0].attemptId, '4242');
    assert.equal(page.items.every((r) => r.billed === false && r.credit === 0 && r.totalTokens === 0), true);
    assert.equal(page.summary.requests, 0);
    assert.equal(page.summary.totalTokens, 0);
    assert.equal(page.summary.credit, 0);
  });

  it('drops the ring when the account is removed', () => {
    const acct = addAccount('ring-removal');
    recordAccountSpend(acct.apiKey, { prompt_tokens: 1 }, { model: 'm' });
    assert.equal(getAccountRequests(acct.id).total, 1);
    removeAccount(acct.id);
    created.delete(acct.id);
    assert.equal(getAccountRequests(acct.id).total, 0);
  });
});

describe('GET /accounts/:id/requests', () => {
  it('fails closed without dashboard auth', async () => {
    _resetRuntimeConfigForTests();
    config.dashboardPassword = 'dash-secret';
    config.apiKey = '';
    configureBindHost('0.0.0.0');

    const res = fakeRes();
    await handleDashboardApi('GET', '/accounts/any/requests', {}, req('/accounts/any/requests'), res);
    assert.equal(res.statusCode, 401);
  });

  it('404s an unknown account', async () => {
    _resetRuntimeConfigForTests();
    config.dashboardPassword = 'dash-secret';
    config.apiKey = '';
    configureBindHost('0.0.0.0');

    const res = fakeRes();
    await handleDashboardApi('GET', '/accounts/missing/requests', {}, authed('/accounts/missing/requests'), res);
    assert.equal(res.statusCode, 404);
  });

  it('returns rows, totals and a hashed account ref — never the key', async () => {
    _resetRuntimeConfigForTests();
    config.dashboardPassword = 'dash-secret';
    config.apiKey = '';
    configureBindHost('0.0.0.0');
    const acct = addAccount('route-history');
    recordAccountSpend(acct.apiKey, { prompt_tokens: 4, completion_tokens: 6 }, { creditCost: 1, model: 'gemini-2.5-flash' });
    recordAccountAttempt({ id: acct.id }, { model: 'gemini-2.5-flash', outcome: 'rate_limited', status: 429 });

    const res = fakeRes();
    await handleDashboardApi('GET', `/accounts/${acct.id}/requests`, {}, authed(`/accounts/${acct.id}/requests?limit=10`), res);
    assert.equal(res.statusCode, 200);
    const body = res.json();
    assert.equal(body.ok, true);
    assert.equal(body.total, 2, 'the window counts billed rows and failed attempts');
    assert.equal(body.billed, 1);
    assert.equal(body.failed, 1);
    assert.equal(body.capacity, ACCOUNT_REQUEST_CAP);
    assert.equal(body.items[0].billed, false, 'the failed attempt is the newest row');
    assert.equal(body.items[1].model, 'gemini-2.5-flash');
    assert.equal(body.items[1].totalTokens, 10);
    assert.equal(body.summary.requests, 1, 'the billed summary ignores the failed row');
    assert.equal(body.summary.totalTokens, 10);
    assert.equal(typeof body.accountRef, 'string');
    assert.ok(body.accountRef.length <= 16, 'the ref is a short hash, not an identifier');
    assert.equal(res.body.includes(acct.apiKey), false, 'the upstream key must never reach the response');
  });

  it('clamps a hostile limit instead of honouring it', async () => {
    _resetRuntimeConfigForTests();
    config.dashboardPassword = 'dash-secret';
    config.apiKey = '';
    configureBindHost('0.0.0.0');
    const acct = addAccount('route-limit');
    for (let i = 0; i < 5; i++) recordAccountSpend(acct.apiKey, { prompt_tokens: 1 }, { model: `m${i}` });

    const res = fakeRes();
    await handleDashboardApi('GET', `/accounts/${acct.id}/requests`, {}, authed(`/accounts/${acct.id}/requests?limit=9999`), res);
    assert.equal(res.statusCode, 200);
    assert.ok(res.json().items.length <= ACCOUNT_REQUEST_CAP);
    assert.equal(res.json().total, 5);
  });
});