use of com.linkedin.restli.internal.testutils.RestLiTestAttachmentDataSource in project rest.li by linkedin.
the class TestParseqTraceDebugRequestHandler method testErrorStreamingAbsorbRequestAbortResponse.
@Test
public void testErrorStreamingAbsorbRequestAbortResponse() throws Exception {
//This test verifies that in the face of an error, the ParseqTraceDebugRequestHandler aborts any potential outgoing
//response attachments and absorbs and drops on the ground any incoming request attachments.
final URI uri = URI.create("http://host/abc/12/__debug/parseqtrace/raw");
ParseqTraceDebugRequestHandler requestHandler = new ParseqTraceDebugRequestHandler();
RestRequestBuilder requestBuilder = new RestRequestBuilder(uri);
RestRequest request = requestBuilder.build();
RequestContext requestContext = new RequestContext();
final RequestExecutionCallback<RestResponse> callback = new RequestExecutionCallback<RestResponse>() {
@Override
public void onError(Throwable e, RequestExecutionReport executionReport, RestLiAttachmentReader requestAttachmentReader, RestLiResponseAttachments responseAttachments) {
//Even though we call callback.onError() below to simulate a failed rest.li request execution, the
//ParseqTraceDebugRequestHandler eventually treats this as a success.
Assert.fail("Request execution passed unexpectedly.");
}
@Override
public void onSuccess(RestResponse result, RequestExecutionReport executionReport, RestLiResponseAttachments responseAttachments) {
}
};
//Create request and response attachments. This is not the wire protocol for rest.li streaming, but
//makes this test easier to write and understand.
//Response attachment.
final RestLiTestAttachmentDataSource responseDataSource = RestLiTestAttachmentDataSource.createWithRandomPayload("1");
final RestLiResponseAttachments responseAttachments = new RestLiResponseAttachments.Builder().appendSingleAttachment(responseDataSource).build();
//Request attachment. We need to create a reader here.
final RestLiTestAttachmentDataSource requestAttachment = RestLiTestAttachmentDataSource.createWithRandomPayload("2");
final MultiPartMIMEWriter.Builder builder = new MultiPartMIMEWriter.Builder();
AttachmentUtils.appendSingleAttachmentToBuilder(builder, requestAttachment);
final ByteStringWriter byteStringWriter = new ByteStringWriter(ByteString.copyString("Normal rest.li request payload", Charset.defaultCharset()));
final MultiPartMIMEWriter writer = AttachmentUtils.createMultiPartMIMEWriter(byteStringWriter, "application/json", builder);
final StreamRequest streamRequest = MultiPartMIMEStreamRequestFactory.generateMultiPartMIMEStreamRequest(new URI(""), "related", writer);
final MultiPartMIMEReader reader = MultiPartMIMEReader.createAndAcquireStream(streamRequest);
final RestLiAttachmentReader attachmentReader = new RestLiAttachmentReader(reader);
//Absorb the first part as rest.li server does and then give the beginning of the next part to the
//ParseqTraceDebugRequestHandler.
final MultiPartMIMEReaderCallback multiPartMIMEReaderCallback = new MultiPartMIMEReaderCallback() {
int partCounter = 0;
@Override
public void onNewPart(MultiPartMIMEReader.SinglePartMIMEReader singlePartMIMEReader) {
if (partCounter == 0) {
singlePartMIMEReader.drainPart();
partCounter++;
} else {
//When the first part is read in, at the beginning of the 2nd part, we move to the debug request handler.
requestHandler.handleRequest(request, requestContext, new RestLiDebugRequestHandler.ResourceDebugRequestHandler() {
@Override
public void handleRequest(RestRequest request, RequestContext requestContext, RequestExecutionCallback<RestResponse> callback) {
callback.onError(RestException.forError(500, "An error has occurred"), new RequestExecutionReportBuilder().build(), attachmentReader, responseAttachments);
}
}, attachmentReader, callback);
}
}
@Override
public void onFinished() {
Assert.fail();
}
@Override
public void onDrainComplete() {
//Eventually this should occur.
}
@Override
public void onStreamError(Throwable throwable) {
Assert.fail();
}
};
reader.registerReaderCallback(multiPartMIMEReaderCallback);
//The response data source should have been aborted.
Assert.assertTrue(responseDataSource.dataSourceAborted());
//The request attachment should have been absorbed and finished.
Assert.assertTrue(requestAttachment.finished());
}
use of com.linkedin.restli.internal.testutils.RestLiTestAttachmentDataSource in project rest.li by linkedin.
the class TestStreamingGreetings method resourceMethodDoesNotAcceptAttachments.
@Test(dataProvider = com.linkedin.restli.internal.common.TestConstants.RESTLI_PROTOCOL_1_2_PREFIX + "requestBuilderDataProvider")
public void resourceMethodDoesNotAcceptAttachments(final RootBuilderWrapper<Long, Greeting> builders) throws RemoteInvocationException {
//Resource method does not desire request attachments. Assert that all the attachments are drained and that a 400
//bad request is observed.
final RestLiTestAttachmentDataSource greetingAttachment = new RestLiTestAttachmentDataSource("1", ByteString.copyString("clientData", Charset.defaultCharset()));
RootBuilderWrapper.MethodBuilderWrapper<Long, Greeting, Object> methodBuilderWrapper = builders.action("actionNoAttachmentsAllowed");
methodBuilderWrapper.appendSingleAttachment(greetingAttachment);
final Request<Object> request = methodBuilderWrapper.build();
try {
getClient().sendRequest(request).getResponse().getEntity();
Assert.fail();
} catch (final RestLiResponseException responseException) {
Assert.assertEquals(responseException.getStatus(), 400);
Assert.assertEquals(responseException.getServiceErrorMessage(), "Resource method endpoint invoked does not accept any request attachments.");
}
//Then verify the response and request attachments were fully absorbed.
Assert.assertTrue(greetingAttachment.finished());
}
use of com.linkedin.restli.internal.testutils.RestLiTestAttachmentDataSource in project rest.li by linkedin.
the class TestAttachmentUtils method testSingleAttachment.
@Test
public void testSingleAttachment() {
final MultiPartMIMEWriter.Builder builder = new MultiPartMIMEWriter.Builder();
final List<RestLiTestAttachmentDataSource> testAttachmentDataSources = generateTestDataSources();
for (RestLiTestAttachmentDataSource dataSource : testAttachmentDataSources) {
AttachmentUtils.appendSingleAttachmentToBuilder(builder, dataSource);
}
final StreamRequest streamRequest = MultiPartMIMEStreamRequestFactory.generateMultiPartMIMEStreamRequest(URI.create("foo"), "related", builder.build());
final MultiPartMIMEReader streamRequestReader = MultiPartMIMEReader.createAndAcquireStream(streamRequest);
final CountDownLatch streamRequestReaderLatch = new CountDownLatch(1);
final MIMETestUtils.MultiPartMIMEFullReaderCallback streamRequestReaderCallback = new MIMETestUtils.MultiPartMIMEFullReaderCallback(streamRequestReaderLatch);
streamRequestReader.registerReaderCallback(streamRequestReaderCallback);
try {
streamRequestReaderLatch.await(3000, TimeUnit.MILLISECONDS);
} catch (InterruptedException interruptedException) {
Assert.fail();
}
verifyAttachments(streamRequestReaderCallback.getSinglePartMIMEReaderCallbacks(), testAttachmentDataSources);
}
use of com.linkedin.restli.internal.testutils.RestLiTestAttachmentDataSource in project rest.li by linkedin.
the class TestAttachmentUtils method testMixtureOfAttachments.
@Test
public void testMixtureOfAttachments() {
final MultiPartMIMEWriter.Builder builder = new MultiPartMIMEWriter.Builder();
final List<RestLiTestAttachmentDataSource> iteratorDataSources = generateTestDataSources();
final RestLiTestAttachmentDataSourceIterator dataSourceIterator = new RestLiTestAttachmentDataSourceIterator(iteratorDataSources, new IllegalArgumentException());
//Let each data source know its parent, so that when the data source is done, it can notify it's parent to call onNewDataSourceWriter()
for (final RestLiTestAttachmentDataSource dataSource : iteratorDataSources) {
dataSource.setParentDataSourceIterator(dataSourceIterator);
}
//Now one at the beginning
final RestLiTestAttachmentDataSource dataSourceBeginning = RestLiTestAttachmentDataSource.createWithRandomPayload("BEG");
//And one at the end
final RestLiTestAttachmentDataSource dataSourceEnd = RestLiTestAttachmentDataSource.createWithRandomPayload("END");
AttachmentUtils.appendSingleAttachmentToBuilder(builder, dataSourceBeginning);
AttachmentUtils.appendMultipleAttachmentsToBuilder(builder, dataSourceIterator);
AttachmentUtils.appendSingleAttachmentToBuilder(builder, dataSourceEnd);
final StreamRequest streamRequest = MultiPartMIMEStreamRequestFactory.generateMultiPartMIMEStreamRequest(URI.create("foo"), "related", builder.build());
final MultiPartMIMEReader streamRequestReader = MultiPartMIMEReader.createAndAcquireStream(streamRequest);
final CountDownLatch streamRequestReaderLatch = new CountDownLatch(1);
final MIMETestUtils.MultiPartMIMEFullReaderCallback streamRequestReaderCallback = new MIMETestUtils.MultiPartMIMEFullReaderCallback(streamRequestReaderLatch);
streamRequestReader.registerReaderCallback(streamRequestReaderCallback);
try {
streamRequestReaderLatch.await(3000, TimeUnit.MILLISECONDS);
} catch (InterruptedException interruptedException) {
Assert.fail();
}
final List<RestLiTestAttachmentDataSource> allAttachmentDataSources = new ArrayList<>();
allAttachmentDataSources.add(dataSourceBeginning);
allAttachmentDataSources.addAll(iteratorDataSources);
allAttachmentDataSources.add(dataSourceEnd);
verifyAttachments(streamRequestReaderCallback.getSinglePartMIMEReaderCallbacks(), allAttachmentDataSources);
}
use of com.linkedin.restli.internal.testutils.RestLiTestAttachmentDataSource in project rest.li by linkedin.
the class TestRestLiServer method testRequestAttachmentsResponseAttachmentsException.
@Test
public void testRequestAttachmentsResponseAttachmentsException() throws Exception {
//This test verifies the server's behavior in the face of an exception. In this case the resource method
//threw an exception AFTER setting response attachments. Additionally the resource method failed to absorb any
//incoming request attachments. We verify in this test that StreamResponseCallbackAdaptor in RestLiServer
//drains and absorbs all bytes from the incoming request and that the response attachments set by the resource method
//are told to abort.
//Define the server side resource attachments to be sent back.
final RestLiResponseAttachments.Builder responseAttachmentsBuilder = new RestLiResponseAttachments.Builder();
final RestLiTestAttachmentDataSource toBeAbortedDataSource = RestLiTestAttachmentDataSource.createWithRandomPayload("1");
responseAttachmentsBuilder.appendSingleAttachment(toBeAbortedDataSource);
Capture<ResourceContext> resourceContextCapture = new Capture<ResourceContext>();
final AsyncStatusCollectionResource statusResource = getMockResource(AsyncStatusCollectionResource.class, EasyMock.capture(resourceContextCapture));
statusResource.streamingAction(EasyMock.<String>anyObject(), EasyMock.<RestLiAttachmentReader>anyObject(), EasyMock.<Callback<Long>>anyObject());
EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
@Override
public Object answer() throws Throwable {
//Verify there are still attachments to be read.
final RestLiAttachmentReader attachmentReader = (RestLiAttachmentReader) EasyMock.getCurrentArguments()[1];
Assert.assertFalse(attachmentReader.haveAllAttachmentsFinished());
//Verify the action param.
Assert.assertEquals((String) EasyMock.getCurrentArguments()[0], "someMetadata");
//Set the response attachments
resourceContextCapture.getValue().setResponseAttachments(responseAttachmentsBuilder.build());
//Now throw an exception.
@SuppressWarnings("unchecked") Callback<Long> callback = (Callback<Long>) EasyMock.getCurrentArguments()[2];
callback.onError(new RestLiServiceException(HttpStatus.S_409_CONFLICT, "Some conflict"));
return null;
}
});
EasyMock.replay(statusResource);
//Now we create a multipart/related payload.
final String payload = "{\"metadata\": \"someMetadata\"}";
final ByteStringWriter byteStringWriter = new ByteStringWriter(ByteString.copyString(payload, Charset.defaultCharset()));
final MultiPartMIMEWriter.Builder builder = new MultiPartMIMEWriter.Builder();
final RestLiTestAttachmentDataSource toBeDrainedDataSource = RestLiTestAttachmentDataSource.createWithRandomPayload("2");
AttachmentUtils.appendSingleAttachmentToBuilder(builder, toBeDrainedDataSource);
final MultiPartMIMEWriter writer = AttachmentUtils.createMultiPartMIMEWriter(byteStringWriter, "application/json", builder);
final StreamRequest streamRequest = MultiPartMIMEStreamRequestFactory.generateMultiPartMIMEStreamRequest(new URI("/asyncstatuses/?action=streamingAction"), "related", writer, Collections.<String, String>emptyMap(), "POST", ImmutableMap.of(RestConstants.HEADER_ACCEPT, RestConstants.HEADER_VALUE_MULTIPART_RELATED), Collections.emptyList());
final Callback<StreamResponse> callback = new Callback<StreamResponse>() {
@Override
public void onSuccess(StreamResponse streamResponse) {
fail();
}
@Override
public void onError(Throwable e) {
//Verify the exception.
assertTrue(e instanceof StreamException);
StreamException streamException = (StreamException) e;
StreamResponse streamResponse = streamException.getResponse();
assertEquals(streamResponse.getStatus(), 409);
final FullEntityReader fullEntityReader = new FullEntityReader(new Callback<ByteString>() {
@Override
public void onError(Throwable e) {
Assert.fail();
}
@Override
public void onSuccess(ByteString result) {
//We have the body so assert exception made it.
assertTrue(result.length() > 0);
assertTrue(result.asString(Charset.defaultCharset()).contains("Some conflict"));
}
});
streamResponse.getEntityStream().setReader(fullEntityReader);
EasyMock.verify(statusResource);
EasyMock.reset(statusResource);
}
};
_server.handleRequest(streamRequest, new RequestContext(), callback);
//Verify that the request level attachments were drained.
Assert.assertTrue(toBeDrainedDataSource.finished());
//Verify that response attachments were told to abort.
Assert.assertTrue(toBeAbortedDataSource.dataSourceAborted());
}
Aggregations