mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-27 09:21:35 +07:00
test: collapse msteams state and monitor suites
This commit is contained in:
@@ -3,6 +3,7 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
import { createMSTeamsConversationStoreFs } from "./conversation-store-fs.js";
|
||||
import { createMSTeamsConversationStoreMemory } from "./conversation-store-memory.js";
|
||||
import type { StoredConversationReference } from "./conversation-store.js";
|
||||
import { setMSTeamsRuntime } from "./runtime.js";
|
||||
import { msteamsRuntimeStub } from "./test-runtime.js";
|
||||
@@ -123,3 +124,64 @@ describe("msteams conversation store (fs)", () => {
|
||||
expect(retrieved!.timezone).toBe("Europe/London");
|
||||
});
|
||||
});
|
||||
|
||||
describe("msteams conversation store (memory)", () => {
|
||||
it("upserts, lists, removes, and resolves users by both AAD and Bot Framework ids", async () => {
|
||||
const store = createMSTeamsConversationStoreMemory([
|
||||
{
|
||||
conversationId: "conv-a",
|
||||
reference: {
|
||||
conversation: { id: "conv-a" },
|
||||
user: { id: "user-a", aadObjectId: "aad-a", name: "Alice" },
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
await store.upsert("conv-b", {
|
||||
conversation: { id: "conv-b" },
|
||||
user: { id: "user-b", aadObjectId: "aad-b", name: "Bob" },
|
||||
});
|
||||
|
||||
await expect(store.get("conv-a")).resolves.toEqual({
|
||||
conversation: { id: "conv-a" },
|
||||
user: { id: "user-a", aadObjectId: "aad-a", name: "Alice" },
|
||||
});
|
||||
|
||||
await expect(store.list()).resolves.toEqual([
|
||||
{
|
||||
conversationId: "conv-a",
|
||||
reference: {
|
||||
conversation: { id: "conv-a" },
|
||||
user: { id: "user-a", aadObjectId: "aad-a", name: "Alice" },
|
||||
},
|
||||
},
|
||||
{
|
||||
conversationId: "conv-b",
|
||||
reference: {
|
||||
conversation: { id: "conv-b" },
|
||||
user: { id: "user-b", aadObjectId: "aad-b", name: "Bob" },
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
await expect(store.findByUserId(" aad-b ")).resolves.toEqual({
|
||||
conversationId: "conv-b",
|
||||
reference: {
|
||||
conversation: { id: "conv-b" },
|
||||
user: { id: "user-b", aadObjectId: "aad-b", name: "Bob" },
|
||||
},
|
||||
});
|
||||
await expect(store.findByUserId("user-a")).resolves.toEqual({
|
||||
conversationId: "conv-a",
|
||||
reference: {
|
||||
conversation: { id: "conv-a" },
|
||||
user: { id: "user-a", aadObjectId: "aad-a", name: "Alice" },
|
||||
},
|
||||
});
|
||||
await expect(store.findByUserId(" ")).resolves.toBeNull();
|
||||
|
||||
await expect(store.remove("conv-a")).resolves.toBe(true);
|
||||
await expect(store.get("conv-a")).resolves.toBeNull();
|
||||
await expect(store.remove("missing")).resolves.toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createMSTeamsConversationStoreMemory } from "./conversation-store-memory.js";
|
||||
|
||||
describe("createMSTeamsConversationStoreMemory", () => {
|
||||
it("upserts, lists, removes, and resolves users by both AAD and Bot Framework ids", async () => {
|
||||
const store = createMSTeamsConversationStoreMemory([
|
||||
{
|
||||
conversationId: "conv-a",
|
||||
reference: {
|
||||
conversation: { id: "conv-a" },
|
||||
user: { id: "user-a", aadObjectId: "aad-a", name: "Alice" },
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
await store.upsert("conv-b", {
|
||||
conversation: { id: "conv-b" },
|
||||
user: { id: "user-b", aadObjectId: "aad-b", name: "Bob" },
|
||||
});
|
||||
|
||||
await expect(store.get("conv-a")).resolves.toEqual({
|
||||
conversation: { id: "conv-a" },
|
||||
user: { id: "user-a", aadObjectId: "aad-a", name: "Alice" },
|
||||
});
|
||||
|
||||
await expect(store.list()).resolves.toEqual([
|
||||
{
|
||||
conversationId: "conv-a",
|
||||
reference: {
|
||||
conversation: { id: "conv-a" },
|
||||
user: { id: "user-a", aadObjectId: "aad-a", name: "Alice" },
|
||||
},
|
||||
},
|
||||
{
|
||||
conversationId: "conv-b",
|
||||
reference: {
|
||||
conversation: { id: "conv-b" },
|
||||
user: { id: "user-b", aadObjectId: "aad-b", name: "Bob" },
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
await expect(store.findByUserId(" aad-b ")).resolves.toEqual({
|
||||
conversationId: "conv-b",
|
||||
reference: {
|
||||
conversation: { id: "conv-b" },
|
||||
user: { id: "user-b", aadObjectId: "aad-b", name: "Bob" },
|
||||
},
|
||||
});
|
||||
await expect(store.findByUserId("user-a")).resolves.toEqual({
|
||||
conversationId: "conv-a",
|
||||
reference: {
|
||||
conversation: { id: "conv-a" },
|
||||
user: { id: "user-a", aadObjectId: "aad-a", name: "Alice" },
|
||||
},
|
||||
});
|
||||
await expect(store.findByUserId(" ")).resolves.toBeNull();
|
||||
|
||||
await expect(store.remove("conv-a")).resolves.toBe(true);
|
||||
await expect(store.get("conv-a")).resolves.toBeNull();
|
||||
await expect(store.remove("missing")).resolves.toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,12 @@
|
||||
import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
|
||||
import { prepareFileConsentActivity, requiresFileConsent } from "./file-consent-helpers.js";
|
||||
import {
|
||||
clearPendingUploads,
|
||||
getPendingUpload,
|
||||
getPendingUploadCount,
|
||||
removePendingUpload,
|
||||
storePendingUpload,
|
||||
} from "./pending-uploads.js";
|
||||
import * as pendingUploads from "./pending-uploads.js";
|
||||
|
||||
describe("requiresFileConsent", () => {
|
||||
@@ -241,3 +248,79 @@ describe("prepareFileConsentActivity", () => {
|
||||
expect(result.activity.type).toBe("message");
|
||||
});
|
||||
});
|
||||
|
||||
describe("msteams pending uploads", () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
clearPendingUploads();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
clearPendingUploads();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it("stores uploads, exposes them by id, and tracks count", () => {
|
||||
const id = storePendingUpload({
|
||||
buffer: Buffer.from("hello"),
|
||||
filename: "hello.txt",
|
||||
contentType: "text/plain",
|
||||
conversationId: "conv-1",
|
||||
});
|
||||
|
||||
expect(getPendingUploadCount()).toBe(1);
|
||||
expect(getPendingUpload(id)).toEqual(
|
||||
expect.objectContaining({
|
||||
id,
|
||||
filename: "hello.txt",
|
||||
contentType: "text/plain",
|
||||
conversationId: "conv-1",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("removes uploads explicitly and ignores empty ids", () => {
|
||||
const id = storePendingUpload({
|
||||
buffer: Buffer.from("hello"),
|
||||
filename: "hello.txt",
|
||||
conversationId: "conv-1",
|
||||
});
|
||||
|
||||
removePendingUpload(undefined);
|
||||
expect(getPendingUploadCount()).toBe(1);
|
||||
|
||||
removePendingUpload(id);
|
||||
expect(getPendingUpload(id)).toBeUndefined();
|
||||
expect(getPendingUploadCount()).toBe(0);
|
||||
});
|
||||
|
||||
it("expires uploads by ttl even if the timeout callback has not been observed yet", () => {
|
||||
const id = storePendingUpload({
|
||||
buffer: Buffer.from("hello"),
|
||||
filename: "hello.txt",
|
||||
conversationId: "conv-1",
|
||||
});
|
||||
|
||||
vi.advanceTimersByTime(5 * 60 * 1000 + 1);
|
||||
|
||||
expect(getPendingUpload(id)).toBeUndefined();
|
||||
expect(getPendingUploadCount()).toBe(0);
|
||||
});
|
||||
|
||||
it("clears all uploads for test cleanup", () => {
|
||||
storePendingUpload({
|
||||
buffer: Buffer.from("a"),
|
||||
filename: "a.txt",
|
||||
conversationId: "conv-1",
|
||||
});
|
||||
storePendingUpload({
|
||||
buffer: Buffer.from("b"),
|
||||
filename: "b.txt",
|
||||
conversationId: "conv-2",
|
||||
});
|
||||
|
||||
clearPendingUploads();
|
||||
|
||||
expect(getPendingUploadCount()).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -37,6 +37,21 @@ async function waitForSlowBodySocketClose(port: number, timeoutMs: number): Prom
|
||||
}
|
||||
|
||||
describe("msteams monitor webhook hardening", () => {
|
||||
it("applies default timeouts and header clamp", async () => {
|
||||
const app = express();
|
||||
const server = app.listen(0, "127.0.0.1");
|
||||
await once(server, "listening");
|
||||
try {
|
||||
applyMSTeamsWebhookTimeouts(server);
|
||||
|
||||
expect(server.timeout).toBe(30_000);
|
||||
expect(server.requestTimeout).toBe(30_000);
|
||||
expect(server.headersTimeout).toBe(15_000);
|
||||
} finally {
|
||||
await closeServer(server);
|
||||
}
|
||||
});
|
||||
|
||||
it("applies explicit webhook timeout values", async () => {
|
||||
const app = express();
|
||||
const server = app.listen(0, "127.0.0.1");
|
||||
@@ -56,6 +71,25 @@ describe("msteams monitor webhook hardening", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("clamps headers timeout when explicit value exceeds request timeout", async () => {
|
||||
const app = express();
|
||||
const server = app.listen(0, "127.0.0.1");
|
||||
await once(server, "listening");
|
||||
try {
|
||||
applyMSTeamsWebhookTimeouts(server, {
|
||||
inactivityTimeoutMs: 12_000,
|
||||
requestTimeoutMs: 9_000,
|
||||
headersTimeoutMs: 15_000,
|
||||
});
|
||||
|
||||
expect(server.timeout).toBe(12_000);
|
||||
expect(server.requestTimeout).toBe(9_000);
|
||||
expect(server.headersTimeout).toBe(9_000);
|
||||
} finally {
|
||||
await closeServer(server);
|
||||
}
|
||||
});
|
||||
|
||||
it("drops slow-body webhook requests within configured inactivity timeout", async () => {
|
||||
const app = express();
|
||||
app.use(express.json({ limit: "1mb" }));
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
clearPendingUploads,
|
||||
getPendingUpload,
|
||||
getPendingUploadCount,
|
||||
removePendingUpload,
|
||||
storePendingUpload,
|
||||
} from "./pending-uploads.js";
|
||||
|
||||
describe("msteams pending uploads", () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
clearPendingUploads();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
clearPendingUploads();
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it("stores uploads, exposes them by id, and tracks count", () => {
|
||||
const id = storePendingUpload({
|
||||
buffer: Buffer.from("hello"),
|
||||
filename: "hello.txt",
|
||||
contentType: "text/plain",
|
||||
conversationId: "conv-1",
|
||||
});
|
||||
|
||||
expect(getPendingUploadCount()).toBe(1);
|
||||
expect(getPendingUpload(id)).toEqual(
|
||||
expect.objectContaining({
|
||||
id,
|
||||
filename: "hello.txt",
|
||||
contentType: "text/plain",
|
||||
conversationId: "conv-1",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("removes uploads explicitly and ignores empty ids", () => {
|
||||
const id = storePendingUpload({
|
||||
buffer: Buffer.from("hello"),
|
||||
filename: "hello.txt",
|
||||
conversationId: "conv-1",
|
||||
});
|
||||
|
||||
removePendingUpload(undefined);
|
||||
expect(getPendingUploadCount()).toBe(1);
|
||||
|
||||
removePendingUpload(id);
|
||||
expect(getPendingUpload(id)).toBeUndefined();
|
||||
expect(getPendingUploadCount()).toBe(0);
|
||||
});
|
||||
|
||||
it("expires uploads by ttl even if the timeout callback has not been observed yet", () => {
|
||||
const id = storePendingUpload({
|
||||
buffer: Buffer.from("hello"),
|
||||
filename: "hello.txt",
|
||||
conversationId: "conv-1",
|
||||
});
|
||||
|
||||
vi.advanceTimersByTime(5 * 60 * 1000 + 1);
|
||||
|
||||
expect(getPendingUpload(id)).toBeUndefined();
|
||||
expect(getPendingUploadCount()).toBe(0);
|
||||
});
|
||||
|
||||
it("clears all uploads for test cleanup", () => {
|
||||
storePendingUpload({
|
||||
buffer: Buffer.from("a"),
|
||||
filename: "a.txt",
|
||||
conversationId: "conv-1",
|
||||
});
|
||||
storePendingUpload({
|
||||
buffer: Buffer.from("b"),
|
||||
filename: "b.txt",
|
||||
conversationId: "conv-2",
|
||||
});
|
||||
|
||||
clearPendingUploads();
|
||||
|
||||
expect(getPendingUploadCount()).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -1,65 +0,0 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createMSTeamsPollStoreMemory } from "./polls-store-memory.js";
|
||||
|
||||
describe("createMSTeamsPollStoreMemory", () => {
|
||||
it("creates polls, reads them back, and records normalized votes", async () => {
|
||||
const store = createMSTeamsPollStoreMemory([
|
||||
{
|
||||
id: "poll-1",
|
||||
question: "Pick one",
|
||||
options: ["A", "B"],
|
||||
maxSelections: 1,
|
||||
votes: {},
|
||||
createdAt: "2026-03-22T00:00:00.000Z",
|
||||
updatedAt: "2026-03-22T00:00:00.000Z",
|
||||
},
|
||||
]);
|
||||
|
||||
await expect(store.getPoll("poll-1")).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
id: "poll-1",
|
||||
question: "Pick one",
|
||||
}),
|
||||
);
|
||||
|
||||
const originalUpdatedAt = "2026-03-22T00:00:00.000Z";
|
||||
await store.getPoll("poll-1");
|
||||
const result = await store.recordVote({
|
||||
pollId: "poll-1",
|
||||
voterId: "user-1",
|
||||
selections: ["1", "0", "missing"],
|
||||
});
|
||||
|
||||
expect(result?.votes["user-1"]).toEqual(["1"]);
|
||||
expect(result?.updatedAt).not.toBe(originalUpdatedAt);
|
||||
|
||||
await store.createPoll({
|
||||
id: "poll-2",
|
||||
question: "Pick many",
|
||||
options: ["X", "Y"],
|
||||
maxSelections: 2,
|
||||
votes: {},
|
||||
createdAt: "2026-03-22T00:00:00.000Z",
|
||||
updatedAt: "2026-03-22T00:00:00.000Z",
|
||||
});
|
||||
|
||||
await expect(
|
||||
store.recordVote({
|
||||
pollId: "poll-2",
|
||||
voterId: "user-2",
|
||||
selections: ["1", "0", "1"],
|
||||
}),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
id: "poll-2",
|
||||
votes: {
|
||||
"user-2": ["1", "0"],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(
|
||||
store.recordVote({ pollId: "missing", voterId: "nobody", selections: ["x"] }),
|
||||
).resolves.toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -1,41 +0,0 @@
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createMSTeamsPollStoreMemory } from "./polls-store-memory.js";
|
||||
import { createMSTeamsPollStoreFs } from "./polls.js";
|
||||
|
||||
const createFsStore = async () => {
|
||||
const stateDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "openclaw-msteams-polls-"));
|
||||
return createMSTeamsPollStoreFs({ stateDir });
|
||||
};
|
||||
|
||||
const createMemoryStore = () => createMSTeamsPollStoreMemory();
|
||||
|
||||
describe.each([
|
||||
{ name: "memory", createStore: createMemoryStore },
|
||||
{ name: "fs", createStore: createFsStore },
|
||||
])("$name poll store", ({ createStore }) => {
|
||||
it("stores polls and records normalized votes", async () => {
|
||||
const store = await createStore();
|
||||
await store.createPoll({
|
||||
id: "poll-1",
|
||||
question: "Lunch?",
|
||||
options: ["Pizza", "Sushi"],
|
||||
maxSelections: 1,
|
||||
createdAt: new Date().toISOString(),
|
||||
votes: {},
|
||||
});
|
||||
|
||||
const poll = await store.recordVote({
|
||||
pollId: "poll-1",
|
||||
voterId: "user-1",
|
||||
selections: ["0", "1"],
|
||||
});
|
||||
|
||||
if (!poll) {
|
||||
throw new Error("poll store did not return the updated poll");
|
||||
}
|
||||
expect(poll.votes["user-1"]).toEqual(["0"]);
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,7 @@ import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
import { createMSTeamsPollStoreMemory } from "./polls-store-memory.js";
|
||||
import { buildMSTeamsPollCard, createMSTeamsPollStoreFs, extractMSTeamsPollVote } from "./polls.js";
|
||||
import { setMSTeamsRuntime } from "./runtime.js";
|
||||
import { msteamsRuntimeStub } from "./test-runtime.js";
|
||||
@@ -60,3 +61,100 @@ describe("msteams polls", () => {
|
||||
expect(stored.votes["user-1"]).toEqual(["0"]);
|
||||
});
|
||||
});
|
||||
|
||||
const createFsStore = async () => {
|
||||
const stateDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), "openclaw-msteams-polls-"));
|
||||
return createMSTeamsPollStoreFs({ stateDir });
|
||||
};
|
||||
|
||||
const createMemoryStore = () => createMSTeamsPollStoreMemory();
|
||||
|
||||
describe.each([
|
||||
{ name: "memory", createStore: createMemoryStore },
|
||||
{ name: "fs", createStore: createFsStore },
|
||||
])("$name poll store", ({ createStore }) => {
|
||||
it("stores polls and records normalized votes", async () => {
|
||||
const store = await createStore();
|
||||
await store.createPoll({
|
||||
id: "poll-1",
|
||||
question: "Lunch?",
|
||||
options: ["Pizza", "Sushi"],
|
||||
maxSelections: 1,
|
||||
createdAt: new Date().toISOString(),
|
||||
votes: {},
|
||||
});
|
||||
|
||||
const poll = await store.recordVote({
|
||||
pollId: "poll-1",
|
||||
voterId: "user-1",
|
||||
selections: ["0", "1"],
|
||||
});
|
||||
|
||||
if (!poll) {
|
||||
throw new Error("poll store did not return the updated poll");
|
||||
}
|
||||
expect(poll.votes["user-1"]).toEqual(["0"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("memory poll store", () => {
|
||||
it("reads seeded polls back, updates timestamps, and returns null for missing polls", async () => {
|
||||
const store = createMSTeamsPollStoreMemory([
|
||||
{
|
||||
id: "poll-1",
|
||||
question: "Pick one",
|
||||
options: ["A", "B"],
|
||||
maxSelections: 1,
|
||||
votes: {},
|
||||
createdAt: "2026-03-22T00:00:00.000Z",
|
||||
updatedAt: "2026-03-22T00:00:00.000Z",
|
||||
},
|
||||
]);
|
||||
|
||||
await expect(store.getPoll("poll-1")).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
id: "poll-1",
|
||||
question: "Pick one",
|
||||
}),
|
||||
);
|
||||
|
||||
const originalUpdatedAt = "2026-03-22T00:00:00.000Z";
|
||||
const result = await store.recordVote({
|
||||
pollId: "poll-1",
|
||||
voterId: "user-1",
|
||||
selections: ["1", "0", "missing"],
|
||||
});
|
||||
|
||||
expect(result?.votes["user-1"]).toEqual(["1"]);
|
||||
expect(result?.updatedAt).not.toBe(originalUpdatedAt);
|
||||
|
||||
await store.createPoll({
|
||||
id: "poll-2",
|
||||
question: "Pick many",
|
||||
options: ["X", "Y"],
|
||||
maxSelections: 2,
|
||||
votes: {},
|
||||
createdAt: "2026-03-22T00:00:00.000Z",
|
||||
updatedAt: "2026-03-22T00:00:00.000Z",
|
||||
});
|
||||
|
||||
await expect(
|
||||
store.recordVote({
|
||||
pollId: "poll-2",
|
||||
voterId: "user-2",
|
||||
selections: ["1", "0", "1"],
|
||||
}),
|
||||
).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
id: "poll-2",
|
||||
votes: {
|
||||
"user-2": ["1", "0"],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(
|
||||
store.recordVote({ pollId: "missing", voterId: "nobody", selections: ["x"] }),
|
||||
).resolves.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import type { Server } from "node:http";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { applyMSTeamsWebhookTimeouts } from "./webhook-timeouts.js";
|
||||
|
||||
describe("applyMSTeamsWebhookTimeouts", () => {
|
||||
it("applies default timeouts and header clamp", () => {
|
||||
const httpServer: Pick<Server, "setTimeout" | "requestTimeout" | "headersTimeout"> = {
|
||||
setTimeout: vi.fn(),
|
||||
requestTimeout: 0,
|
||||
headersTimeout: 0,
|
||||
};
|
||||
|
||||
applyMSTeamsWebhookTimeouts(httpServer as Server);
|
||||
|
||||
expect(httpServer.setTimeout).toHaveBeenCalledWith(30_000);
|
||||
expect(httpServer.requestTimeout).toBe(30_000);
|
||||
expect(httpServer.headersTimeout).toBe(15_000);
|
||||
});
|
||||
|
||||
it("uses explicit overrides and clamps headers timeout to request timeout", () => {
|
||||
const httpServer: Pick<Server, "setTimeout" | "requestTimeout" | "headersTimeout"> = {
|
||||
setTimeout: vi.fn(),
|
||||
requestTimeout: 0,
|
||||
headersTimeout: 0,
|
||||
};
|
||||
|
||||
applyMSTeamsWebhookTimeouts(httpServer as Server, {
|
||||
inactivityTimeoutMs: 12_000,
|
||||
requestTimeoutMs: 9_000,
|
||||
headersTimeoutMs: 15_000,
|
||||
});
|
||||
|
||||
expect(httpServer.setTimeout).toHaveBeenCalledWith(12_000);
|
||||
expect(httpServer.requestTimeout).toBe(9_000);
|
||||
expect(httpServer.headersTimeout).toBe(9_000);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user