1313import com .fasterxml .jackson .databind .ObjectMapper ;
1414import com .googlecode .jsonrpc4j .JsonRpcServer ;
1515import java .io .IOException ;
16+ import java .io .InputStream ;
17+ import java .io .OutputStream ;
1618import java .lang .reflect .Field ;
1719import java .nio .charset .StandardCharsets ;
1820import javax .servlet .http .HttpServletRequest ;
@@ -87,16 +89,20 @@ public void batchExceedsLimit_returnsExceedLimitAsArray() throws Exception {
8789 @ Test
8890 public void batchWithinLimit_proceedsToRpcServer () throws Exception {
8991 CommonParameter .getInstance ().jsonRpcMaxBatchSize = 5 ;
90- byte [] rpcResp = "[{\" result\" :\" ok\" }]" .getBytes (StandardCharsets .UTF_8 );
92+ byte [] singleResp = "{\" jsonrpc\" :\" 2.0\" ,\" result\" :\" ok\" ,\" id\" :1}"
93+ .getBytes (StandardCharsets .UTF_8 );
9194 doAnswer (inv -> {
92- HttpServletResponse r = inv .getArgument (1 );
93- r . getOutputStream (). write (rpcResp );
94- return null ;
95- }).when (mockRpcServer ).handle (any (HttpServletRequest .class ), any (HttpServletResponse .class ));
95+ OutputStream out = inv .getArgument (1 );
96+ out . write (singleResp );
97+ return 0 ;
98+ }).when (mockRpcServer ).handleRequest (any (InputStream .class ), any (OutputStream .class ));
9699
97100 MockHttpServletResponse resp = doPost ("[{\" id\" :1},{\" id\" :2}]" );
98101 assertEquals (200 , resp .getStatus ());
99- assertArrayEquals (rpcResp , resp .getContentAsByteArray ());
102+ JsonNode body = MAPPER .readTree (resp .getContentAsByteArray ());
103+ assertTrue ("batch response must be a JSON array" , body .isArray ());
104+ assertEquals ("each sub-request must produce a response" , 2 , body .size ());
105+ assertEquals ("ok" , body .get (0 ).get ("result" ).asText ());
100106 }
101107
102108 @ Test
@@ -113,12 +119,9 @@ public void emptyBatch_returnsInvalidRequest() throws Exception {
113119 @ Test
114120 public void batchLimitDisabled_largeBatchAllowed () throws Exception {
115121 CommonParameter .getInstance ().jsonRpcMaxBatchSize = 0 ;
116- byte [] rpcResp = "[]" .getBytes (StandardCharsets .UTF_8 );
117- doAnswer (inv -> {
118- HttpServletResponse r = inv .getArgument (1 );
119- r .getOutputStream ().write (rpcResp );
120- return null ;
121- }).when (mockRpcServer ).handle (any (HttpServletRequest .class ), any (HttpServletResponse .class ));
122+ // write nothing — simulates notifications (no response expected)
123+ doAnswer (inv -> 0 ).when (mockRpcServer )
124+ .handleRequest (any (InputStream .class ), any (OutputStream .class ));
122125
123126 StringBuilder sb = new StringBuilder ("[" );
124127 for (int i = 0 ; i < 500 ; i ++) {
@@ -130,7 +133,9 @@ public void batchLimitDisabled_largeBatchAllowed() throws Exception {
130133 sb .append ("]" );
131134 MockHttpServletResponse resp = doPost (sb .toString ());
132135 assertEquals (200 , resp .getStatus ());
133- assertArrayEquals (rpcResp , resp .getContentAsByteArray ());
136+ JsonNode body = MAPPER .readTree (resp .getContentAsByteArray ());
137+ assertTrue ("response must be a JSON array" , body .isArray ());
138+ assertEquals ("all notifications produce no response entries" , 0 , body .size ());
134139 }
135140
136141 // --- rpcServer.handle exceptions ---
@@ -149,7 +154,7 @@ public void rpcServerThrowsRuntimeException_returnsInternalError() throws Except
149154 @ Test
150155 public void batchRpcServerThrows_internalErrorIsArray () throws Exception {
151156 doThrow (new RuntimeException ("boom" )).when (mockRpcServer )
152- .handle (( HttpServletRequest ) any (), any ());
157+ .handleRequest ( any (InputStream . class ), any (OutputStream . class ));
153158 MockHttpServletResponse resp = doPost ("[{\" method\" :\" eth_blockNumber\" }]" );
154159 assertEquals (200 , resp .getStatus ());
155160 JsonNode body = MAPPER .readTree (resp .getContentAsString ());
@@ -181,10 +186,10 @@ public void batchResponseTooLarge_returnsErrorArray() throws Exception {
181186 int limit = 50 ;
182187 CommonParameter .getInstance ().jsonRpcMaxResponseSize = limit ;
183188 doAnswer (inv -> {
184- HttpServletResponse r = inv .getArgument (1 );
185- r . getOutputStream () .write (new byte [limit + 1 ]);
186- return null ;
187- }).when (mockRpcServer ).handle (any (HttpServletRequest .class ), any (HttpServletResponse .class ));
189+ OutputStream out = inv .getArgument (1 );
190+ out .write (new byte [limit + 1 ]);
191+ return 0 ;
192+ }).when (mockRpcServer ).handleRequest (any (InputStream .class ), any (OutputStream .class ));
188193
189194 MockHttpServletResponse resp = doPost ("[{\" method\" :\" eth_getLogs\" }]" );
190195 assertEquals (200 , resp .getStatus ());
@@ -193,6 +198,30 @@ public void batchResponseTooLarge_returnsErrorArray() throws Exception {
193198 assertEquals (-32003 , body .get (0 ).get ("error" ).get ("code" ).asInt ());
194199 }
195200
201+ @ Test
202+ public void batchShortCircuitsOnOverflow () throws Exception {
203+ int limit = 50 ;
204+ CommonParameter .getInstance ().jsonRpcMaxResponseSize = limit ;
205+ int [] callCount = {0 };
206+ doAnswer (inv -> {
207+ OutputStream out = inv .getArgument (1 );
208+ callCount [0 ]++;
209+ if (callCount [0 ] == 1 ) {
210+ out .write ("{\" result\" :\" ok\" }" .getBytes (StandardCharsets .UTF_8 ));
211+ } else {
212+ out .write (new byte [limit ]); // triggers overflow when added to accumulated size
213+ }
214+ return 0 ;
215+ }).when (mockRpcServer ).handleRequest (any (InputStream .class ), any (OutputStream .class ));
216+
217+ MockHttpServletResponse resp = doPost ("[{\" id\" :1},{\" id\" :2},{\" id\" :3}]" );
218+ assertEquals (200 , resp .getStatus ());
219+ JsonNode body = MAPPER .readTree (resp .getContentAsString ());
220+ assertTrue ("overflow response must be an array" , body .isArray ());
221+ assertEquals (-32003 , body .get (0 ).get ("error" ).get ("code" ).asInt ());
222+ assertEquals ("third sub-request must not be executed after overflow" , 2 , callCount [0 ]);
223+ }
224+
196225 // --- normal path ---
197226
198227 @ Test
0 commit comments