use of com.github.ambry.account.Container in project ambry by linkedin.
the class HelixAccountServiceTest method generateRefAccountsForDeprecationTest.
/**
* Randomly generates a collection of {@link Account}s, which do not have the same id or name with needed container status.
* @param idToRefAccountMap A map from id to {@link Account} to populate with the generated {@link Account}s.
* @param idToRefContainerMap A map from name to {@link Account} to populate with the generated {@link Account}s.
* @param accountIdSet A set of ids that could not be used to generate {@link Account}s.
* @param accountCount The number of {@link Account}s to generate.
* @param timestamp timestamp for delete trigger time.
*/
static void generateRefAccountsForDeprecationTest(Map<Short, Account> idToRefAccountMap, Map<Short, Map<Short, Container>> idToRefContainerMap, Set<Short> accountIdSet, int accountCount, long timestamp) {
idToRefAccountMap.clear();
idToRefContainerMap.clear();
for (int i = 0; i < accountCount; i++) {
short accountId = Utils.getRandomShort(random);
if (!accountIdSet.add(accountId)) {
i--;
continue;
}
String accountName = UUID.randomUUID().toString();
Account.AccountStatus accountStatus = random.nextBoolean() ? Account.AccountStatus.ACTIVE : Account.AccountStatus.INACTIVE;
Map<Short, Container> idToContainers = new HashMap<>();
List<Container> containers = new ArrayList<>();
List<ContainerBuilder> containerBuilders = AccountTestUtils.generateContainerBuilders(4, accountId);
containerBuilders.get(0).setStatus(Container.ContainerStatus.ACTIVE);
containerBuilders.get(1).setStatus(Container.ContainerStatus.INACTIVE);
containerBuilders.get(2).setStatus(Container.ContainerStatus.DELETE_IN_PROGRESS);
containerBuilders.get(2).setDeleteTriggerTime(timestamp);
containerBuilders.get(3).setStatus(Container.ContainerStatus.DELETE_IN_PROGRESS);
containerBuilders.get(3).setDeleteTriggerTime(timestamp + 10000);
containers.addAll(containerBuilders.stream().map(containerBuilder -> containerBuilder.build()).collect(Collectors.toList()));
idToContainers = containers.stream().collect(Collectors.toMap(Container::getId, Function.identity()));
Account account = new AccountBuilder(accountId, accountName, accountStatus).containers(containers).build();
assertEquals("Wrong number of generated containers for the account", 4, account.getAllContainers().size());
idToRefAccountMap.put(accountId, account);
idToRefContainerMap.put(accountId, idToContainers);
}
assertEquals("Wrong number of generated accounts", accountCount, idToRefAccountMap.size());
}
use of com.github.ambry.account.Container in project ambry by linkedin.
the class MySqlAccountServiceIntegrationTest method testConflictingUpdatesWithContainers.
/**
* Tests name/id conflicts in Containers
*/
@Test
public void testConflictingUpdatesWithContainers() throws Exception {
List<Container> containersList = new ArrayList<>();
containersList.add(new ContainerBuilder((short) 1, "c1", ContainerStatus.ACTIVE, "c1", (short) 1).build());
containersList.add(new ContainerBuilder((short) 2, "c2", ContainerStatus.ACTIVE, "c2", (short) 1).build());
Account accountToUpdate = new AccountBuilder((short) 1, "a", Account.AccountStatus.ACTIVE).containers(containersList).build();
AccountServiceMetrics accountServiceMetrics = mySqlAccountService.accountServiceMetrics;
// write account (1,a) with containers (1,c1), (2,c2)
mySqlAccountService.updateAccounts(Collections.singletonList(accountToUpdate));
assertEquals("Mismatch in number of containers", 2, mySqlAccountService.getAccountById(accountToUpdate.getId()).getAllContainers().size());
// case A: Verify that changing name of container (1,c1) to (1,c3) replaces existing record
Container containerToUpdate = new ContainerBuilder((short) 1, "c3", ContainerStatus.ACTIVE, "c3", (short) 1).build();
accountToUpdate = new AccountBuilder(accountToUpdate).addOrUpdateContainer(containerToUpdate).build();
mySqlAccountService.updateAccounts(Collections.singletonList(accountToUpdate));
assertEquals("Mismatch in container information", containerToUpdate, mySqlAccountService.getAccountById((short) 1).getContainerById((short) 1));
// case B: Verify addition of new container (3,c3) conflicts in name with existing container (1,c3)
containerToUpdate = new ContainerBuilder((short) 3, "c3", ContainerStatus.ACTIVE, "c3", (short) 1).build();
accountToUpdate = new AccountBuilder(accountToUpdate).containers(Collections.singletonList(containerToUpdate)).build();
assertUpdateAccountsFails(Collections.singletonList(accountToUpdate), AccountServiceErrorCode.ResourceConflict, mySqlAccountService);
accountToUpdate = new AccountBuilder(accountToUpdate).removeContainer(containerToUpdate).build();
assertEquals("UpdateAccountErrorCount in metrics should be 1", 1, accountServiceMetrics.updateAccountErrorCount.getCount());
// case C: Verify addition of new container (3,c4) is successful
containerToUpdate = new ContainerBuilder((short) 3, "c4", ContainerStatus.ACTIVE, "c4", (short) 1).build();
accountToUpdate = new AccountBuilder(accountToUpdate).addOrUpdateContainer(containerToUpdate).build();
mySqlAccountService.updateAccounts(Collections.singletonList(accountToUpdate));
assertEquals("Mismatch in container information", containerToUpdate, mySqlAccountService.getAccountById((short) 1).getContainerById((short) 3));
// case D: Verify updating name of container (3,c4) to c2 conflicts in name with existing container (2,c2)
containerToUpdate = new ContainerBuilder(mySqlAccountService.getAccountById((short) 1).getContainerById((short) 3)).setName("c2").build();
accountToUpdate = new AccountBuilder(accountToUpdate).addOrUpdateContainer(containerToUpdate).build();
assertUpdateAccountsFails(Collections.singletonList(accountToUpdate), AccountServiceErrorCode.ResourceConflict, mySqlAccountService);
assertEquals("UpdateAccountErrorCount in metrics should be 2", 2, accountServiceMetrics.updateAccountErrorCount.getCount());
}
use of com.github.ambry.account.Container in project ambry by linkedin.
the class MySqlAccountServiceIntegrationTest method testContainerFetchOnDemand.
/**
* Container on-demand fetch for multiple account services.
*/
@Test
public void testContainerFetchOnDemand() throws Exception {
MySqlAccountService producerAccountService = mySqlAccountService;
// Create second account service with scheduled polling disabled
mySqlConfigProps.setProperty(UPDATER_POLLING_INTERVAL_SECONDS, "0");
accountServiceConfig = new MySqlAccountServiceConfig(new VerifiableProperties(mySqlConfigProps));
MySqlAccountStore consumerAccountStore = spy(new MySqlAccountStoreFactory(new VerifiableProperties(mySqlConfigProps), new MetricRegistry()).getMySqlAccountStore());
MySqlAccountStoreFactory mockMySqlAccountStoreFactory = mock(MySqlAccountStoreFactory.class);
when(mockMySqlAccountStoreFactory.getMySqlAccountStore()).thenReturn(consumerAccountStore);
AccountServiceMetrics accountServiceMetrics = new AccountServiceMetrics(new MetricRegistry());
// Note: for these tests, consumer must NOT be notified of changes
MySqlAccountService consumerAccountService = new MySqlAccountService(accountServiceMetrics, accountServiceConfig, mockMySqlAccountStoreFactory, null);
// Add new account "a1" on producer account service
short accountId = 101;
String accountName = "a1";
int onDemandContainerFetchCount = 0;
Container container = new ContainerBuilder((short) 1, "c1", ContainerStatus.ACTIVE, DESCRIPTION, accountId).build();
Account account = new AccountBuilder(accountId, accountName, Account.AccountStatus.ACTIVE).containers(Collections.singletonList(container)).build();
producerAccountService.updateAccounts(Collections.singletonList(account));
// Test getContainer on consumer account service should fail since account doesn't exist
assertNull("Expected null since Account doesn't exist in consumerAccountService cache", consumerAccountService.getContainerByName(accountName, "c1"));
assertNull("Expected null since Account doesn't exist in consumerAccountService cache", consumerAccountService.getContainerById(accountId, (short) 1));
// Fetch and update cache in consumer account service
consumerAccountService.fetchAndUpdateCache();
assertEquals("Account mismatch", account, consumerAccountService.getAccountByName(accountName));
assertEquals("Container mismatch", container, consumerAccountService.getContainerByName(accountName, "c1"));
assertEquals("Container mismatch", container, consumerAccountService.getContainerById(accountId, (short) 1));
// Add new container in producer account service
producerAccountService.updateContainers(accountName, Collections.singletonList(new ContainerBuilder((short) -1, "c2", ContainerStatus.ACTIVE, DESCRIPTION, accountId).build()));
Container newContainer = producerAccountService.getContainerByName(accountName, "c2");
// Test getContainerByName() on consumer account service is successful (by fetching from mysql on demand)
assertEquals("getContainerByName() expected to fetch container from MySql db", newContainer, consumerAccountService.getContainerByName(accountName, "c2"));
verify(consumerAccountStore).getContainerByName(eq((int) accountId), eq(newContainer.getName()));
assertEquals("Number of on-demand container requests should be 1", ++onDemandContainerFetchCount, accountServiceMetrics.onDemandContainerFetchCount.getCount());
// verify in-memory cache is updated with the fetched container "c2"
assertEquals("Container c2 should be present in consumer account service", newContainer, consumerAccountService.getAccountByName(accountName).getContainerByName(newContainer.getName()));
// Add new container in producer account service
producerAccountService.updateContainers(accountName, Collections.singletonList(new ContainerBuilder((short) -1, "c3", ContainerStatus.ACTIVE, DESCRIPTION, accountId).build()));
newContainer = producerAccountService.getContainerById(accountId, (short) 3);
// Test getContainerById() on consumer account service is successful (by fetching from mysql on demand)
assertEquals("getContainerById() expected to fetch container from MySql db", newContainer, consumerAccountService.getContainerById(accountId, (short) 3));
verify(consumerAccountStore).getContainerById(eq((int) accountId), eq((int) newContainer.getId()));
assertEquals("Number of on-demand container requests should be 2", ++onDemandContainerFetchCount, accountServiceMetrics.onDemandContainerFetchCount.getCount());
// verify in-memory cache is updated with the fetched container "c3"
assertEquals("Container c3 should be present in consumer account service", newContainer, consumerAccountService.getAccountByName(accountName).getContainerById(newContainer.getId()));
}
use of com.github.ambry.account.Container in project ambry by linkedin.
the class HelixAccountServiceTest method testUpdateContainer.
/**
* Test updating an existing container (id specified).
*/
@Test
public void testUpdateContainer() throws Exception {
assumeTrue(!useNewZNodePath);
accountService = mockHelixAccountServiceFactory.getAccountService();
assertEquals("The number of account in HelixAccountService is incorrect", 0, accountService.getAllAccounts().size());
// add an account with single container
accountService.updateAccounts(Collections.singletonList(refAccount));
// 1. Update existing container (success case)
Container modifiedContainer = new ContainerBuilder(refContainer).setDescription("Different than before").build();
Collection<Container> updatedContainers = accountService.updateContainers(refAccountName, Collections.singleton(modifiedContainer));
assertEquals("Mismatch in return count", 1, updatedContainers.size());
assertEquals("Mismatch in container data", modifiedContainer, updatedContainers.iterator().next());
// 2. Update container with invalid name
Container badContainer = new ContainerBuilder(refContainerId, "Unknown container", ContainerStatus.ACTIVE, "foo", refAccountId).build();
try {
accountService.updateContainers(refAccountName, Collections.singleton(badContainer));
fail("should fail because container is not found");
} catch (AccountServiceException e) {
assertEquals("Mismatch in error code", AccountServiceErrorCode.NotFound, e.getErrorCode());
}
// 3. Update container with valid name and wrong id
badContainer = new ContainerBuilder(refContainer).setId((short) (refContainerId + 7)).build();
try {
accountService.updateContainers(refAccountName, Collections.singleton(badContainer));
fail("should fail due to wrong id");
} catch (AccountServiceException e) {
assertEquals("Mismatch in error code", AccountServiceErrorCode.ResourceConflict, e.getErrorCode());
}
}
use of com.github.ambry.account.Container in project ambry by linkedin.
the class AccountDao method getContainerById.
/**
* Gets container by its Id and parent account Id.
* @param accountId the id for the parent account.
* @param containerId the id of the container.
* @return {@link Container} if found in mysql db or {@code null} if it doesn't exist.
* @throws SQLException
*/
public synchronized Container getContainerById(int accountId, int containerId) throws SQLException {
long startTimeMs = System.currentTimeMillis();
ResultSet rs = null;
try {
PreparedStatement getContainerByIdStatement = dataAccessor.getPreparedStatement(getContainerByIdSql, false);
getContainerByIdStatement.setInt(1, accountId);
getContainerByIdStatement.setInt(2, containerId);
rs = getContainerByIdStatement.executeQuery();
List<Container> containers = convertContainersResultSet(rs);
dataAccessor.onSuccess(Read, System.currentTimeMillis() - startTimeMs);
return containers.isEmpty() ? null : containers.get(0);
} catch (SQLException e) {
dataAccessor.onException(e, Read);
throw e;
} finally {
closeQuietly(rs);
}
}
Aggregations