use of com.github.ambry.account.Container in project ambry by linkedin.
the class PostBlobHandlerTest method stitchedUploadTest.
/**
* Test flows related to the {@link Operations#STITCH} operation.
* @throws Exception
*/
@Test
public void stitchedUploadTest() throws Exception {
idConverterFactory.translation = CONVERTED_ID;
String uploadSession = UUID.randomUUID().toString();
long creationTimeMs = System.currentTimeMillis();
time.setCurrentMilliseconds(creationTimeMs);
String[] prefixToTest = new String[] { "/" + CLUSTER_NAME, "" };
for (String prefix : prefixToTest) {
// success cases
// multiple chunks
List<ChunkInfo> chunksToStitch = uploadChunksViaRouter(creationTimeMs, REF_CONTAINER, 45, 10, 200, 19, 0, 50);
List<String> signedChunkIds = chunksToStitch.stream().map(chunkInfo -> prefix + getSignedId(chunkInfo, uploadSession)).collect(Collectors.toList());
stitchBlobAndVerify(getStitchRequestBody(signedChunkIds), chunksToStitch, null);
// one chunk
chunksToStitch = uploadChunksViaRouter(creationTimeMs, REF_CONTAINER, 45);
signedChunkIds = chunksToStitch.stream().map(chunkInfo -> prefix + getSignedId(chunkInfo, uploadSession)).collect(Collectors.toList());
stitchBlobAndVerify(getStitchRequestBody(signedChunkIds), chunksToStitch, null);
// failure cases
// invalid json input
stitchBlobAndVerify("badjsonbadjson".getBytes(StandardCharsets.UTF_8), null, restServiceExceptionChecker(RestServiceErrorCode.BadRequest));
// no chunk ids in request
stitchBlobAndVerify(getStitchRequestBody(Collections.emptyList()), null, restServiceExceptionChecker(RestServiceErrorCode.MissingArgs));
stitchBlobAndVerify(new JSONObject().toString().getBytes(StandardCharsets.UTF_8), null, restServiceExceptionChecker(RestServiceErrorCode.MissingArgs));
// differing session IDs
signedChunkIds = uploadChunksViaRouter(creationTimeMs, REF_CONTAINER, 45, 22).stream().map(chunkInfo -> prefix + getSignedId(chunkInfo, UUID.randomUUID().toString())).collect(Collectors.toList());
stitchBlobAndVerify(getStitchRequestBody(signedChunkIds), null, restServiceExceptionChecker(RestServiceErrorCode.BadRequest));
// differing containers
signedChunkIds = Stream.concat(uploadChunksViaRouter(creationTimeMs, REF_CONTAINER, 50, 50).stream(), uploadChunksViaRouter(creationTimeMs, REF_CONTAINER_WITH_TTL_REQUIRED, 50).stream()).map(chunkInfo -> prefix + getSignedId(chunkInfo, uploadSession)).collect(Collectors.toList());
stitchBlobAndVerify(getStitchRequestBody(signedChunkIds), null, restServiceExceptionChecker(RestServiceErrorCode.BadRequest));
// differing accounts
Container altAccountContainer = ACCOUNT_SERVICE.createAndAddRandomAccount().getContainerById(Container.DEFAULT_PRIVATE_CONTAINER_ID);
signedChunkIds = Stream.concat(uploadChunksViaRouter(creationTimeMs, REF_CONTAINER, 50, 50).stream(), uploadChunksViaRouter(creationTimeMs, altAccountContainer, 50).stream()).map(chunkInfo -> prefix + getSignedId(chunkInfo, uploadSession)).collect(Collectors.toList());
stitchBlobAndVerify(getStitchRequestBody(signedChunkIds), null, restServiceExceptionChecker(RestServiceErrorCode.BadRequest));
// invalid blob ID
stitchBlobAndVerify(getStitchRequestBody(Collections.singletonList(getSignedId(new ChunkInfo("abcd", 200, -1), uploadSession))), null, restServiceExceptionChecker(RestServiceErrorCode.BadRequest));
// unsigned ID
stitchBlobAndVerify(getStitchRequestBody(Collections.singletonList("/notASignedId")), null, restServiceExceptionChecker(RestServiceErrorCode.BadRequest));
}
}
use of com.github.ambry.account.Container in project ambry by linkedin.
the class FrontendTestUrlSigningServiceFactory method containerMetricsExclusionTest.
/**
* Tests that container metrics are not generated when the target account is in the excluded list.
* @throws Exception
*/
@Test
public void containerMetricsExclusionTest() throws Exception {
short excludedAccountId = Utils.getRandomShort(TestUtils.RANDOM);
short containerId = 2;
String containerName = "tenant1";
Container container = new ContainerBuilder(containerId, containerName, Container.ContainerStatus.ACTIVE, "test", excludedAccountId).build();
Account excludedAccount = new AccountBuilder(excludedAccountId, excludedAccountName, Account.AccountStatus.ACTIVE).addOrUpdateContainer(container).build();
accountService.updateAccounts(Collections.singletonList(excludedAccount));
postBlobAndVerifyWithAccountAndContainer(excludedAccountName, containerName, "serviceId", !container.isCacheable(), excludedAccount, container, null);
}
use of com.github.ambry.account.Container in project ambry by linkedin.
the class FrontendTestUrlSigningServiceFactory method validateSecurePathTest.
/**
* Test that the secure path is validated if required by {@link Container}.
* @throws Exception
*/
@Test
public void validateSecurePathTest() throws Exception {
short refAccountId = Utils.getRandomShort(TestUtils.RANDOM);
String refAccountName = TestUtils.getRandomString(10);
short[] refContainerIds = new short[] { 2, 3 };
String[] refContainerNames = new String[] { "SecurePathValidation", "NoValidation" };
Container signedPathRequiredContainer = new ContainerBuilder(refContainerIds[0], refContainerNames[0], Container.ContainerStatus.ACTIVE, "validate secure path", refAccountId).setSecurePathRequired(true).build();
Container noValidationContainer = new ContainerBuilder(refContainerIds[1], refContainerNames[1], Container.ContainerStatus.ACTIVE, "no validation on secure path", refAccountId).setSecurePathRequired(false).build();
Account account = new AccountBuilder(refAccountId, refAccountName, Account.AccountStatus.ACTIVE).addOrUpdateContainer(signedPathRequiredContainer).addOrUpdateContainer(noValidationContainer).build();
accountService.updateAccounts(Collections.singletonList(account));
ByteBuffer content = ByteBuffer.wrap(TestUtils.getRandomBytes(CONTENT_LENGTH));
String contentType = "application/octet-stream";
String ownerId = "SecurePathValidationTest";
JSONObject headers = new JSONObject();
setAmbryHeadersForPut(headers, TTL_SECS, false, refAccountName, contentType, ownerId, refAccountName, refContainerNames[0], null);
Map<String, String> userMetadata = new HashMap<>();
userMetadata.put(RestUtils.Headers.USER_META_DATA_HEADER_PREFIX + "key1", "value1");
RestUtilsTest.setUserMetadataHeaders(headers, userMetadata);
String blobId = postBlobAndVerify(headers, content, account, signedPathRequiredContainer);
headers.put(RestUtils.Headers.BLOB_SIZE, (long) CONTENT_LENGTH);
// test that secure path validation succeeded
String testUri = "/" + frontendConfig.securePathPrefix + blobId;
getBlobAndVerify(testUri, null, null, headers, content, account, signedPathRequiredContainer);
// test that no secure path should fail (return AccessDenied)
try {
getBlobAndVerify(blobId, null, null, headers, content, account, signedPathRequiredContainer);
fail("get blob should fail because secure path is missing");
} catch (RestServiceException e) {
assertEquals("Mismatch in error code", RestServiceErrorCode.AccessDenied, e.getErrorCode());
}
// test that secure path equals other prefix should fail (return AccessDenied)
try {
getBlobAndVerify("/media" + blobId, null, null, headers, content, account, signedPathRequiredContainer);
fail("get blob should fail because secure path equals other prefix and doesn't match expected one");
} catch (RestServiceException e) {
assertEquals("Mismatch in error code", RestServiceErrorCode.AccessDenied, e.getErrorCode());
}
// test that incorrect path should fail (return BadRequest)
try {
getBlobAndVerify("/incorrect-path" + blobId, null, null, headers, content, account, signedPathRequiredContainer);
fail("get blob should fail because secure path is incorrect");
} catch (RestServiceException e) {
assertEquals("Mismatch in error code", RestServiceErrorCode.BadRequest, e.getErrorCode());
}
// test container with no validation
setAmbryHeadersForPut(headers, TTL_SECS, false, refAccountName, contentType, ownerId, refAccountName, refContainerNames[1], null);
content = ByteBuffer.wrap(TestUtils.getRandomBytes(CONTENT_LENGTH));
blobId = postBlobAndVerify(headers, content, account, noValidationContainer);
// test container with no validation should fail if there is invalid path in URI
try {
getBlobAndVerify("/incorrect-path" + blobId, null, null, headers, content, account, noValidationContainer);
fail("get blob should fail because there is invalid path in uri");
} catch (RestServiceException e) {
assertEquals("Mismatch in error code", RestServiceErrorCode.BadRequest, e.getErrorCode());
}
// test container with no validation should succeed if URI is correct
getBlobAndVerify(blobId, null, null, headers, content, account, noValidationContainer);
}
use of com.github.ambry.account.Container in project ambry by linkedin.
the class GetAccountsHandlerTest method getSingleContainerSuccessTest.
/**
* Test success case of getting single container.
* @throws Exception
*/
@Test
public void getSingleContainerSuccessTest() throws Exception {
Account existingAccount = accountService.createAndAddRandomAccount();
Container existingContainer = existingAccount.getAllContainers().iterator().next();
ThrowingBiConsumer<RestRequest, Container> testAction = (request, expectedContainer) -> {
RestResponseChannel restResponseChannel = new MockRestResponseChannel();
ReadableStreamChannel channel = sendRequestGetResponse(request, restResponseChannel);
assertNotNull("There should be a response", channel);
Assert.assertNotNull("Date has not been set", restResponseChannel.getHeader(RestUtils.Headers.DATE));
assertEquals("Content-type is not as expected", RestUtils.JSON_CONTENT_TYPE, restResponseChannel.getHeader(RestUtils.Headers.CONTENT_TYPE));
assertEquals("Content-length is not as expected", channel.getSize(), Integer.parseInt((String) restResponseChannel.getHeader(RestUtils.Headers.CONTENT_LENGTH)));
RetainingAsyncWritableChannel asyncWritableChannel = new RetainingAsyncWritableChannel((int) channel.getSize());
channel.readInto(asyncWritableChannel, null).get();
assertEquals("Container does not match", Collections.singletonList(expectedContainer), AccountCollectionSerde.containersFromInputStreamInJson(asyncWritableChannel.consumeContentAsInputStream(), existingAccount.getId()));
};
testAction.accept(createRestRequest(existingAccount.getName(), null, existingContainer.getName(), Operations.ACCOUNTS_CONTAINERS), existingContainer);
}
use of com.github.ambry.account.Container in project ambry by linkedin.
the class MySqlNamedBlobDbIntegrationTest method testPutGetListDeleteSequence.
/**
* Tests sequences of puts, gets, lists, and deletes across multiple containers.
* @throws Exception
*/
@Test
public void testPutGetListDeleteSequence() throws Exception {
int blobsPerContainer = 5;
List<NamedBlobRecord> records = new ArrayList<>();
for (Account account : accountService.getAllAccounts()) {
for (Container container : account.getAllContainers()) {
for (int i = 0; i < blobsPerContainer; i++) {
String blobId = getBlobId(account, container);
String blobName = "name/" + i + "/more path segments--";
long expirationTime = i % 2 == 0 ? Utils.Infinite_Time : System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1);
NamedBlobRecord record = new NamedBlobRecord(account.getName(), container.getName(), blobName, blobId, expirationTime);
namedBlobDb.put(record).get();
records.add(record);
}
}
}
// get records just inserted
for (NamedBlobRecord record : records) {
NamedBlobRecord recordFromStore = namedBlobDb.get(record.getAccountName(), record.getContainerName(), record.getBlobName()).get();
assertEquals("Record does not match expectations.", record, recordFromStore);
}
// list records in each container
for (Account account : accountService.getAllAccounts()) {
for (Container container : account.getAllContainers()) {
Page<NamedBlobRecord> page = namedBlobDb.list(account.getName(), container.getName(), "name", null).get();
assertNull("No continuation token expected", page.getNextPageToken());
assertEquals("Unexpected number of blobs in container", blobsPerContainer, page.getEntries().size());
}
}
// check that puts to the same keys fail.
for (Account account : accountService.getAllAccounts()) {
for (Container container : account.getAllContainers()) {
for (int i = 0; i < blobsPerContainer; i++) {
String blobId = getBlobId(account, container);
String blobName = "name/" + i + "/more path segments--";
NamedBlobRecord record = new NamedBlobRecord(account.getName(), container.getName(), blobName, blobId, Utils.Infinite_Time);
checkErrorCode(() -> namedBlobDb.put(record), RestServiceErrorCode.Conflict);
}
}
}
// delete the records and check that they cannot be fetched with a get call.
for (NamedBlobRecord record : records) {
DeleteResult deleteResult = namedBlobDb.delete(record.getAccountName(), record.getContainerName(), record.getBlobName()).get();
assertEquals("Unexpected deleted ID", record.getBlobId(), deleteResult.getBlobId());
assertFalse("Unexpected alreadyDeleted value", deleteResult.isAlreadyDeleted());
checkErrorCode(() -> namedBlobDb.get(record.getAccountName(), record.getContainerName(), record.getBlobName()), RestServiceErrorCode.Deleted);
}
// deletes should be idempotent and additional delete calls should succeed
for (NamedBlobRecord record : records) {
DeleteResult deleteResult = namedBlobDb.delete(record.getAccountName(), record.getContainerName(), record.getBlobName()).get();
assertEquals("Unexpected deleted ID", record.getBlobId(), deleteResult.getBlobId());
assertTrue("Unexpected alreadyDeleted value", deleteResult.isAlreadyDeleted());
}
// delete and get for non existent blobs should return not found.
for (NamedBlobRecord record : records) {
String nonExistentName = record.getBlobName() + "-other";
checkErrorCode(() -> namedBlobDb.get(record.getAccountName(), record.getContainerName(), nonExistentName), RestServiceErrorCode.NotFound);
checkErrorCode(() -> namedBlobDb.delete(record.getAccountName(), record.getContainerName(), nonExistentName), RestServiceErrorCode.NotFound);
}
records.clear();
// should be able to put new records again after deletion
for (Account account : accountService.getAllAccounts()) {
for (Container container : account.getAllContainers()) {
for (int i = 0; i < blobsPerContainer; i++) {
String blobId = getBlobId(account, container);
String blobName = "name/" + i + "/more path segments--";
long expirationTime = i % 2 == 1 ? Utils.Infinite_Time : System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1);
NamedBlobRecord record = new NamedBlobRecord(account.getName(), container.getName(), blobName, blobId, expirationTime);
namedBlobDb.put(record).get();
records.add(record);
}
}
}
}
Aggregations