11import crypto from "node:crypto" ;
2- import { createServer } from "node:http" ;
3- import type { AddressInfo } from "node:net" ;
4- import type { ClawdbotConfig } from "openclaw/plugin-sdk/feishu" ;
52import { afterEach , describe , expect , it , vi } from "vitest" ;
63import { createFeishuRuntimeMockModule } from "./monitor.test-mocks.js" ;
4+ import { withRunningWebhookMonitor } from "./monitor.webhook.test-helpers.js" ;
75
86const probeFeishuMock = vi . hoisted ( ( ) => vi . fn ( ) ) ;
97
@@ -23,61 +21,6 @@ vi.mock("./runtime.js", () => createFeishuRuntimeMockModule());
2321
2422import { monitorFeishuProvider , stopFeishuMonitor } from "./monitor.js" ;
2523
26- async function getFreePort ( ) : Promise < number > {
27- const server = createServer ( ) ;
28- await new Promise < void > ( ( resolve ) => server . listen ( 0 , "127.0.0.1" , ( ) => resolve ( ) ) ) ;
29- const address = server . address ( ) as AddressInfo | null ;
30- if ( ! address ) {
31- throw new Error ( "missing server address" ) ;
32- }
33- await new Promise < void > ( ( resolve ) => server . close ( ( ) => resolve ( ) ) ) ;
34- return address . port ;
35- }
36-
37- async function waitUntilServerReady ( url : string ) : Promise < void > {
38- for ( let i = 0 ; i < 50 ; i += 1 ) {
39- try {
40- const response = await fetch ( url , { method : "GET" } ) ;
41- if ( response . status >= 200 && response . status < 500 ) {
42- return ;
43- }
44- } catch {
45- // retry
46- }
47- await new Promise ( ( resolve ) => setTimeout ( resolve , 20 ) ) ;
48- }
49- throw new Error ( `server did not start: ${ url } ` ) ;
50- }
51-
52- function buildConfig ( params : {
53- accountId : string ;
54- path : string ;
55- port : number ;
56- verificationToken ?: string ;
57- encryptKey ?: string ;
58- } ) : ClawdbotConfig {
59- return {
60- channels : {
61- feishu : {
62- enabled : true ,
63- accounts : {
64- [ params . accountId ] : {
65- enabled : true ,
66- appId : "cli_test" ,
67- appSecret : "secret_test" , // pragma: allowlist secret
68- connectionMode : "webhook" ,
69- webhookHost : "127.0.0.1" ,
70- webhookPort : params . port ,
71- webhookPath : params . path ,
72- encryptKey : params . encryptKey ,
73- verificationToken : params . verificationToken ,
74- } ,
75- } ,
76- } ,
77- } ,
78- } as ClawdbotConfig ;
79- }
80-
8124function signFeishuPayload ( params : {
8225 encryptKey : string ;
8326 payload : Record < string , unknown > ;
@@ -107,43 +50,6 @@ function encryptFeishuPayload(encryptKey: string, payload: Record<string, unknow
10750 return Buffer . concat ( [ iv , encrypted ] ) . toString ( "base64" ) ;
10851}
10952
110- async function withRunningWebhookMonitor (
111- params : {
112- accountId : string ;
113- path : string ;
114- verificationToken : string ;
115- encryptKey : string ;
116- } ,
117- run : ( url : string ) => Promise < void > ,
118- ) {
119- const port = await getFreePort ( ) ;
120- const cfg = buildConfig ( {
121- accountId : params . accountId ,
122- path : params . path ,
123- port,
124- encryptKey : params . encryptKey ,
125- verificationToken : params . verificationToken ,
126- } ) ;
127-
128- const abortController = new AbortController ( ) ;
129- const runtime = { log : vi . fn ( ) , error : vi . fn ( ) , exit : vi . fn ( ) } ;
130- const monitorPromise = monitorFeishuProvider ( {
131- config : cfg ,
132- runtime,
133- abortSignal : abortController . signal ,
134- } ) ;
135-
136- const url = `http://127.0.0.1:${ port } ${ params . path } ` ;
137- await waitUntilServerReady ( url ) ;
138-
139- try {
140- await run ( url ) ;
141- } finally {
142- abortController . abort ( ) ;
143- await monitorPromise ;
144- }
145- }
146-
14753afterEach ( ( ) => {
14854 stopFeishuMonitor ( ) ;
14955} ) ;
@@ -159,6 +65,7 @@ describe("Feishu webhook signed-request e2e", () => {
15965 verificationToken : "verify_token" ,
16066 encryptKey : "encrypt_key" ,
16167 } ,
68+ monitorFeishuProvider ,
16269 async ( url ) => {
16370 const payload = { type : "url_verification" , challenge : "challenge-token" } ;
16471 const response = await fetch ( url , {
@@ -185,6 +92,7 @@ describe("Feishu webhook signed-request e2e", () => {
18592 verificationToken : "verify_token" ,
18693 encryptKey : "encrypt_key" ,
18794 } ,
95+ monitorFeishuProvider ,
18896 async ( url ) => {
18997 const response = await fetch ( url , {
19098 method : "POST" ,
@@ -208,6 +116,7 @@ describe("Feishu webhook signed-request e2e", () => {
208116 verificationToken : "verify_token" ,
209117 encryptKey : "encrypt_key" ,
210118 } ,
119+ monitorFeishuProvider ,
211120 async ( url ) => {
212121 const response = await fetch ( url , {
213122 method : "POST" ,
@@ -231,6 +140,7 @@ describe("Feishu webhook signed-request e2e", () => {
231140 verificationToken : "verify_token" ,
232141 encryptKey : "encrypt_key" ,
233142 } ,
143+ monitorFeishuProvider ,
234144 async ( url ) => {
235145 const payload = { type : "url_verification" , challenge : "challenge-token" } ;
236146 const response = await fetch ( url , {
@@ -255,6 +165,7 @@ describe("Feishu webhook signed-request e2e", () => {
255165 verificationToken : "verify_token" ,
256166 encryptKey : "encrypt_key" ,
257167 } ,
168+ monitorFeishuProvider ,
258169 async ( url ) => {
259170 const payload = {
260171 schema : "2.0" ,
@@ -283,6 +194,7 @@ describe("Feishu webhook signed-request e2e", () => {
283194 verificationToken : "verify_token" ,
284195 encryptKey : "encrypt_key" ,
285196 } ,
197+ monitorFeishuProvider ,
286198 async ( url ) => {
287199 const payload = {
288200 encrypt : encryptFeishuPayload ( "encrypt_key" , {
0 commit comments