@@ -5,6 +5,7 @@ import { MockRedisClient, setRedisClient } from '../redis.js';
5
5
import { handleStreamableHTTP } from './shttp.js' ;
6
6
import { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js' ;
7
7
import { randomUUID } from 'crypto' ;
8
+ import { shutdownSession } from '../services/redisTransport.js' ;
8
9
9
10
describe ( 'Streamable HTTP Handler Integration Tests' , ( ) => {
10
11
let mockRedis : MockRedisClient ;
@@ -21,20 +22,26 @@ describe('Streamable HTTP Handler Integration Tests', () => {
21
22
status : jest . fn ( ) . mockReturnThis ( ) ,
22
23
json : jest . fn ( ) . mockReturnThis ( ) ,
23
24
on : jest . fn ( ) . mockReturnThis ( ) ,
25
+ once : jest . fn ( ) . mockReturnThis ( ) ,
26
+ emit : jest . fn ( ) . mockReturnThis ( ) ,
24
27
headersSent : false ,
25
28
setHeader : jest . fn ( ) . mockReturnThis ( ) ,
26
29
writeHead : jest . fn ( ) . mockReturnThis ( ) ,
27
30
write : jest . fn ( ) . mockReturnThis ( ) ,
28
31
end : jest . fn ( ) . mockReturnThis ( ) ,
29
32
getHeader : jest . fn ( ) ,
30
33
removeHeader : jest . fn ( ) . mockReturnThis ( ) ,
31
- } as Partial < Response > ;
34
+ socket : {
35
+ setTimeout : jest . fn ( ) ,
36
+ } ,
37
+ } as unknown as Partial < Response > ;
32
38
33
39
// Create mock request
34
40
mockReq = {
35
41
method : 'POST' ,
36
42
headers : {
37
43
'content-type' : 'application/json' ,
44
+ 'accept' : 'application/json, text/event-stream' ,
38
45
'mcp-protocol-version' : '2024-11-05' ,
39
46
} ,
40
47
body : { } ,
@@ -57,12 +64,12 @@ describe('Streamable HTTP Handler Integration Tests', () => {
57
64
} ;
58
65
59
66
// Helper to extract session ID from test context
60
- const getSessionIdFromTest = ( ) => {
67
+ const getSessionIdFromTest = ( ) : string | undefined => {
61
68
// Try to get from response headers first
62
69
const setHeaderCalls = ( mockRes . setHeader as jest . Mock ) . mock . calls ;
63
70
const sessionIdHeader = setHeaderCalls . find ( ( [ name ] ) => name === 'mcp-session-id' ) ;
64
71
if ( sessionIdHeader ?. [ 1 ] ) {
65
- return sessionIdHeader [ 1 ] ;
72
+ return sessionIdHeader [ 1 ] as string ;
66
73
}
67
74
68
75
// Fall back to extracting from Redis channels
@@ -105,6 +112,10 @@ describe('Streamable HTTP Handler Integration Tests', () => {
105
112
106
113
// Wait longer for async initialization to complete
107
114
await new Promise ( resolve => setTimeout ( resolve , 200 ) ) ;
115
+
116
+ // get the sessionId from the response
117
+ const sessionId = getSessionIdFromTest ( ) ;
118
+ expect ( sessionId ) . toBeDefined ( ) ;
108
119
109
120
// Check if any subscriptions were created on any channels
110
121
// Since we don't know the exact sessionId generated, check all channels
@@ -129,6 +140,10 @@ describe('Streamable HTTP Handler Integration Tests', () => {
129
140
130
141
// Verify cleanup handler was registered
131
142
expect ( mockRes . on ) . toHaveBeenCalledWith ( 'finish' , expect . any ( Function ) ) ;
143
+
144
+ if ( sessionId ) {
145
+ await shutdownSession ( sessionId )
146
+ }
132
147
} ) ;
133
148
134
149
it ( 'should handle cleanup errors gracefully' , async ( ) => {
@@ -175,7 +190,9 @@ describe('Streamable HTTP Handler Integration Tests', () => {
175
190
// Send DELETE request to clean up MCP server
176
191
jest . clearAllMocks ( ) ;
177
192
mockReq . method = 'DELETE' ;
178
- mockReq . headers [ 'mcp-session-id' ] = cleanupSessionId ;
193
+ if ( mockReq . headers ) {
194
+ mockReq . headers [ 'mcp-session-id' ] = cleanupSessionId ;
195
+ }
179
196
mockReq . body = { } ;
180
197
181
198
await handleStreamableHTTP ( mockReq as Request , mockRes as Response ) ;
@@ -223,7 +240,7 @@ describe('Streamable HTTP Handler Integration Tests', () => {
223
240
let sessionId : string | undefined ;
224
241
225
242
if ( jsonCalls . length > 0 ) {
226
- const response = jsonCalls [ 0 ] [ 0 ] ;
243
+ const response = jsonCalls [ 0 ] [ 0 ] as any ;
227
244
if ( response ?. result ?. _meta ?. sessionId ) {
228
245
sessionId = response . result . _meta . sessionId ;
229
246
}
@@ -237,7 +254,7 @@ describe('Streamable HTTP Handler Integration Tests', () => {
237
254
try {
238
255
// SSE data format: "data: {...}\n\n"
239
256
const jsonStr = data . replace ( / ^ d a t a : / , '' ) . trim ( ) ;
240
- const parsed = JSON . parse ( jsonStr ) ;
257
+ const parsed = JSON . parse ( jsonStr ) as any ;
241
258
if ( parsed ?. result ?. _meta ?. sessionId ) {
242
259
sessionId = parsed . result . _meta . sessionId ;
243
260
}
@@ -327,7 +344,7 @@ describe('Streamable HTTP Handler Integration Tests', () => {
327
344
// Check JSON responses
328
345
const jsonCalls = ( mockRes . json as jest . Mock ) . mock . calls ;
329
346
if ( jsonCalls . length > 0 ) {
330
- const response = jsonCalls [ 0 ] [ 0 ] ;
347
+ const response = jsonCalls [ 0 ] [ 0 ] as any ;
331
348
if ( response ?. result ?. _meta ?. sessionId ) {
332
349
sessionId = response . result . _meta . sessionId ;
333
350
}
@@ -340,7 +357,7 @@ describe('Streamable HTTP Handler Integration Tests', () => {
340
357
if ( typeof data === 'string' && data . includes ( 'sessionId' ) ) {
341
358
try {
342
359
const jsonStr = data . replace ( / ^ d a t a : / , '' ) . trim ( ) ;
343
- const parsed = JSON . parse ( jsonStr ) ;
360
+ const parsed = JSON . parse ( jsonStr ) as any ;
344
361
if ( parsed ?. result ?. _meta ?. sessionId ) {
345
362
sessionId = parsed . result . _meta . sessionId ;
346
363
}
@@ -374,13 +391,17 @@ describe('Streamable HTTP Handler Integration Tests', () => {
374
391
375
392
// Should return 401 for unauthorized access to another user's session
376
393
expect ( mockRes . status ) . toHaveBeenCalledWith ( 401 ) ;
394
+
395
+ // shutdown the session
396
+ if ( sessionId ) {
397
+ await shutdownSession ( sessionId )
398
+ }
377
399
} ) ;
378
400
} ) ;
379
401
380
402
describe ( 'User Session Isolation' , ( ) => {
381
403
it ( 'should prevent users from accessing sessions created by other users' , async ( ) => {
382
404
// Create session for user 1
383
- const sessionId = randomUUID ( ) ;
384
405
const user1Auth : AuthInfo = {
385
406
clientId : 'user1-client' ,
386
407
token : 'user1-token' ,
@@ -421,7 +442,7 @@ describe('Streamable HTTP Handler Integration Tests', () => {
421
442
// Check JSON responses
422
443
const jsonCalls = ( mockRes . json as jest . Mock ) . mock . calls ;
423
444
if ( jsonCalls . length > 0 ) {
424
- const response = jsonCalls [ 0 ] [ 0 ] ;
445
+ const response = jsonCalls [ 0 ] [ 0 ] as any ;
425
446
if ( response ?. result ?. _meta ?. sessionId ) {
426
447
actualSessionId = response . result . _meta . sessionId ;
427
448
}
0 commit comments