/** * Tests creating a number of new {@link Account} through {@link HelixAccountService}, where there is no {@link ZNRecord} * exists on the {@code ZooKeeper}. */ @Test public void testCreateAccount() { accountService = mockHelixAccountServiceFactory.getAccountService(); assertEquals("The number of account in HelixAccountService is incorrect", 0, accountService.getAllAccounts().size()); boolean res = accountService.updateAccounts(idToRefAccountMap.values()); assertTrue("Failed to update accounts", res); assertAccountsInAccountService(idToRefAccountMap.values(), NUM_REF_ACCOUNT, accountService); }
/** * Updates a collection of {@link Account}s through {@link HelixAccountService}, and verifies that the * {@link Account}s have been successfully updated, so they can be queried through {@link HelixAccountService}. * @param accounts A collection of {@link Account}s to update through {@link HelixAccountService}. */ private void updateAccountsAndAssertAccountExistence(Collection<Account> accounts, int expectedAccountCount, boolean shouldUpdateSucceed) throws Exception { Collection<Account> expectedOldState = accountService.getAllAccounts(); boolean hasUpdateAccountSucceed = accountService.updateAccounts(accounts); assertEquals("Wrong update return status", shouldUpdateSucceed, hasUpdateAccountSucceed); if (shouldUpdateSucceed) { assertAccountsInAccountService(accounts, expectedAccountCount, accountService); if (helixConfigProps.containsKey(HelixAccountServiceConfig.BACKUP_DIRECTORY_KEY)) { Path oldStateBackup = Files.list(accountBackupDir) .filter(path -> path.getFileName().toString().endsWith(OLD_STATE_SUFFIX)) .max(Comparator.naturalOrder()) .get(); checkBackupFile(expectedOldState, oldStateBackup); String newStateFilename = oldStateBackup.getFileName().toString().replace(OLD_STATE_SUFFIX, NEW_STATE_SUFFIX); Path newStateBackup = oldStateBackup.getParent().resolve(newStateFilename); checkBackupFile(accountService.getAllAccounts(), newStateBackup); } else { assertEquals("No backup files should exist.", 0, Files.list(accountBackupDir).count()); } } else { assertEquals("Wrong number of accounts in accountService", expectedAccountCount, accountService.getAllAccounts().size()); } }
/** * 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 collection of {@link Account}s, where the {@link Account}s are conflicting among themselves * in name. * @throws Exception Any unexpected exception. */ @Test public void testUpdateNameConflictingAccounts() 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) 2, "a", AccountStatus.INACTIVE).build()); assertFalse("Wrong return value from update operation.", accountService.updateAccounts(conflictAccounts)); }
/** * 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 adding/removing {@link Consumer}. */ @Test public void testAddRemoveConsumer() { List<Collection<Account>> updatedAccountsReceivedByConsumers = new ArrayList<>(); // add consumers Consumer<Collection<Account>> accountUpdateConsumer = updatedAccounts -> { updatedAccountsReceivedByConsumers.add(updatedAccounts); }; accountService.addAccountUpdateConsumer(accountUpdateConsumer); Account updatedAccount = new AccountBuilder(InMemoryUnknownAccountService.UNKNOWN_ACCOUNT).name("newName").build(); accountService.updateAccounts(Collections.singletonList(updatedAccount)); assertEquals("Wrong number of updated accounts received by consumer.", 0, updatedAccountsReceivedByConsumers.size()); Account newAccount = new AccountBuilder((short) 1, "newAccount", Account.AccountStatus.ACTIVE).build(); accountService.updateAccounts(Collections.singletonList(newAccount)); assertEquals("Wrong number of updated accounts received by consumer.", 0, updatedAccountsReceivedByConsumers.size()); accountService.removeAccountUpdateConsumer(accountUpdateConsumer); } }
/** * Tests {@code null} inputs. */ @Test public void testNullInputs() { try { accountService.updateAccounts(null); fail("should have thrown"); } catch (NullPointerException e) { // expected } try { accountService.getAccountByName(null); fail("should have thrown"); } catch (NullPointerException e) { // expected } }
/** * Tests updating a {@link Account}, which has a new id but a name conflicting with an existing record. The update * operation will fail. This test corresponds to case D specified in the JavaDoc of {@link AccountService}. * @throws Exception Any unexpected exception. */ @Test public void testConflictingUpdateCaseD() throws Exception { accountService = mockHelixAccountServiceFactory.getAccountService(); // write two accounts (1, "a") and (2, "b") writeAccountsForConflictTest(); Collection<Account> conflictAccounts = Collections.singleton((new AccountBuilder((short) 3, "a", AccountStatus.INACTIVE).build())); assertFalse("Wrong return value from update operation.", accountService.updateAccounts(conflictAccounts)); assertEquals("Wrong account number in HelixAccountService", 2, accountService.getAllAccounts().size()); assertNull("Wrong account got from HelixAccountService", accountService.getAccountById((short) 3)); }
/** * Tests updating a {@link Account}, which has the same id as an existing record, but the name conflicting with * another existing record. The update operation will fail. This test corresponds to case E specified in the JavaDoc * of {@link AccountService}. * @throws Exception Any unexpected exception. */ @Test public void testConflictingUpdateCaseE() throws Exception { accountService = mockHelixAccountServiceFactory.getAccountService(); // write two accounts (1, "a") and (2, "b") writeAccountsForConflictTest(); Collection<Account> conflictAccounts = Collections.singleton((new AccountBuilder((short) 1, "b", AccountStatus.INACTIVE).build())); assertFalse("Wrong return value from update operation.", accountService.updateAccounts(conflictAccounts)); assertEquals("Wrong account number in HelixAccountService", 2, accountService.getAllAccounts().size()); assertEquals("Wrong account name got from HelixAccountService", "a", accountService.getAccountById((short) 1).getName()); }
/** * Tests a series of operations. * 1. PrePopulates account (1, "a"); * 2. Starts up a {@link HelixAccountService}; * 3. Remote copy adds a new account (2, "b"), and the update has not been propagated to the {@link HelixAccountService}; * 4. The {@link HelixAccountService} attempts to update an account (3, "b"), which should fail because it will eventually * conflict with the remote copy; * @throws Exception Any unexpected exception. */ @Test public void testReadConflictAccountDataFromHelixPropertyStoreCase3() throws Exception { Account account1 = new AccountBuilder((short) 1, "a", AccountStatus.INACTIVE).build(); List<Account> accounts = Collections.singletonList(account1); writeAccountsToHelixPropertyStore(accounts, false); accountService = mockHelixAccountServiceFactory.getAccountService(); assertAccountInAccountService(account1, accountService); Account account2 = new AccountBuilder((short) 2, "b", AccountStatus.INACTIVE).build(); accounts = Collections.singletonList(account2); writeAccountsToHelixPropertyStore(accounts, false); Account conflictingAccount = new AccountBuilder((short) 3, "b", AccountStatus.INACTIVE).build(); accounts = Collections.singletonList(conflictingAccount); assertFalse(accountService.updateAccounts(accounts)); assertEquals("Number of account is wrong.", 1, accountService.getAllAccounts().size()); assertAccountInAccountService(account1, accountService); }
accountService = mockHelixAccountServiceFactory.getAccountService(); try { accountService.updateAccounts(null); fail("should have thrown"); } catch (NullPointerException e) {
@Test public void testAllMethods() throws Exception { assertEquals("Wrong account", null, accountService.getAccountById(Utils.getRandomShort(random))); assertEquals("Wrong account", InMemoryUnknownAccountService.UNKNOWN_ACCOUNT, accountService.getAccountById((short) -1)); assertEquals("Wrong account", InMemoryUnknownAccountService.UNKNOWN_ACCOUNT, accountService.getAccountByName(UtilsTest.getRandomString(10))); assertEquals("Wrong size of account collection", 1, accountService.getAllAccounts().size()); // updating the InMemoryUnknownAccountService should fail. Account account = new AccountBuilder((short) 1, "a", Account.AccountStatus.INACTIVE).build(); assertFalse("Wrong return value from an unsuccessful update operation", accountService.updateAccounts(Collections.singletonList(account))); assertEquals("Wrong size of account collection", 1, accountService.getAllAccounts().size()); try { accountService.getAllAccounts().add(account); fail("Should have thrown."); } catch (UnsupportedOperationException e) { // expected } accountService.close(); }
/** * Test updating an account with a conflicting expected snapshot version. */ @Test public void testConflictingSnapshotVersionUpdate() throws Exception { accountService = mockHelixAccountServiceFactory.getAccountService(); // write two accounts (1, "a") and (2, "b") writeAccountsForConflictTest(); Account expectedAccount = accountService.getAccountById((short) 1); int currentSnapshotVersion = expectedAccount.getSnapshotVersion(); for (int snapshotVersionOffset : new int[]{-2, -1, 1}) { int snapshotVersionToUse = currentSnapshotVersion + snapshotVersionOffset; Collection<Account> conflictAccounts = Collections.singleton( new AccountBuilder((short) 1, "c", AccountStatus.INACTIVE).snapshotVersion(snapshotVersionToUse).build()); assertFalse("Wrong return value from update operation.", accountService.updateAccounts(conflictAccounts)); assertEquals("Wrong account number in HelixAccountService", 2, accountService.getAllAccounts().size()); Account account = accountService.getAccountById((short) 1); assertEquals("Account should not have been updated", expectedAccount, account); assertEquals("Snapshot version should not have been updated", currentSnapshotVersion, account.getSnapshotVersion()); } Collection<Account> validAccounts = Collections.singleton( new AccountBuilder((short) 1, "c", AccountStatus.INACTIVE).snapshotVersion(currentSnapshotVersion).build()); updateAccountsAndAssertAccountExistence(validAccounts, 2, true); }