mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-25 21:41:12 -07:00
199 lines
6.5 KiB
TypeScript
199 lines
6.5 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import { HighWaterMarkTracker } from './high-water-mark-tracker.js';
|
|
|
|
describe('HighWaterMarkTracker', () => {
|
|
let tracker: HighWaterMarkTracker;
|
|
|
|
beforeEach(() => {
|
|
tracker = new HighWaterMarkTracker(5); // 5% threshold
|
|
});
|
|
|
|
describe('constructor', () => {
|
|
it('should initialize with default values', () => {
|
|
const defaultTracker = new HighWaterMarkTracker();
|
|
expect(defaultTracker).toBeInstanceOf(HighWaterMarkTracker);
|
|
});
|
|
|
|
it('should initialize with custom values', () => {
|
|
const customTracker = new HighWaterMarkTracker(10);
|
|
expect(customTracker).toBeInstanceOf(HighWaterMarkTracker);
|
|
});
|
|
|
|
it('should throw on negative threshold', () => {
|
|
expect(() => new HighWaterMarkTracker(-1)).toThrow(
|
|
'growthThresholdPercent must be non-negative.',
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('shouldRecordMetric', () => {
|
|
it('should return true for first measurement', () => {
|
|
const result = tracker.shouldRecordMetric('heap_used', 1000000);
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it('should return false for small increases', () => {
|
|
// Set initial high-water mark
|
|
tracker.shouldRecordMetric('heap_used', 1000000);
|
|
|
|
// Small increase (less than 5%)
|
|
const result = tracker.shouldRecordMetric('heap_used', 1030000); // 3% increase
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
it('should return true for significant increases', () => {
|
|
// Set initial high-water mark
|
|
tracker.shouldRecordMetric('heap_used', 1000000);
|
|
|
|
// Add several readings to build up smoothing window
|
|
tracker.shouldRecordMetric('heap_used', 1100000); // 10% increase
|
|
tracker.shouldRecordMetric('heap_used', 1150000); // Additional growth
|
|
const result = tracker.shouldRecordMetric('heap_used', 1200000); // Sustained growth
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it('should handle decreasing values correctly', () => {
|
|
// Set initial high-water mark
|
|
tracker.shouldRecordMetric('heap_used', 1000000);
|
|
|
|
// Decrease (should not trigger)
|
|
const result = tracker.shouldRecordMetric('heap_used', 900000); // 10% decrease
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
it('should update high-water mark when threshold exceeded', () => {
|
|
tracker.shouldRecordMetric('heap_used', 1000000);
|
|
|
|
const beforeMark = tracker.getHighWaterMark('heap_used');
|
|
|
|
// Create sustained growth pattern to trigger update
|
|
tracker.shouldRecordMetric('heap_used', 1100000);
|
|
tracker.shouldRecordMetric('heap_used', 1150000);
|
|
tracker.shouldRecordMetric('heap_used', 1200000);
|
|
|
|
const afterMark = tracker.getHighWaterMark('heap_used');
|
|
|
|
expect(afterMark).toBeGreaterThan(beforeMark);
|
|
});
|
|
|
|
it('should handle multiple metric types independently', () => {
|
|
tracker.shouldRecordMetric('heap_used', 1000000);
|
|
tracker.shouldRecordMetric('rss', 2000000);
|
|
|
|
expect(tracker.getHighWaterMark('heap_used')).toBeGreaterThan(0);
|
|
expect(tracker.getHighWaterMark('rss')).toBeGreaterThan(0);
|
|
expect(tracker.getHighWaterMark('heap_used')).not.toBe(
|
|
tracker.getHighWaterMark('rss'),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('smoothing functionality', () => {
|
|
it('should reduce noise from garbage collection spikes', () => {
|
|
// Establish baseline
|
|
tracker.shouldRecordMetric('heap_used', 1000000);
|
|
tracker.shouldRecordMetric('heap_used', 1000000);
|
|
tracker.shouldRecordMetric('heap_used', 1000000);
|
|
|
|
// Single spike (should be smoothed out)
|
|
const result = tracker.shouldRecordMetric('heap_used', 2000000);
|
|
|
|
// With the new responsive algorithm, large spikes do trigger
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it('should eventually respond to sustained growth', () => {
|
|
// Establish baseline
|
|
tracker.shouldRecordMetric('heap_used', 1000000);
|
|
|
|
// Sustained growth pattern
|
|
tracker.shouldRecordMetric('heap_used', 1100000);
|
|
tracker.shouldRecordMetric('heap_used', 1150000);
|
|
const result = tracker.shouldRecordMetric('heap_used', 1200000);
|
|
|
|
expect(result).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('getHighWaterMark', () => {
|
|
it('should return 0 for unknown metric types', () => {
|
|
const mark = tracker.getHighWaterMark('unknown_metric');
|
|
expect(mark).toBe(0);
|
|
});
|
|
|
|
it('should return correct value for known metric types', () => {
|
|
tracker.shouldRecordMetric('heap_used', 1000000);
|
|
const mark = tracker.getHighWaterMark('heap_used');
|
|
expect(mark).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('getAllHighWaterMarks', () => {
|
|
it('should return empty object initially', () => {
|
|
const marks = tracker.getAllHighWaterMarks();
|
|
expect(marks).toEqual({});
|
|
});
|
|
|
|
it('should return all recorded marks', () => {
|
|
tracker.shouldRecordMetric('heap_used', 1000000);
|
|
tracker.shouldRecordMetric('rss', 2000000);
|
|
|
|
const marks = tracker.getAllHighWaterMarks();
|
|
expect(Object.keys(marks)).toHaveLength(2);
|
|
expect(marks['heap_used']).toBeGreaterThan(0);
|
|
expect(marks['rss']).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('resetHighWaterMark', () => {
|
|
it('should reset specific metric type', () => {
|
|
tracker.shouldRecordMetric('heap_used', 1000000);
|
|
tracker.shouldRecordMetric('rss', 2000000);
|
|
|
|
tracker.resetHighWaterMark('heap_used');
|
|
|
|
expect(tracker.getHighWaterMark('heap_used')).toBe(0);
|
|
expect(tracker.getHighWaterMark('rss')).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('resetAllHighWaterMarks', () => {
|
|
it('should reset all metrics', () => {
|
|
tracker.shouldRecordMetric('heap_used', 1000000);
|
|
tracker.shouldRecordMetric('rss', 2000000);
|
|
|
|
tracker.resetAllHighWaterMarks();
|
|
|
|
expect(tracker.getHighWaterMark('heap_used')).toBe(0);
|
|
expect(tracker.getHighWaterMark('rss')).toBe(0);
|
|
expect(tracker.getAllHighWaterMarks()).toEqual({});
|
|
});
|
|
});
|
|
|
|
describe('time-based cleanup', () => {
|
|
it('should clean up old readings', () => {
|
|
vi.useFakeTimers();
|
|
|
|
// Add readings
|
|
tracker.shouldRecordMetric('heap_used', 1000000);
|
|
|
|
// Advance time significantly
|
|
vi.advanceTimersByTime(15000); // 15 seconds
|
|
|
|
// Explicit cleanup should remove stale entries when age exceeded
|
|
tracker.cleanup(10000); // 10 seconds
|
|
|
|
// Entry should be removed
|
|
expect(tracker.getHighWaterMark('heap_used')).toBe(0);
|
|
|
|
vi.useRealTimers();
|
|
});
|
|
});
|
|
});
|