CoolFace
Datasetpublic

basant307/AI_Governance_Project

sourceHugging Faceapache-2.0updated 2mo agoView on Hugging Face
0likes45downloads
memoryDiagnostics.test.ts789 linesDownload Raw Back to utils
1/**2 * @license3 * Copyright 2025 Qwen4 * SPDX-License-Identifier: Apache-2.05 */6 7import * as os from 'node:os';8import * as path from 'node:path';9import * as fs from 'node:fs';10 11import { afterEach, describe, expect, it, vi } from 'vitest';12import {13  clearHeapSnapshotRateLimit,14  collectMemoryPressureSamples,15  formatMemoryDiagnostics,16  formatMemoryPressureSamples,17  getMemoryDiagnostics,18  isHighHeapPressure,19  writeMemoryHeapSnapshot,20} from './memoryDiagnostics.js';21 22describe('memoryDiagnostics', () => {23  afterEach(() => {24    clearHeapSnapshotRateLimit();25    vi.restoreAllMocks();26    vi.doUnmock('node:fs');27    vi.doUnmock('node:v8');28  });29 30  it('collects baseline memory fields', () => {31    const diagnostics = getMemoryDiagnostics();32 33    expect(diagnostics.process.pid).toBe(process.pid);34    expect(diagnostics.process.nodeVersion).toBe(process.version);35    expect(diagnostics.process.platform).toBe(process.platform);36    expect(diagnostics.process.arch).toBe(process.arch);37    expect(diagnostics.memory.rss).toBeGreaterThan(0);38    expect(diagnostics.memory.heapTotal).toBeGreaterThan(0);39    expect(diagnostics.memory.heapUsed).toBeGreaterThan(0);40    expect(diagnostics.memory.external).toBeGreaterThanOrEqual(0);41    expect(diagnostics.memory.arrayBuffers).toBeGreaterThanOrEqual(0);42    expect(diagnostics.v8.heapStatistics).toBeDefined();43    expect(diagnostics.v8.heapSpaces.length).toBeGreaterThan(0);44    expect(diagnostics.activeHandles.count).toBeGreaterThanOrEqual(0);45    expect(diagnostics.activeRequests.count).toBeGreaterThanOrEqual(0);46  });47 48  it('formats a paste-safe human-readable report with key sections', () => {49    vi.useFakeTimers();50    vi.setSystemTime(new Date('2026-05-15T12:00:00.000Z'));51 52    try {53      const report = formatMemoryDiagnostics({54        generatedAt: new Date().toISOString(),55        process: {56          pid: 123,57          nodeVersion: 'v22.0.0',58          platform: 'linux',59          arch: 'x64',60          uptimeSeconds: 42.4,61        },62        memory: {63          rss: 100 * 1024 * 1024,64          heapTotal: 80 * 1024 * 1024,65          heapUsed: 40 * 1024 * 1024,66          external: 5 * 1024 * 1024,67          arrayBuffers: 2 * 1024 * 1024,68        },69        v8: {70          heapStatistics: {71            heap_size_limit: 4096 * 1024 * 1024,72            total_available_size: 3000 * 1024 * 1024,73          },74          heapSpaces: [75            {76              space_name: 'old_space',77              space_size: 30 * 1024 * 1024,78              space_used_size: 20 * 1024 * 1024,79            },80          ],81        },82        activeHandles: { count: 3, unavailable: false },83        activeRequests: { count: 1, unavailable: false },84      });85 86      expect(report).toContain('Memory diagnostics');87      expect(report).toContain('Generated: 2026-05-15T12:00:00.000Z');88      expect(report).toContain('Node.js: v22.0.0');89      expect(report).toContain('RSS: 100.0 MiB');90      expect(report).toContain('Heap used / total: 40.0 MiB / 80.0 MiB');91      expect(report).toContain('External: 5.0 MiB');92      expect(report).toContain('Array buffers: 2.0 MiB');93      expect(report).toContain('Heap size limit: 4096.0 MiB');94      expect(report).toContain('old_space: 20.0 MiB / 30.0 MiB');95      expect(report).toContain('Active handles: 3');96      expect(report).toContain('Active requests: 1');97      expect(report).toContain('Assessment');98      expect(report).toContain('Status: ok');99      expect(report).toContain('Heap pressure: 1.0%');100    } finally {101      vi.useRealTimers();102    }103  });104 105  it('surfaces high heap pressure with actionable recommendations', () => {106    const report = formatMemoryDiagnostics({107      generatedAt: '2026-05-15T12:00:00.000Z',108      process: {109        pid: 123,110        nodeVersion: 'v22.0.0',111        platform: 'linux',112        arch: 'x64',113        uptimeSeconds: 120,114      },115      memory: {116        rss: 3900 * 1024 * 1024,117        heapTotal: 3600 * 1024 * 1024,118        heapUsed: 3500 * 1024 * 1024,119        external: 20 * 1024 * 1024,120        arrayBuffers: 10 * 1024 * 1024,121      },122      v8: {123        heapStatistics: {124          heap_size_limit: 4096 * 1024 * 1024,125          total_available_size: 200 * 1024 * 1024,126        },127        heapSpaces: [],128      },129      activeHandles: { count: 3, unavailable: false },130      activeRequests: { count: 1, unavailable: false },131    });132 133    expect(report).toContain('Status: warn');134    expect(report).toContain('Heap pressure: 85.4%');135    expect(report).toContain('V8 heap usage is high');136    expect(report).toContain('restart Qwen Code to recover memory');137    expect(report).toContain('capture a heap snapshot');138  });139 140  it('surfaces large non-heap memory gaps separately from V8 heap pressure', () => {141    const report = formatMemoryDiagnostics({142      generatedAt: '2026-05-15T12:00:00.000Z',143      process: {144        pid: 123,145        nodeVersion: 'v22.0.0',146        platform: 'linux',147        arch: 'x64',148        uptimeSeconds: 120,149      },150      memory: {151        rss: 1800 * 1024 * 1024,152        heapTotal: 500 * 1024 * 1024,153        heapUsed: 300 * 1024 * 1024,154        external: 900 * 1024 * 1024,155        arrayBuffers: 300 * 1024 * 1024,156      },157      v8: {158        heapStatistics: {159          heap_size_limit: 4096 * 1024 * 1024,160          total_available_size: 3000 * 1024 * 1024,161        },162        heapSpaces: [],163      },164      activeHandles: { count: 3, unavailable: false },165      activeRequests: { count: 1, unavailable: false },166    });167 168    expect(report).toContain('Status: warn');169    expect(report).toContain('RSS / heap-total gap: 1300.0 MiB');170    expect(report).toContain('Non-heap memory is high');171    expect(report).toContain(172      'large tool results, buffers, or native allocations',173    );174  });175 176  it('writes heap snapshots to a diagnostics directory with stable filenames', () => {177    const outputDir = path.join(os.tmpdir(), 'qwen-memory-diagnostics-test');178    const writtenPath = writeMemoryHeapSnapshot({179      outputDir,180      now: new Date('2026-05-15T12:00:00.000Z'),181      writeSnapshot: (filePath) => {182        fs.writeFileSync(filePath, 'snapshot');183        return filePath;184      },185    });186 187    expect(writtenPath).toBe(188      path.join(189        outputDir,190        `qwen-code-heap-${process.pid}-2026-05-15T12-00-00-000Z.heapsnapshot`,191      ),192    );193  });194 195  it('refuses heap snapshots when estimated heap dump would leave little free disk', () => {196    const outputDir = path.join(197      os.tmpdir(),198      `qwen-memory-diagnostics-disk-${process.pid}`,199    );200    fs.rmSync(outputDir, { recursive: true, force: true });201 202    try {203      expect(() =>204        writeMemoryHeapSnapshot({205          outputDir,206          writeSnapshot: (filePath) => {207            fs.writeFileSync(filePath, 'snapshot');208            return filePath;209          },210          estimateSnapshotBytes: () => 900,211          getAvailableBytes: () => 1000,212          minFreeBytesAfterSnapshot: 200,213        }),214      ).toThrow('Insufficient free disk space');215      expect(fs.readdirSync(outputDir)).toHaveLength(0);216    } finally {217      fs.rmSync(outputDir, { recursive: true, force: true });218    }219  });220 221  it('rate-limits repeated heap snapshot writes in the same directory', () => {222    const outputDir = path.join(223      os.tmpdir(),224      `qwen-memory-diagnostics-rate-limit-${process.pid}`,225    );226    fs.rmSync(outputDir, { recursive: true, force: true });227 228    try {229      const writeSnapshot = (filePath: string) => {230        fs.writeFileSync(filePath, 'snapshot');231        return filePath;232      };233 234      writeMemoryHeapSnapshot({235        outputDir,236        now: new Date('2026-05-15T12:00:00.000Z'),237        writeSnapshot,238      });239 240      expect(() =>241        writeMemoryHeapSnapshot({242          outputDir,243          now: new Date('2026-05-15T12:00:30.000Z'),244          writeSnapshot,245        }),246      ).toThrow('Heap snapshot rate limit');247    } finally {248      fs.rmSync(outputDir, { recursive: true, force: true });249    }250  });251 252  it('keeps only the newest heap snapshots after writing', () => {253    const outputDir = path.join(254      os.tmpdir(),255      `qwen-memory-diagnostics-cleanup-${process.pid}`,256    );257    fs.rmSync(outputDir, { recursive: true, force: true });258    fs.mkdirSync(outputDir, { recursive: true });259 260    const oldSnapshot = path.join(261      outputDir,262      `qwen-code-heap-${process.pid}-2026-05-15T11-00-00-000Z.heapsnapshot`,263    );264    const newerSnapshot = path.join(265      outputDir,266      `qwen-code-heap-${process.pid}-2026-05-15T11-30-00-000Z.heapsnapshot`,267    );268    fs.writeFileSync(oldSnapshot, 'old');269    fs.writeFileSync(newerSnapshot, 'newer');270 271    const writtenPath = writeMemoryHeapSnapshot({272      outputDir,273      now: new Date('2026-05-15T12:00:00.000Z'),274      maxSnapshots: 2,275      writeSnapshot: (filePath) => {276        fs.writeFileSync(filePath, 'snapshot');277        return filePath;278      },279    });280 281    try {282      expect(fs.existsSync(oldSnapshot)).toBe(false);283      expect(fs.existsSync(newerSnapshot)).toBe(true);284      expect(fs.existsSync(writtenPath)).toBe(true);285    } finally {286      fs.rmSync(outputDir, { recursive: true, force: true });287    }288  });289 290  it('orders heap snapshot cleanup by modification time across process ids', () => {291    const outputDir = path.join(292      os.tmpdir(),293      `qwen-memory-diagnostics-mtime-cleanup-${process.pid}`,294    );295    fs.rmSync(outputDir, { recursive: true, force: true });296    fs.mkdirSync(outputDir, { recursive: true });297 298    const newerLowPidSnapshot = path.join(299      outputDir,300      'qwen-code-heap-9-2026-05-15T12-30-00-000Z.heapsnapshot',301    );302    const olderHighPidSnapshot = path.join(303      outputDir,304      'qwen-code-heap-12345-2026-05-15T12-00-00-000Z.heapsnapshot',305    );306    fs.writeFileSync(newerLowPidSnapshot, 'newer');307    fs.writeFileSync(olderHighPidSnapshot, 'older');308    fs.utimesSync(309      olderHighPidSnapshot,310      new Date('2026-05-15T12:00:00.000Z'),311      new Date('2026-05-15T12:00:00.000Z'),312    );313    fs.utimesSync(314      newerLowPidSnapshot,315      new Date('2026-05-15T12:30:00.000Z'),316      new Date('2026-05-15T12:30:00.000Z'),317    );318 319    const writtenPath = writeMemoryHeapSnapshot({320      outputDir,321      now: new Date('2026-05-15T13:00:00.000Z'),322      maxSnapshots: 2,323      writeSnapshot: (filePath) => {324        fs.writeFileSync(filePath, 'snapshot');325        return filePath;326      },327    });328 329    try {330      expect(fs.existsSync(olderHighPidSnapshot)).toBe(false);331      expect(fs.existsSync(newerLowPidSnapshot)).toBe(true);332      expect(fs.existsSync(writtenPath)).toBe(true);333    } finally {334      fs.rmSync(outputDir, { recursive: true, force: true });335    }336  });337 338  it('uses filename timestamps to break equal-mtime cleanup ties', () => {339    const outputDir = path.join(340      os.tmpdir(),341      `qwen-memory-diagnostics-equal-mtime-cleanup-${process.pid}`,342    );343    fs.rmSync(outputDir, { recursive: true, force: true });344    fs.mkdirSync(outputDir, { recursive: true });345 346    const olderSnapshot = path.join(347      outputDir,348      'qwen-code-heap-1-2026-05-15T11-00-00-000Z.heapsnapshot',349    );350    const newerSnapshot = path.join(351      outputDir,352      'qwen-code-heap-1-2026-05-15T12-00-00-000Z.heapsnapshot',353    );354    fs.writeFileSync(olderSnapshot, 'older');355    fs.writeFileSync(newerSnapshot, 'newer');356    const sameMtime = new Date('2026-05-15T12:00:00.000Z');357    fs.utimesSync(olderSnapshot, sameMtime, sameMtime);358    fs.utimesSync(newerSnapshot, sameMtime, sameMtime);359 360    const writtenPath = writeMemoryHeapSnapshot({361      outputDir,362      now: new Date('2026-05-15T13:00:00.000Z'),363      maxSnapshots: 2,364      writeSnapshot: (filePath) => {365        fs.writeFileSync(filePath, 'snapshot');366        return filePath;367      },368    });369 370    try {371      expect(fs.existsSync(olderSnapshot)).toBe(false);372      expect(fs.existsSync(newerSnapshot)).toBe(true);373      expect(fs.existsSync(writtenPath)).toBe(true);374    } finally {375      fs.rmSync(outputDir, { recursive: true, force: true });376    }377  });378 379  it('keeps successful heap snapshot writes when cleanup fails', () => {380    const outputDir = path.join(381      os.tmpdir(),382      `qwen-memory-diagnostics-cleanup-fail-${process.pid}`,383    );384    fs.rmSync(outputDir, { recursive: true, force: true });385    fs.mkdirSync(outputDir, { recursive: true });386    const brokenSymlink = path.join(387      outputDir,388      'qwen-code-heap-999-2026-05-15T11-00-00-000Z.heapsnapshot',389    );390    fs.symlinkSync('missing-target.heapsnapshot', brokenSymlink);391 392    try {393      const writtenPath = writeMemoryHeapSnapshot({394        outputDir,395        now: new Date('2026-05-15T12:00:00.000Z'),396        maxSnapshots: 1,397        writeSnapshot: (filePath) => {398          fs.writeFileSync(filePath, 'snapshot');399          return filePath;400        },401      });402 403      expect(fs.existsSync(writtenPath)).toBe(true);404      expect(() => fs.lstatSync(brokenSymlink)).toThrow();405    } finally {406      fs.rmSync(outputDir, { recursive: true, force: true });407    }408  });409 410  it('removes partial heap snapshot files after a failed write', () => {411    const outputDir = path.join(412      os.tmpdir(),413      `qwen-memory-diagnostics-partial-${process.pid}`,414    );415    fs.rmSync(outputDir, { recursive: true, force: true });416    let partialPath = '';417 418    try {419      expect(() =>420        writeMemoryHeapSnapshot({421          outputDir,422          now: new Date('2026-05-15T12:00:00.000Z'),423          writeSnapshot: (filePath) => {424            partialPath = filePath;425            fs.writeFileSync(filePath, 'partial');426            throw new Error('write failed');427          },428        }),429      ).toThrow('write failed');430 431      expect(fs.existsSync(partialPath)).toBe(false);432    } finally {433      fs.rmSync(outputDir, { recursive: true, force: true });434    }435  });436 437  it('creates heap snapshot directories and files with private permissions', () => {438    const outputDir = path.join(439      os.tmpdir(),440      `qwen-memory-diagnostics-private-${process.pid}`,441    );442    fs.rmSync(outputDir, { recursive: true, force: true });443 444    const writtenPath = writeMemoryHeapSnapshot({445      outputDir,446      now: new Date('2026-05-15T12:00:00.000Z'),447      writeSnapshot: (filePath) => {448        fs.writeFileSync(filePath, 'snapshot');449        return filePath;450      },451    });452 453    try {454      expect(fs.existsSync(outputDir)).toBe(true);455      expect(fs.existsSync(writtenPath)).toBe(true);456      if (process.platform !== 'win32') {457        expect(fs.statSync(outputDir).mode & 0o777).toBe(0o700);458        expect(fs.statSync(writtenPath).mode & 0o777).toBe(0o600);459      }460    } finally {461      fs.rmSync(outputDir, { recursive: true, force: true });462    }463  });464 465  it('refuses heap snapshot writes when free disk space cannot be read', async () => {466    const outputDir = path.join(467      os.tmpdir(),468      `qwen-memory-diagnostics-statfs-fallback-${process.pid}`,469    );470    fs.rmSync(outputDir, { recursive: true, force: true });471    vi.resetModules();472    const statfsSync = vi.fn(() => {473      throw new Error('statfs unavailable');474    });475    vi.doMock('node:fs', async (importOriginal) => {476      const actual = await importOriginal<typeof import('node:fs')>();477      return { ...actual, statfsSync };478    });479    const { writeMemoryHeapSnapshot: writeWithMockedFs } = await import(480      './memoryDiagnostics.js'481    );482 483    try {484      expect(() =>485        writeWithMockedFs({486          outputDir,487          now: new Date('2026-05-15T12:00:00.000Z'),488          writeSnapshot: (filePath) => {489            fs.writeFileSync(filePath, 'snapshot');490            return filePath;491          },492        }),493      ).toThrow('Unable to check available disk space');494 495      expect(statfsSync).toHaveBeenCalledWith(outputDir);496      expect(fs.readdirSync(outputDir)).toHaveLength(0);497    } finally {498      fs.rmSync(outputDir, { recursive: true, force: true });499    }500  });501 502  it('falls back to process heap total when V8 heap statistics are unavailable for snapshot sizing', async () => {503    const outputDir = path.join(504      os.tmpdir(),505      `qwen-memory-diagnostics-estimate-fallback-${process.pid}`,506    );507    fs.rmSync(outputDir, { recursive: true, force: true });508    vi.resetModules();509    const getHeapStatistics = vi.fn(() => {510      throw new Error('heap statistics unavailable');511    });512    vi.doMock('node:v8', async (importOriginal) => {513      const actual = await importOriginal<typeof import('node:v8')>();514      return { ...actual, getHeapStatistics };515    });516    const { writeMemoryHeapSnapshot: writeWithMockedV8 } = await import(517      './memoryDiagnostics.js'518    );519    vi.spyOn(process, 'memoryUsage').mockReturnValue({520      rss: 40,521      heapTotal: 100,522      heapUsed: 50,523      external: 10,524      arrayBuffers: 5,525    });526 527    try {528      expect(() =>529        writeWithMockedV8({530          outputDir,531          now: new Date('2026-05-15T12:00:00.000Z'),532          writeSnapshot: (filePath) => {533            fs.writeFileSync(filePath, 'snapshot');534            return filePath;535          },536          getAvailableBytes: () => 350,537          minFreeBytesAfterSnapshot: 60,538        }),539      ).toThrow('Insufficient free disk space');540      expect(getHeapStatistics).toHaveBeenCalled();541    } finally {542      fs.rmSync(outputDir, { recursive: true, force: true });543    }544  });545 546  it('uses the default sample count for non-positive sample counts', async () => {547    const samples = await collectMemoryPressureSamples({548      sampleCount: 0,549      intervalMs: 0,550      now: () => new Date('2026-05-15T12:00:00.000Z'),551      memoryUsage: () => ({552        rss: 100,553        heapTotal: 80,554        heapUsed: 40,555        external: 5,556        arrayBuffers: 2,557      }),558      wait: async () => {},559    });560 561    expect(samples).toHaveLength(3);562  });563 564  it('marks V8 diagnostics as warning when heap statistics are unavailable', () => {565    const report = formatMemoryDiagnostics({566      generatedAt: '2026-05-15T12:00:00.000Z',567      process: {568        pid: 123,569        nodeVersion: 'v22.0.0',570        platform: 'linux',571        arch: 'x64',572        uptimeSeconds: 120,573      },574      memory: {575        rss: 100 * 1024 * 1024,576        heapTotal: 80 * 1024 * 1024,577        heapUsed: 40 * 1024 * 1024,578        external: 5 * 1024 * 1024,579        arrayBuffers: 2 * 1024 * 1024,580      },581      v8: {582        unavailable: true,583        heapSpaces: [],584      },585      activeHandles: { count: 3, unavailable: false },586      activeRequests: { count: 1, unavailable: false },587    });588 589    expect(report).toContain('Status: warn');590    expect(report).toContain('V8 heap statistics are unavailable');591    expect(report).not.toContain(592      'No immediate memory pressure signals detected.',593    );594  });595 596  it('surfaces high active handle counts with actionable recommendations', () => {597    const report = formatMemoryDiagnostics({598      generatedAt: '2026-05-15T12:00:00.000Z',599      process: {600        pid: 123,601        nodeVersion: 'v22.0.0',602        platform: 'linux',603        arch: 'x64',604        uptimeSeconds: 120,605      },606      memory: {607        rss: 100 * 1024 * 1024,608        heapTotal: 80 * 1024 * 1024,609        heapUsed: 40 * 1024 * 1024,610        external: 5 * 1024 * 1024,611        arrayBuffers: 2 * 1024 * 1024,612      },613      v8: {614        heapStatistics: {615          heap_size_limit: 4096 * 1024 * 1024,616        },617        heapSpaces: [],618      },619      activeHandles: { count: 1000, unavailable: false },620      activeRequests: { count: 1, unavailable: false },621    });622 623    expect(report).toContain('Active handle count is high');624    expect(report).toContain('MCP servers, watchers, or streaming sessions');625  });626 627  it('reports high heap pressure only with a finite positive heap limit', () => {628    const baseDiagnostics = {629      generatedAt: '2026-05-15T12:00:00.000Z',630      process: {631        pid: 123,632        nodeVersion: 'v22.0.0',633        platform: 'linux' as const,634        arch: 'x64',635        uptimeSeconds: 120,636      },637      memory: {638        rss: 100,639        heapTotal: 80,640        heapUsed: 90,641        external: 5,642        arrayBuffers: 2,643      },644      v8: {645        heapSpaces: [],646      },647      activeHandles: { count: 3, unavailable: false },648      activeRequests: { count: 1, unavailable: false },649    };650 651    expect(652      isHighHeapPressure({653        ...baseDiagnostics,654        v8: { ...baseDiagnostics.v8, heapStatistics: { heap_size_limit: 0 } },655      }),656    ).toBe(false);657    expect(658      isHighHeapPressure({659        ...baseDiagnostics,660        v8: { ...baseDiagnostics.v8, heapStatistics: {} },661      }),662    ).toBe(false);663    expect(isHighHeapPressure(baseDiagnostics)).toBe(false);664    expect(665      isHighHeapPressure({666        ...baseDiagnostics,667        v8: {668          ...baseDiagnostics.v8,669          heapStatistics: { heap_size_limit: 100 },670        },671      }),672    ).toBe(true);673  });674 675  it('collects repeated memory pressure samples with waits between samples', async () => {676    const waits: number[] = [];677    const memoryUsages = [678      {679        rss: 100 * 1024 * 1024,680        heapTotal: 80 * 1024 * 1024,681        heapUsed: 40 * 1024 * 1024,682        external: 5 * 1024 * 1024,683        arrayBuffers: 2 * 1024 * 1024,684      },685      {686        rss: 130 * 1024 * 1024,687        heapTotal: 90 * 1024 * 1024,688        heapUsed: 60 * 1024 * 1024,689        external: 6 * 1024 * 1024,690        arrayBuffers: 3 * 1024 * 1024,691      },692      {693        rss: 150 * 1024 * 1024,694        heapTotal: 100 * 1024 * 1024,695        heapUsed: 70 * 1024 * 1024,696        external: 7 * 1024 * 1024,697        arrayBuffers: 4 * 1024 * 1024,698      },699    ];700 701    const samples = await collectMemoryPressureSamples({702      sampleCount: 3,703      intervalMs: 25,704      now: () => new Date('2026-05-15T12:00:00.000Z'),705      memoryUsage: () => memoryUsages.shift()!,706      wait: async (ms) => {707        waits.push(ms);708      },709    });710 711    expect(samples).toHaveLength(3);712    expect(waits).toEqual([25, 25]);713    expect(samples[0]).toMatchObject({ index: 1, rss: 100 * 1024 * 1024 });714    expect(samples[2]).toMatchObject({ index: 3, heapUsed: 70 * 1024 * 1024 });715  });716 717  it('stops collecting memory pressure samples when aborted', async () => {718    const abortController = new AbortController();719    const samples = await collectMemoryPressureSamples({720      sampleCount: 3,721      intervalMs: 25,722      signal: abortController.signal,723      now: () => new Date('2026-05-15T12:00:00.000Z'),724      memoryUsage: () => {725        abortController.abort();726        return {727          rss: 100,728          heapTotal: 80,729          heapUsed: 40,730          external: 5,731          arrayBuffers: 2,732        };733      },734      wait: async () => {735        throw new Error('should not wait after abort');736      },737    });738 739    expect(samples).toHaveLength(1);740  });741 742  it('formats single memory pressure sample deltas as unavailable', () => {743    const report = formatMemoryPressureSamples([744      {745        index: 1,746        timestamp: '2026-05-15T12:00:00.000Z',747        rss: 100 * 1024 * 1024,748        heapTotal: 80 * 1024 * 1024,749        heapUsed: 40 * 1024 * 1024,750        external: 5 * 1024 * 1024,751        arrayBuffers: 2 * 1024 * 1024,752      },753    ]);754 755    expect(report).toContain('Sample count: 1');756    expect(report).toContain('RSS delta: unavailable');757    expect(report).toContain('Heap used delta: unavailable');758  });759 760  it('formats memory pressure sample deltas', () => {761    const report = formatMemoryPressureSamples([762      {763        index: 1,764        timestamp: '2026-05-15T12:00:00.000Z',765        rss: 100 * 1024 * 1024,766        heapTotal: 80 * 1024 * 1024,767        heapUsed: 40 * 1024 * 1024,768        external: 5 * 1024 * 1024,769        arrayBuffers: 2 * 1024 * 1024,770      },771      {772        index: 2,773        timestamp: '2026-05-15T12:00:01.000Z',774        rss: 130 * 1024 * 1024,775        heapTotal: 90 * 1024 * 1024,776        heapUsed: 60 * 1024 * 1024,777        external: 6 * 1024 * 1024,778        arrayBuffers: 3 * 1024 * 1024,779      },780    ]);781 782    expect(report).toContain('Memory pressure samples');783    expect(report).toContain('Sample count: 2');784    expect(report).toContain('RSS delta: 30.0 MiB');785    expect(report).toContain('Heap used delta: 20.0 MiB');786    expect(report).toContain('#2 2026-05-15T12:00:01.000Z');787  });788});789 
basant307/AI_Governance_Project · CoolFace