99 * A copy of the Apache 2.0 License can be found in the LICENSE file.
1010 */
1111
12+
1213package com .tencent .trpc .proto .http .server ;
1314
1415
1516import static org .junit .Assert .assertEquals ;
17+ import static org .mockito .Matchers .any ;
18+ import static org .mockito .Mockito .verify ;
19+ import static org .powermock .api .mockito .PowerMockito .doAnswer ;
20+ import static org .powermock .api .mockito .PowerMockito .doCallRealMethod ;
1621import static org .powermock .api .mockito .PowerMockito .doReturn ;
1722import static org .powermock .api .mockito .PowerMockito .mock ;
1823import static org .powermock .api .mockito .PowerMockito .when ;
1924
25+ import com .tencent .trpc .core .common .config .ProviderConfig ;
26+ import com .tencent .trpc .core .exception .ErrorCode ;
27+ import com .tencent .trpc .core .exception .TRpcException ;
28+ import com .tencent .trpc .core .rpc .ProviderInvoker ;
2029import com .tencent .trpc .core .rpc .RpcInvocation ;
2130import com .tencent .trpc .core .rpc .common .RpcMethodInfo ;
31+ import com .tencent .trpc .core .rpc .common .RpcMethodInfoAndInvoker ;
32+ import com .tencent .trpc .core .worker .spi .WorkerPool ;
33+ import com .tencent .trpc .core .worker .spi .WorkerPool .Task ;
2234import com .tencent .trpc .proto .http .common .HttpConstants ;
35+ import java .util .concurrent .CompletableFuture ;
2336import javax .servlet .http .HttpServletRequest ;
37+ import javax .servlet .http .HttpServletResponse ;
38+ import org .apache .http .HttpStatus ;
2439import org .junit .Test ;
2540import org .junit .runner .RunWith ;
2641import org .powermock .core .classloader .annotations .PowerMockIgnore ;
@@ -48,4 +63,152 @@ public void buildRpcInvocation_shouldSuccess() throws Exception {
4863 methodInfo );
4964 assertEquals (rpcInvocation .getFunc (), "/trpc.demo.server/hello" );
5065 }
51- }
66+
67+ @ Test
68+ public void execute_shouldHandleTimeoutException () throws Exception {
69+ // 准备测试数据
70+ HttpServletRequest request = mock (HttpServletRequest .class );
71+ HttpServletResponse response = mock (HttpServletResponse .class );
72+ AbstractHttpExecutor abstractHttpExecutor = mock (AbstractHttpExecutor .class );
73+ RpcMethodInfoAndInvoker methodInfoAndInvoker = mock (RpcMethodInfoAndInvoker .class );
74+ RpcMethodInfo methodInfo = mock (RpcMethodInfo .class );
75+ ProviderInvoker <?> invoker = mock (ProviderInvoker .class );
76+ ProviderConfig providerConfig = mock (ProviderConfig .class );
77+ WorkerPool workerPool = mock (WorkerPool .class );
78+
79+ // 模拟配置和基本信息
80+ when (methodInfoAndInvoker .getMethodInfo ()).thenReturn (methodInfo );
81+ doReturn (invoker ).when (methodInfoAndInvoker , "getInvoker" );
82+ when (invoker .getConfig ()).thenReturn (providerConfig );
83+ when (providerConfig .getRequestTimeout ()).thenReturn (100 ); // 设置100ms超时
84+ when (providerConfig .getWorkerPoolObj ()).thenReturn (workerPool );
85+
86+ // 模拟请求属性
87+ when (request .getAttribute (HttpConstants .REQUEST_ATTRIBUTE_TRPC_SERVICE )).thenReturn ("trpc.demo.server" );
88+ when (request .getAttribute (HttpConstants .REQUEST_ATTRIBUTE_TRPC_METHOD )).thenReturn ("hello" );
89+ when (request .getRemoteAddr ()).thenReturn ("127.0.0.1" );
90+ when (request .getRemotePort ()).thenReturn (8080 );
91+
92+ // 模拟一个永远不会完成的CompletionStage,导致超时
93+ CompletableFuture <com .tencent .trpc .core .rpc .Response > neverCompleteFuture = new CompletableFuture <>();
94+ when (invoker .invoke (any ())).thenReturn (neverCompleteFuture );
95+
96+ // 模拟私有方法调用
97+ doReturn (null ).when (abstractHttpExecutor , "parseRpcParams" , any (), any ());
98+ when (abstractHttpExecutor , "execute" , request , response , methodInfoAndInvoker ).thenCallRealMethod ();
99+ doCallRealMethod ().when (abstractHttpExecutor , "doErrorReply" , any (), any (), any ());
100+ doCallRealMethod ().when (abstractHttpExecutor , "httpErrorReply" , any (), any (), any ());
101+
102+ // 执行测试
103+ Whitebox .invokeMethod (abstractHttpExecutor , "execute" , request , response , methodInfoAndInvoker );
104+
105+ // 验证超时后调用了错误响应(由于异步执行,超时也通过handleError处理,返回503)
106+ verify (response ).setStatus (HttpStatus .SC_SERVICE_UNAVAILABLE );
107+ }
108+
109+ @ Test
110+ public void execute_shouldHandleInvokeException () throws Exception {
111+ // 准备测试数据
112+ HttpServletRequest request = mock (HttpServletRequest .class );
113+ HttpServletResponse response = mock (HttpServletResponse .class );
114+ AbstractHttpExecutor abstractHttpExecutor = mock (AbstractHttpExecutor .class );
115+ RpcMethodInfoAndInvoker methodInfoAndInvoker = mock (RpcMethodInfoAndInvoker .class );
116+ RpcMethodInfo methodInfo = mock (RpcMethodInfo .class );
117+ ProviderInvoker <?> invoker = mock (ProviderInvoker .class );
118+ ProviderConfig providerConfig = mock (ProviderConfig .class );
119+ WorkerPool workerPool = mock (WorkerPool .class );
120+
121+ // 模拟配置和基本信息
122+ when (methodInfoAndInvoker .getMethodInfo ()).thenReturn (methodInfo );
123+ doReturn (invoker ).when (methodInfoAndInvoker , "getInvoker" );
124+ when (invoker .getConfig ()).thenReturn (providerConfig );
125+ when (providerConfig .getRequestTimeout ()).thenReturn (5000 );
126+ when (providerConfig .getWorkerPoolObj ()).thenReturn (workerPool );
127+
128+ // 模拟请求属性
129+ when (request .getAttribute (HttpConstants .REQUEST_ATTRIBUTE_TRPC_SERVICE )).thenReturn ("trpc.demo.server" );
130+ when (request .getAttribute (HttpConstants .REQUEST_ATTRIBUTE_TRPC_METHOD )).thenReturn ("hello" );
131+ when (request .getRemoteAddr ()).thenReturn ("127.0.0.1" );
132+ when (request .getRemotePort ()).thenReturn (8080 );
133+ when (request .getMethod ()).thenReturn ("POST" );
134+ when (request .getRequestURI ()).thenReturn ("/api/test" );
135+
136+ // 模拟WorkerPool同步执行任务
137+ doAnswer (invocation -> {
138+ Task task = invocation .getArgumentAt (0 , Task .class );
139+ task .run ();
140+ return null ;
141+ }).when (workerPool ).execute (any (Task .class ));
142+
143+ // 模拟invoke抛出异常
144+ CompletableFuture <com .tencent .trpc .core .rpc .Response > failedFuture = new CompletableFuture <>();
145+ failedFuture .completeExceptionally (new RuntimeException ("Service invoke failed" ));
146+ when (invoker .invoke (any ())).thenReturn (failedFuture );
147+
148+ // 模拟私有方法调用
149+ doReturn (null ).when (abstractHttpExecutor , "parseRpcParams" , any (), any ());
150+ when (abstractHttpExecutor , "execute" , request , response , methodInfoAndInvoker ).thenCallRealMethod ();
151+ doCallRealMethod ().when (abstractHttpExecutor , "doErrorReply" , any (), any (), any ());
152+ doCallRealMethod ().when (abstractHttpExecutor , "httpErrorReply" , any (), any (), any ());
153+
154+ // 执行测试
155+ Whitebox .invokeMethod (abstractHttpExecutor , "execute" , request , response , methodInfoAndInvoker );
156+
157+ // 验证调用了错误响应(invoke异常在handleError中处理,返回503)
158+ verify (response ).setStatus (HttpStatus .SC_SERVICE_UNAVAILABLE );
159+ }
160+
161+ @ Test
162+ public void execute_shouldHandleResponseException () throws Exception {
163+ // 准备测试数据
164+ HttpServletRequest request = mock (HttpServletRequest .class );
165+ HttpServletResponse response = mock (HttpServletResponse .class );
166+ AbstractHttpExecutor abstractHttpExecutor = mock (AbstractHttpExecutor .class );
167+ RpcMethodInfoAndInvoker methodInfoAndInvoker = mock (RpcMethodInfoAndInvoker .class );
168+ RpcMethodInfo methodInfo = mock (RpcMethodInfo .class );
169+ ProviderInvoker <?> invoker = mock (ProviderInvoker .class );
170+ ProviderConfig providerConfig = mock (ProviderConfig .class );
171+ WorkerPool workerPool = mock (WorkerPool .class );
172+
173+ // 模拟配置和基本信息
174+ when (methodInfoAndInvoker .getMethodInfo ()).thenReturn (methodInfo );
175+ doReturn (invoker ).when (methodInfoAndInvoker , "getInvoker" );
176+ when (invoker .getConfig ()).thenReturn (providerConfig );
177+ when (providerConfig .getRequestTimeout ()).thenReturn (5000 );
178+ when (providerConfig .getWorkerPoolObj ()).thenReturn (workerPool );
179+
180+ // 模拟请求属性
181+ when (request .getAttribute (HttpConstants .REQUEST_ATTRIBUTE_TRPC_SERVICE )).thenReturn ("trpc.demo.server" );
182+ when (request .getAttribute (HttpConstants .REQUEST_ATTRIBUTE_TRPC_METHOD )).thenReturn ("hello" );
183+ when (request .getRemoteAddr ()).thenReturn ("127.0.0.1" );
184+ when (request .getRemotePort ()).thenReturn (8080 );
185+ when (request .getMethod ()).thenReturn ("POST" );
186+ when (request .getRequestURI ()).thenReturn ("/api/test" );
187+
188+ // 模拟WorkerPool同步执行任务
189+ doAnswer (invocation -> {
190+ Task task = invocation .getArgumentAt (0 , Task .class );
191+ task .run ();
192+ return null ;
193+ }).when (workerPool ).execute (any (Task .class ));
194+
195+ // 模拟Response包含异常
196+ com .tencent .trpc .core .rpc .Response rpcResponse = mock (com .tencent .trpc .core .rpc .Response .class );
197+ when (rpcResponse .getException ()).thenReturn (
198+ TRpcException .newFrameException (ErrorCode .TRPC_SERVER_VALIDATE_ERR , "Validation failed" ));
199+ CompletableFuture <com .tencent .trpc .core .rpc .Response > responseFuture = CompletableFuture .completedFuture (rpcResponse );
200+ when (invoker .invoke (any ())).thenReturn (responseFuture );
201+
202+ // 模拟私有方法调用
203+ doReturn (null ).when (abstractHttpExecutor , "parseRpcParams" , any (), any ());
204+ when (abstractHttpExecutor , "execute" , request , response , methodInfoAndInvoker ).thenCallRealMethod ();
205+ doCallRealMethod ().when (abstractHttpExecutor , "doErrorReply" , any (), any (), any ());
206+ doCallRealMethod ().when (abstractHttpExecutor , "httpErrorReply" , any (), any (), any ());
207+
208+ // 执行测试
209+ Whitebox .invokeMethod (abstractHttpExecutor , "execute" , request , response , methodInfoAndInvoker );
210+
211+ // 验证调用了错误响应(Response异常在handleError中处理,返回503)
212+ verify (response ).setStatus (HttpStatus .SC_SERVICE_UNAVAILABLE );
213+ }
214+ }
0 commit comments