/**
* @file degradation-policy.test.ts
* @description Unit tests for degradation-policy module
*
* Tests the acceleration tier degradation system including:
* - AccelerationTier enum
* - Policy creation and configuration
* - Tier enablement checking
* - Degradation logging
* - Environment variable handling
*
* @since 3.1.1
*/
import { describe, it, expect, vi, beforeEach } from 'vitest';
import {
AccelerationTier,
isTierEnabled,
getConfigurationDescription,
} from '../../src/degradation-policy.js';
describe('degradation-policy', () => {
let consoleLogSpy: ReturnType<typeof vi.spyOn>;
let consoleWarnSpy: ReturnType<typeof vi.spyOn>;
beforeEach(() => {
consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
});
describe('AccelerationTier enum', () => {
it('should define all acceleration tiers', () => {
expect(AccelerationTier.MATHJS).toBe('mathjs');
expect(AccelerationTier.WASM).toBe('wasm');
expect(AccelerationTier.WORKERS).toBe('workers');
expect(AccelerationTier.GPU).toBe('gpu');
});
it('should have string values for logging', () => {
const tiers = Object.values(AccelerationTier);
for (const tier of tiers) {
expect(typeof tier).toBe('string');
}
});
it('should have exactly 4 tiers', () => {
const tiers = Object.values(AccelerationTier);
expect(tiers).toHaveLength(4);
});
});
describe('isTierEnabled', () => {
it('should return true for mathjs tier (always enabled)', () => {
expect(isTierEnabled(AccelerationTier.MATHJS)).toBe(true);
});
it('should handle WASM tier based on default configuration', () => {
// Default is enabled (unless ENABLE_WASM=false)
const isEnabled = isTierEnabled(AccelerationTier.WASM);
expect(typeof isEnabled).toBe('boolean');
});
it('should handle WORKERS tier based on default configuration', () => {
// Default is enabled (unless ENABLE_WORKERS=false)
const isEnabled = isTierEnabled(AccelerationTier.WORKERS);
expect(typeof isEnabled).toBe('boolean');
});
it('should handle GPU tier based on default configuration', () => {
// Default is disabled (unless ENABLE_GPU=true)
const isEnabled = isTierEnabled(AccelerationTier.GPU);
expect(typeof isEnabled).toBe('boolean');
});
it('should consistently return same result for same tier', () => {
const firstCheck = isTierEnabled(AccelerationTier.WASM);
const secondCheck = isTierEnabled(AccelerationTier.WASM);
expect(firstCheck).toBe(secondCheck);
});
});
describe('getConfigurationDescription', () => {
it('should return a string describing the configuration', () => {
const description = getConfigurationDescription();
expect(typeof description).toBe('string');
expect(description).toContain('Acceleration:');
});
it('should include mathjs in the configuration', () => {
const description = getConfigurationDescription();
expect(description).toContain('mathjs');
});
it('should use arrow notation for tier chain', () => {
const description = getConfigurationDescription();
// Should have arrow separators if multiple tiers are enabled
if (description.includes('wasm') || description.includes('workers')) {
expect(description).toContain('→');
}
});
it('should order tiers from highest to lowest performance', () => {
const description = getConfigurationDescription();
// If GPU is enabled, it should come before workers
if (description.includes('gpu') && description.includes('workers')) {
const gpuIndex = description.indexOf('gpu');
const workersIndex = description.indexOf('workers');
expect(gpuIndex).toBeLessThan(workersIndex);
}
// If workers is enabled, it should come before wasm
if (description.includes('workers') && description.includes('wasm')) {
const workersIndex = description.indexOf('workers');
const wasmIndex = description.indexOf('wasm');
expect(workersIndex).toBeLessThan(wasmIndex);
}
// If wasm is enabled, it should come before mathjs
if (description.includes('wasm') && description.includes('mathjs')) {
const wasmIndex = description.indexOf('wasm');
const mathjsIndex = description.indexOf('mathjs');
expect(wasmIndex).toBeLessThan(mathjsIndex);
}
});
it('should not be empty', () => {
const description = getConfigurationDescription();
expect(description.length).toBeGreaterThan(0);
});
});
describe('tier priority ordering', () => {
it('should prioritize GPU over WORKERS', () => {
// This is implicit in the enum definition and tier priority
const gpuValue = AccelerationTier.GPU;
const workersValue = AccelerationTier.WORKERS;
expect(gpuValue).toBeDefined();
expect(workersValue).toBeDefined();
// Priority is determined by TIER_PRIORITY mapping, not enum values
});
it('should prioritize WORKERS over WASM', () => {
const workersValue = AccelerationTier.WORKERS;
const wasmValue = AccelerationTier.WASM;
expect(workersValue).toBeDefined();
expect(wasmValue).toBeDefined();
});
it('should prioritize WASM over MATHJS', () => {
const wasmValue = AccelerationTier.WASM;
const mathjsValue = AccelerationTier.MATHJS;
expect(wasmValue).toBeDefined();
expect(mathjsValue).toBeDefined();
});
});
describe('policy consistency', () => {
it('should maintain consistent tier enablement', () => {
const checks = [];
for (let i = 0; i < 5; i++) {
checks.push({
mathjs: isTierEnabled(AccelerationTier.MATHJS),
wasm: isTierEnabled(AccelerationTier.WASM),
workers: isTierEnabled(AccelerationTier.WORKERS),
gpu: isTierEnabled(AccelerationTier.GPU),
});
}
// All checks should be identical
for (let i = 1; i < checks.length; i++) {
expect(checks[i]).toEqual(checks[0]);
}
});
it('should have at least one tier enabled (mathjs)', () => {
const mathjs = isTierEnabled(AccelerationTier.MATHJS);
const wasm = isTierEnabled(AccelerationTier.WASM);
const workers = isTierEnabled(AccelerationTier.WORKERS);
const gpu = isTierEnabled(AccelerationTier.GPU);
// At least mathjs should be enabled
expect(mathjs || wasm || workers || gpu).toBe(true);
expect(mathjs).toBe(true); // mathjs is always enabled
});
});
describe('module initialization', () => {
it('should initialize policy on module load', () => {
// The module should have logged initialization
// We can't test this directly without reloading the module,
// but we can verify the policy is accessible
expect(isTierEnabled).toBeDefined();
expect(getConfigurationDescription).toBeDefined();
});
it('should create valid configuration description on init', () => {
const description = getConfigurationDescription();
expect(description).toBeTruthy();
expect(description).toMatch(/Acceleration:/);
});
});
describe('type safety', () => {
it('should only accept valid AccelerationTier values', () => {
// TypeScript ensures this, but we can test runtime behavior
const validTiers = [
AccelerationTier.MATHJS,
AccelerationTier.WASM,
AccelerationTier.WORKERS,
AccelerationTier.GPU,
];
for (const tier of validTiers) {
expect(() => isTierEnabled(tier)).not.toThrow();
}
});
});
describe('default configuration behavior', () => {
it('should enable MATHJS by default', () => {
expect(isTierEnabled(AccelerationTier.MATHJS)).toBe(true);
});
it('should enable WASM by default (unless explicitly disabled)', () => {
// WASM defaults to enabled unless ENABLE_WASM=false
const isEnabled = isTierEnabled(AccelerationTier.WASM);
// We can't assert the exact value without knowing env vars,
// but we can verify it's a boolean
expect(typeof isEnabled).toBe('boolean');
});
it('should enable WORKERS by default (unless explicitly disabled)', () => {
// WORKERS defaults to enabled unless ENABLE_WORKERS=false
const isEnabled = isTierEnabled(AccelerationTier.WORKERS);
expect(typeof isEnabled).toBe('boolean');
});
it('should disable GPU by default (unless explicitly enabled)', () => {
// GPU defaults to disabled unless ENABLE_GPU=true
const isEnabled = isTierEnabled(AccelerationTier.GPU);
expect(typeof isEnabled).toBe('boolean');
});
});
describe('configuration description format', () => {
it('should start with "Acceleration:"', () => {
const description = getConfigurationDescription();
expect(description).toMatch(/^Acceleration:/);
});
it('should contain valid tier names only', () => {
const description = getConfigurationDescription();
const validTiers = ['mathjs', 'wasm', 'workers', 'gpu'];
// Extract tier names from description
const parts = description.split('→').map(p => p.trim().replace('Acceleration: ', ''));
for (const part of parts) {
expect(validTiers).toContain(part);
}
});
it('should not have duplicate tiers', () => {
const description = getConfigurationDescription();
const parts = description.split('→').map(p => p.trim().replace('Acceleration: ', ''));
const uniqueParts = [...new Set(parts)];
expect(parts.length).toBe(uniqueParts.length);
});
});
});