mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 11:20:43 +00:00
test(google-meet): verify twilio setup readiness
This commit is contained in:
@@ -80,6 +80,7 @@ type NodeListResult = {
|
||||
function setup(
|
||||
config: Record<string, unknown> = {},
|
||||
options: {
|
||||
fullConfig?: Record<string, unknown>;
|
||||
nodesListResult?: NodeListResult;
|
||||
nodesInvokeResult?: unknown;
|
||||
browserActResult?: Record<string, unknown>;
|
||||
@@ -163,6 +164,7 @@ function setup(
|
||||
description: "test",
|
||||
version: "0",
|
||||
source: "test",
|
||||
config: options.fullConfig ?? {},
|
||||
pluginConfig: config,
|
||||
runtime: {
|
||||
system: {
|
||||
@@ -537,6 +539,94 @@ describe("google-meet plugin", () => {
|
||||
expect(result.details.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("reports Twilio delegation readiness when voice-call is enabled", async () => {
|
||||
vi.stubEnv("TWILIO_ACCOUNT_SID", "AC123");
|
||||
vi.stubEnv("TWILIO_AUTH_TOKEN", "secret");
|
||||
vi.stubEnv("TWILIO_FROM_NUMBER", "+15550001234");
|
||||
const { tools } = setup(
|
||||
{
|
||||
defaultTransport: "chrome-node",
|
||||
chromeNode: { node: "parallels-macos" },
|
||||
},
|
||||
{
|
||||
fullConfig: {
|
||||
plugins: {
|
||||
allow: ["google-meet", "voice-call"],
|
||||
entries: {
|
||||
"voice-call": {
|
||||
enabled: true,
|
||||
config: { provider: "twilio" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
const tool = tools[0] as {
|
||||
execute: (
|
||||
id: string,
|
||||
params: unknown,
|
||||
) => Promise<{ details: { ok?: boolean; checks?: unknown[] } }>;
|
||||
};
|
||||
|
||||
const result = await tool.execute("id", { action: "setup_status" });
|
||||
|
||||
expect(result.details.ok).toBe(true);
|
||||
expect(result.details.checks).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: "twilio-voice-call-plugin",
|
||||
ok: true,
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: "twilio-voice-call-credentials",
|
||||
ok: true,
|
||||
}),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("reports missing voice-call wiring for Twilio transport", async () => {
|
||||
vi.stubEnv("TWILIO_ACCOUNT_SID", "");
|
||||
vi.stubEnv("TWILIO_AUTH_TOKEN", "");
|
||||
vi.stubEnv("TWILIO_FROM_NUMBER", "");
|
||||
const { tools } = setup(
|
||||
{ defaultTransport: "twilio" },
|
||||
{
|
||||
fullConfig: {
|
||||
plugins: {
|
||||
allow: ["google-meet"],
|
||||
entries: {
|
||||
"voice-call": { enabled: false },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
const tool = tools[0] as {
|
||||
execute: (
|
||||
id: string,
|
||||
params: unknown,
|
||||
) => Promise<{ details: { ok?: boolean; checks?: unknown[] } }>;
|
||||
};
|
||||
|
||||
const result = await tool.execute("id", { action: "setup_status" });
|
||||
|
||||
expect(result.details.ok).toBe(false);
|
||||
expect(result.details.checks).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: "twilio-voice-call-plugin",
|
||||
ok: false,
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: "twilio-voice-call-credentials",
|
||||
ok: false,
|
||||
}),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("launches Chrome after the BlackHole check", async () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, "platform", { value: "darwin" });
|
||||
|
||||
@@ -81,7 +81,7 @@ export class GoogleMeetRuntime {
|
||||
}
|
||||
|
||||
setupStatus() {
|
||||
return getGoogleMeetSetupStatus(this.params.config);
|
||||
return getGoogleMeetSetupStatus(this.params.config, { fullConfig: this.params.fullConfig });
|
||||
}
|
||||
|
||||
async join(request: GoogleMeetJoinRequest): Promise<GoogleMeetJoinResult> {
|
||||
|
||||
@@ -22,8 +22,32 @@ function resolveUserPath(input: string): string {
|
||||
export function getGoogleMeetSetupStatus(config: GoogleMeetConfig): {
|
||||
ok: boolean;
|
||||
checks: SetupCheck[];
|
||||
} {
|
||||
};
|
||||
export function getGoogleMeetSetupStatus(
|
||||
config: GoogleMeetConfig,
|
||||
options?: {
|
||||
env?: NodeJS.ProcessEnv;
|
||||
fullConfig?: unknown;
|
||||
},
|
||||
): {
|
||||
ok: boolean;
|
||||
checks: SetupCheck[];
|
||||
};
|
||||
export function getGoogleMeetSetupStatus(
|
||||
config: GoogleMeetConfig,
|
||||
options?: {
|
||||
env?: NodeJS.ProcessEnv;
|
||||
fullConfig?: unknown;
|
||||
},
|
||||
) {
|
||||
const checks: SetupCheck[] = [];
|
||||
const env = options?.env ?? process.env;
|
||||
const fullConfig = asRecord(options?.fullConfig);
|
||||
const pluginEntries = asRecord(asRecord(fullConfig.plugins).entries);
|
||||
const pluginAllow = asRecord(fullConfig.plugins).allow;
|
||||
const voiceCallEntry = asRecord(pluginEntries["voice-call"]);
|
||||
const voiceCallConfig = asRecord(voiceCallEntry.config);
|
||||
const voiceCallTwilioConfig = asRecord(voiceCallConfig.twilio);
|
||||
|
||||
if (config.auth.tokenPath) {
|
||||
const tokenPath = resolveUserPath(config.auth.tokenPath);
|
||||
@@ -110,8 +134,55 @@ export function getGoogleMeetSetupStatus(config: GoogleMeetConfig): {
|
||||
: "Set chrome.waitForInCallMs to delay realtime intro until the Meet tab is in-call",
|
||||
});
|
||||
|
||||
const shouldCheckTwilioDelegation =
|
||||
config.voiceCall.enabled &&
|
||||
(config.defaultTransport === "twilio" ||
|
||||
Boolean(config.twilio.defaultDialInNumber) ||
|
||||
Object.hasOwn(pluginEntries, "voice-call"));
|
||||
if (shouldCheckTwilioDelegation) {
|
||||
const voiceCallAllowed = !Array.isArray(pluginAllow) || pluginAllow.includes("voice-call");
|
||||
const voiceCallEnabled = voiceCallEntry.enabled !== false;
|
||||
checks.push({
|
||||
id: "twilio-voice-call-plugin",
|
||||
ok: voiceCallAllowed && voiceCallEnabled,
|
||||
message:
|
||||
voiceCallAllowed && voiceCallEnabled
|
||||
? "Twilio transport can delegate dialing to the voice-call plugin"
|
||||
: "Enable plugins.entries.voice-call and include voice-call in plugins.allow for Twilio dialing",
|
||||
});
|
||||
|
||||
const provider = normalizeOptionalString(voiceCallConfig.provider) ?? "twilio";
|
||||
if (provider === "twilio") {
|
||||
const accountSid = normalizeOptionalString(voiceCallTwilioConfig.accountSid);
|
||||
const authToken = normalizeOptionalString(voiceCallTwilioConfig.authToken);
|
||||
const fromNumber = normalizeOptionalString(voiceCallConfig.fromNumber);
|
||||
const twilioReady = Boolean(
|
||||
(accountSid || env.TWILIO_ACCOUNT_SID) &&
|
||||
(authToken || env.TWILIO_AUTH_TOKEN) &&
|
||||
(fromNumber || env.TWILIO_FROM_NUMBER),
|
||||
);
|
||||
checks.push({
|
||||
id: "twilio-voice-call-credentials",
|
||||
ok: twilioReady,
|
||||
message: twilioReady
|
||||
? "Twilio voice-call credentials are configured"
|
||||
: "Set TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN, and TWILIO_FROM_NUMBER or configure voice-call Twilio credentials",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
ok: checks.every((check) => check.ok),
|
||||
checks,
|
||||
};
|
||||
}
|
||||
|
||||
function asRecord(value: unknown): Record<string, unknown> {
|
||||
return value && typeof value === "object" && !Array.isArray(value)
|
||||
? (value as Record<string, unknown>)
|
||||
: {};
|
||||
}
|
||||
|
||||
function normalizeOptionalString(value: unknown): string | undefined {
|
||||
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user