Feat/upgrade openclaw (#729)
This commit is contained in:
committed by
GitHub
Unverified
parent
bf5b089158
commit
d34a88e629
@@ -2,15 +2,13 @@ import { describe, expect, it } from 'vitest';
|
||||
import { GatewayRestartGovernor } from '@electron/gateway/restart-governor';
|
||||
|
||||
describe('GatewayRestartGovernor', () => {
|
||||
it('suppresses restart during exponential cooldown window', () => {
|
||||
const governor = new GatewayRestartGovernor({
|
||||
baseCooldownMs: 1000,
|
||||
maxCooldownMs: 8000,
|
||||
maxRestartsPerWindow: 10,
|
||||
windowMs: 60000,
|
||||
stableResetMs: 60000,
|
||||
circuitOpenMs: 60000,
|
||||
});
|
||||
it('allows first restart unconditionally', () => {
|
||||
const governor = new GatewayRestartGovernor();
|
||||
expect(governor.decide(1000).allow).toBe(true);
|
||||
});
|
||||
|
||||
it('suppresses restart during cooldown window', () => {
|
||||
const governor = new GatewayRestartGovernor({ cooldownMs: 1000 });
|
||||
|
||||
expect(governor.decide(1000).allow).toBe(true);
|
||||
governor.recordExecuted(1000);
|
||||
@@ -18,76 +16,26 @@ describe('GatewayRestartGovernor', () => {
|
||||
const blocked = governor.decide(1500);
|
||||
expect(blocked.allow).toBe(false);
|
||||
expect(blocked.allow ? '' : blocked.reason).toBe('cooldown_active');
|
||||
expect(blocked.allow ? 0 : blocked.retryAfterMs).toBeGreaterThan(0);
|
||||
expect(blocked.allow ? 0 : blocked.retryAfterMs).toBe(500);
|
||||
|
||||
expect(governor.decide(3000).allow).toBe(true);
|
||||
// After cooldown expires, restart is allowed again
|
||||
expect(governor.decide(2001).allow).toBe(true);
|
||||
});
|
||||
|
||||
it('opens circuit after restart budget is exceeded', () => {
|
||||
const governor = new GatewayRestartGovernor({
|
||||
maxRestartsPerWindow: 2,
|
||||
windowMs: 60000,
|
||||
baseCooldownMs: 0,
|
||||
maxCooldownMs: 0,
|
||||
stableResetMs: 120000,
|
||||
circuitOpenMs: 30000,
|
||||
});
|
||||
it('allows unlimited restarts as long as cooldown is respected', () => {
|
||||
const governor = new GatewayRestartGovernor({ cooldownMs: 100 });
|
||||
|
||||
expect(governor.decide(1000).allow).toBe(true);
|
||||
governor.recordExecuted(1000);
|
||||
expect(governor.decide(2000).allow).toBe(true);
|
||||
governor.recordExecuted(2000);
|
||||
|
||||
const budgetBlocked = governor.decide(3000);
|
||||
expect(budgetBlocked.allow).toBe(false);
|
||||
expect(budgetBlocked.allow ? '' : budgetBlocked.reason).toBe('budget_exceeded');
|
||||
|
||||
const circuitBlocked = governor.decide(4000);
|
||||
expect(circuitBlocked.allow).toBe(false);
|
||||
expect(circuitBlocked.allow ? '' : circuitBlocked.reason).toBe('circuit_open');
|
||||
|
||||
expect(governor.decide(62001).allow).toBe(true);
|
||||
// 10 restarts in a row, each respecting cooldown — all should be allowed
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const t = 1000 + i * 200;
|
||||
expect(governor.decide(t).allow).toBe(true);
|
||||
governor.recordExecuted(t);
|
||||
}
|
||||
});
|
||||
|
||||
it('resets consecutive backoff after stable running period', () => {
|
||||
const governor = new GatewayRestartGovernor({
|
||||
baseCooldownMs: 1000,
|
||||
maxCooldownMs: 8000,
|
||||
maxRestartsPerWindow: 10,
|
||||
windowMs: 600000,
|
||||
stableResetMs: 5000,
|
||||
circuitOpenMs: 60000,
|
||||
});
|
||||
|
||||
governor.recordExecuted(0);
|
||||
governor.recordExecuted(1000);
|
||||
const blockedBeforeStable = governor.decide(2500);
|
||||
expect(blockedBeforeStable.allow).toBe(false);
|
||||
expect(blockedBeforeStable.allow ? '' : blockedBeforeStable.reason).toBe('cooldown_active');
|
||||
|
||||
governor.onRunning(3000);
|
||||
const allowedAfterStable = governor.decide(9000);
|
||||
expect(allowedAfterStable.allow).toBe(true);
|
||||
});
|
||||
|
||||
it('resets time-based state when clock moves backwards', () => {
|
||||
const governor = new GatewayRestartGovernor({
|
||||
maxRestartsPerWindow: 2,
|
||||
windowMs: 60000,
|
||||
baseCooldownMs: 1000,
|
||||
maxCooldownMs: 8000,
|
||||
stableResetMs: 60000,
|
||||
circuitOpenMs: 30000,
|
||||
});
|
||||
|
||||
governor.recordExecuted(10_000);
|
||||
governor.recordExecuted(11_000);
|
||||
const blocked = governor.decide(11_500);
|
||||
expect(blocked.allow).toBe(false);
|
||||
|
||||
// Simulate clock rewind and verify stale guard state does not lock out restarts.
|
||||
const afterRewind = governor.decide(9_000);
|
||||
expect(afterRewind.allow).toBe(true);
|
||||
it('onRunning is a no-op but does not throw', () => {
|
||||
const governor = new GatewayRestartGovernor();
|
||||
expect(() => governor.onRunning(1000)).not.toThrow();
|
||||
});
|
||||
|
||||
it('wraps counters safely at MAX_SAFE_INTEGER', () => {
|
||||
@@ -103,4 +51,12 @@ describe('GatewayRestartGovernor', () => {
|
||||
suppressedTotal: 0,
|
||||
});
|
||||
});
|
||||
|
||||
it('getObservability returns circuit_open_until as always 0', () => {
|
||||
const governor = new GatewayRestartGovernor();
|
||||
governor.recordExecuted(1000);
|
||||
const obs = governor.getObservability();
|
||||
expect(obs.circuit_open_until).toBe(0);
|
||||
expect(obs.executed_total).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user