All files / src/__tests__/gc gc-test-utils.mts

3.33% Statements 1/30
0% Branches 0/11
0% Functions 0/12
3.7% Lines 1/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137                    5x                                                                                                                                                                                                                                                            
/**
 * Shared utilities for garbage collection tests
 *
 * These tests require Node.js to be started with --expose-gc flag
 * to enable manual garbage collection triggering via global.gc()
 */
 
/**
 * Check if garbage collection is available
 */
export const isGCAvailable = typeof global.gc === 'function'
 
/**
 * Force garbage collection if available
 * Should be called after removing references to test objects
 */
export function forceGC(): void {
  if (isGCAvailable) {
    global.gc!()
  }
}
 
/**
 * Get current heap memory usage in bytes
 */
export function getHeapUsed(): number {
  return process.memoryUsage().heapUsed
}
 
/**
 * Get current heap memory usage in MB
 */
export function getHeapUsedMB(): number {
  return getHeapUsed() / 1024 / 1024
}
 
/**
 * Measure memory delta during a callback execution
 * Forces GC before and after to get accurate measurements
 */
export async function measureMemoryDelta(
  callback: () => Promise<void>
): Promise<{ before: number; after: number; delta: number }> {
  forceGC()
  const before = getHeapUsed()
 
  await callback()
 
  forceGC()
  const after = getHeapUsed()
 
  return {
    before,
    after,
    delta: after - before,
  }
}
 
/**
 * Create a WeakRef tracker for an object
 * Returns a function that checks if the object has been collected
 */
export function createGCTracker<T extends object>(
  obj: T
): () => { collected: boolean; ref: WeakRef<T> } {
  const ref = new WeakRef(obj)
  return () => ({
    collected: ref.deref() === undefined,
    ref,
  })
}
 
/**
 * Wait for an object to be garbage collected
 * Returns true if collected within timeout, false otherwise
 */
export async function waitForGC<T extends object>(
  ref: WeakRef<T>,
  timeoutMs: number = 1000,
  intervalMs: number = 10
): Promise<boolean> {
  const startTime = Date.now()
 
  while (Date.now() - startTime < timeoutMs) {
    forceGC()
 
    if (ref.deref() === undefined) {
      return true
    }
 
    await new Promise((resolve) => setTimeout(resolve, intervalMs))
  }
 
  return false
}
 
/**
 * Create a large object to simulate memory pressure
 * Size is in bytes (approximately)
 */
export function createLargeObject(sizeBytes: number): { data: Uint8Array } {
  return {
    data: new Uint8Array(sizeBytes),
  }
}
 
/**
 * Create multiple large objects to simulate batch allocations
 */
export function createLargeObjects(
  count: number,
  sizePerObject: number
): Array<{ data: Uint8Array }> {
  return Array.from({ length: count }, () => createLargeObject(sizePerObject))
}
 
/**
 * Memory threshold check - verifies memory is within expected bounds
 * Useful for detecting memory leaks
 */
export function assertMemoryWithinBounds(
  actualBytes: number,
  expectedBytes: number,
  tolerancePercent: number = 20
): void {
  const tolerance = expectedBytes * (tolerancePercent / 100)
  const lowerBound = expectedBytes - tolerance
  const upperBound = expectedBytes + tolerance
 
  if (actualBytes < lowerBound || actualBytes > upperBound) {
    throw new Error(
      `Memory usage ${actualBytes} bytes is outside expected bounds ` +
        `[${lowerBound}, ${upperBound}] (expected: ${expectedBytes} ±${tolerancePercent}%)`
    )
  }
}