


























@@ -432,6 +432,117 @@ describe("mattermost inbound user posts", () => {
432432expect(ctx?.Provider).toBe("mattermost");
433433});
434434435+it("uses websocket channel type when REST channel lookup fails", async () => {
436+const socket = new FakeWebSocket();
437+const abortController = new AbortController();
438+mockState.abortController = abortController;
439+const runtimeCore = createRuntimeCore(testConfig);
440+mockState.runtimeCore = runtimeCore;
441+mockState.resolveChannelInfo.mockResolvedValue(null);
442+443+const monitor = monitorMattermostProvider({
444+config: testConfig,
445+runtime: testRuntime(),
446+abortSignal: abortController.signal,
447+webSocketFactory: () => socket,
448+});
449+450+await vi.waitFor(() => {
451+expect(socket.openListenerCount).toBeGreaterThan(0);
452+});
453+socket.emitOpen();
454+455+await socket.emitMessage({
456+event: "posted",
457+data: {
458+channel_id: "chan-1",
459+channel_name: "town-square",
460+channel_display_name: "Town Square",
461+channel_type: "O",
462+sender_name: "alice",
463+post: JSON.stringify({
464+id: "post-ws-kind",
465+channel_id: "chan-1",
466+user_id: "user-1",
467+message: "hello with websocket kind",
468+create_at: 1_714_000_000_000,
469+}),
470+},
471+broadcast: {
472+channel_id: "chan-1",
473+user_id: "user-1",
474+},
475+});
476+socket.emitClose(1000);
477+await monitor;
478+479+expect(mockState.dispatchReplyFromConfig).toHaveBeenCalledTimes(1);
480+const ctx = mockState.dispatchReplyFromConfig.mock.calls.at(0)?.[0].ctx;
481+expect(ctx?.BodyForAgent).toBe("hello with websocket kind");
482+expect(ctx?.ChatType).toBe("channel");
483+expect(ctx?.ConversationLabel).toBe("Town Square id:chan-1");
484+expect(runtimeCore.channel.session.recordInboundSession).toHaveBeenCalledTimes(1);
485+});
486+487+it("drops posts when neither REST nor websocket channel type can be resolved", async () => {
488+const socket = new FakeWebSocket();
489+const abortController = new AbortController();
490+mockState.abortController = abortController;
491+const channelTypeConfig: OpenClawConfig = {
492+channels: {
493+mattermost: {
494+enabled: true,
495+baseUrl: "https://mattermost.example.com",
496+botToken: "bot-token",
497+chatmode: "onmessage",
498+dmPolicy: "allowlist",
499+groupPolicy: "open",
500+allowFrom: ["trusted-user"],
501+},
502+},
503+};
504+const runtimeCore = createRuntimeCore(channelTypeConfig);
505+mockState.runtimeCore = runtimeCore;
506+mockState.resolveChannelInfo.mockResolvedValue(null);
507+508+const monitor = monitorMattermostProvider({
509+config: channelTypeConfig,
510+runtime: testRuntime(),
511+abortSignal: abortController.signal,
512+webSocketFactory: () => socket,
513+});
514+515+await vi.waitFor(() => {
516+expect(socket.openListenerCount).toBeGreaterThan(0);
517+});
518+socket.emitOpen();
519+520+await socket.emitMessage({
521+event: "posted",
522+data: {
523+channel_id: "dm-1",
524+sender_name: "mallory",
525+post: JSON.stringify({
526+id: "post-missing-kind",
527+channel_id: "dm-1",
528+user_id: "new-user",
529+message: "hello",
530+create_at: 1_714_000_000_000,
531+}),
532+},
533+broadcast: {
534+channel_id: "dm-1",
535+user_id: "new-user",
536+},
537+});
538+abortController.abort();
539+socket.emitClose(1000);
540+await monitor;
541+542+expect(mockState.dispatchReplyFromConfig).not.toHaveBeenCalled();
543+expect(runtimeCore.channel.session.recordInboundSession).not.toHaveBeenCalled();
544+});
545+435546it("pins direct-message main route updates to the configured owner", async () => {
436547const socket = new FakeWebSocket();
437548const abortController = new AbortController();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。