use of com.github.ambry.router.FutureResult in project ambry by linkedin.
the class NamedBlobPutHandlerTest method doTtlRequiredEnforcementTest.
/**
* Does the TTL required enforcement test by selecting the right verification methods based on container and frontend
* config
* @param container the {@link Container} to upload to
* @param blobTtlSecs the TTL to set for the blob
* @throws Exception
*/
private void doTtlRequiredEnforcementTest(Container container, long blobTtlSecs) throws Exception {
JSONObject headers = new JSONObject();
FrontendRestRequestServiceTest.setAmbryHeadersForPut(headers, blobTtlSecs, !container.isCacheable(), SERVICE_ID, CONTENT_TYPE, OWNER_ID, null, null, null);
byte[] content = TestUtils.getRandomBytes(1024);
RestRequest request = getRestRequest(headers, request_path, content);
RestResponseChannel restResponseChannel = new MockRestResponseChannel();
FutureResult<Void> future = new FutureResult<>();
namedBlobPutHandler.handle(request, restResponseChannel, future::done);
if (container.isTtlRequired() && (blobTtlSecs == Utils.Infinite_Time || blobTtlSecs > frontendConfig.maxAcceptableTtlSecsIfTtlRequired)) {
if (frontendConfig.failIfTtlRequiredButNotProvided) {
try {
future.get(TIMEOUT_SECS, TimeUnit.SECONDS);
fail("Post should have failed");
} catch (ExecutionException e) {
RestServiceException rootCause = (RestServiceException) Utils.getRootCause(e);
assertNotNull("Root cause should be a RestServiceException", rootCause);
assertEquals("Incorrect RestServiceErrorCode", RestServiceErrorCode.InvalidArgs, rootCause.getErrorCode());
}
} else {
verifySuccessResponseOnTtlEnforcement(future, content, blobTtlSecs, restResponseChannel, true);
}
} else {
verifySuccessResponseOnTtlEnforcement(future, content, blobTtlSecs, restResponseChannel, false);
}
}
use of com.github.ambry.router.FutureResult in project ambry by linkedin.
the class PostAccountsHandlerTest method sendRequestGetResponse.
// helpers
// general
/**
* Sends a request to the {@link PostAccountsHandler} and waits for the response.
* @param requestBody body of the request in string form.
* @param restResponseChannel the {@link RestResponseChannel} where headers will be set.
* @throws Exception
*/
private void sendRequestGetResponse(String requestBody, RestResponseChannel restResponseChannel) throws Exception {
JSONObject data = new JSONObject();
data.put(MockRestRequest.REST_METHOD_KEY, RestMethod.POST.name());
data.put(MockRestRequest.URI_KEY, Operations.ACCOUNTS);
List<ByteBuffer> body = new LinkedList<>();
body.add(ByteBuffer.wrap(requestBody.getBytes(StandardCharsets.UTF_8)));
body.add(null);
RestRequest restRequest = new MockRestRequest(data, body);
restRequest.setArg(RestUtils.InternalKeys.REQUEST_PATH, RequestPath.parse(restRequest, null, null));
FutureResult<ReadableStreamChannel> future = new FutureResult<>();
handler.handle(restRequest, restResponseChannel, future::done);
try {
future.get(1, TimeUnit.SECONDS);
} catch (ExecutionException e) {
throw e.getCause() instanceof Exception ? (Exception) e.getCause() : new Exception(e.getCause());
}
}
use of com.github.ambry.router.FutureResult in project ambry by linkedin.
the class PostBlobHandlerTest method doTtlRequiredEnforcementTest.
// ttlRequiredEnforcementTest() helpers
/**
* Does the TTL required enforcement test by selecting the right verification methods based on container and frontend
* config
* @param container the {@link Container} to upload to
* @param blobTtlSecs the TTL to set for the blob
* @throws Exception
*/
private void doTtlRequiredEnforcementTest(Container container, long blobTtlSecs) throws Exception {
JSONObject headers = new JSONObject();
FrontendRestRequestServiceTest.setAmbryHeadersForPut(headers, blobTtlSecs, !container.isCacheable(), SERVICE_ID, CONTENT_TYPE, OWNER_ID, REF_ACCOUNT.getName(), container.getName(), null);
byte[] content = TestUtils.getRandomBytes(1024);
RestRequest request = getRestRequest(headers, "/", content);
RestResponseChannel restResponseChannel = new MockRestResponseChannel();
FutureResult<Void> future = new FutureResult<>();
postBlobHandler.handle(request, restResponseChannel, future::done);
if (container.isTtlRequired() && (blobTtlSecs == Utils.Infinite_Time || blobTtlSecs > frontendConfig.maxAcceptableTtlSecsIfTtlRequired)) {
if (frontendConfig.failIfTtlRequiredButNotProvided) {
try {
future.get(TIMEOUT_SECS, TimeUnit.SECONDS);
fail("Post should have failed");
} catch (ExecutionException e) {
RestServiceException rootCause = (RestServiceException) Utils.getRootCause(e);
assertNotNull("Root cause should be a RestServiceException", rootCause);
assertEquals("Incorrect RestServiceErrorCode", RestServiceErrorCode.InvalidArgs, rootCause.getErrorCode());
}
} else {
verifySuccessResponseOnTtlEnforcement(future, content, blobTtlSecs, restResponseChannel, true);
}
} else {
verifySuccessResponseOnTtlEnforcement(future, content, blobTtlSecs, restResponseChannel, false);
}
}
use of com.github.ambry.router.FutureResult in project ambry by linkedin.
the class NettyResponseChannel method write.
@Override
public Future<Long> write(ByteBuf src, Callback<Long> callback) {
long writeProcessingStartTime = System.currentTimeMillis();
if (!responseMetadataWriteInitiated.get()) {
maybeWriteResponseMetadata(responseMetadata, new ResponseMetadataWriteListener());
}
if (finalResponseMetadata == null) {
// If finalResponseMetadata is still null, it indicates channel becomes inactive.
if (ctx.channel().isActive()) {
logger.warn("Channel should be inactive status. {}", ctx.channel());
nettyMetrics.channelStatusInconsistentCount.inc();
} else {
logger.debug("Scheduling a chunk cleanup on channel {} because response channel is closed.", ctx.channel());
writeFuture.addListener(new CleanupCallback(new ClosedChannelException()));
}
FutureResult<Long> future = new FutureResult<Long>();
future.done(0L, new ClosedChannelException());
if (callback != null) {
callback.onCompletion(0L, new ClosedChannelException());
}
return future;
}
Chunk chunk = new Chunk(src, callback);
logger.debug("Netty Response Chunk size: {}", src.readableBytes());
chunksToWrite.add(chunk);
if (HttpUtil.isContentLengthSet(finalResponseMetadata) && totalBytesReceived.get() > HttpUtil.getContentLength(finalResponseMetadata)) {
Exception exception = new IllegalStateException("Size of provided content [" + totalBytesReceived.get() + "] is greater than Content-Length set [" + HttpUtil.getContentLength(finalResponseMetadata) + "]");
if (!writeFuture.isDone()) {
writeFuture.setFailure(exception);
}
writeFuture.addListener(new CleanupCallback(exception));
} else if (!isOpen()) {
// the isOpen() check is not before addition to the queue because chunks need to be acknowledged in the order
// they were received. If we don't add it to the queue and clean up, chunks may be acknowledged out of order.
logger.debug("Scheduling a chunk cleanup on channel {} because response channel is closed", ctx.channel());
writeFuture.addListener(new CleanupCallback(new ClosedChannelException()));
} else if (finalResponseMetadata instanceof FullHttpResponse) {
logger.debug("Scheduling a chunk cleanup on channel {} because Content-Length is 0", ctx.channel());
Exception exception = null;
// this is only allowed to be a 0 sized buffer.
if (src.readableBytes() > 0) {
exception = new IllegalStateException("Provided non zero size content after setting Content-Length to 0");
if (!writeFuture.isDone()) {
writeFuture.setFailure(exception);
}
}
writeFuture.addListener(new CleanupCallback(exception));
} else {
chunkedWriteHandler.resumeTransfer();
}
long writeProcessingTime = System.currentTimeMillis() - writeProcessingStartTime;
nettyMetrics.writeProcessingTimeInMs.update(writeProcessingTime);
if (request != null) {
request.getMetricsTracker().nioMetricsTracker.addToResponseProcessingTime(writeProcessingTime);
}
return chunk.future;
}
use of com.github.ambry.router.FutureResult in project ambry by linkedin.
the class BadRestRequest method readInto.
/**
* Either throws the exception provided or returns immediately saying no bytes were read.
* @param asyncWritableChannel the {@link AsyncWritableChannel} to read the data into.
* @param callback the {@link Callback} that will be invoked either when all the data in the channel has been emptied
* into the {@code asyncWritableChannel} or if there is an exception in doing so. This can be null.
* @return a {@link Future} that will eventually contain the result of the operation.
*/
@Override
public Future<Long> readInto(AsyncWritableChannel asyncWritableChannel, Callback<Long> callback) {
Exception exception;
if (!channelOpen.get()) {
exception = new ClosedChannelException();
} else {
exception = exceptionToThrow;
}
FutureResult<Long> futureResult = new FutureResult<Long>();
futureResult.done(bytesRead, exception);
if (callback != null) {
callback.onCompletion(bytesRead, exception);
}
return futureResult;
}
Aggregations