use of com.github.ambry.commons.Callback in project ambry by linkedin.
the class GetBlobOperationTest method getAndAssertSuccess.
/**
* Construct GetBlob operations with appropriate callbacks, then poll those operations until they complete,
* and ensure that the whole blob data is read out and the contents match.
* @param getChunksBeforeRead {@code true} if all chunks should be cached by the router before reading from the
* stream.
* @param initiateReadBeforeChunkGet Whether readInto() should be initiated immediately before data chunks are
* fetched by the router to simulate chunk arrival delay.
* @param expectedLifeVersion the expected lifeVersion from get operation.
*/
private void getAndAssertSuccess(final boolean getChunksBeforeRead, final boolean initiateReadBeforeChunkGet, short expectedLifeVersion) throws Exception {
final CountDownLatch readCompleteLatch = new CountDownLatch(1);
final AtomicReference<Throwable> readCompleteThrowable = new AtomicReference<>(null);
final AtomicLong readCompleteResult = new AtomicLong(0);
final AtomicReference<Exception> operationException = new AtomicReference<>(null);
final int numChunks = ((blobSize + maxChunkSize - 1) / maxChunkSize) + (blobSize > maxChunkSize ? 1 : 0);
mockNetworkClient.resetProcessedResponseCount();
Callback<GetBlobResultInternal> callback = (result, exception) -> {
if (exception != null) {
operationException.set(exception);
readCompleteLatch.countDown();
} else {
try {
if (options.getChunkIdsOnly) {
Assert.assertNull("Unexpected blob result when getChunkIdsOnly", result.getBlobResult);
if (blobSize > maxChunkSize) {
// CompositeBlob
Assert.assertNotNull("CompositeBlob should return a list of blob ids when getting chunk ids", result.storeKeys);
Assert.assertEquals(result.storeKeys.size(), (blobSize + maxChunkSize - 1) / maxChunkSize);
} else {
// SimpleBlob
Assert.assertNull("Unexpected list of blob id when getChunkIdsOnly is true on a simple blob", result.storeKeys);
}
readCompleteLatch.countDown();
return;
}
BlobInfo blobInfo;
switch(options.getBlobOptions.getOperationType()) {
case All:
if (!options.getBlobOptions.isRawMode()) {
blobInfo = result.getBlobResult.getBlobInfo();
Assert.assertTrue("Blob properties must be the same", RouterTestHelpers.arePersistedFieldsEquivalent(blobProperties, blobInfo.getBlobProperties()));
Assert.assertEquals("Blob size should in received blobProperties should be the same as actual", blobSize, blobInfo.getBlobProperties().getBlobSize());
Assert.assertArrayEquals("User metadata must be the same", userMetadata, blobInfo.getUserMetadata());
Assert.assertEquals("LifeVersion mismatch", expectedLifeVersion, blobInfo.getLifeVersion());
}
break;
case Data:
Assert.assertNull("Unexpected blob info in operation result", result.getBlobResult.getBlobInfo());
break;
case BlobInfo:
blobInfo = result.getBlobResult.getBlobInfo();
Assert.assertTrue("Blob properties must be the same", RouterTestHelpers.arePersistedFieldsEquivalent(blobProperties, blobInfo.getBlobProperties()));
Assert.assertEquals("Blob size should in received blobProperties should be the same as actual", blobSize, blobInfo.getBlobProperties().getBlobSize());
Assert.assertNull("Unexpected blob data in operation result", result.getBlobResult.getBlobDataChannel());
Assert.assertEquals("LifeVersion mismatch", expectedLifeVersion, blobInfo.getLifeVersion());
}
} catch (Throwable e) {
readCompleteThrowable.set(e);
}
if (options.getBlobOptions.getOperationType() != GetBlobOptions.OperationType.BlobInfo) {
final ByteBufferAsyncWritableChannel asyncWritableChannel = new ByteBufferAsyncWritableChannel();
final Future<Long> preSetReadIntoFuture = initiateReadBeforeChunkGet ? result.getBlobResult.getBlobDataChannel().readInto(asyncWritableChannel, null) : null;
Utils.newThread(() -> {
if (getChunksBeforeRead) {
// wait for all chunks (data + metadata) to be received
while (mockNetworkClient.getProcessedResponseCount() < numChunks * routerConfig.routerGetRequestParallelism) {
Thread.yield();
}
}
Future<Long> readIntoFuture = initiateReadBeforeChunkGet ? preSetReadIntoFuture : result.getBlobResult.getBlobDataChannel().readInto(asyncWritableChannel, null);
assertBlobReadSuccess(options.getBlobOptions, readIntoFuture, asyncWritableChannel, result.getBlobResult.getBlobDataChannel(), readCompleteLatch, readCompleteResult, readCompleteThrowable);
}, false).start();
} else {
readCompleteLatch.countDown();
}
}
};
GetBlobOperation op = createOperationAndComplete(callback);
readCompleteLatch.await();
Assert.assertTrue("Operation should be complete at this time", op.isOperationComplete());
if (operationException.get() != null) {
throw operationException.get();
}
if (readCompleteThrowable.get() != null) {
throw new IllegalStateException(readCompleteThrowable.get());
}
// Ensure that a ChannelClosed exception is not set when the ReadableStreamChannel is closed correctly.
Assert.assertNull("Callback operation exception should be null", op.getOperationException());
if (options.getBlobOptions.getOperationType() != GetBlobOptions.OperationType.BlobInfo && !options.getBlobOptions.isRawMode() && !options.getChunkIdsOnly) {
int sizeWritten = blobSize;
if (options.getBlobOptions.getRange() != null) {
ByteRange range = options.getBlobOptions.getRange().toResolvedByteRange(blobSize, options.getBlobOptions.resolveRangeOnEmptyBlob());
sizeWritten = (int) range.getRangeSize();
}
Assert.assertEquals("Size read must equal size written", sizeWritten, readCompleteResult.get());
}
}
use of com.github.ambry.commons.Callback in project ambry by linkedin.
the class GetManagerTest method testBadCallback.
/**
* Test that a bad user defined callback will not crash the router.
* @param getBlobCallback User defined callback to be called after getBlob operation.
* @param getBlobCallbackCalled This latch should be at 0 after {@code getBlobCallback} has been called.
* @param checkBadCallbackBlob {@code true} if the blob contents provided by the getBlob operation with the bad
* callback should be inspected for correctness.
* @throws Exception
*/
private void testBadCallback(Callback<GetBlobResult> getBlobCallback, CountDownLatch getBlobCallbackCalled, Boolean checkBadCallbackBlob) throws Exception {
router = getNonBlockingRouter();
setOperationParams(LARGE_BLOB_SIZE, new GetBlobOptionsBuilder().build());
final CountDownLatch getBlobInfoCallbackCalled = new CountDownLatch(1);
String blobId = router.putBlob(putBlobProperties, putUserMetadata, putChannel, new PutBlobOptionsBuilder().build()).get();
List<Future<GetBlobResult>> getBlobInfoFutures = new ArrayList<>();
List<Future<GetBlobResult>> getBlobDataFutures = new ArrayList<>();
GetBlobOptions infoOptions = new GetBlobOptionsBuilder().operationType(GetBlobOptions.OperationType.BlobInfo).build();
GetBlobOptions dataOptions = new GetBlobOptionsBuilder().operationType(GetBlobOptions.OperationType.Data).build();
for (int i = 0; i < 5; i++) {
if (i == 1) {
getBlobInfoFutures.add(router.getBlob(blobId, infoOptions, new Callback<GetBlobResult>() {
@Override
public void onCompletion(GetBlobResult result, Exception exception) {
getBlobInfoCallbackCalled.countDown();
throw new RuntimeException("Throwing an exception in the user callback");
}
}, quotaChargeCallback));
getBlobDataFutures.add(router.getBlob(blobId, dataOptions, getBlobCallback, quotaChargeCallback));
} else {
getBlobInfoFutures.add(router.getBlob(blobId, infoOptions));
getBlobDataFutures.add(router.getBlob(blobId, dataOptions));
}
}
options = dataOptions;
for (int i = 0; i < getBlobDataFutures.size(); i++) {
if (i != 1 || checkBadCallbackBlob) {
compareContent(getBlobDataFutures.get(i).get().getBlobDataChannel());
}
}
options = infoOptions;
for (Future<GetBlobResult> future : getBlobInfoFutures) {
compareBlobInfo(future.get().getBlobInfo(), -1);
}
Assert.assertTrue("getBlobInfo callback not called.", getBlobInfoCallbackCalled.await(2, TimeUnit.SECONDS));
Assert.assertTrue("getBlob callback not called.", getBlobCallbackCalled.await(2, TimeUnit.SECONDS));
Assert.assertEquals("All operations should be finished.", 0, router.getOperationsCount());
Assert.assertTrue("Router should not be closed", router.isOpen());
// Test that GetManager is still operational
setOperationParams(CHUNK_SIZE, new GetBlobOptionsBuilder().build());
blobId = router.putBlob(putBlobProperties, putUserMetadata, putChannel, new PutBlobOptionsBuilder().build()).get();
getBlobAndCompareContent(blobId, -1);
this.options = infoOptions;
getBlobAndCompareContent(blobId, -1);
router.close();
}
use of com.github.ambry.commons.Callback in project ambry by linkedin.
the class AmbryServerSecurityServiceTest method validateRequestTest.
/**
* Tests for {@link AmbryServerSecurityService#validateRequest(RestRequest, Callback)}
* @throws Exception
*/
@Test
public void validateRequestTest() throws Exception {
// request is null
TestUtils.assertException(IllegalArgumentException.class, () -> serverSecurityService.validateRequest(null).get(), null);
// success case
RestRequest request = new MockRestRequest(MockRestRequest.DUMMY_DATA, null);
serverSecurityService.validateRequest(request, (r, e) -> {
Assert.assertNull("result not null", r);
Assert.assertNull("exception not null", e);
});
// service is closed
serverSecurityService.close();
ThrowingConsumer<ExecutionException> errorAction = e -> {
Assert.assertTrue("Exception should have been an instance of RestServiceException", e.getCause() instanceof RestServiceException);
RestServiceException re = (RestServiceException) e.getCause();
Assert.assertEquals("Unexpected RestServerErrorCode (Future)", RestServiceErrorCode.ServiceUnavailable, re.getErrorCode());
};
TestUtils.assertException(ExecutionException.class, () -> serverSecurityService.validateRequest(request).get(), errorAction);
}
Aggregations