File tree Expand file tree Collapse file tree 3 files changed +74
-0
lines changed
Expand file tree Collapse file tree 3 files changed +74
-0
lines changed Original file line number Diff line number Diff line change 1+ import { Server } from "../server/index.js" ;
2+ import { StdioServerTransport } from "../server/stdio.js" ;
3+
4+ describe ( "Process cleanup" , ( ) => {
5+ jest . setTimeout ( 5000 ) ; // 5 second timeout
6+
7+ it ( "should exit cleanly after closing transport" , async ( ) => {
8+ const server = new Server (
9+ {
10+ name : "test-server" ,
11+ version : "1.0.0" ,
12+ } ,
13+ {
14+ capabilities : { } ,
15+ }
16+ ) ;
17+
18+ const transport = new StdioServerTransport ( ) ;
19+ await server . connect ( transport ) ;
20+
21+ // Close the transport
22+ await transport . close ( ) ;
23+
24+ // If we reach here without hanging, the test passes
25+ // The test runner will fail if the process hangs
26+ expect ( true ) . toBe ( true ) ;
27+ } ) ;
28+ } ) ;
Original file line number Diff line number Diff line change @@ -100,3 +100,41 @@ test("should read multiple messages", async () => {
100100 await finished ;
101101 expect ( readMessages ) . toEqual ( messages ) ;
102102} ) ;
103+
104+ test ( "should properly clean up resources when closed" , async ( ) => {
105+ // Create mock streams that track their destroyed state
106+ const mockStdin = new Readable ( {
107+ read ( ) { } , // No-op implementation
108+ destroy ( ) {
109+ this . destroyed = true ;
110+ return this ;
111+ }
112+ } ) ;
113+ const mockStdout = new Writable ( {
114+ write ( chunk , encoding , callback ) {
115+ callback ( ) ;
116+ } ,
117+ destroy ( ) {
118+ this . destroyed = true ;
119+ return this ;
120+ }
121+ } ) ;
122+
123+ const transport = new StdioServerTransport ( mockStdin , mockStdout ) ;
124+ await transport . start ( ) ;
125+
126+ // Send a message to potentially create 'drain' listeners
127+ await transport . send ( { jsonrpc : "2.0" , method : "test" , id : 1 } ) ;
128+
129+ // Close the transport
130+ await transport . close ( ) ;
131+
132+ // Check that all listeners were removed
133+ expect ( mockStdin . listenerCount ( 'data' ) ) . toBe ( 0 ) ;
134+ expect ( mockStdin . listenerCount ( 'error' ) ) . toBe ( 0 ) ;
135+ expect ( mockStdout . listenerCount ( 'drain' ) ) . toBe ( 0 ) ;
136+
137+ // Check that streams were properly ended
138+ expect ( mockStdin . destroyed ) . toBe ( true ) ;
139+ expect ( mockStdout . destroyed ) . toBe ( true ) ;
140+ } ) ;
Original file line number Diff line number Diff line change @@ -62,8 +62,16 @@ export class StdioServerTransport implements Transport {
6262 }
6363
6464 async close ( ) : Promise < void > {
65+ // Remove all event listeners
6566 this . _stdin . off ( "data" , this . _ondata ) ;
6667 this . _stdin . off ( "error" , this . _onerror ) ;
68+ this . _stdout . removeAllListeners ( 'drain' ) ;
69+
70+ // Destroy both streams
71+ this . _stdin . destroy ( ) ;
72+ this . _stdout . destroy ( ) ;
73+
74+ // Clear the buffer and notify closure
6775 this . _readBuffer . clear ( ) ;
6876 this . onclose ?.( ) ;
6977 }
You can’t perform that action at this time.
0 commit comments