Files
MATTERMOST_OPENCLAW_LIVESTATUS/test/unit/config.test.js
sol 43cfebee96 feat: Phase 0+1 — repo sync, pino, lint fixes, core components
Phase 0:
- Synced latest live-status.js from workspace (9928 bytes)
- Fixed 43 lint issues: empty catch blocks, console statements
- Added pino dependency
- Created src/tool-labels.json with all known tool mappings
- make check passes

Phase 1 (Core Components):
- src/config.js: env-var config with validation, throws on missing required vars
- src/logger.js: pino singleton with child loggers, level validation
- src/circuit-breaker.js: CLOSED/OPEN/HALF_OPEN state machine with callbacks
- src/tool-labels.js: exact/prefix/regex tool->label resolver with external override
- src/status-box.js: Mattermost post manager (keepAlive, throttle, retry, circuit breaker)
- src/status-formatter.js: pure SessionState->text formatter (nested, compact)
- src/health.js: HTTP health endpoint + metrics
- src/status-watcher.js: JSONL file watcher (inotify, compaction detection, idle detection)

Tests:
- test/unit/config.test.js: 7 tests
- test/unit/circuit-breaker.test.js: 12 tests
- test/unit/logger.test.js: 5 tests
- test/unit/status-formatter.test.js: 20 tests
- test/unit/tool-labels.test.js: 15 tests

All 59 unit tests pass. make check clean.
2026-03-07 17:26:53 +00:00

136 lines
3.8 KiB
JavaScript

'use strict';
/**
* Unit tests for config.js
*/
const { describe, it, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const { buildConfig, resetConfig } = require('../../src/config');
describe('config.js', () => {
const originalEnv = {};
beforeEach(() => {
// Save and clear relevant env vars
const keys = [
'MM_BOT_TOKEN',
'MM_BASE_URL',
'MM_MAX_SOCKETS',
'TRANSCRIPT_DIR',
'THROTTLE_MS',
'IDLE_TIMEOUT_S',
'SESSION_POLL_MS',
'MAX_ACTIVE_SESSIONS',
'MAX_MESSAGE_CHARS',
'MAX_STATUS_LINES',
'MAX_RETRIES',
'CIRCUIT_BREAKER_THRESHOLD',
'CIRCUIT_BREAKER_COOLDOWN_S',
'HEALTH_PORT',
'LOG_LEVEL',
'PID_FILE',
'OFFSET_FILE',
'TOOL_LABELS_FILE',
'DEFAULT_CHANNEL',
'ENABLE_FS_WATCH',
'MM_PORT',
];
for (const k of keys) {
originalEnv[k] = process.env[k];
delete process.env[k];
}
resetConfig();
});
afterEach(() => {
// Restore env
for (const [k, v] of Object.entries(originalEnv)) {
if (v === undefined) delete process.env[k];
else process.env[k] = v;
}
resetConfig();
});
it('throws if MM_BOT_TOKEN is missing', () => {
assert.throws(() => buildConfig(), /MM_BOT_TOKEN/);
});
it('builds config with only required vars', () => {
process.env.MM_BOT_TOKEN = 'test-token';
const cfg = buildConfig();
assert.equal(cfg.mm.token, 'test-token');
assert.equal(cfg.mm.baseUrl, 'https://slack.solio.tech');
assert.equal(cfg.throttleMs, 500);
assert.equal(cfg.idleTimeoutS, 60);
assert.equal(cfg.maxActiveSessions, 20);
assert.equal(cfg.healthPort, 9090);
assert.equal(cfg.logLevel, 'info');
});
it('reads all env vars correctly', () => {
process.env.MM_BOT_TOKEN = 'mytoken';
process.env.MM_BASE_URL = 'https://mm.example.com';
process.env.MM_MAX_SOCKETS = '8';
process.env.THROTTLE_MS = '250';
process.env.IDLE_TIMEOUT_S = '120';
process.env.MAX_ACTIVE_SESSIONS = '10';
process.env.MAX_MESSAGE_CHARS = '5000';
process.env.LOG_LEVEL = 'debug';
process.env.HEALTH_PORT = '8080';
process.env.ENABLE_FS_WATCH = 'false';
const cfg = buildConfig();
assert.equal(cfg.mm.token, 'mytoken');
assert.equal(cfg.mm.baseUrl, 'https://mm.example.com');
assert.equal(cfg.mm.maxSockets, 8);
assert.equal(cfg.throttleMs, 250);
assert.equal(cfg.idleTimeoutS, 120);
assert.equal(cfg.maxActiveSessions, 10);
assert.equal(cfg.maxMessageChars, 5000);
assert.equal(cfg.logLevel, 'debug');
assert.equal(cfg.healthPort, 8080);
assert.equal(cfg.enableFsWatch, false);
});
it('throws on invalid MM_BASE_URL', () => {
process.env.MM_BOT_TOKEN = 'token';
process.env.MM_BASE_URL = 'not-a-url';
assert.throws(() => buildConfig(), /MM_BASE_URL/);
});
it('throws on non-integer THROTTLE_MS', () => {
process.env.MM_BOT_TOKEN = 'token';
process.env.THROTTLE_MS = 'abc';
assert.throws(() => buildConfig(), /THROTTLE_MS/);
});
it('ENABLE_FS_WATCH accepts "1", "true", "yes"', () => {
process.env.MM_BOT_TOKEN = 'token';
process.env.ENABLE_FS_WATCH = '1';
assert.equal(buildConfig().enableFsWatch, true);
resetConfig();
process.env.ENABLE_FS_WATCH = 'true';
assert.equal(buildConfig().enableFsWatch, true);
resetConfig();
process.env.ENABLE_FS_WATCH = 'yes';
assert.equal(buildConfig().enableFsWatch, true);
resetConfig();
process.env.ENABLE_FS_WATCH = '0';
assert.equal(buildConfig().enableFsWatch, false);
resetConfig();
});
it('nullish defaults for optional string fields', () => {
process.env.MM_BOT_TOKEN = 'token';
const cfg = buildConfig();
assert.equal(cfg.toolLabelsFile, null);
assert.equal(cfg.defaultChannel, null);
});
});