use of com.linkedin.restli.server.filter.FilterRequestContext in project rest.li by linkedin.
the class TestRestLiCallback method testOnErrorWithFiltersSuccessfulyHandlingAppEx.
@SuppressWarnings("unchecked")
@Test
public void testOnErrorWithFiltersSuccessfulyHandlingAppEx() throws Exception {
Exception exFromApp = new RuntimeException("Runtime exception from app");
RestLiServiceException appException = new RestLiServiceException(HttpStatus.S_404_NOT_FOUND);
RequestExecutionReport executionReport = new RequestExecutionReportBuilder().build();
RestLiResponseAttachments responseAttachments = new RestLiResponseAttachments.Builder().build();
final Map<String, String> headersFromApp = Maps.newHashMap();
headersFromApp.put("Key", "Input");
final RecordTemplate entityFromFilter = Foo.createFoo("Key", "Two");
final Map<String, String> headersFromFilter = Maps.newHashMap();
headersFromFilter.put("Key", "Output");
RestLiResponseDataImpl responseData = new RestLiResponseDataImpl(appException, headersFromApp, Collections.<HttpCookie>emptyList());
responseData.setResponseEnvelope(new CreateResponseEnvelope(new EmptyRecord(), responseData));
PartialRestResponse partialResponse = new PartialRestResponse.Builder().build();
ArgumentCaptor<RestLiServiceException> exCapture = ArgumentCaptor.forClass(RestLiServiceException.class);
when(_requestExecutionReportBuilder.build()).thenReturn(executionReport);
when(_responseHandler.buildExceptionResponseData(eq(_restRequest), eq(_routingResult), exCapture.capture(), anyMap(), anyList())).thenReturn(responseData);
when(_responseHandler.buildPartialResponse(_routingResult, responseData)).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();
Throwable t = (Throwable) args[0];
FilterRequestContext requestContext = (FilterRequestContext) args[1];
FilterResponseContext responseContext = (FilterResponseContext) args[2];
// Verify incoming data.
assertEquals(HttpStatus.S_404_NOT_FOUND, responseContext.getResponseData().getStatus());
assertEquals(headersFromApp, responseContext.getResponseData().getHeaders());
assertNull(responseContext.getResponseData().getRecordResponseEnvelope().getRecord());
// Modify data in filter.
setStatus(responseContext, HttpStatus.S_400_BAD_REQUEST);
responseContext.getResponseData().getHeaders().clear();
return CompletableFuture.completedFuture(null);
}
}).when(_filter).onError(any(Throwable.class), eq(_filterRequestContext), any(FilterResponseContext.class));
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());
assertNull(responseContext.getResponseData().getRecordResponseEnvelope().getRecord());
// Modify data in filter.
setStatus(responseContext, HttpStatus.S_403_FORBIDDEN);
responseContext.getResponseData().getRecordResponseEnvelope().setRecord(entityFromFilter, HttpStatus.S_403_FORBIDDEN);
responseContext.getResponseData().getHeaders().putAll(headersFromFilter);
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.
_twoFilterRestLiCallback.onError(exFromApp, executionReport, _requestAttachmentReader, responseAttachments);
// Verify.
assertNotNull(responseData);
assertEquals(HttpStatus.S_403_FORBIDDEN, responseData.getStatus());
assertEquals(entityFromFilter, responseData.getRecordResponseEnvelope().getRecord());
assertEquals(headersFromFilter, responseData.getHeaders());
verify(_responseHandler).buildExceptionResponseData(eq(_restRequest), eq(_routingResult), exCapture.capture(), anyMap(), anyList());
verify(_responseHandler).buildPartialResponse(_routingResult, responseData);
verify(_responseHandler).buildResponse(_routingResult, partialResponse);
verify(_callback).onSuccess(restResponse, executionReport, responseAttachments);
verify(_restRequest, times(1)).getHeaders();
verifyZeroInteractions(_routingResult);
verifyNoMoreInteractions(_restRequest, _responseHandler, _callback);
RestLiServiceException restliEx = exCapture.getValue();
assertNotNull(restliEx);
assertEquals(HttpStatus.S_500_INTERNAL_SERVER_ERROR, restliEx.getStatus());
assertEquals(exFromApp.getMessage(), restliEx.getMessage());
assertEquals(exFromApp, restliEx.getCause());
}
use of com.linkedin.restli.server.filter.FilterRequestContext 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.restli.server.filter.FilterRequestContext in project rest.li by linkedin.
the class TestResponseCompression method initClass.
@BeforeClass
public void initClass() throws Exception {
class TestHelperFilter implements Filter {
@Override
public CompletableFuture<Void> onRequest(FilterRequestContext requestContext) {
Map<String, String> requestHeaders = requestContext.getRequestHeaders();
if (requestHeaders.containsKey(EXPECTED_ACCEPT_ENCODING)) {
String expected = requestHeaders.get(EXPECTED_ACCEPT_ENCODING);
if (expected.equals(NONE)) {
if (requestHeaders.containsKey(HttpConstants.ACCEPT_ENCODING)) {
throw new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "Accept-Encoding header should not be present.");
}
} else {
if (!expected.equals(requestHeaders.get(HttpConstants.ACCEPT_ENCODING))) {
throw new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "Accept-Encoding header should be " + expected + ", but received " + requestHeaders.get(HttpConstants.ACCEPT_ENCODING));
}
}
}
if (requestHeaders.containsKey(EXPECTED_COMPRESSION_THRESHOLD)) {
if (!requestHeaders.get(EXPECTED_COMPRESSION_THRESHOLD).equals(requestHeaders.get(HttpConstants.HEADER_RESPONSE_COMPRESSION_THRESHOLD))) {
throw new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "Expected " + HttpConstants.HEADER_RESPONSE_COMPRESSION_THRESHOLD + " " + requestHeaders.get(EXPECTED_COMPRESSION_THRESHOLD) + ", but received " + requestHeaders.get(HttpConstants.HEADER_RESPONSE_COMPRESSION_THRESHOLD));
}
}
return CompletableFuture.completedFuture(null);
}
}
// The default compression threshold is between tiny and huge threshold.
final FilterChain fc = FilterChains.empty().addLastRest(new TestCompressionServer.SaveContentEncodingHeaderFilter()).addLastRest(new ServerCompressionFilter("x-snappy-framed,snappy,gzip,deflate", new CompressionConfig(10000))).addLastRest(new SimpleLoggingFilter());
super.init(Arrays.asList(new TestHelperFilter()), fc, false);
}
use of com.linkedin.restli.server.filter.FilterRequestContext in project rest.li by linkedin.
the class TestFilterRequestContextInternalImpl method testGetActionReturnType.
@Test
public void testGetActionReturnType() {
when(resourceMethod.getMethodType()).thenReturn(ResourceMethod.ACTION);
Mockito.doReturn(String.class).when(resourceMethod).getActionReturnType();
FilterRequestContext filterContext = new FilterRequestContextInternalImpl(context, resourceMethod, null);
Assert.assertEquals(filterContext.getActionReturnType(), String.class);
when(resourceMethod.getMethodType()).thenReturn(ResourceMethod.GET);
Assert.assertNull(filterContext.getActionReturnType());
}
use of com.linkedin.restli.server.filter.FilterRequestContext in project rest.li by linkedin.
the class TestFilterRequestContextInternalImpl method testFilterRequestContextAdapter.
@Test
@SuppressWarnings("unchecked")
public void testFilterRequestContextAdapter() throws Exception {
final String resourceName = "resourceName";
final String resourceNamespace = "resourceNamespace";
final ResourceMethod methodType = ResourceMethod.GET;
final DataMap customAnnotations = new DataMap();
customAnnotations.put("foo", "Bar");
final ProjectionMode projectionMode = ProjectionMode.AUTOMATIC;
final MaskTree maskTree = new MaskTree();
final MaskTree metadataMaskTree = new MaskTree();
final MaskTree pagingMaskTree = new MaskTree();
final MutablePathKeys pathKeys = new PathKeysImpl();
final Map<String, String> requestHeaders = new HashMap<>();
requestHeaders.put("Key1", "Value1");
final URI requestUri = new URI("foo.bar.com");
final ProtocolVersion protoVersion = AllProtocolVersions.BASELINE_PROTOCOL_VERSION;
final DataMap queryParams = new DataMap();
queryParams.put("Param1", "Val1");
final Map<String, Object> localAttrs = new HashMap<>();
localAttrs.put("Key1", "Val1");
final RequestContext r2RequestContext = new RequestContext();
r2RequestContext.putLocalAttr("Key1", "Val1");
final String finderName = UUID.randomUUID().toString();
final String batchFinderName = UUID.randomUUID().toString();
final String actionName = UUID.randomUUID().toString();
final List<ServiceError> methodServiceErrors = Collections.singletonList(TestServiceError.METHOD_LEVEL_ERROR);
final List<ServiceError> resourceServiceErrors = Collections.singletonList(TestServiceError.RESOURCE_LEVEL_ERROR);
final List<Parameter<?>> methodParameters = Collections.singletonList(Mockito.mock(Parameter.class));
when(resourceModel.getName()).thenReturn(resourceName);
when(resourceModel.getNamespace()).thenReturn(resourceNamespace);
when(filterResourceModel.getServiceErrors()).thenReturn(resourceServiceErrors);
when(resourceMethod.getResourceModel()).thenReturn(resourceModel);
when(resourceMethod.getMethodType()).thenReturn(methodType);
when(resourceMethod.getFinderName()).thenReturn(finderName);
when(resourceMethod.getBatchFinderName()).thenReturn(batchFinderName);
when(resourceMethod.getActionName()).thenReturn(actionName);
when(resourceMethod.getCustomAnnotationData()).thenReturn(customAnnotations);
when(resourceMethod.getMethod()).thenReturn(null);
when(resourceMethod.getParameters()).thenReturn(methodParameters);
when(resourceMethod.getServiceErrors()).thenReturn(methodServiceErrors);
when(context.getProjectionMode()).thenReturn(projectionMode);
when(context.getProjectionMask()).thenReturn(maskTree);
when(context.getMetadataProjectionMask()).thenReturn(metadataMaskTree);
when(context.getPagingProjectionMask()).thenReturn(pagingMaskTree);
when(context.getPathKeys()).thenReturn(pathKeys);
when(context.getRequestHeaders()).thenReturn(requestHeaders);
when(context.getRequestURI()).thenReturn(requestUri);
when(context.getRestliProtocolVersion()).thenReturn(protoVersion);
when(context.getParameters()).thenReturn(queryParams);
when(context.getRawRequestContext()).thenReturn(r2RequestContext);
FilterRequestContext filterContext = new FilterRequestContextInternalImpl(context, resourceMethod, null);
filterContext.setProjectionMask(maskTree);
filterContext.setMetadataProjectionMask(metadataMaskTree);
filterContext.setPagingProjectionMask(pagingMaskTree);
assertEquals(filterContext.getFilterResourceModel().getResourceName(), resourceName);
assertEquals(filterContext.getFilterResourceModel().getResourceNamespace(), resourceNamespace);
assertEquals(filterContext.getMethodType(), methodType);
assertEquals(filterContext.getCustomAnnotations(), customAnnotations);
assertEquals(filterContext.getProjectionMode(), projectionMode);
assertEquals(filterContext.getProjectionMask(), maskTree);
assertEquals(filterContext.getMetadataProjectionMask(), metadataMaskTree);
assertEquals(filterContext.getPagingProjectionMask(), pagingMaskTree);
assertEquals(filterContext.getPathKeys(), pathKeys);
assertEquals(filterContext.getRequestHeaders(), requestHeaders);
assertEquals(filterContext.getRequestURI(), requestUri);
assertEquals(filterContext.getRestliProtocolVersion(), protoVersion);
assertEquals(filterContext.getQueryParameters(), queryParams);
assertEquals(filterContext.getActionName(), actionName);
assertEquals(filterContext.getFinderName(), finderName);
assertEquals(filterContext.getBatchFinderName(), batchFinderName);
assertEquals(filterContext.getRequestContextLocalAttrs(), localAttrs);
assertNull(filterContext.getMethod());
assertEquals(filterContext.getMethodParameters(), methodParameters);
assertNotSame(filterContext.getMethodParameters(), methodParameters);
assertEquals(filterContext.getMethodServiceErrors(), methodServiceErrors);
filterContext.getRequestHeaders().put("header2", "value2");
assertEquals(requestHeaders.get("header2"), "value2");
verify(resourceModel).getName();
verify(resourceModel).getNamespace();
verify(resourceMethod).getMethodType();
verify(resourceMethod).getResourceModel();
verify(resourceMethod).getCustomAnnotationData();
verify(resourceMethod).getFinderName();
verify(resourceMethod).getBatchFinderName();
verify(resourceMethod).getActionName();
verify(resourceMethod).getMethod();
verify(resourceMethod, times(2)).getParameters();
verify(resourceMethod).getServiceErrors();
verify(context).getProjectionMode();
verify(context).setProjectionMask(maskTree);
verify(context).getProjectionMask();
verify(context).setMetadataProjectionMask(metadataMaskTree);
verify(context).getMetadataProjectionMask();
verify(context).setPagingProjectionMask(pagingMaskTree);
verify(context).getPagingProjectionMask();
verify(context).getPathKeys();
verify(context, times(2)).getRequestHeaders();
verify(context).getRequestURI();
verify(context).getRestliProtocolVersion();
verify(context).getParameters();
verify(context).getRawRequestContext();
verify(resourceMethod).getCollectionCustomMetadataType();
verifyNoMoreInteractions(context, resourceMethod, resourceModel);
}
Aggregations