use of com.github.ambry.rest.RestRequest in project ambry by linkedin.
the class PostAccountContainersHandlerTest method createRestRequest.
/**
* Creates a {@link RestRequest} for a /accounts/updateContainers request
* @param requestBody body of the request in string form.
* @param accountName if set, add this account name as a request header.
* @param accountId if set, add this account ID as a request header.
* @return the {@link RestRequest}
* @throws Exception
*/
private RestRequest createRestRequest(String requestBody, String accountName, String accountId) throws Exception {
JSONObject data = new JSONObject();
data.put(MockRestRequest.REST_METHOD_KEY, RestMethod.POST.name());
data.put(MockRestRequest.URI_KEY, Operations.ACCOUNTS_CONTAINERS);
JSONObject headers = new JSONObject();
if (accountName != null) {
headers.put(RestUtils.Headers.TARGET_ACCOUNT_NAME, accountName);
}
if (accountId != null) {
headers.put(RestUtils.Headers.TARGET_ACCOUNT_ID, accountId);
}
data.put(MockRestRequest.HEADERS_KEY, headers);
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));
return restRequest;
}
use of com.github.ambry.rest.RestRequest in project ambry by linkedin.
the class PostAccountContainersHandlerTest method validRequestsTest.
/**
* Test valid request cases.
* @throws Exception
*/
@Test
public void validRequestsTest() throws Exception {
String accountName = theAccount.getName();
short accountId = theAccount.getId();
ThrowingConsumer<Collection<Container>> testAction = inputContainers -> {
String requestBody = new String(AccountCollectionSerde.serializeContainersInJson(inputContainers));
RestResponseChannel restResponseChannel = new MockRestResponseChannel();
RestRequest request = createRestRequest(requestBody, accountName, null);
ReadableStreamChannel responseChannel = sendRequestGetResponse(request, restResponseChannel);
assertNotNull("Date has not been set", restResponseChannel.getHeader(RestUtils.Headers.DATE));
assertEquals("Content-length is not as expected", responseChannel.getSize(), Integer.parseInt((String) restResponseChannel.getHeader(RestUtils.Headers.CONTENT_LENGTH)));
assertEquals("Account id in response header is not as expected", accountId, Short.parseShort((String) restResponseChannel.getHeader(RestUtils.Headers.TARGET_ACCOUNT_ID)));
RetainingAsyncWritableChannel asyncWritableChannel = new RetainingAsyncWritableChannel((int) responseChannel.getSize());
responseChannel.readInto(asyncWritableChannel, null).get();
Collection<Container> outputContainers = AccountCollectionSerde.containersFromInputStreamInJson(asyncWritableChannel.consumeContentAsInputStream(), accountId);
assertEquals("Unexpected count returned", inputContainers.size(), outputContainers.size());
for (Container container : outputContainers) {
assertEquals("Container in account service not as expected", container, accountService.getContainerByName(accountName, container.getName()));
}
};
// add new container
testAction.accept(Collections.singleton(accountService.getRandomContainer(accountId)));
// add multiple containers
List<Container> containerList = new ArrayList<>();
for (int j = 0; j < 10; j++) {
containerList.add(new ContainerBuilder(Container.UNKNOWN_CONTAINER_ID, "Test-" + j, Container.ContainerStatus.ACTIVE, "", accountId).build());
}
testAction.accept(containerList);
// TODO: update existing containers when support is added
}
use of com.github.ambry.rest.RestRequest in project ambry by linkedin.
the class PostBlobHandlerTest method doChunkUploadTest.
// chunkUploadTest() helpers
/**
* Make a post request and verify behavior related to chunk uploads (for stitched blobs).
* @param contentLength the size of the blob to upload.
* @param chunkUpload {@code true} to send the "x-ambry-chunk-upload" header, or {@code false} to test full uploads.
* @param uploadSession the value for the "x-ambry-chunk-upload-session" request header, or null to not set it.
* @param maxUploadSize the value for the "x-ambry-max-upload-size" request header, or null to not set it.
* @param blobTtlSecs the blob TTL to use.
* @param errorChecker if non-null, expect an exception to be thrown by the post flow and verify it using this
* {@link ThrowingConsumer}.
* @throws Exception
*/
private void doChunkUploadTest(int contentLength, boolean chunkUpload, String uploadSession, Integer maxUploadSize, long blobTtlSecs, ThrowingConsumer<ExecutionException> errorChecker) throws Exception {
JSONObject headers = new JSONObject();
FrontendRestRequestServiceTest.setAmbryHeadersForPut(headers, blobTtlSecs, !REF_CONTAINER.isCacheable(), SERVICE_ID, CONTENT_TYPE, OWNER_ID, REF_ACCOUNT.getName(), REF_CONTAINER.getName(), null);
if (chunkUpload) {
headers.put(RestUtils.Headers.CHUNK_UPLOAD, true);
}
if (uploadSession != null) {
headers.put(RestUtils.Headers.SESSION, uploadSession);
}
if (maxUploadSize != null) {
headers.put(RestUtils.Headers.MAX_UPLOAD_SIZE, maxUploadSize);
}
byte[] content = TestUtils.getRandomBytes(contentLength);
RestRequest request = getRestRequest(headers, "/", content);
long creationTimeMs = System.currentTimeMillis();
time.setCurrentMilliseconds(creationTimeMs);
RestResponseChannel restResponseChannel = new MockRestResponseChannel();
FutureResult<Void> future = new FutureResult<>();
idConverterFactory.lastInput = null;
postBlobHandler.handle(request, restResponseChannel, future::done);
if (errorChecker == null) {
future.get(TIMEOUT_SECS, TimeUnit.SECONDS);
assertEquals("Unexpected converted ID", CONVERTED_ID, restResponseChannel.getHeader(RestUtils.Headers.LOCATION));
Object metadata = request.getArgs().get(RestUtils.InternalKeys.SIGNED_ID_METADATA_KEY);
if (chunkUpload) {
Map<String, String> expectedMetadata = new HashMap<>(3);
expectedMetadata.put(RestUtils.Headers.BLOB_SIZE, Integer.toString(contentLength));
expectedMetadata.put(RestUtils.Headers.SESSION, uploadSession);
expectedMetadata.put(PostBlobHandler.EXPIRATION_TIME_MS_KEY, Long.toString(Utils.addSecondsToEpochTime(creationTimeMs, blobTtlSecs)));
assertEquals("Unexpected signed ID metadata", expectedMetadata, metadata);
} else {
assertNull("Signed id metadata should not be set on non-chunk uploads", metadata);
}
InMemoryRouter.InMemoryBlob blob = router.getActiveBlobs().get(idConverterFactory.lastInput);
assertEquals("Unexpected blob content stored", ByteBuffer.wrap(content), blob.getBlob());
assertEquals("Unexpected ttl stored", blobTtlSecs, blob.getBlobProperties().getTimeToLiveInSeconds());
// check that blob size matches the actual upload size
assertEquals("Invalid blob size", Integer.toString(contentLength), restResponseChannel.getHeader(RestUtils.Headers.BLOB_SIZE));
} else {
TestUtils.assertException(ExecutionException.class, () -> future.get(TIMEOUT_SECS, TimeUnit.SECONDS), errorChecker);
}
}
use of com.github.ambry.rest.RestRequest in project ambry by linkedin.
the class PostBlobHandlerTest method getRestRequest.
/**
* Method to easily create a POST {@link RestRequest}. This will set {@link RestUtils.InternalKeys#REQUEST_PATH} to a
* valid {@link RequestPath} object.
* @param headers any associated headers as a {@link JSONObject}.
* @param path the path for the request.
* @param requestBody the body of the request.
* @return A {@link RestRequest} object that defines the request required by the input.
*/
private RestRequest getRestRequest(JSONObject headers, String path, byte[] requestBody) throws UnsupportedEncodingException, URISyntaxException, RestServiceException {
RestRequest request = FrontendRestRequestServiceTest.createRestRequest(RestMethod.POST, path, headers, new LinkedList<>(Arrays.asList(ByteBuffer.wrap(requestBody), null)));
request.setArg(RestUtils.InternalKeys.REQUEST_PATH, RequestPath.parse(request, frontendConfig.pathPrefixesToRemove, CLUSTER_NAME));
return request;
}
use of com.github.ambry.rest.RestRequest in project ambry by linkedin.
the class PostBlobHandlerTest method stitchBlobAndVerify.
/**
* Make a stitch blob call using {@link PostBlobHandler} and verify the result of the operation.
* @param requestBody the body of the stitch request to supply.
* @param expectedStitchedChunks the expected chunks stitched together.
* @param errorChecker if non-null, expect an exception to be thrown by the post flow and verify it using this
* {@link ThrowingConsumer}.
* @throws Exception
*/
private void stitchBlobAndVerify(byte[] requestBody, List<ChunkInfo> expectedStitchedChunks, ThrowingConsumer<ExecutionException> errorChecker) throws Exception {
JSONObject headers = new JSONObject();
FrontendRestRequestServiceTest.setAmbryHeadersForPut(headers, TestUtils.TTL_SECS, !REF_CONTAINER.isCacheable(), SERVICE_ID, CONTENT_TYPE, OWNER_ID, REF_ACCOUNT.getName(), REF_CONTAINER.getName(), null);
RestRequest request = getRestRequest(headers, "/" + Operations.STITCH, requestBody);
RestResponseChannel restResponseChannel = new MockRestResponseChannel();
FutureResult<Void> future = new FutureResult<>();
idConverterFactory.lastInput = null;
postBlobHandler.handle(request, restResponseChannel, future::done);
if (errorChecker == null) {
future.get(TIMEOUT_SECS, TimeUnit.SECONDS);
assertEquals("Unexpected converted ID", CONVERTED_ID, restResponseChannel.getHeader(RestUtils.Headers.LOCATION));
InMemoryRouter.InMemoryBlob blob = router.getActiveBlobs().get(idConverterFactory.lastInput);
assertEquals("List of chunks stitched does not match expected", expectedStitchedChunks, blob.getStitchedChunks());
ByteArrayOutputStream expectedContent = new ByteArrayOutputStream();
expectedStitchedChunks.stream().map(chunkInfo -> router.getActiveBlobs().get(chunkInfo.getBlobId()).getBlob().array()).forEach(buf -> expectedContent.write(buf, 0, buf.length));
assertEquals("Unexpected blob content stored", ByteBuffer.wrap(expectedContent.toByteArray()), blob.getBlob());
// check actual size of stitched blob
assertEquals("Unexpected blob size", Long.toString(getStitchedBlobSize(expectedStitchedChunks)), restResponseChannel.getHeader(RestUtils.Headers.BLOB_SIZE));
} else {
TestUtils.assertException(ExecutionException.class, () -> future.get(TIMEOUT_SECS, TimeUnit.SECONDS), errorChecker);
}
}
Aggregations