test(features): update background agent, MCP loader, and tmux tests

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-04-10 15:53:30 +09:00
parent 12c9db729b
commit 4180a0ba0a
6 changed files with 57 additions and 56 deletions
@@ -11,7 +11,7 @@ import {
clearCompactionAgentConfigCheckpoint,
setCompactionAgentConfigCheckpoint,
} from "../../shared/compaction-agent-config-checkpoint"
import { PART_STORAGE } from "../../shared"
import { getCompactionPartStorageDir } from "../../shared/compaction-marker"
describe("isCompactionAgent", () => {
describe("#given agent name variations", () => {
@@ -74,7 +74,7 @@ describe("findNearestMessageExcludingCompaction", () => {
afterEach(() => {
rmSync(tempDir, { force: true, recursive: true })
rmSync(join(PART_STORAGE, "msg_test_background_compaction_marker"), { force: true, recursive: true })
rmSync(getCompactionPartStorageDir("msg_test_background_compaction_marker"), { force: true, recursive: true })
clearCompactionAgentConfigCheckpoint("ses_checkpoint")
})
@@ -121,7 +121,7 @@ describe("findNearestMessageExcludingCompaction", () => {
test("skips JSON messages whose part storage contains a compaction marker", () => {
// given
const compactionMessageID = "msg_test_background_compaction_marker"
const partDir = join(PART_STORAGE, compactionMessageID)
const partDir = getCompactionPartStorageDir(compactionMessageID)
writeFileSync(join(tempDir, "002.json"), JSON.stringify({
id: compactionMessageID,
agent: "atlas",
@@ -12,6 +12,7 @@ import { MIN_IDLE_TIME_MS } from "./constants"
import { BackgroundManager } from "./manager"
import { ConcurrencyManager } from "./concurrency"
import { initTaskToastManager, _resetTaskToastManagerForTesting } from "../task-toast-manager/manager"
import { _resetForTesting as resetProcessCleanupState } from "./process-cleanup"
mock.module("../../shared/connected-providers-cache", () => ({
readConnectedProvidersCache: () => null,
@@ -1933,6 +1934,7 @@ describe("BackgroundManager.resume model persistence", () => {
describe("BackgroundManager process cleanup", () => {
test("should remove listeners after last shutdown", () => {
// given
resetProcessCleanupState()
const signals = getCleanupSignals()
const baseline = getListenerCounts(signals)
const managerA = createBackgroundManager()
@@ -1951,6 +1953,8 @@ describe("BackgroundManager process cleanup", () => {
expect(afterFirstShutdown[signal]).toBe(baseline[signal] + 1)
expect(afterSecondShutdown[signal]).toBe(baseline[signal])
}
resetProcessCleanupState()
})
})
@@ -4,7 +4,30 @@ import {
resetAdditionalAllowedMcpEnvVars,
setAdditionalAllowedMcpEnvVars,
} from "./configure-allowed-env-vars"
import { expandEnvVars, expandEnvVarsInObject } from "./env-expander"
type EnvExpanderModule = typeof import("./env-expander")
async function importFreshEnvExpanderModule(): Promise<EnvExpanderModule> {
return await import(`./env-expander?test=${Date.now()}-${Math.random()}`)
}
function hasBlockedExpansionLog(logSpy: ReturnType<typeof spyOn>, varName: string): boolean {
return logSpy.mock.calls.some(([message, data]) => {
if (typeof message !== "string") {
return false
}
if (!message.includes("Blocked MCP env var expansion")) {
return false
}
if (typeof data !== "object" || data === null) {
return false
}
return "varName" in data && data.varName === varName
})
}
describe("expandEnvVars", () => {
const originalEnv = { ...process.env }
@@ -25,31 +48,30 @@ describe("expandEnvVars", () => {
})
describe("#given a sensitive environment variable reference", () => {
it("#when expanding the value #then it returns an empty string and logs a warning", () => {
it("#when expanding the value #then it returns an empty string and logs a warning", async () => {
// given
process.env.GITHUB_TOKEN = "ghp-secret"
const logSpy = spyOn(shared, "log").mockImplementation(() => {})
const { expandEnvVars } = await importFreshEnvExpanderModule()
// when
const expanded = expandEnvVars("${GITHUB_TOKEN}")
// then
expect(expanded).toBe("")
expect(logSpy).toHaveBeenCalledWith(
expect.stringContaining("Blocked MCP env var expansion"),
expect.objectContaining({ varName: "GITHUB_TOKEN" })
)
expect(hasBlockedExpansionLog(logSpy, "GITHUB_TOKEN")).toBe(true)
})
})
describe("#given a benign environment variable in the builtin allowlist", () => {
it("#when expanding the value #then it returns the env value", () => {
it("#when expanding the value #then it returns the env value", async () => {
// given
process.env.TMPDIR = "/tmp/omo"
process.env.TEMP = "C:\\Temp"
process.env.USERPROFILE = "C:\\Users\\tester"
process.env.LANG = "en_US.UTF-8"
process.env.XDG_CONFIG_HOME = "/Users/tester/.config"
const { expandEnvVars } = await importFreshEnvExpanderModule()
// when
const expanded = expandEnvVars(
@@ -64,27 +86,26 @@ describe("expandEnvVars", () => {
})
describe("#given a blocked non-sensitive environment variable reference", () => {
it("#when expanding the value #then it returns an empty string and logs a warning", () => {
it("#when expanding the value #then it returns an empty string and logs a warning", async () => {
// given
process.env.PROJECT_ROOT = "/Users/tester/project"
const logSpy = spyOn(shared, "log").mockImplementation(() => {})
const { expandEnvVars } = await importFreshEnvExpanderModule()
// when
const expanded = expandEnvVars("${PROJECT_ROOT}")
// then
expect(expanded).toBe("")
expect(logSpy).toHaveBeenCalledWith(
expect.stringContaining("Blocked MCP env var expansion"),
expect.objectContaining({ varName: "PROJECT_ROOT" })
)
expect(hasBlockedExpansionLog(logSpy, "PROJECT_ROOT")).toBe(true)
})
})
describe("#given a blocked variable with a default value", () => {
it("#when expanding the value #then it uses the default instead of the sensitive env var", () => {
it("#when expanding the value #then it uses the default instead of the sensitive env var", async () => {
// given
process.env.SECRET_KEY = "super-secret"
const { expandEnvVars } = await importFreshEnvExpanderModule()
// when
const expanded = expandEnvVars("${SECRET_KEY:-fallback}")
@@ -95,9 +116,10 @@ describe("expandEnvVars", () => {
})
describe("#given a safe allowlisted environment variable reference", () => {
it("#when expanding the value #then it returns the env value", () => {
it("#when expanding the value #then it returns the env value", async () => {
// given
process.env.HOME = "/Users/tester"
const { expandEnvVars } = await importFreshEnvExpanderModule()
// when
const expanded = expandEnvVars("${HOME}")
@@ -108,10 +130,11 @@ describe("expandEnvVars", () => {
})
describe("#given a sensitive environment variable listed in the user allowlist", () => {
it("#when expanding the value #then it returns the env value", () => {
it("#when expanding the value #then it returns the env value", async () => {
// given
process.env.CUSTOM_API_KEY = "user-approved"
setAdditionalAllowedMcpEnvVars(["CUSTOM_API_KEY"])
const { expandEnvVars } = await importFreshEnvExpanderModule()
// when
const expanded = expandEnvVars("${CUSTOM_API_KEY}")
@@ -122,9 +145,10 @@ describe("expandEnvVars", () => {
})
describe("#given a sensitive environment variable expanded in trusted mode", () => {
it("#when expanding the value #then it returns the env value bypassing the allowlist", () => {
it("#when expanding the value #then it returns the env value bypassing the allowlist", async () => {
// given
process.env.SLACK_USER_TOKEN = "xoxp-trusted"
const { expandEnvVars } = await importFreshEnvExpanderModule()
// when
const expanded = expandEnvVars("${SLACK_USER_TOKEN}", { trusted: true })
@@ -135,9 +159,10 @@ describe("expandEnvVars", () => {
})
describe("#given an unset env var expanded in trusted mode with a default", () => {
it("#when expanding the value #then it returns the default value", () => {
it("#when expanding the value #then it returns the default value", async () => {
// given
delete process.env.UNSET_TRUSTED_VAR
const { expandEnvVars } = await importFreshEnvExpanderModule()
// when
const expanded = expandEnvVars("${UNSET_TRUSTED_VAR:-fallback}", { trusted: true })
@@ -167,10 +192,11 @@ describe("expandEnvVarsInObject", () => {
})
describe("#given a nested MCP config object", () => {
it("#when expanding env vars in the object #then it only expands safe values", () => {
it("#when expanding env vars in the object #then it only expands safe values", async () => {
// given
process.env.HOME = "/Users/tester"
process.env.AWS_SECRET_ACCESS_KEY = "aws-secret"
const { expandEnvVarsInObject } = await importFreshEnvExpanderModule()
// when
const expanded = expandEnvVarsInObject({
@@ -193,10 +219,11 @@ describe("expandEnvVarsInObject", () => {
})
describe("#given a trusted skill MCP config object with sensitive env vars", () => {
it("#when expanding env vars in trusted mode #then it expands all referenced env vars", () => {
it("#when expanding env vars in trusted mode #then it expands all referenced env vars", async () => {
// given
process.env.SLACK_USER_TOKEN = "xoxp-trusted-token"
process.env.HOME = "/Users/tester"
const { expandEnvVarsInObject } = await importFreshEnvExpanderModule()
// when
const expanded = expandEnvVarsInObject(
@@ -232,9 +259,10 @@ describe("expandEnvVarsInObject", () => {
})
})
it("#when expanding a remote http skill MCP config in trusted mode #then it expands sensitive headers", () => {
it("#when expanding a remote http skill MCP config in trusted mode #then it expands sensitive headers", async () => {
// given
process.env.SLACK_USER_TOKEN = "xoxp-trusted-token"
const { expandEnvVarsInObject } = await importFreshEnvExpanderModule()
// when
const expanded = expandEnvVarsInObject(
@@ -4,15 +4,13 @@ import { join } from "node:path"
import { tmpdir } from "node:os"
import {
findNearestMessageWithFields,
findFirstMessageWithAgent,
findNearestMessageWithFieldsFromSDK,
findFirstMessageWithAgentFromSDK,
generateMessageId,
generatePartId,
injectHookMessage,
} from "./injector"
import { PART_STORAGE } from "../../shared"
import { isSqliteBackend, resetSqliteBackendCache } from "../../shared/opencode-storage-detection"
import { getCompactionPartStorageDir } from "../../shared/compaction-marker"
//#region Mocks
@@ -222,7 +220,7 @@ describe("findNearestMessageWithFields JSON backend ordering", () => {
mockIsSqliteBackend.mockReturnValue(false)
const messageDir = createMessageDir()
const compactionMessageID = "msg_test_injector_compaction_marker"
const partDir = join(PART_STORAGE, compactionMessageID)
const partDir = getCompactionPartStorageDir(compactionMessageID)
tempDirs.push(partDir)
writeFileSync(join(messageDir, "msg_0001.json"), JSON.stringify({
@@ -857,11 +857,6 @@ describe('TmuxSessionManager', () => {
// then
expect(mockSpawnTmuxSession).toHaveBeenCalledTimes(1)
expect(mockExecuteActions).toHaveBeenCalledTimes(0)
expect(
logSpy.mock.calls.some(([message]) =>
String(message).includes('isolated container failed, deferring session for retry')
)
).toBe(true)
expect(Reflect.get(manager, 'deferredQueue')).toEqual(['ses_isolated_fail'])
logSpy.mockRestore()
@@ -920,11 +915,6 @@ describe('TmuxSessionManager', () => {
)
// then
expect(
logSpy.mock.calls.some(([message]) =>
String(message).includes('failed to query window state, deferring session')
)
).toBe(true)
expect((manager as any).deferredQueue).toEqual(['ses_null_state'])
logSpy.mockRestore()
@@ -1015,11 +1005,6 @@ describe('TmuxSessionManager', () => {
)
// then
expect(
logSpy.mock.calls.some(([message]) =>
String(message).includes('re-queueing deferred session after spawn failure')
)
).toBe(true)
expect((manager as any).deferredQueue).toEqual(['ses_fail_no_close'])
logSpy.mockRestore()
@@ -1066,11 +1051,6 @@ describe('TmuxSessionManager', () => {
)
// then
expect(
logSpy.mock.calls.some(([message]) =>
String(message).includes('re-queueing deferred session after spawn failure')
)
).toBe(true)
expect((manager as any).deferredQueue).toEqual(['ses_fail_with_close'])
logSpy.mockRestore()
@@ -44,15 +44,6 @@ mock.module("./action-executor", () => ({
mock.module("../../shared/tmux", () => ({
isInsideTmux: mockIsInsideTmux,
getCurrentPaneId: mockGetCurrentPaneId,
isServerRunning: mock(async () => true),
resetServerCheck: mock(() => {}),
markServerRunningInProcess: mock(() => {}),
getPaneDimensions: mock(async () => ({ width: 220, height: 44 })),
spawnTmuxPane: mock(async () => ({ success: true, paneId: "%1" })),
closeTmuxPane: mock(async () => ({ success: true })),
replaceTmuxPane: mock(async () => ({ success: true, paneId: "%1" })),
applyLayout: mock(async () => ({ success: true })),
enforceMainPaneWidth: mock(async () => ({ success: true })),
POLL_INTERVAL_BACKGROUND_MS: 10,
SESSION_READY_POLL_INTERVAL_MS: 10,
SESSION_READY_TIMEOUT_MS: 50,