22
33import static java .net .HttpURLConnection .HTTP_OK ;
44import static org .assertj .core .api .Assertions .assertThat ;
5+ import static org .mockito .ArgumentMatchers .any ;
6+ import static org .mockito .ArgumentMatchers .anyString ;
7+ import static org .mockito .Mockito .doAnswer ;
58import static org .mockito .Mockito .mock ;
69import static org .mockito .Mockito .when ;
710
811import com .retailsvc .http .Request ;
912import com .retailsvc .http .RequestHandler ;
13+ import com .retailsvc .http .RequestInterceptor ;
1014import com .retailsvc .http .Response ;
15+ import com .retailsvc .http .ResponseDecorator ;
1116import com .sun .net .httpserver .Headers ;
1217import com .sun .net .httpserver .HttpExchange ;
18+ import java .util .HashMap ;
1319import java .util .List ;
1420import java .util .Map ;
1521import java .util .concurrent .atomic .AtomicBoolean ;
22+ import java .util .concurrent .atomic .AtomicReference ;
1623import org .junit .jupiter .api .Test ;
1724
1825class DispatchHandlerTest {
1926
27+ private static final ScopedValue <String > CORRELATION_ID = ScopedValue .newInstance ();
28+
2029 private static HttpExchange stubExchange () {
2130 HttpExchange exchange = mock (HttpExchange .class );
2231 when (exchange .getResponseHeaders ()).thenReturn (new Headers ());
32+ Map <String , Object > attrs = new HashMap <>();
33+ doAnswer (
34+ inv -> {
35+ attrs .put (inv .getArgument (0 ), inv .getArgument (1 ));
36+ return null ;
37+ })
38+ .when (exchange )
39+ .setAttribute (anyString (), any ());
40+ when (exchange .getAttribute (anyString ())).thenAnswer (inv -> attrs .get (inv .getArgument (0 )));
2341 return exchange ;
2442 }
2543
2644 private static DispatchHandler dispatcher (Map <String , RequestHandler > handlers ) {
2745 return new DispatchHandler (handlers , List .of (), List .of (), new ResponseRenderer (Map .of ()));
2846 }
2947
48+ private static DispatchHandler dispatcher (
49+ Map <String , RequestHandler > handlers ,
50+ List <RequestInterceptor > interceptors ,
51+ List <ResponseDecorator > decorators ) {
52+ return new DispatchHandler (handlers , interceptors , decorators , new ResponseRenderer (Map .of ()));
53+ }
54+
3055 private static void withRequest (String operationId , ScopedValue .CallableOp <Void , Exception > body )
3156 throws Exception {
3257 Request req = new Request (new byte [0 ], null , null , operationId , Map .of (), null , n -> null );
@@ -52,4 +77,26 @@ void invokesRegisteredHandler() throws Exception {
5277
5378 assertThat (called .get ()).isTrue ();
5479 }
80+
81+ @ Test
82+ void decoratorSeesInterceptorBoundScopedValue () throws Exception {
83+ RequestHandler ok = req -> Response .status (HTTP_OK );
84+ RequestInterceptor bindCid =
85+ (request , next ) -> ScopedValue .where (CORRELATION_ID , "cid-123" ).call (next ::proceed );
86+ ResponseDecorator stampCid =
87+ (req , resp ) -> resp .withHeader ("X-Correlation-Id" , CORRELATION_ID .get ());
88+
89+ HttpExchange ex = stubExchange ();
90+ AtomicReference <Response > rendered = new AtomicReference <>();
91+
92+ withRequest (
93+ "get-x" ,
94+ () -> {
95+ dispatcher (Map .of ("get-x" , ok ), List .of (bindCid ), List .of (stampCid )).handle (ex );
96+ rendered .set ((Response ) ex .getAttribute (DispatchHandler .RESPONSE_ATTR ));
97+ return null ;
98+ });
99+
100+ assertThat (rendered .get ().headers ()).containsEntry ("X-Correlation-Id" , "cid-123" );
101+ }
55102}
0 commit comments