mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-23 14:45:46 +00:00
fix(ci): restore boundary and test seams
This commit is contained in:
@@ -1,49 +1,46 @@
|
||||
export { resolveAckReaction } from "../../../src/agents/identity.js";
|
||||
export { resolveAckReaction } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export {
|
||||
createActionGate,
|
||||
jsonResult,
|
||||
readNumberParam,
|
||||
readReactionParams,
|
||||
readStringParam,
|
||||
} from "../../../src/agents/tools/common.js";
|
||||
export type { HistoryEntry } from "../../../src/auto-reply/reply/history.js";
|
||||
} from "openclaw/plugin-sdk/bluebubbles";
|
||||
export type { HistoryEntry } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export {
|
||||
evictOldHistoryKeys,
|
||||
recordPendingHistoryEntryIfEnabled,
|
||||
} from "../../../src/auto-reply/reply/history.js";
|
||||
export { resolveControlCommandGate } from "../../../src/channels/command-gating.js";
|
||||
export { logAckFailure, logInboundDrop, logTypingFailure } from "../../../src/channels/logging.js";
|
||||
export {
|
||||
BLUEBUBBLES_ACTION_NAMES,
|
||||
BLUEBUBBLES_ACTIONS,
|
||||
} from "../../../src/channels/plugins/bluebubbles-actions.js";
|
||||
export { resolveChannelMediaMaxBytes } from "../../../src/channels/plugins/media-limits.js";
|
||||
export { PAIRING_APPROVED_MESSAGE } from "../../../src/channels/plugins/pairing-message.js";
|
||||
export { collectBlueBubblesStatusIssues } from "../../../src/channels/plugins/status-issues/bluebubbles.js";
|
||||
} from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { resolveControlCommandGate } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { logAckFailure, logInboundDrop, logTypingFailure } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { BLUEBUBBLES_ACTION_NAMES, BLUEBUBBLES_ACTIONS } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { PAIRING_APPROVED_MESSAGE } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { collectBlueBubblesStatusIssues } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export type {
|
||||
BaseProbeResult,
|
||||
ChannelAccountSnapshot,
|
||||
ChannelMessageActionAdapter,
|
||||
ChannelMessageActionName,
|
||||
} from "../../../src/channels/plugins/types.js";
|
||||
export type { ChannelPlugin } from "../../../src/channels/plugins/types.plugin.js";
|
||||
export type { OpenClawConfig } from "../../../src/config/config.js";
|
||||
export { parseFiniteNumber } from "../../../src/infra/parse-finite-number.js";
|
||||
export type { PluginRuntime } from "../../../src/plugins/runtime/types.js";
|
||||
export { DEFAULT_ACCOUNT_ID } from "../../../src/routing/session-key.js";
|
||||
} from "openclaw/plugin-sdk/bluebubbles";
|
||||
export type { ChannelPlugin } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export type { OpenClawConfig } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { parseFiniteNumber } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export type { PluginRuntime } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export {
|
||||
DM_GROUP_ACCESS_REASON,
|
||||
readStoreAllowFromForDmPolicy,
|
||||
resolveDmGroupAccessWithLists,
|
||||
} from "../../../src/security/dm-policy-shared.js";
|
||||
export { readBooleanParam } from "../../../src/plugin-sdk/boolean-param.js";
|
||||
export { mapAllowFromEntries } from "../../../src/plugin-sdk/channel-config-helpers.js";
|
||||
export { createChannelPairingController } from "../../../src/plugin-sdk/channel-pairing.js";
|
||||
export { createChannelReplyPipeline } from "../../../src/plugin-sdk/channel-reply-pipeline.js";
|
||||
export { resolveRequestUrl } from "../../../src/plugin-sdk/request-url.js";
|
||||
export { buildProbeChannelStatusSummary } from "../../../src/plugin-sdk/status-helpers.js";
|
||||
export { stripMarkdown } from "../../../src/plugin-sdk/text-runtime.js";
|
||||
export { extractToolSend } from "../../../src/plugin-sdk/tool-send.js";
|
||||
} from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { readBooleanParam } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { mapAllowFromEntries } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { createChannelPairingController } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { createChannelReplyPipeline } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { resolveRequestUrl } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { buildProbeChannelStatusSummary } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { stripMarkdown } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export { extractToolSend } from "openclaw/plugin-sdk/bluebubbles";
|
||||
export {
|
||||
WEBHOOK_RATE_LIMIT_DEFAULTS,
|
||||
createFixedWindowRateLimiter,
|
||||
@@ -53,4 +50,4 @@ export {
|
||||
resolveRequestClientIp,
|
||||
resolveWebhookTargetWithAuthOrRejectSync,
|
||||
withResolvedWebhookRequestPipeline,
|
||||
} from "../../../src/plugin-sdk/webhook-ingress.js";
|
||||
} from "openclaw/plugin-sdk/bluebubbles";
|
||||
|
||||
@@ -14,14 +14,21 @@ const sendReactionSignal = vi.hoisted(() => vi.fn(async (..._args: unknown[]) =>
|
||||
const removeReactionSignal = vi.hoisted(() => vi.fn(async (..._args: unknown[]) => ({ ok: true })));
|
||||
const handleSlackAction = vi.hoisted(() => vi.fn(async (..._args: unknown[]) => actionResult()));
|
||||
|
||||
vi.mock("../../../../extensions/discord/src/actions/runtime.js", () => ({
|
||||
handleDiscordAction: async (...args: unknown[]) => await handleDiscordAction(...args),
|
||||
}));
|
||||
|
||||
vi.mock("../../../../extensions/signal/src/send-reactions.js", () => ({
|
||||
sendReactionSignal: async (...args: unknown[]) => await sendReactionSignal(...args),
|
||||
removeReactionSignal: async (...args: unknown[]) => await removeReactionSignal(...args),
|
||||
}));
|
||||
|
||||
let discordMessageActions: typeof import("../../../../extensions/discord/runtime-api.js").discordMessageActions;
|
||||
let handleDiscordMessageAction: typeof import("./discord/handle-action.js").handleDiscordMessageAction;
|
||||
let telegramMessageActions: typeof import("../../../../extensions/telegram/runtime-api.js").telegramMessageActions;
|
||||
let signalMessageActions: typeof import("../../../../extensions/signal/api.js").signalMessageActions;
|
||||
let createSlackActions: typeof import("../../../../extensions/slack/test-api.js").createSlackActions;
|
||||
let discordRuntimeModule: typeof import("../../../../extensions/discord/runtime-api.js");
|
||||
let telegramTestApiModule: typeof import("../../../../extensions/telegram/test-api.js");
|
||||
let signalReactionModule: typeof import("../../../../extensions/signal/api.js");
|
||||
|
||||
function getDescribedActions(params: {
|
||||
describeMessageTool?: ChannelMessageActionAdapter["describeMessageTool"];
|
||||
@@ -198,28 +205,17 @@ beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({ discordMessageActions } = await import("../../../../extensions/discord/runtime-api.js"));
|
||||
({ handleDiscordMessageAction } = await import("./discord/handle-action.js"));
|
||||
discordRuntimeModule = await import("../../../../extensions/discord/runtime-api.js");
|
||||
({ telegramMessageActions } = await import("../../../../extensions/telegram/runtime-api.js"));
|
||||
telegramTestApiModule = await import("../../../../extensions/telegram/test-api.js");
|
||||
({ signalMessageActions } = await import("../../../../extensions/signal/api.js"));
|
||||
signalReactionModule = await import("../../../../extensions/signal/api.js");
|
||||
({ createSlackActions } = await import("../../../../extensions/slack/test-api.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.restoreAllMocks();
|
||||
vi.spyOn(discordRuntimeModule, "handleDiscordAction").mockImplementation(
|
||||
async (...args) => await handleDiscordAction(...args),
|
||||
);
|
||||
telegramTestApiModule.telegramMessageActionRuntime.handleTelegramAction = async (...args) =>
|
||||
await handleTelegramAction(...args);
|
||||
vi.spyOn(signalReactionModule, "sendReactionSignal").mockImplementation(
|
||||
async (...args) => await sendReactionSignal(...args),
|
||||
);
|
||||
vi.spyOn(signalReactionModule, "removeReactionSignal").mockImplementation(
|
||||
async (...args) => await removeReactionSignal(...args),
|
||||
);
|
||||
});
|
||||
|
||||
describe("discord message actions", () => {
|
||||
|
||||
@@ -6,7 +6,8 @@ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi }
|
||||
import type { SessionEntry } from "./types.js";
|
||||
|
||||
// Keep integration tests deterministic: never read a real openclaw.json.
|
||||
vi.mock("../config.js", () => ({
|
||||
vi.mock("../config.js", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("../config.js")>()),
|
||||
loadConfig: vi.fn().mockReturnValue({}),
|
||||
}));
|
||||
|
||||
@@ -18,6 +19,15 @@ let saveSessionStore: typeof import("./store.js").saveSessionStore;
|
||||
let mockLoadConfig: ReturnType<typeof vi.fn>;
|
||||
|
||||
const DAY_MS = 24 * 60 * 60 * 1000;
|
||||
const ENFORCED_MAINTENANCE_OVERRIDE = {
|
||||
mode: "enforce" as const,
|
||||
pruneAfterMs: 7 * DAY_MS,
|
||||
maxEntries: 500,
|
||||
rotateBytes: 10_485_760,
|
||||
resetArchiveRetentionMs: 7 * DAY_MS,
|
||||
maxDiskBytes: null,
|
||||
highWaterBytes: null,
|
||||
};
|
||||
|
||||
const archiveTimestamp = (ms: number) => new Date(ms).toISOString().replaceAll(":", "-");
|
||||
|
||||
@@ -109,9 +119,11 @@ describe("Integration: saveSessionStore with pruning", () => {
|
||||
|
||||
const store = createStaleAndFreshStore();
|
||||
|
||||
await saveSessionStore(storePath, store);
|
||||
await saveSessionStore(storePath, store, {
|
||||
maintenanceOverride: ENFORCED_MAINTENANCE_OVERRIDE,
|
||||
});
|
||||
|
||||
const loaded = loadSessionStore(storePath);
|
||||
const loaded = loadSessionStore(storePath, { skipCache: true });
|
||||
expect(loaded.stale).toBeUndefined();
|
||||
expect(loaded.fresh).toBeDefined();
|
||||
});
|
||||
|
||||
@@ -6,6 +6,11 @@ import {
|
||||
resolveGatewayPort,
|
||||
resolveStateDir,
|
||||
} from "../config/config.js";
|
||||
import {
|
||||
resolveConfigPath as resolveConfigPathFromPaths,
|
||||
resolveGatewayPort as resolveGatewayPortFromPaths,
|
||||
resolveStateDir as resolveStateDirFromPaths,
|
||||
} from "../config/paths.js";
|
||||
import { resolveSecretInputRef } from "../config/types.secrets.js";
|
||||
import { loadOrCreateDeviceIdentity } from "../infra/device-identity.js";
|
||||
import { loadGatewayTlsRuntime } from "../infra/tls/gateway.js";
|
||||
@@ -95,6 +100,30 @@ const gatewayCallDeps = {
|
||||
...defaultGatewayCallDeps,
|
||||
};
|
||||
|
||||
function resolveGatewayStateDir(env: NodeJS.ProcessEnv): string {
|
||||
const resolveStateDirFn =
|
||||
typeof gatewayCallDeps.resolveStateDir === "function"
|
||||
? gatewayCallDeps.resolveStateDir
|
||||
: resolveStateDirFromPaths;
|
||||
return resolveStateDirFn(env);
|
||||
}
|
||||
|
||||
function resolveGatewayConfigPath(env: NodeJS.ProcessEnv): string {
|
||||
const resolveConfigPathFn =
|
||||
typeof gatewayCallDeps.resolveConfigPath === "function"
|
||||
? gatewayCallDeps.resolveConfigPath
|
||||
: resolveConfigPathFromPaths;
|
||||
return resolveConfigPathFn(env, resolveGatewayStateDir(env));
|
||||
}
|
||||
|
||||
function resolveGatewayPortValue(config?: OpenClawConfig, env?: NodeJS.ProcessEnv): number {
|
||||
const resolveGatewayPortFn =
|
||||
typeof gatewayCallDeps.resolveGatewayPort === "function"
|
||||
? gatewayCallDeps.resolveGatewayPort
|
||||
: resolveGatewayPortFromPaths;
|
||||
return resolveGatewayPortFn(config, env);
|
||||
}
|
||||
|
||||
export const __testing = {
|
||||
setDepsForTests(deps: Partial<typeof defaultGatewayCallDeps> | undefined): void {
|
||||
gatewayCallDeps.createGatewayClient =
|
||||
@@ -203,13 +232,11 @@ export function buildGatewayConnectionDetails(
|
||||
} = {},
|
||||
): GatewayConnectionDetails {
|
||||
const config = options.config ?? gatewayCallDeps.loadConfig();
|
||||
const configPath =
|
||||
options.configPath ??
|
||||
gatewayCallDeps.resolveConfigPath(process.env, gatewayCallDeps.resolveStateDir(process.env));
|
||||
const configPath = options.configPath ?? resolveGatewayConfigPath(process.env);
|
||||
const isRemoteMode = config.gateway?.mode === "remote";
|
||||
const remote = isRemoteMode ? config.gateway?.remote : undefined;
|
||||
const tlsEnabled = config.gateway?.tls?.enabled === true;
|
||||
const localPort = gatewayCallDeps.resolveGatewayPort(config);
|
||||
const localPort = resolveGatewayPortValue(config);
|
||||
const bindMode = config.gateway?.bind ?? "loopback";
|
||||
const scheme = tlsEnabled ? "wss" : "ws";
|
||||
// Self-connections should always target loopback; bind mode only controls listener exposure.
|
||||
@@ -322,9 +349,7 @@ function resolveGatewayCallTimeout(timeoutValue: unknown): {
|
||||
|
||||
function resolveGatewayCallContext(opts: CallGatewayBaseOptions): ResolvedGatewayCallContext {
|
||||
const config = opts.config ?? gatewayCallDeps.loadConfig();
|
||||
const configPath =
|
||||
opts.configPath ??
|
||||
gatewayCallDeps.resolveConfigPath(process.env, gatewayCallDeps.resolveStateDir(process.env));
|
||||
const configPath = opts.configPath ?? resolveGatewayConfigPath(process.env);
|
||||
const isRemoteMode = config.gateway?.mode === "remote";
|
||||
const remote = isRemoteMode
|
||||
? (config.gateway?.remote as GatewayRemoteSettings | undefined)
|
||||
@@ -732,10 +757,7 @@ export async function resolveGatewayCredentialsWithSecretInputs(params: {
|
||||
: undefined;
|
||||
const context: ResolvedGatewayCallContext = {
|
||||
config: params.config,
|
||||
configPath: gatewayCallDeps.resolveConfigPath(
|
||||
process.env,
|
||||
gatewayCallDeps.resolveStateDir(process.env),
|
||||
),
|
||||
configPath: resolveGatewayConfigPath(process.env),
|
||||
isRemoteMode,
|
||||
remote: remoteFromOverride ?? remoteFromConfig,
|
||||
urlOverride: trimToUndefined(params.urlOverride),
|
||||
|
||||
@@ -4,17 +4,23 @@ type TestMock = ReturnType<typeof vi.fn>;
|
||||
|
||||
export const loadConfigMock: TestMock = vi.fn();
|
||||
export const resolveGatewayPortMock: TestMock = vi.fn();
|
||||
export const resolveStateDirMock: TestMock = vi.fn(
|
||||
(env: NodeJS.ProcessEnv) => env.OPENCLAW_STATE_DIR ?? "/tmp/openclaw",
|
||||
);
|
||||
export const resolveConfigPathMock: TestMock = vi.fn(
|
||||
(env: NodeJS.ProcessEnv, stateDir: string) =>
|
||||
env.OPENCLAW_CONFIG_PATH ?? `${stateDir}/openclaw.json`,
|
||||
);
|
||||
export const pickPrimaryTailnetIPv4Mock: TestMock = vi.fn();
|
||||
export const pickPrimaryLanIPv4Mock: TestMock = vi.fn();
|
||||
|
||||
vi.mock("../config/config.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../config/config.js")>();
|
||||
return {
|
||||
...actual,
|
||||
loadConfig: loadConfigMock,
|
||||
resolveGatewayPort: resolveGatewayPortMock,
|
||||
};
|
||||
});
|
||||
vi.mock("../config/config.js", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("../config/config.js")>()),
|
||||
loadConfig: loadConfigMock,
|
||||
resolveGatewayPort: resolveGatewayPortMock,
|
||||
resolveStateDir: resolveStateDirMock,
|
||||
resolveConfigPath: resolveConfigPathMock,
|
||||
}));
|
||||
|
||||
vi.mock("../infra/tailnet.js", () => ({
|
||||
pickPrimaryTailnetIPv4: pickPrimaryTailnetIPv4Mock,
|
||||
|
||||
@@ -4,7 +4,9 @@ import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import {
|
||||
loadConfigMock as loadConfig,
|
||||
resolveConfigPathMock as resolveConfigPath,
|
||||
resolveGatewayPortMock as resolveGatewayPort,
|
||||
resolveStateDirMock as resolveStateDir,
|
||||
} from "../gateway/gateway-connection.test-mocks.js";
|
||||
import { captureEnv, withEnvAsync } from "../test-utils/env.js";
|
||||
|
||||
@@ -91,7 +93,16 @@ describe("resolveGatewayConnection", () => {
|
||||
]);
|
||||
loadConfig.mockReset();
|
||||
resolveGatewayPort.mockReset();
|
||||
resolveStateDir.mockReset();
|
||||
resolveConfigPath.mockReset();
|
||||
resolveGatewayPort.mockReturnValue(18789);
|
||||
resolveStateDir.mockImplementation(
|
||||
(env: NodeJS.ProcessEnv) => env.OPENCLAW_STATE_DIR ?? "/tmp/openclaw",
|
||||
);
|
||||
resolveConfigPath.mockImplementation(
|
||||
(env: NodeJS.ProcessEnv, stateDir: string) =>
|
||||
env.OPENCLAW_CONFIG_PATH ?? `${stateDir}/openclaw.json`,
|
||||
);
|
||||
delete process.env.OPENCLAW_GATEWAY_URL;
|
||||
delete process.env.OPENCLAW_GATEWAY_TOKEN;
|
||||
delete process.env.OPENCLAW_GATEWAY_PASSWORD;
|
||||
|
||||
Reference in New Issue
Block a user