mirror of https://github.com/openclaw/openclaw.git
368 lines
9.2 KiB
TypeScript
368 lines
9.2 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
createAsyncComputedAccountStatusAdapter,
|
|
buildBaseAccountStatusSnapshot,
|
|
buildBaseChannelStatusSummary,
|
|
buildComputedAccountStatusSnapshot,
|
|
buildRuntimeAccountStatusSnapshot,
|
|
createComputedAccountStatusAdapter,
|
|
buildTokenChannelStatusSummary,
|
|
collectStatusIssuesFromLastError,
|
|
createDefaultChannelRuntimeState,
|
|
} from "./status-helpers.js";
|
|
|
|
describe("createDefaultChannelRuntimeState", () => {
|
|
it("builds default runtime state without extra fields", () => {
|
|
expect(createDefaultChannelRuntimeState("default")).toEqual({
|
|
accountId: "default",
|
|
running: false,
|
|
lastStartAt: null,
|
|
lastStopAt: null,
|
|
lastError: null,
|
|
});
|
|
});
|
|
|
|
it("merges extra fields into the default runtime state", () => {
|
|
expect(
|
|
createDefaultChannelRuntimeState("alerts", {
|
|
probeAt: 123,
|
|
healthy: true,
|
|
}),
|
|
).toEqual({
|
|
accountId: "alerts",
|
|
running: false,
|
|
lastStartAt: null,
|
|
lastStopAt: null,
|
|
lastError: null,
|
|
probeAt: 123,
|
|
healthy: true,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("buildBaseChannelStatusSummary", () => {
|
|
it("defaults missing values", () => {
|
|
expect(buildBaseChannelStatusSummary({})).toEqual({
|
|
configured: false,
|
|
running: false,
|
|
lastStartAt: null,
|
|
lastStopAt: null,
|
|
lastError: null,
|
|
});
|
|
});
|
|
|
|
it("keeps explicit values", () => {
|
|
expect(
|
|
buildBaseChannelStatusSummary({
|
|
configured: true,
|
|
running: true,
|
|
lastStartAt: 1,
|
|
lastStopAt: 2,
|
|
lastError: "boom",
|
|
}),
|
|
).toEqual({
|
|
configured: true,
|
|
running: true,
|
|
lastStartAt: 1,
|
|
lastStopAt: 2,
|
|
lastError: "boom",
|
|
});
|
|
});
|
|
|
|
it("merges extra fields into the normalized channel summary", () => {
|
|
expect(
|
|
buildBaseChannelStatusSummary(
|
|
{
|
|
configured: true,
|
|
},
|
|
{
|
|
mode: "webhook",
|
|
secretSource: "env",
|
|
},
|
|
),
|
|
).toEqual({
|
|
configured: true,
|
|
mode: "webhook",
|
|
secretSource: "env",
|
|
running: false,
|
|
lastStartAt: null,
|
|
lastStopAt: null,
|
|
lastError: null,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("buildBaseAccountStatusSnapshot", () => {
|
|
it("builds account status with runtime defaults", () => {
|
|
expect(
|
|
buildBaseAccountStatusSnapshot({
|
|
account: { accountId: "default", enabled: true, configured: true },
|
|
}),
|
|
).toEqual({
|
|
accountId: "default",
|
|
name: undefined,
|
|
enabled: true,
|
|
configured: true,
|
|
running: false,
|
|
lastStartAt: null,
|
|
lastStopAt: null,
|
|
lastError: null,
|
|
probe: undefined,
|
|
lastInboundAt: null,
|
|
lastOutboundAt: null,
|
|
});
|
|
});
|
|
|
|
it("merges extra snapshot fields after the shared account shape", () => {
|
|
expect(
|
|
buildBaseAccountStatusSnapshot(
|
|
{
|
|
account: { accountId: "default", configured: true },
|
|
},
|
|
{
|
|
connected: true,
|
|
mode: "polling",
|
|
},
|
|
),
|
|
).toEqual({
|
|
accountId: "default",
|
|
name: undefined,
|
|
enabled: undefined,
|
|
configured: true,
|
|
running: false,
|
|
lastStartAt: null,
|
|
lastStopAt: null,
|
|
lastError: null,
|
|
probe: undefined,
|
|
lastInboundAt: null,
|
|
lastOutboundAt: null,
|
|
connected: true,
|
|
mode: "polling",
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("buildComputedAccountStatusSnapshot", () => {
|
|
it("builds account status when configured is computed outside resolver", () => {
|
|
expect(
|
|
buildComputedAccountStatusSnapshot({
|
|
accountId: "default",
|
|
enabled: true,
|
|
configured: false,
|
|
}),
|
|
).toEqual({
|
|
accountId: "default",
|
|
name: undefined,
|
|
enabled: true,
|
|
configured: false,
|
|
running: false,
|
|
lastStartAt: null,
|
|
lastStopAt: null,
|
|
lastError: null,
|
|
probe: undefined,
|
|
lastInboundAt: null,
|
|
lastOutboundAt: null,
|
|
});
|
|
});
|
|
|
|
it("merges computed extras after the shared fields", () => {
|
|
expect(
|
|
buildComputedAccountStatusSnapshot(
|
|
{
|
|
accountId: "default",
|
|
configured: true,
|
|
},
|
|
{
|
|
connected: true,
|
|
},
|
|
),
|
|
).toEqual({
|
|
accountId: "default",
|
|
name: undefined,
|
|
enabled: undefined,
|
|
configured: true,
|
|
running: false,
|
|
lastStartAt: null,
|
|
lastStopAt: null,
|
|
lastError: null,
|
|
probe: undefined,
|
|
lastInboundAt: null,
|
|
lastOutboundAt: null,
|
|
connected: true,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("createComputedAccountStatusAdapter", () => {
|
|
it("builds account snapshots from computed account metadata and extras", () => {
|
|
const status = createComputedAccountStatusAdapter<
|
|
{ accountId: string; enabled: boolean; profileUrl: string },
|
|
{ ok: boolean }
|
|
>({
|
|
defaultRuntime: createDefaultChannelRuntimeState("default"),
|
|
resolveAccountSnapshot: ({ account, runtime, probe }) => ({
|
|
accountId: account.accountId,
|
|
enabled: account.enabled,
|
|
configured: true,
|
|
extra: {
|
|
profileUrl: account.profileUrl,
|
|
connected: runtime?.running ?? false,
|
|
probe,
|
|
},
|
|
}),
|
|
});
|
|
|
|
expect(
|
|
status.buildAccountSnapshot?.({
|
|
account: { accountId: "default", enabled: true, profileUrl: "https://example.test" },
|
|
cfg: {} as never,
|
|
runtime: { accountId: "default", running: true },
|
|
probe: { ok: true },
|
|
}),
|
|
).toEqual({
|
|
accountId: "default",
|
|
name: undefined,
|
|
enabled: true,
|
|
configured: true,
|
|
running: true,
|
|
lastStartAt: null,
|
|
lastStopAt: null,
|
|
lastError: null,
|
|
probe: { ok: true },
|
|
lastInboundAt: null,
|
|
lastOutboundAt: null,
|
|
profileUrl: "https://example.test",
|
|
connected: true,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("createAsyncComputedAccountStatusAdapter", () => {
|
|
it("builds account snapshots from async computed account metadata and extras", async () => {
|
|
const status = createAsyncComputedAccountStatusAdapter<
|
|
{ accountId: string; enabled: boolean; profileUrl: string },
|
|
{ ok: boolean }
|
|
>({
|
|
defaultRuntime: createDefaultChannelRuntimeState("default"),
|
|
resolveAccountSnapshot: async ({ account, runtime, probe }) => ({
|
|
accountId: account.accountId,
|
|
enabled: account.enabled,
|
|
configured: true,
|
|
extra: {
|
|
profileUrl: account.profileUrl,
|
|
connected: runtime?.running ?? false,
|
|
probe,
|
|
},
|
|
}),
|
|
});
|
|
|
|
await expect(
|
|
status.buildAccountSnapshot?.({
|
|
account: { accountId: "default", enabled: true, profileUrl: "https://example.test" },
|
|
cfg: {} as never,
|
|
runtime: { accountId: "default", running: true },
|
|
probe: { ok: true },
|
|
}),
|
|
).resolves.toEqual({
|
|
accountId: "default",
|
|
name: undefined,
|
|
enabled: true,
|
|
configured: true,
|
|
running: true,
|
|
lastStartAt: null,
|
|
lastStopAt: null,
|
|
lastError: null,
|
|
probe: { ok: true },
|
|
lastInboundAt: null,
|
|
lastOutboundAt: null,
|
|
profileUrl: "https://example.test",
|
|
connected: true,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("buildRuntimeAccountStatusSnapshot", () => {
|
|
it("builds runtime lifecycle fields with defaults", () => {
|
|
expect(buildRuntimeAccountStatusSnapshot({})).toEqual({
|
|
running: false,
|
|
lastStartAt: null,
|
|
lastStopAt: null,
|
|
lastError: null,
|
|
probe: undefined,
|
|
});
|
|
});
|
|
|
|
it("merges extra fields into runtime snapshots", () => {
|
|
expect(buildRuntimeAccountStatusSnapshot({}, { port: 3978 })).toEqual({
|
|
running: false,
|
|
lastStartAt: null,
|
|
lastStopAt: null,
|
|
lastError: null,
|
|
probe: undefined,
|
|
port: 3978,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("buildTokenChannelStatusSummary", () => {
|
|
it("includes token/probe fields with mode by default", () => {
|
|
expect(buildTokenChannelStatusSummary({})).toEqual({
|
|
configured: false,
|
|
tokenSource: "none",
|
|
running: false,
|
|
mode: null,
|
|
lastStartAt: null,
|
|
lastStopAt: null,
|
|
lastError: null,
|
|
probe: undefined,
|
|
lastProbeAt: null,
|
|
});
|
|
});
|
|
|
|
it("can omit mode for channels without a mode state", () => {
|
|
expect(
|
|
buildTokenChannelStatusSummary(
|
|
{
|
|
configured: true,
|
|
tokenSource: "env",
|
|
running: true,
|
|
lastStartAt: 1,
|
|
lastStopAt: 2,
|
|
lastError: "boom",
|
|
probe: { ok: true },
|
|
lastProbeAt: 3,
|
|
},
|
|
{ includeMode: false },
|
|
),
|
|
).toEqual({
|
|
configured: true,
|
|
tokenSource: "env",
|
|
running: true,
|
|
lastStartAt: 1,
|
|
lastStopAt: 2,
|
|
lastError: "boom",
|
|
probe: { ok: true },
|
|
lastProbeAt: 3,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("collectStatusIssuesFromLastError", () => {
|
|
it("returns runtime issues only for non-empty string lastError values", () => {
|
|
expect(
|
|
collectStatusIssuesFromLastError("telegram", [
|
|
{ accountId: "default", lastError: " timeout " },
|
|
{ accountId: "silent", lastError: " " },
|
|
{ accountId: "typed", lastError: { message: "boom" } },
|
|
]),
|
|
).toEqual([
|
|
{
|
|
channel: "telegram",
|
|
accountId: "default",
|
|
kind: "runtime",
|
|
message: "Channel error: timeout",
|
|
},
|
|
]);
|
|
});
|
|
});
|