@Override public Account getAccountById(short accountId) { checkOpen(); return accountId == Account.UNKNOWN_ACCOUNT_ID ? UNKNOWN_ACCOUNT : null; }
@Override public Account getAccountById(short id) { checkOpen(); return accountInfoMapRef.get().getAccountById(id); }
/** * Tests updating a {@link Account}, which has the same id and name as an existing record, and will replace the * existing record. This test corresponds to case A specified in the JavaDoc of {@link AccountService}. * @throws Exception Any unexpected exception. */ @Test public void testNonConflictingUpdateCaseA() throws Exception { accountService = mockHelixAccountServiceFactory.getAccountService(); // write two accounts (1, "a") and (2, "b") writeAccountsForConflictTest(); Account accountToUpdate = accountService.getAccountById((short) 1); Collection<Account> nonConflictAccounts = Collections.singleton(new AccountBuilder(accountToUpdate).status(AccountStatus.ACTIVE).build()); updateAccountsAndAssertAccountExistence(nonConflictAccounts, 2, true); }
/** * Assert that a {@link Container} exists in the {@link AccountService}. * @param container The {@link Container} to assert. * @param accountService The {@link AccountService} to assert {@link Container} existence. */ static void assertContainerInAccountService(Container container, AccountService accountService) { Container containerFoundById = accountService.getAccountById(container.getParentAccountId()).getContainerById(container.getId()); Container containerFoundByName = accountService.getAccountById(container.getParentAccountId()).getContainerByName(container.getName()); assertEquals("Container got by id from accountService/account does not match container got by name.", containerFoundById, containerFoundByName); assertEquals("Container got by id from accountService/account does not match the container to assert", containerFoundById, container); }
/** * Tests updating a collection of {@link Account}s, where there are duplicate {@link Account}s in id and name. * @throws Exception Any unexpected exception. */ @Test public void testUpdateDuplicateAccounts() throws Exception { accountService = mockHelixAccountServiceFactory.getAccountService(); List<Account> conflictAccounts = new ArrayList<>(); conflictAccounts.add(new AccountBuilder((short) 1, "a", AccountStatus.INACTIVE).build()); conflictAccounts.add(new AccountBuilder((short) 1, "a", AccountStatus.INACTIVE).build()); assertFalse("Wrong return value from update operation.", accountService.updateAccounts(conflictAccounts)); }
/** * Tests updating a {@link Account}, which has a new id and name different from any of the existing record. The * new record will replace the existing record. This test corresponds to case C specified in the JavaDoc of * {@link AccountService}. * @throws Exception Any unexpected exception. */ @Test public void testNonConflictingUpdateCaseC() throws Exception { accountService = mockHelixAccountServiceFactory.getAccountService(); // write two accounts (1, "a") and (2, "b") writeAccountsForConflictTest(); Collection<Account> nonConflictAccounts = Collections.singleton((new AccountBuilder((short) 3, "c", AccountStatus.ACTIVE).build())); updateAccountsAndAssertAccountExistence(nonConflictAccounts, 3, true); }
/** * Pre-populates two {@link Account}s: (id=1, name="a") and (id=2, name="b") in * {@link org.apache.helix.store.HelixPropertyStore}. * @throws Exception Any unexpected exception. */ private void writeAccountsForConflictTest() throws Exception { List<Account> existingAccounts = new ArrayList<>(); existingAccounts.add(new AccountBuilder((short) 1, "a", AccountStatus.INACTIVE).build()); existingAccounts.add(new AccountBuilder((short) 2, "b", AccountStatus.INACTIVE).build()); updateAccountsAndAssertAccountExistence(existingAccounts, 2, true); }
/** * Tests receiving a bad message, it will not be recognized by {@link HelixAccountService}, but will also not * crash the service. * @throws Exception Any unexpected exception. */ @Test public void receiveBadMessage() throws Exception { accountService = mockHelixAccountServiceFactory.getAccountService(); updateAccountsAndAssertAccountExistence(idToRefAccountMap.values(), NUM_REF_ACCOUNT, true); notifier.publish(ACCOUNT_METADATA_CHANGE_TOPIC, "badMessage"); assertEquals("The number of account in HelixAccountService is different from expected", NUM_REF_ACCOUNT, accountService.getAllAccounts().size()); }
/** * PrePopulates a collection of self-conflicting {@link Account}s, which will impact {@link HelixAccountService} * startup and update. * @param accounts The self-conflicting {@link Account}s. */ private void readAndUpdateBadRecord(Collection<Account> accounts) throws Exception { writeAccountsToHelixPropertyStore(accounts, false); accountService = mockHelixAccountServiceFactory.getAccountService(); assertEquals("Wrong number of accounts in helixAccountService", 0, accountService.getAllAccounts().size()); updateAccountsAndAssertAccountExistence(Collections.singletonList(refAccount), 0, false); writeAccountsToHelixPropertyStore(accounts, true); assertEquals("Number of account is wrong.", 0, accountService.getAllAccounts().size()); }
/** * Tests starting up a {@link HelixAccountService}, when the corresponding {@code ZooKeeper} has account metadata * already stored on it. * @throws Exception Any unexpected exception. */ @Test public void testStartUpWithMetadataExists() throws Exception { // pre-populate account metadata in ZK. writeAccountsToHelixPropertyStore(idToRefAccountMap.values(), false); // When start, the helixAccountService should get the account metadata. accountService = mockHelixAccountServiceFactory.getAccountService(); assertAccountsInAccountService(idToRefAccountMap.values(), NUM_REF_ACCOUNT, accountService); }
@Override public AccountService getAccountService() { try { ScheduledExecutorService scheduler = accountServiceConfig.updaterPollingIntervalMs > 0 ? Utils.newScheduler(1, updaterThreadPrefix, false) : null; return new HelixAccountService(getHelixStore(accountServiceConfig.zkClientConnectString, storeConfig), accountServiceMetrics, notifier, scheduler, accountServiceConfig); } catch (Exception e) { throw new IllegalStateException("Could not instantiate HelixAccountService", e); } }
/** * Assert a collection of {@link Account}s exist in the {@link AccountService}. * @param accounts The collection of {@link Account}s to assert their existence. * @param expectedAccountCount The expected number of {@link Account}s in the {@link AccountService}. * @param accountService The {@link AccountService} to assert {@link Account}s existence. */ static void assertAccountsInAccountService(Collection<Account> accounts, int expectedAccountCount, AccountService accountService) { assertEquals("Wrong number of accounts in accountService", expectedAccountCount, accountService.getAllAccounts().size()); for (Account account : accounts) { assertAccountInAccountService(account, accountService); } }
/** * Tests reading {@link ZNRecord} from {@link HelixPropertyStore}, where the {@link ZNRecord} is empty. This is a * good {@link ZNRecord} format that should NOT fail fetch or update. * @throws Exception Any unexpected exception. */ @Test public void testReadBadZNRecordCase1() throws Exception { ZNRecord zNRecord = makeZNRecordWithSimpleField(null, null, null); updateAndWriteZNRecord(zNRecord, true); }
/** * Writes a {@link ZNRecord} to {@link org.apache.helix.store.HelixPropertyStore}. * @param zNRecord The {@link ZNRecord} to write. * @throws Exception Any unexpected exception. */ private void writeZNRecordToHelixPropertyStore(ZNRecord zNRecord, boolean shouldNotify) throws Exception { HelixStoreOperator storeOperator = new HelixStoreOperator(mockHelixAccountServiceFactory.getHelixStore(ZK_CONNECT_STRING, storeConfig)); storeOperator.write(HelixAccountService.FULL_ACCOUNT_METADATA_PATH, zNRecord); if (shouldNotify) { notifier.publish(ACCOUNT_METADATA_CHANGE_TOPIC, FULL_ACCOUNT_METADATA_CHANGE_MESSAGE); } }
/** * Tests updating a {@link Account}, which has the same id as an existing record and a non-conflicting name with any * of the existing record. The new record will replace the existing record. This test corresponds to case B specified * in the JavaDoc of {@link AccountService}. * @throws Exception Any unexpected exception. */ @Test public void testNonConflictingUpdateCaseB() throws Exception { accountService = mockHelixAccountServiceFactory.getAccountService(); // write two accounts (1, "a") and (2, "b") writeAccountsForConflictTest(); Account accountToUpdate = accountService.getAccountById((short) 1); Collection<Account> nonConflictAccounts = Collections.singleton((new AccountBuilder(accountToUpdate).status(AccountStatus.ACTIVE).build())); updateAccountsAndAssertAccountExistence(nonConflictAccounts, 2, true); }
/** * Tests updating a collection of {@link Account}s, where the {@link Account}s are conflicting among themselves * in id. * @throws Exception Any unexpected exception. */ @Test public void testUpdateIdConflictingAccounts() throws Exception { accountService = mockHelixAccountServiceFactory.getAccountService(); List<Account> conflictAccounts = new ArrayList<>(); conflictAccounts.add(new AccountBuilder((short) 1, "a", AccountStatus.INACTIVE).build()); conflictAccounts.add(new AccountBuilder((short) 1, "b", AccountStatus.INACTIVE).build()); assertFalse("Wrong return value from update operation.", accountService.updateAccounts(conflictAccounts)); }
/** * Tests receiving a bad topic, it will not be recognized by {@link HelixAccountService}, but will also not * crash the service. * @throws Exception Any unexpected exception. */ @Test public void receiveBadTopic() throws Exception { accountService = mockHelixAccountServiceFactory.getAccountService(); updateAccountsAndAssertAccountExistence(idToRefAccountMap.values(), NUM_REF_ACCOUNT, true); notifier.publish("badTopic", FULL_ACCOUNT_METADATA_CHANGE_MESSAGE); assertEquals("The number of account in HelixAccountService is different from expected", NUM_REF_ACCOUNT, accountService.getAllAccounts().size()); }
@Override public Collection<Account> getAllAccounts() { checkOpen(); return accounts; }
@Override public boolean updateAccounts(Collection<Account> accounts) { checkOpen(); Objects.requireNonNull(accounts, "accounts cannot be null"); return false; }
@Override public boolean addAccountUpdateConsumer(Consumer<Collection<Account>> accountUpdateConsumer) { checkOpen(); Objects.requireNonNull(accountUpdateConsumer, "accountUpdateConsumer to subscribe cannot be null"); return true; }