use of com.linkedin.r2.message.RequestContext in project rest.li by linkedin.
the class TestRestLiCallback method testOnErrorWithFiltersExceptionFromFirstFilterSecondFilterHandles.
@SuppressWarnings("unchecked")
@Test(dataProvider = "provideResponseEntities")
public void testOnErrorWithFiltersExceptionFromFirstFilterSecondFilterHandles(final ResourceMethod resourceMethod, final Object entityFromFilter2) throws Exception {
// App stuff.
RestLiServiceException exFromApp = new RestLiServiceException(HttpStatus.S_404_NOT_FOUND, "App failure");
RequestExecutionReport executionReport = new RequestExecutionReportBuilder().build();
RestLiResponseAttachments responseAttachments = new RestLiResponseAttachments.Builder().build();
RestLiServiceException appException = new RestLiServiceException(HttpStatus.S_404_NOT_FOUND);
RestLiResponseDataImpl responseAppData = new RestLiResponseDataImpl(appException, Collections.<String, String>emptyMap(), Collections.<HttpCookie>emptyList());
RestLiResponseEnvelope responseAppEnvelope = EnvelopeBuilderUtil.buildBlankResponseEnvelope(resourceMethod, responseAppData);
responseAppData.setResponseEnvelope(responseAppEnvelope);
// Filter stuff.
final Exception exFromFirstFilter = new RuntimeException("Runtime exception from first filter");
RestLiServiceException filterException = new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR);
final Map<String, String> headersFromFilter = Maps.newHashMap();
headersFromFilter.put(RestConstants.HEADER_RESTLI_PROTOCOL_VERSION, AllProtocolVersions.LATEST_PROTOCOL_VERSION.toString());
String errorResponseHeaderName = HeaderUtil.getErrorResponseHeaderName(AllProtocolVersions.LATEST_PROTOCOL_VERSION);
headersFromFilter.put(errorResponseHeaderName, RestConstants.HEADER_VALUE_ERROR);
RestLiResponseDataImpl responseFilterData = new RestLiResponseDataImpl(filterException, headersFromFilter, Collections.<HttpCookie>emptyList());
RestLiResponseEnvelope responseFilterEnvelope = EnvelopeBuilderUtil.buildBlankResponseEnvelope(resourceMethod, responseFilterData);
responseFilterData.setResponseEnvelope(responseFilterEnvelope);
PartialRestResponse partialResponse = new PartialRestResponse.Builder().build();
ArgumentCaptor<RestLiServiceException> wrappedExCapture = ArgumentCaptor.forClass(RestLiServiceException.class);
RestResponse restResponse = new RestResponseBuilder().build();
final String customHeader = "Custom-Header";
final String customHeaderValue = "CustomValue";
// Setup.
when(_requestExecutionReportBuilder.build()).thenReturn(executionReport);
when(_responseHandler.buildExceptionResponseData(eq(_restRequest), eq(_routingResult), wrappedExCapture.capture(), anyMap(), anyList())).thenReturn(responseAppData);
when(_responseHandler.buildPartialResponse(_routingResult, responseAppData)).thenReturn(partialResponse);
when(_responseHandler.buildResponse(_routingResult, partialResponse)).thenReturn(restResponse);
when(_restRequest.getHeaders()).thenReturn(null);
// Mock filter behavior.
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
FilterRequestContext requestContext = (FilterRequestContext) args[1];
FilterResponseContext responseContext = (FilterResponseContext) args[2];
((RestLiResponseDataImpl) responseContext.getResponseData()).setException(exFromFirstFilter);
responseContext.getResponseData().getHeaders().putAll(headersFromFilter);
return completedFutureWithError(exFromFirstFilter);
}
}).doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
FilterRequestContext requestContext = (FilterRequestContext) args[1];
FilterResponseContext responseContext = (FilterResponseContext) args[2];
// The second filter should be invoked with details of the exception thrown by the first
// filter. Verify incoming data.
assertEquals(responseContext.getResponseData().getStatus(), HttpStatus.S_500_INTERNAL_SERVER_ERROR);
switch(ResponseType.fromMethodType(resourceMethod)) {
case SINGLE_ENTITY:
assertNull(responseContext.getResponseData().getRecordResponseEnvelope().getRecord());
break;
case GET_COLLECTION:
assertNull(responseContext.getResponseData().getCollectionResponseEnvelope().getCollectionResponse());
break;
case CREATE_COLLECTION:
assertNull(responseContext.getResponseData().getBatchCreateResponseEnvelope().getCreateResponses());
break;
case BATCH_ENTITIES:
assertNull(responseContext.getResponseData().getBatchResponseEnvelope().getBatchResponseMap());
break;
case STATUS_ONLY:
break;
}
assertEquals(responseContext.getResponseData().getHeaders(), headersFromFilter);
assertTrue(responseContext.getResponseData().isErrorResponse());
// Modify data.
responseContext.getResponseData().getHeaders().put(customHeader, customHeaderValue);
setStatus(responseContext, HttpStatus.S_402_PAYMENT_REQUIRED);
// filter.
if (entityFromFilter2 instanceof RecordTemplate) {
responseContext.getResponseData().getRecordResponseEnvelope().setRecord((RecordTemplate) entityFromFilter2, HttpStatus.S_402_PAYMENT_REQUIRED);
} else if (entityFromFilter2 instanceof List) {
responseContext.getResponseData().getCollectionResponseEnvelope().setCollectionResponse((List<? extends RecordTemplate>) entityFromFilter2, new CollectionMetadata(), null, HttpStatus.S_402_PAYMENT_REQUIRED);
} else {
Map<Object, BatchResponseEnvelope.BatchResponseEntry> responseMap = new HashMap<Object, BatchResponseEnvelope.BatchResponseEntry>();
for (Map.Entry<?, RecordTemplate> entry : ((Map<?, RecordTemplate>) entityFromFilter2).entrySet()) {
responseMap.put(entry.getKey(), new BatchResponseEnvelope.BatchResponseEntry(HttpStatus.S_200_OK, entry.getValue()));
}
responseContext.getResponseData().getBatchResponseEnvelope().setBatchResponseMap(responseMap, HttpStatus.S_402_PAYMENT_REQUIRED);
}
return CompletableFuture.completedFuture(null);
}
}).when(_filter).onError(any(Throwable.class), eq(_filterRequestContext), any(FilterResponseContext.class));
// invoke request filters so cursor is in correct place
when(_filter.onRequest(any(FilterRequestContext.class))).thenReturn(CompletableFuture.completedFuture(null));
_twoFilterChain.onRequest(_filterRequestContext, _filterResponseContextFactory);
// Invoke.
_twoFilterRestLiCallback.onError(exFromApp, executionReport, _requestAttachmentReader, responseAttachments);
// Verify.
verify(_responseHandler).buildExceptionResponseData(eq(_restRequest), eq(_routingResult), wrappedExCapture.capture(), anyMap(), anyList());
verify(_responseHandler).buildPartialResponse(_routingResult, responseAppData);
verify(_responseHandler).buildResponse(_routingResult, partialResponse);
verify(_callback).onSuccess(restResponse, executionReport, responseAttachments);
verify(_restRequest).getHeaders();
verifyZeroInteractions(_routingResult);
verifyNoMoreInteractions(_restRequest, _responseHandler, _callback);
assertNotNull(responseAppData);
assertEquals(HttpStatus.S_402_PAYMENT_REQUIRED, responseAppData.getStatus());
// Only the error header should have been cleared.
assertFalse(responseAppData.getHeaders().containsKey(errorResponseHeaderName));
assertEquals(responseAppData.getHeaders().get(customHeader), customHeaderValue);
if (entityFromFilter2 instanceof RecordTemplate) {
assertTrue(responseAppData.getResponseType() == ResponseType.SINGLE_ENTITY);
assertEquals(responseAppData.getRecordResponseEnvelope().getRecord(), entityFromFilter2);
} else if (entityFromFilter2 instanceof List) {
if (responseAppData.getResponseType() == ResponseType.GET_COLLECTION) {
assertEquals(responseAppData.getCollectionResponseEnvelope().getCollectionResponse(), entityFromFilter2);
} else {
fail();
}
} else {
assertTrue(responseAppData.getResponseType() == ResponseType.BATCH_ENTITIES);
Map<Object, RecordTemplate> values = new HashMap<Object, RecordTemplate>();
for (Map.Entry<?, BatchResponseEnvelope.BatchResponseEntry> entry : responseAppData.getBatchResponseEnvelope().getBatchResponseMap().entrySet()) {
values.put(entry.getKey(), entry.getValue().getRecord());
}
assertEquals(values, entityFromFilter2);
}
assertFalse(responseAppData.isErrorResponse());
RestLiServiceException restliEx = wrappedExCapture.getAllValues().get(0);
assertNotNull(restliEx);
assertEquals(exFromApp.getStatus(), restliEx.getStatus());
assertEquals(exFromApp.getMessage(), restliEx.getMessage());
}
use of com.linkedin.r2.message.RequestContext in project rest.li by linkedin.
the class TestRestLiCallback method testOnSuccessWithFiltersSuccessful.
@Test
public void testOnSuccessWithFiltersSuccessful() throws Exception {
String result = "foo";
RequestExecutionReport executionReport = new RequestExecutionReportBuilder().build();
final RestLiResponseAttachments restLiResponseAttachments = new RestLiResponseAttachments.Builder().build();
final RecordTemplate entityFromApp = Foo.createFoo("Key", "One");
final Map<String, String> headersFromApp = Maps.newHashMap();
headersFromApp.put("Key", "Input");
final RecordTemplate entityFromFilter1 = Foo.createFoo("Key", "Two");
final RecordTemplate entityFromFilter2 = Foo.createFoo("Key", "Three");
final Map<String, String> headersFromFilters = Maps.newHashMap();
headersFromFilters.put("Key", "Output");
RestLiResponseDataImpl appResponseData = new RestLiResponseDataImpl(HttpStatus.S_200_OK, headersFromApp, Collections.<HttpCookie>emptyList());
appResponseData.setResponseEnvelope(new CreateResponseEnvelope(entityFromApp, appResponseData));
PartialRestResponse partialResponse = new PartialRestResponse.Builder().build();
// Setup.
when(_requestExecutionReportBuilder.build()).thenReturn(executionReport);
when(_responseHandler.buildRestLiResponseData(_restRequest, _routingResult, result)).thenReturn(appResponseData);
when(_responseHandler.buildPartialResponse(_routingResult, appResponseData)).thenReturn(partialResponse);
// Mock the behavior of the first filter.
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
FilterRequestContext requestContext = (FilterRequestContext) args[0];
FilterResponseContext responseContext = (FilterResponseContext) args[1];
// Verify incoming data.
assertEquals(HttpStatus.S_200_OK, responseContext.getResponseData().getStatus());
assertEquals(headersFromApp, responseContext.getResponseData().getHeaders());
assertEquals(entityFromApp, responseContext.getResponseData().getRecordResponseEnvelope().getRecord());
// Modify data in filter.
setStatus(responseContext, HttpStatus.S_400_BAD_REQUEST);
responseContext.getResponseData().getRecordResponseEnvelope().setRecord(entityFromFilter1, HttpStatus.S_400_BAD_REQUEST);
responseContext.getResponseData().getHeaders().clear();
return CompletableFuture.completedFuture(null);
}
}).doAnswer(new Answer<Object>() {
// Mock the behavior of the second filter.
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
FilterRequestContext requestContext = (FilterRequestContext) args[0];
FilterResponseContext responseContext = (FilterResponseContext) args[1];
// Verify incoming data.
assertEquals(HttpStatus.S_400_BAD_REQUEST, responseContext.getResponseData().getStatus());
assertTrue(responseContext.getResponseData().getHeaders().isEmpty());
assertEquals(responseContext.getResponseData().getRecordResponseEnvelope().getRecord(), entityFromFilter1);
// Modify data in filter.
setStatus(responseContext, HttpStatus.S_403_FORBIDDEN);
responseContext.getResponseData().getRecordResponseEnvelope().setRecord(entityFromFilter2, HttpStatus.S_403_FORBIDDEN);
responseContext.getResponseData().getHeaders().putAll(headersFromFilters);
return CompletableFuture.completedFuture(null);
}
}).when(_filter).onResponse(eq(_filterRequestContext), any(FilterResponseContext.class));
RestResponse restResponse = new RestResponseBuilder().build();
when(_responseHandler.buildResponse(_routingResult, partialResponse)).thenReturn(restResponse);
// invoke request filters so cursor is in correct place
when(_filter.onRequest(any(FilterRequestContext.class))).thenReturn(CompletableFuture.completedFuture(null));
_twoFilterChain.onRequest(_filterRequestContext, _filterResponseContextFactory);
// Invoke with some response attachments.
_twoFilterRestLiCallback.onSuccess(result, executionReport, restLiResponseAttachments);
// Verify.
assertNotNull(appResponseData);
assertEquals(HttpStatus.S_403_FORBIDDEN, appResponseData.getStatus());
assertEquals(entityFromFilter2, appResponseData.getRecordResponseEnvelope().getRecord());
assertEquals(headersFromFilters, appResponseData.getHeaders());
verify(_responseHandler).buildRestLiResponseData(_restRequest, _routingResult, result);
verify(_responseHandler).buildPartialResponse(_routingResult, appResponseData);
verify(_responseHandler).buildResponse(_routingResult, partialResponse);
verify(_callback).onSuccess(restResponse, executionReport, restLiResponseAttachments);
verifyZeroInteractions(_restRequest, _routingResult);
verifyNoMoreInteractions(_responseHandler, _callback);
}
use of com.linkedin.r2.message.RequestContext in project rest.li by linkedin.
the class TestRestLiMethodInvocation method checkInvocation.
private void checkInvocation(Object resource, ResourceMethodDescriptor resourceMethodDescriptor, String httpMethod, ProtocolVersion version, String uri, String entityBody, MutablePathKeys pathkeys, final RequestExecutionCallback<RestResponse> callback, final boolean isDebugMode, final boolean expectRoutingException, final RestLiAttachmentReader expectedRequestAttachments, final RestLiResponseAttachments expectedResponseAttachments) throws URISyntaxException, RestLiSyntaxException {
assertNotNull(resource);
assertNotNull(resourceMethodDescriptor);
try {
EasyMock.replay(resource);
RestRequestBuilder builder = new RestRequestBuilder(new URI(uri)).setMethod(httpMethod).addHeaderValue("Accept", "application/json").setHeader(RestConstants.HEADER_RESTLI_PROTOCOL_VERSION, version.toString());
if (entityBody != null) {
builder.setEntity(entityBody.getBytes(Data.UTF_8_CHARSET));
}
RestRequest request = builder.build();
final ResourceContext resourceContext = new ResourceContextImpl(pathkeys, request, new RequestContext(), true, expectedRequestAttachments);
resourceContext.setResponseAttachments(expectedResponseAttachments);
RoutingResult routingResult = new RoutingResult(resourceContext, resourceMethodDescriptor);
FilterRequestContextInternal filterContext = new FilterRequestContextInternalImpl((ServerResourceContext) routingResult.getContext(), resourceMethodDescriptor);
final CountDownLatch latch = new CountDownLatch(1);
final CountDownLatch expectedRoutingExceptionLatch = new CountDownLatch(1);
RestLiArgumentBuilder adapter = _methodAdapterRegistry.getArgumentBuilder(resourceMethodDescriptor.getType());
RestLiRequestData requestData = adapter.extractRequestData(routingResult, request);
filterContext.setRequestData(requestData);
RestLiResponseHandler restLiResponseHandler = new RestLiResponseHandler.Builder().build();
RequestExecutionReportBuilder requestExecutionReportBuilder = null;
if (isDebugMode) {
requestExecutionReportBuilder = new RequestExecutionReportBuilder();
}
RequestExecutionCallback<RestResponse> executionCallback = new RequestExecutionCallback<RestResponse>() {
@Override
public void onError(Throwable e, RequestExecutionReport executionReport, RestLiAttachmentReader requestAttachmentReader, RestLiResponseAttachments responseAttachments) {
if (isDebugMode) {
Assert.assertNotNull(executionReport);
} else {
Assert.assertNull(executionReport);
}
if (e.getCause().getCause() instanceof RoutingException) {
expectedRoutingExceptionLatch.countDown();
}
if (callback != null) {
callback.onError(e, executionReport, null, null);
}
Assert.assertEquals(requestAttachmentReader, expectedRequestAttachments);
Assert.assertEquals(responseAttachments, expectedResponseAttachments);
latch.countDown();
}
@Override
public void onSuccess(final RestResponse result, RequestExecutionReport executionReport, RestLiResponseAttachments responseAttachments) {
if (isDebugMode) {
Assert.assertNotNull(executionReport);
} else {
Assert.assertNull(executionReport);
}
if (callback != null) {
callback.onSuccess(result, executionReport, null);
}
Assert.assertEquals(responseAttachments, expectedResponseAttachments);
latch.countDown();
}
};
FilterChainCallback filterChainCallback = new FilterChainCallbackImpl(routingResult, _invoker, adapter, requestExecutionReportBuilder, expectedRequestAttachments, restLiResponseHandler, executionCallback);
final RestLiCallback<Object> outerCallback = new RestLiCallback<Object>(filterContext, new RestLiFilterResponseContextFactory<Object>(request, routingResult, restLiResponseHandler), new RestLiFilterChain(null, filterChainCallback));
RestUtils.validateRequestHeadersAndUpdateResourceContext(request.getHeaders(), (ServerResourceContext) routingResult.getContext());
filterContext.setRequestData(adapter.extractRequestData(routingResult, request));
_invoker.invoke(filterContext.getRequestData(), routingResult, adapter, outerCallback, requestExecutionReportBuilder);
try {
latch.await();
if (expectRoutingException) {
expectedRoutingExceptionLatch.await();
}
} catch (InterruptedException e) {
// Ignore
}
EasyMock.verify(resource);
Assert.assertEquals(((ServerResourceContext) routingResult.getContext()).getResponseMimeType(), "application/json");
} catch (RestLiSyntaxException e) {
throw new RoutingException("syntax exception", 400);
} finally {
EasyMock.reset(resource);
EasyMock.makeThreadSafe(resource, true);
}
}
use of com.linkedin.r2.message.RequestContext in project rest.li by linkedin.
the class TestRestLiMethodInvocation method testAction_BadParameterTypes.
@Test
public void testAction_BadParameterTypes() throws Exception {
ResourceModel accountsResourceModel = buildResourceModel(TwitterAccountsResource.class);
ResourceMethodDescriptor methodDescriptor;
// #1 no defaults provided
methodDescriptor = accountsResourceModel.findActionMethod("register", ResourceLevel.COLLECTION);
String jsonEntityBody = RestLiTestHelper.doubleQuote("{'first': 42, 'last': 42, 'email': 42, " + "'company': 42, 'openToMarketingEmails': 'false'}");
RestRequest request = new RestRequestBuilder(new URI("/accounts?action=register")).setMethod("POST").setEntity(jsonEntityBody.getBytes(Data.UTF_8_CHARSET)).setHeader(RestConstants.HEADER_RESTLI_PROTOCOL_VERSION, version.toString()).build();
RoutingResult routingResult = new RoutingResult(new ResourceContextImpl(null, request, new RequestContext()), methodDescriptor);
final FilterRequestContextInternal filterContext = new FilterRequestContextInternalImpl((ServerResourceContext) routingResult.getContext(), routingResult.getResourceMethod());
try {
RestUtils.validateRequestHeadersAndUpdateResourceContext(request.getHeaders(), (ServerResourceContext) routingResult.getContext());
filterContext.setRequestData(_methodAdapterRegistry.getArgumentBuilder(methodDescriptor.getMethodType()).extractRequestData(routingResult, request));
_invoker.invoke(null, routingResult, _methodAdapterRegistry.getArgumentBuilder(methodDescriptor.getMethodType()), null, null);
Assert.fail("expected routing exception");
} catch (RoutingException e) {
Assert.assertEquals(e.getStatus(), 400);
}
}
use of com.linkedin.r2.message.RequestContext in project rest.li by linkedin.
the class TestRestLiMethodInvocation method testInvokeWithUnsupportedAcceptMimeType.
@Test
public void testInvokeWithUnsupportedAcceptMimeType() throws Exception {
RestRequestBuilder builder = new RestRequestBuilder(new URI("")).addHeaderValue("Accept", "text/plain").setHeader(RestConstants.HEADER_RESTLI_PROTOCOL_VERSION, version.toString());
RestRequest request = builder.build();
final RestLiAttachmentReader attachmentReader = new RestLiAttachmentReader(null);
final CountDownLatch latch = new CountDownLatch(1);
RestLiResponseHandler restLiResponseHandler = new RestLiResponseHandler.Builder().build();
RequestExecutionCallback<RestResponse> executionCallback = new RequestExecutionCallback<RestResponse>() {
@Override
public void onError(Throwable e, RequestExecutionReport executionReport, RestLiAttachmentReader requestAttachmentReader, RestLiResponseAttachments responseAttachments) {
latch.countDown();
Assert.assertTrue(e instanceof RestException);
RestException ex = (RestException) e;
Assert.assertEquals(ex.getResponse().getStatus(), HttpStatus.S_406_NOT_ACCEPTABLE.getCode());
Assert.assertEquals(requestAttachmentReader, attachmentReader);
Assert.assertNull(responseAttachments);
}
@Override
public void onSuccess(RestResponse result, RequestExecutionReport executionReport, RestLiResponseAttachments responseAttachments) {
Assert.fail();
}
};
ServerResourceContext resourceContext = new ResourceContextImpl(new PathKeysImpl(), new RestRequestBuilder(URI.create("")).setHeader(RestConstants.HEADER_RESTLI_PROTOCOL_VERSION, AllProtocolVersions.LATEST_PROTOCOL_VERSION.toString()).build(), new RequestContext(), false, attachmentReader);
try {
RoutingResult routingResult = new RoutingResult(resourceContext, null);
RestUtils.validateRequestHeadersAndUpdateResourceContext(request.getHeaders(), (ServerResourceContext) routingResult.getContext());
FilterChainCallback filterChainCallback = new FilterChainCallbackImpl(null, _invoker, null, null, null, restLiResponseHandler, executionCallback);
final RestLiCallback<Object> callback = new RestLiCallback<Object>(null, new RestLiFilterResponseContextFactory<Object>(request, null, restLiResponseHandler), new RestLiFilterChain(null, filterChainCallback));
_invoker.invoke(null, routingResult, null, callback, null);
latch.await();
} catch (Exception e) {
// exception is expected
Assert.assertTrue(e instanceof RestLiServiceException);
}
Assert.assertNull(resourceContext.getResponseMimeType());
}
Aggregations