Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1890,6 +1890,107 @@ public void testGetDatasetVersionOutOfRetentionCount() throws AccountServiceExce
assertEquals("Mismatch on the version", version1, datasetVersionRecordList.get(0).getVersion());
}

/**
* Test case-insensitive behavior for container names.
*/
@Test
public void testCaseInsensitiveContainerNames() throws Exception {
Account testAccount = makeTestAccountWithContainer();
Container testContainer = new ArrayList<>(testAccount.getAllContainers()).get(0);

// Add a dataset with a container name in lowercase
Dataset dataset = new DatasetBuilder(testAccount.getName(), testContainer.getName().toLowerCase(), DATASET_NAME)
.setVersionSchema(Dataset.VersionSchema.MONOTONIC)
.build();
mySqlAccountStore.addDataset(testAccount.getId(), testContainer.getId(), dataset);

// Retrieve the dataset using the container name in uppercase
Dataset retrievedDataset = mySqlAccountStore.getDataset(
testAccount.getId(),
testContainer.getId(),
testAccount.getName(),
testContainer.getName().toUpperCase(),
DATASET_NAME
);

// Verify the dataset is retrieved successfully
assertNotNull("Dataset should be retrieved successfully with case-insensitive container name", retrievedDataset);
assertEquals("Mismatch in dataset name", DATASET_NAME, retrievedDataset.getDatasetName());
}

/**
* Test case-insensitive behavior for creating and retrieving containers.
*/
@Test
public void testCaseInsensitiveContainerCreationAndRetrieval() throws Exception {
// Create and add an account to the database
Account testAccount = new AccountBuilder((short) 1, "testAccount", Account.AccountStatus.ACTIVE).build();
mySqlAccountService.updateAccounts(Collections.singletonList(testAccount));

// Create a container with a name in lowercase
String containerNameLowercase = "testcontainerlowercase";
Container containerLowercase = new ContainerBuilder(
(short) -1, containerNameLowercase, Container.ContainerStatus.ACTIVE, DESCRIPTION, testAccount.getId()).build();
mySqlAccountService.updateContainers(testAccount.getName(), Collections.singletonList(containerLowercase));

// Retrieve the container using the name in uppercase
Container retrievedContainerUppercase = mySqlAccountService.getContainerByName(
testAccount.getName(), containerNameLowercase.toUpperCase());

// Verify the container is retrieved successfully
assertNotNull("Container should be retrieved successfully with case-insensitive name", retrievedContainerUppercase);
assertEquals("Mismatch in container name", containerNameLowercase, retrievedContainerUppercase.getName());

// Retrieve the container using the name in mixed case
String containerNameMixedCase = "TestContainerLowerCase";
Container retrievedContainerMixedCase = mySqlAccountService.getContainerByName(
testAccount.getName(), containerNameMixedCase);

// Verify the container is retrieved successfully
assertNotNull("Container should be retrieved successfully with mixed-case name", retrievedContainerMixedCase);
assertEquals("Mismatch in container name", containerNameLowercase, retrievedContainerMixedCase.getName());
}

/**
* Test case-insensitive conflict when creating containers with the same name in different cases.
*/
@Test
public void testCaseInsensitiveContainerNameConflict() throws Exception {
// Create and add an account to the database
Account testAccount = new AccountBuilder((short) 1, "testAccount", Account.AccountStatus.ACTIVE).build();
mySqlAccountService.updateAccounts(Collections.singletonList(testAccount));

// Create a container with a name in lowercase
String containerNameLowercase = "testcontainer";
Container containerLowercase = new ContainerBuilder(
(short) -1, containerNameLowercase, Container.ContainerStatus.ACTIVE, DESCRIPTION, testAccount.getId()).build();
mySqlAccountService.updateContainers(testAccount.getName(), Collections.singletonList(containerLowercase));

// Attempt to create a container with the same name in uppercase with diff setting
String containerNameUppercase = containerNameLowercase.toUpperCase();
Container containerUppercase =
new ContainerBuilder((short) -1, containerNameUppercase, Container.ContainerStatus.ACTIVE, DESCRIPTION,
testAccount.getId()).setEncrypted(true).build();

try {
mySqlAccountService.updateContainers(testAccount.getName(), Collections.singletonList(containerUppercase));
fail("Expected a conflict when creating a container with the same name in a different case");
} catch (AccountServiceException e) {
assertEquals("Mismatch in error code", AccountServiceErrorCode.ResourceConflict, e.getErrorCode());
}

// Attempt to create a container with the same name in mixed case
String containerNameMixedCase = "TestContainer";
Container containerMixedCase = new ContainerBuilder(
(short) -1, containerNameMixedCase, Container.ContainerStatus.ACTIVE, DESCRIPTION, testAccount.getId()).build();

mySqlAccountService.updateContainers(testAccount.getName(), Collections.singletonList(containerMixedCase));
Container retrievedContainerUpperCase = mySqlAccountService.getContainerByName(
testAccount.getName(), containerNameUppercase);
assertEquals("Mismatch in container name", containerNameLowercase, retrievedContainerUpperCase.getName());

}

private Account makeTestAccountWithContainer() {
Container testContainer =
new ContainerBuilder((short) 1, "testContainer", Container.ContainerStatus.ACTIVE, "testContainer",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public Collection<Container> updateContainers(String accountName, Collection<Con
List<Container> existingUnchangedContainers = new ArrayList<>();
// create a hashmap to map the name to existing containers in account
Map<String, Container> existingContainersInAccount = new HashMap<>();
account.getAllContainers().forEach(c -> existingContainersInAccount.put(c.getName(), c));
account.getAllContainers().forEach(c -> existingContainersInAccount.put(c.getName().toLowerCase(), c));

// Generate container ids for new containers
int nextContainerId = account.getAllContainers()
Expand All @@ -173,7 +173,7 @@ public Collection<Container> updateContainers(String accountName, Collection<Con
for (Container container : containers) {
if (container.getId() == Container.UNKNOWN_CONTAINER_ID) {
// new container
Container existingContainer = existingContainersInAccount.get(container.getName());
Container existingContainer = existingContainersInAccount.get(container.getName().toLowerCase());
if (existingContainer != null) {
switch (existingContainer.getStatus()) {
case INACTIVE:
Expand Down Expand Up @@ -219,7 +219,7 @@ public Collection<Container> updateContainers(String accountName, Collection<Con
}
} else {
// existing container
Container existingContainer = existingContainersInAccount.get(container.getName());
Container existingContainer = existingContainersInAccount.get(container.getName().toLowerCase());
if (existingContainer == null) {
throw new AccountServiceException(
"In account " + accountName + ", container " + container.getName() + " does not exist (containerId "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,30 @@ public void testCreateExistingContainerInDifferentStates() throws Exception {
}
}


/**
* Tests case-insensitive behavior for container names in {@link MySqlAccountService}.
*/
@Test
public void testCaseInsensitiveContainerNames() throws Exception {
Container testContainer =
new ContainerBuilder((short) 1, "TestContainer", Container.ContainerStatus.ACTIVE, "testContainer", (short) 1)
.build();
Account testAccount = new AccountBuilder((short) 1, "testAccount", Account.AccountStatus.ACTIVE)
.containers(Collections.singleton(testContainer))
.build();

mySqlAccountService.updateAccounts(Collections.singletonList(testAccount));

// Verify container retrieval is case-insensitive
assertNotNull("Container should be retrievable with original case",
mySqlAccountService.getContainerByName(testAccount.getName(), "TestContainer"));
assertNotNull("Container should be retrievable with lowercase",
mySqlAccountService.getContainerByName(testAccount.getName(), "testcontainer"));
assertNotNull("Container should be retrievable with uppercase",
mySqlAccountService.getContainerByName(testAccount.getName(), "TESTCONTAINER"));
}

/**
* Asserts that sync time was updated and container count is expected.
* @param accountServiceMetrics the metrics to check
Expand Down
8 changes: 4 additions & 4 deletions ambry-api/src/main/java/com/github/ambry/account/Account.java
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ public Container getContainerById(short containerId) {
* container does not exist.
*/
public Container getContainerByName(String containerName) {
return containerNameToContainerMap.get(containerName);
return containerNameToContainerMap.get(containerName.toLowerCase());
}

/**
Expand Down Expand Up @@ -305,7 +305,7 @@ public void updateContainerMap(Collection<Container> containers) {
checkParentAccountIdInContainers(container);
checkDuplicateContainerNameOrId(container);
containerIdToContainerMap.put(container.getId(), container);
containerNameToContainerMap.put(container.getName(), container);
containerNameToContainerMap.put(container.getName().toLowerCase(), container);
this.containers.add(container);
}
}
Expand Down Expand Up @@ -341,10 +341,10 @@ private void checkRequiredFieldsForBuild() {
*/
private void checkDuplicateContainerNameOrId(Container container) {
if (containerIdToContainerMap.containsKey(container.getId()) || containerNameToContainerMap.containsKey(
container.getName())) {
container.getName().toLowerCase())) {
Container conflictContainer = containerIdToContainerMap.get(container.getId());
conflictContainer =
conflictContainer == null ? containerNameToContainerMap.get(container.getName()) : conflictContainer;
conflictContainer == null ? containerNameToContainerMap.get(container.getName().toLowerCase()) : conflictContainer;
String errorMessage =
new StringBuilder("Duplicate container id or name exists. containerId=").append(container.getId())
.append(" containerName=")
Expand Down
Loading