Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions test/envFingerprint.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
const { describe, it } = require('node:test');
const assert = require('node:assert/strict');
const { captureEnvFingerprint, envFingerprintKey, isSameEnvClass } = require('../src/gep/envFingerprint');

describe('captureEnvFingerprint', function () {
it('returns an object with expected fields', function () {
const fp = captureEnvFingerprint();
assert.equal(typeof fp, 'object');
assert.equal(typeof fp.device_id, 'string');
assert.equal(typeof fp.node_version, 'string');
assert.equal(typeof fp.platform, 'string');
assert.equal(typeof fp.arch, 'string');
assert.equal(typeof fp.os_release, 'string');
assert.equal(typeof fp.hostname, 'string');
assert.equal(typeof fp.container, 'boolean');
assert.equal(typeof fp.cwd, 'string');
});

it('hashes hostname to 12 chars', function () {
const fp = captureEnvFingerprint();
assert.equal(fp.hostname.length, 12);
});

it('hashes cwd to 12 chars', function () {
const fp = captureEnvFingerprint();
assert.equal(fp.cwd.length, 12);
});

it('node_version starts with v', function () {
const fp = captureEnvFingerprint();
assert.ok(fp.node_version.startsWith('v'));
});

it('returns consistent results across calls', function () {
const fp1 = captureEnvFingerprint();
const fp2 = captureEnvFingerprint();
assert.equal(fp1.device_id, fp2.device_id);
assert.equal(fp1.platform, fp2.platform);
assert.equal(fp1.hostname, fp2.hostname);
});
});

describe('envFingerprintKey', function () {
it('returns a 16-char hex string', function () {
const fp = captureEnvFingerprint();
const key = envFingerprintKey(fp);
assert.equal(typeof key, 'string');
assert.equal(key.length, 16);
assert.match(key, /^[0-9a-f]{16}$/);
});

it('returns unknown for null input', function () {
assert.equal(envFingerprintKey(null), 'unknown');
});

it('returns unknown for non-object input', function () {
assert.equal(envFingerprintKey('string'), 'unknown');
});

it('same fingerprint produces same key', function () {
const fp = captureEnvFingerprint();
assert.equal(envFingerprintKey(fp), envFingerprintKey(fp));
});

it('different fingerprints produce different keys', function () {
const fp1 = captureEnvFingerprint();
const fp2 = { ...fp1, device_id: 'different_device' };
assert.notEqual(envFingerprintKey(fp1), envFingerprintKey(fp2));
});
});

describe('isSameEnvClass', function () {
it('returns true for identical fingerprints', function () {
const fp = captureEnvFingerprint();
assert.equal(isSameEnvClass(fp, fp), true);
});

it('returns true for fingerprints with same key fields', function () {
const fp1 = captureEnvFingerprint();
const fp2 = { ...fp1, cwd: 'different_cwd' }; // cwd is not in key
assert.equal(isSameEnvClass(fp1, fp2), true);
});

it('returns false for different environments', function () {
const fp1 = captureEnvFingerprint();
const fp2 = { ...fp1, device_id: 'other_device' };
assert.equal(isSameEnvClass(fp1, fp2), false);
});
});
134 changes: 134 additions & 0 deletions test/strategy.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
const { describe, it, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const { resolveStrategy, getStrategyNames, STRATEGIES } = require('../src/gep/strategy');

describe('STRATEGIES', function () {
it('defines all expected presets', function () {
const names = getStrategyNames();
assert.ok(names.includes('balanced'));
assert.ok(names.includes('innovate'));
assert.ok(names.includes('harden'));
assert.ok(names.includes('repair-only'));
assert.ok(names.includes('early-stabilize'));
assert.ok(names.includes('steady-state'));
});

it('all strategies have required fields', function () {
for (const [name, s] of Object.entries(STRATEGIES)) {
assert.equal(typeof s.repair, 'number', `${name}.repair`);
assert.equal(typeof s.optimize, 'number', `${name}.optimize`);
assert.equal(typeof s.innovate, 'number', `${name}.innovate`);
assert.equal(typeof s.repairLoopThreshold, 'number', `${name}.repairLoopThreshold`);
assert.equal(typeof s.label, 'string', `${name}.label`);
assert.equal(typeof s.description, 'string', `${name}.description`);
}
});

it('all strategy ratios sum to approximately 1.0', function () {
for (const [name, s] of Object.entries(STRATEGIES)) {
const sum = s.repair + s.optimize + s.innovate;
assert.ok(Math.abs(sum - 1.0) < 0.01, `${name} ratios sum to ${sum}`);
}
});
});

describe('resolveStrategy', function () {
let origStrategy;
let origForceInnovation;
let origEvolveForceInnovation;

beforeEach(function () {
origStrategy = process.env.EVOLVE_STRATEGY;
origForceInnovation = process.env.FORCE_INNOVATION;
origEvolveForceInnovation = process.env.EVOLVE_FORCE_INNOVATION;
delete process.env.EVOLVE_STRATEGY;
delete process.env.FORCE_INNOVATION;
delete process.env.EVOLVE_FORCE_INNOVATION;
});

afterEach(function () {
if (origStrategy !== undefined) process.env.EVOLVE_STRATEGY = origStrategy;
else delete process.env.EVOLVE_STRATEGY;
if (origForceInnovation !== undefined) process.env.FORCE_INNOVATION = origForceInnovation;
else delete process.env.FORCE_INNOVATION;
if (origEvolveForceInnovation !== undefined) process.env.EVOLVE_FORCE_INNOVATION = origEvolveForceInnovation;
else delete process.env.EVOLVE_FORCE_INNOVATION;
});

it('defaults to balanced when no env var set', function () {
const s = resolveStrategy({});
// Could be balanced or early-stabilize depending on cycle count
assert.ok(['balanced', 'early-stabilize'].includes(s.name));
});

it('respects explicit EVOLVE_STRATEGY', function () {
process.env.EVOLVE_STRATEGY = 'harden';
const s = resolveStrategy({});
assert.equal(s.name, 'harden');
assert.equal(s.label, 'Hardening');
});

it('respects innovate strategy', function () {
process.env.EVOLVE_STRATEGY = 'innovate';
const s = resolveStrategy({});
assert.equal(s.name, 'innovate');
assert.ok(s.innovate >= 0.8);
});

it('respects repair-only strategy', function () {
process.env.EVOLVE_STRATEGY = 'repair-only';
const s = resolveStrategy({});
assert.equal(s.name, 'repair-only');
assert.equal(s.innovate, 0);
});

it('FORCE_INNOVATION=true maps to innovate', function () {
process.env.FORCE_INNOVATION = 'true';
const s = resolveStrategy({});
assert.equal(s.name, 'innovate');
});

it('EVOLVE_FORCE_INNOVATION=true maps to innovate', function () {
process.env.EVOLVE_FORCE_INNOVATION = 'true';
const s = resolveStrategy({});
assert.equal(s.name, 'innovate');
});

it('explicit EVOLVE_STRATEGY takes precedence over FORCE_INNOVATION', function () {
process.env.EVOLVE_STRATEGY = 'harden';
process.env.FORCE_INNOVATION = 'true';
const s = resolveStrategy({});
assert.equal(s.name, 'harden');
});

it('saturation signal triggers steady-state', function () {
const s = resolveStrategy({ signals: ['evolution_saturation'] });
assert.equal(s.name, 'steady-state');
});

it('force_steady_state signal triggers steady-state', function () {
const s = resolveStrategy({ signals: ['force_steady_state'] });
assert.equal(s.name, 'steady-state');
});

it('falls back to balanced for unknown strategy name', function () {
process.env.EVOLVE_STRATEGY = 'nonexistent';
const s = resolveStrategy({});
const fallback = STRATEGIES['balanced'];
assert.equal(s.repair, fallback.repair);
assert.equal(s.optimize, fallback.optimize);
assert.equal(s.innovate, fallback.innovate);
});

it('auto maps to balanced or heuristic', function () {
process.env.EVOLVE_STRATEGY = 'auto';
const s = resolveStrategy({});
assert.ok(['balanced', 'early-stabilize'].includes(s.name));
});

it('returned strategy has name property', function () {
process.env.EVOLVE_STRATEGY = 'harden';
const s = resolveStrategy({});
assert.equal(s.name, 'harden');
});
});
148 changes: 148 additions & 0 deletions test/validationReport.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
const { describe, it } = require('node:test');
const assert = require('node:assert/strict');
const { buildValidationReport, isValidValidationReport } = require('../src/gep/validationReport');

describe('buildValidationReport', function () {
it('builds a valid report with minimal input', function () {
const report = buildValidationReport({
geneId: 'gene_test',
commands: ['echo hello'],
results: [{ ok: true, stdout: 'hello', stderr: '' }],
});
assert.equal(report.type, 'ValidationReport');
assert.equal(report.gene_id, 'gene_test');
assert.equal(report.overall_ok, true);
assert.equal(report.commands.length, 1);
assert.equal(report.commands[0].command, 'echo hello');
assert.equal(report.commands[0].ok, true);
assert.ok(report.id.startsWith('vr_'));
assert.ok(report.created_at);
assert.ok(report.asset_id);
assert.ok(report.env_fingerprint);
assert.ok(report.env_fingerprint_key);
});

it('marks overall_ok false when any result fails', function () {
const report = buildValidationReport({
geneId: 'gene_fail',
commands: ['cmd1', 'cmd2'],
results: [
{ ok: true, stdout: 'ok' },
{ ok: false, stderr: 'error' },
],
});
assert.equal(report.overall_ok, false);
});

it('marks overall_ok false when results is empty', function () {
const report = buildValidationReport({
geneId: 'gene_empty',
commands: [],
results: [],
});
assert.equal(report.overall_ok, false);
});

it('handles null geneId', function () {
const report = buildValidationReport({
commands: ['test'],
results: [{ ok: true }],
});
assert.equal(report.gene_id, null);
});

it('computes duration_ms from timestamps', function () {
const report = buildValidationReport({
geneId: 'gene_dur',
commands: ['test'],
results: [{ ok: true }],
startedAt: 1000,
finishedAt: 2500,
});
assert.equal(report.duration_ms, 1500);
});

it('duration_ms is null when timestamps missing', function () {
const report = buildValidationReport({
geneId: 'gene_nodur',
commands: ['test'],
results: [{ ok: true }],
});
assert.equal(report.duration_ms, null);
});

it('truncates stdout/stderr to 4000 chars', function () {
const longOutput = 'x'.repeat(5000);
const report = buildValidationReport({
geneId: 'gene_long',
commands: ['test'],
results: [{ ok: true, stdout: longOutput, stderr: longOutput }],
});
assert.equal(report.commands[0].stdout.length, 4000);
assert.equal(report.commands[0].stderr.length, 4000);
});

it('supports both out/stdout and err/stderr field names', function () {
const report = buildValidationReport({
geneId: 'gene_compat',
commands: ['test'],
results: [{ ok: true, out: 'output_via_out', err: 'error_via_err' }],
});
assert.equal(report.commands[0].stdout, 'output_via_out');
assert.equal(report.commands[0].stderr, 'error_via_err');
});

it('infers commands from results when commands not provided', function () {
const report = buildValidationReport({
geneId: 'gene_infer',
results: [{ ok: true, cmd: 'inferred_cmd' }],
});
assert.equal(report.commands[0].command, 'inferred_cmd');
});

it('uses provided envFp instead of capturing', function () {
const customFp = { device_id: 'custom', platform: 'test' };
const report = buildValidationReport({
geneId: 'gene_fp',
commands: ['test'],
results: [{ ok: true }],
envFp: customFp,
});
assert.equal(report.env_fingerprint.device_id, 'custom');
});
});

describe('isValidValidationReport', function () {
it('returns true for a valid report', function () {
const report = buildValidationReport({
geneId: 'gene_valid',
commands: ['test'],
results: [{ ok: true }],
});
assert.equal(isValidValidationReport(report), true);
});

it('returns false for null', function () {
assert.equal(isValidValidationReport(null), false);
});

it('returns false for non-object', function () {
assert.equal(isValidValidationReport('string'), false);
});

it('returns false for wrong type field', function () {
assert.equal(isValidValidationReport({ type: 'Other', id: 'x', commands: [], overall_ok: true }), false);
});

it('returns false for missing id', function () {
assert.equal(isValidValidationReport({ type: 'ValidationReport', commands: [], overall_ok: true }), false);
});

it('returns false for missing commands', function () {
assert.equal(isValidValidationReport({ type: 'ValidationReport', id: 'x', overall_ok: true }), false);
});

it('returns false for missing overall_ok', function () {
assert.equal(isValidValidationReport({ type: 'ValidationReport', id: 'x', commands: [] }), false);
});
});