Search in sources :

Example 31 with ZNRecord

use of org.apache.helix.zookeeper.datamodel.ZNRecord in project ambry by linkedin.

the class HelixAccountServiceTest method testReadBadZNRecordCase5.

/**
 * Tests reading {@link ZNRecord} from {@link HelixPropertyStore}, where the {@link ZNRecord} has a map field
 * ({@link LegacyMetadataStore#ACCOUNT_METADATA_MAP_KEY}: accountMap), and accountMap contains
 * ("accountId": badAccountJsonString). This is a NOT good {@link ZNRecord} format that should fail fetch or update.
 * @throws Exception Any unexpected exception.
 */
@Test
public void testReadBadZNRecordCase5() throws Exception {
    Map<String, String> mapValue = new HashMap<>();
    mapValue.put(String.valueOf(refAccount.getId()), BAD_ACCOUNT_METADATA_STRING);
    ZNRecord zNRecord = null;
    if (useNewZNodePath) {
        String blobID = RouterStore.writeAccountMapToRouter(mapValue, mockRouter);
        List<String> list = Collections.singletonList(new RouterStore.BlobIDAndVersion(blobID, 1).toJson());
        zNRecord = makeZNRecordWithListField(null, RouterStore.ACCOUNT_METADATA_BLOB_IDS_LIST_KEY, list);
    } else {
        zNRecord = makeZNRecordWithMapField(null, LegacyMetadataStore.ACCOUNT_METADATA_MAP_KEY, mapValue);
    }
    updateAndWriteZNRecord(zNRecord, false);
}
Also used : HashMap(java.util.HashMap) ZNRecord(org.apache.helix.zookeeper.datamodel.ZNRecord) Test(org.junit.Test)

Example 32 with ZNRecord

use of org.apache.helix.zookeeper.datamodel.ZNRecord in project ambry by linkedin.

the class HelixAccountServiceTest method testAddContainer.

/**
 * Test adding container to an existing account.
 */
@Test
public void testAddContainer() throws Exception {
    assumeTrue(!useNewZNodePath);
    accountService = mockHelixAccountServiceFactory.getAccountService();
    assertEquals("The number of account in HelixAccountService is incorrect", 0, accountService.getAllAccounts().size());
    // create three containers for testing
    Container activeContainer = new ContainerBuilder((short) (refContainer.getId() + 1), "active", Container.ContainerStatus.ACTIVE, "", refAccount.getId()).build();
    Container inactiveContainer = new ContainerBuilder((short) (refContainer.getId() + 2), "inactive", Container.ContainerStatus.INACTIVE, "", refAccount.getId()).build();
    Container deleteInProgressContainer1 = new ContainerBuilder((short) (refContainer.getId() + 3), "within-retention-period", ContainerStatus.DELETE_IN_PROGRESS, "", refAccount.getId()).setDeleteTriggerTime(System.currentTimeMillis()).build();
    Container deleteInProgressContainer2 = new ContainerBuilder((short) (refContainer.getId() + 4), "past-retention-period", ContainerStatus.DELETE_IN_PROGRESS, "", refAccount.getId()).setDeleteTriggerTime(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(15)).build();
    refAccount.updateContainerMap(Arrays.asList(activeContainer, inactiveContainer, deleteInProgressContainer1, deleteInProgressContainer2));
    // add an account with single container
    accountService.updateAccounts(Collections.singletonList(refAccount));
    Container brandNewContainer = new ContainerBuilder(activeContainer).setId(UNKNOWN_CONTAINER_ID).build();
    // 1. test invalid input
    try {
        accountService.updateContainers("", null);
        fail("should fail because input is invalid");
    } catch (AccountServiceException e) {
        assertEquals("Mismatch in error code", AccountServiceErrorCode.BadRequest, e.getErrorCode());
    }
    // 2. test account is not found
    String fakeAccountName = refAccountName + "fake";
    Container containerToAdd1 = new ContainerBuilder(UNKNOWN_CONTAINER_ID, "newContainer", ContainerStatus.ACTIVE, "description", refParentAccountId).build();
    try {
        accountService.updateContainers(fakeAccountName, Collections.singleton(containerToAdd1));
        fail("should fail because account is not found");
    } catch (AccountServiceException e) {
        assertEquals("Mismatch in error code", AccountServiceErrorCode.NotFound, e.getErrorCode());
    }
    // 3. test containers already exist with INACTIVE and DELETE_IN_PROGRESS state
    Container duplicateInactiveContainer = new ContainerBuilder(inactiveContainer).setId(UNKNOWN_CONTAINER_ID).build();
    Container duplicateDeleteInProgressContainer1 = new ContainerBuilder(deleteInProgressContainer1).setId(UNKNOWN_CONTAINER_ID).build();
    Container duplicateDeleteInProgressContainer2 = new ContainerBuilder(deleteInProgressContainer2).setId(UNKNOWN_CONTAINER_ID).build();
    try {
        accountService.updateContainers(refAccountName, Collections.singleton(duplicateInactiveContainer));
        fail("Should fail because the existing container has been marked INACTIVE.");
    } catch (AccountServiceException ase) {
        assertEquals("Mismatch in error code", AccountServiceErrorCode.ResourceHasGone, ase.getErrorCode());
    }
    try {
        accountService.updateContainers(refAccountName, Collections.singleton(duplicateDeleteInProgressContainer1));
        fail("Should fail because the existing container has been marked DELETE_IN_PROGRESS.");
    } catch (AccountServiceException ase) {
        assertEquals("Mismatch in error code", AccountServiceErrorCode.MethodNotAllowed, ase.getErrorCode());
    }
    try {
        accountService.updateContainers(refAccountName, Collections.singleton(duplicateDeleteInProgressContainer2));
        fail("Should fail because the existing container has been marked DELETE_IN_PROGRESS and past retention time");
    } catch (AccountServiceException ase) {
        assertEquals("Mismatch in error code", AccountServiceErrorCode.ResourceHasGone, ase.getErrorCode());
    }
    // 4. test conflict container (new container with existing name but different attributes)
    Container conflictContainer = new ContainerBuilder(brandNewContainer).setBackupEnabled(true).build();
    try {
        accountService.updateContainers(refAccountName, Collections.singleton(conflictContainer));
        fail("should fail because there is a conflicting container");
    } catch (AccountServiceException e) {
        assertEquals("Mismatch in error code", AccountServiceErrorCode.ResourceConflict, e.getErrorCode());
    }
    // 5. test adding same container twice, should be no-op and return result should include container with id
    Collection<Container> addedContainers = accountService.updateContainers(refAccountName, Collections.singleton(brandNewContainer));
    assertEquals("Mismatch in return count", 1, addedContainers.size());
    for (Container container : addedContainers) {
        assertEquals("Mismatch in account id", refAccountId, container.getParentAccountId());
        assertEquals("Mismatch in container id", activeContainer.getId(), container.getId());
        assertEquals("Mismatch in container name", activeContainer.getName(), container.getName());
    }
    // 6. test adding a different container (failure case due to ZK update failure)
    MockHelixPropertyStore<ZNRecord> mockHelixStore = mockHelixAccountServiceFactory.getHelixStore(ZK_CONNECT_STRING, storeConfig);
    mockHelixStore.setExceptionDuringUpdater(true);
    try {
        accountService.updateContainers(refAccountName, Collections.singleton(containerToAdd1));
        fail("should fail because exception occurs when updating ZK");
    } catch (AccountServiceException e) {
        assertEquals("Mismatch in error code", AccountServiceErrorCode.InternalError, e.getErrorCode());
    }
    mockHelixStore.setExceptionDuringUpdater(false);
    // 7. test adding 2 different containers (success case)
    Container containerToAdd2 = new ContainerBuilder(UNKNOWN_CONTAINER_ID, "newContainer2", ContainerStatus.ACTIVE, "description", refParentAccountId).build();
    addedContainers = accountService.updateContainers(refAccountName, Arrays.asList(containerToAdd1, containerToAdd2));
    for (Container container : addedContainers) {
        assertEquals("Mismatch in account id", refAccountId, container.getParentAccountId());
    }
}
Also used : Container(com.github.ambry.account.Container) ZNRecord(org.apache.helix.zookeeper.datamodel.ZNRecord) Test(org.junit.Test)

Example 33 with ZNRecord

use of org.apache.helix.zookeeper.datamodel.ZNRecord in project ambry by linkedin.

the class HelixAccountServiceTest method testReadBadZNRecordCase6.

/**
 * Tests reading {@link ZNRecord} from {@link HelixPropertyStore}, where the {@link ZNRecord} has an invalid account
 * record and a valid account record. This is a NOT good {@link ZNRecord} format and it should fail fetch or update
 * operations, with none of the record should be read.
 * @throws Exception Any unexpected exception.
 */
@Test
public void testReadBadZNRecordCase6() throws Exception {
    ZNRecord zNRecord = new ZNRecord(String.valueOf(System.currentTimeMillis()));
    Map<String, String> accountMap = new HashMap<>();
    accountMap.put(String.valueOf(refAccount.getId()), objectMapper.writeValueAsString(new AccountBuilder(refAccount).snapshotVersion(refAccount.getSnapshotVersion() + 1).build()));
    accountMap.put(String.valueOf(refAccount.getId() + 1), BAD_ACCOUNT_METADATA_STRING);
    if (useNewZNodePath) {
        String blobID = RouterStore.writeAccountMapToRouter(accountMap, mockRouter);
        List<String> list = Collections.singletonList(new RouterStore.BlobIDAndVersion(blobID, 1).toJson());
        zNRecord.setListField(RouterStore.ACCOUNT_METADATA_BLOB_IDS_LIST_KEY, list);
    } else {
        zNRecord.setMapField(LegacyMetadataStore.ACCOUNT_METADATA_MAP_KEY, accountMap);
    }
    updateAndWriteZNRecord(zNRecord, false);
}
Also used : HashMap(java.util.HashMap) ZNRecord(org.apache.helix.zookeeper.datamodel.ZNRecord) Test(org.junit.Test)

Example 34 with ZNRecord

use of org.apache.helix.zookeeper.datamodel.ZNRecord in project ambry by linkedin.

the class HelixHealthReportAggregationTaskTest method testAggregationTask.

/**
 * Test {@link HelixHealthReportAggregatorTask#run()} method.
 * @throws Exception
 */
@Test
public void testAggregationTask() throws Exception {
    int port = 10000;
    int numNode = 3;
    for (StatsReportType type : StatsReportType.values()) {
        initializeNodeReports(type, numNode, port);
        String healthReportName = type == StatsReportType.ACCOUNT_REPORT ? HEALTH_REPORT_NAME_ACCOUNT : HEALTH_REPORT_NAME_PARTITION;
        String statsFieldName = type == StatsReportType.ACCOUNT_REPORT ? STATS_FIELD_NAME_ACCOUNT : STATS_FIELD_NAME_PARTITION;
        task = new HelixHealthReportAggregatorTask(mockHelixManager, RELEVANT_PERIOD_IN_MINUTES, healthReportName, statsFieldName, type, null, clusterMapConfig, mockTime);
        task.run();
        // Verify the targeted znode has value, don't worry about the correctness of the value, it's verified by other tests.
        Stat stat = new Stat();
        ZNRecord record = mockHelixManager.getHelixPropertyStore().get(String.format("/%s%s", HelixHealthReportAggregatorTask.AGGREGATED_REPORT_PREFIX, healthReportName), stat, AccessOption.PERSISTENT);
        Assert.assertNotNull(record);
        Assert.assertNotNull(record.getSimpleField(HelixHealthReportAggregatorTask.VALID_SIZE_FIELD_NAME));
        Assert.assertNotNull(record.getSimpleField(HelixHealthReportAggregatorTask.RAW_VALID_SIZE_FIELD_NAME));
    }
}
Also used : Stat(org.apache.zookeeper.data.Stat) StatsReportType(com.github.ambry.server.StatsReportType) ZNRecord(org.apache.helix.zookeeper.datamodel.ZNRecord) Test(org.junit.Test)

Example 35 with ZNRecord

use of org.apache.helix.zookeeper.datamodel.ZNRecord in project ambry by linkedin.

the class HelixBootstrapUpgradeToolTest method testGeneratePartitionOverrideMapFromStaticFile.

/**
 * Test that bootstrap tool is able to generate partition override map from static file (if adminConfigFilePath is not
 * null). It tests both success and failure cases.
 * @throws Exception
 */
@Test
public void testGeneratePartitionOverrideMapFromStaticFile() throws Exception {
    List<PartitionId> writablePartitions = new ArrayList<>(testPartitionLayout.getPartitionLayout().getWritablePartitions(null));
    int partitionCount = testPartitionLayout.getPartitionCount();
    Utils.writeJsonObjectToFile(zkJson, zkLayoutPath);
    Utils.writeJsonObjectToFile(testHardwareLayout.getHardwareLayout().toJSONObject(), hardwareLayoutPath);
    Utils.writeJsonObjectToFile(testPartitionLayout.getPartitionLayout().toJSONObject(), partitionLayoutPath);
    Utils.writeStringToFile(String.valueOf(partitionCount + 1), adminConfigFilePath);
    // failure case 1: partition id is out of valid range
    try {
        HelixBootstrapUpgradeUtil.uploadOrDeleteAdminConfigs(hardwareLayoutPath, partitionLayoutPath, zkLayoutPath, CLUSTER_NAME_PREFIX, dcStr, false, new String[] { ClusterMapUtils.PARTITION_OVERRIDE_STR }, adminConfigFilePath);
        fail("should fail because input partition id is out of valid range");
    } catch (IllegalArgumentException e) {
    // expected
    }
    // failure case 2: partition id is non-numeric
    Utils.writeStringToFile("non-numeric", adminConfigFilePath);
    try {
        HelixBootstrapUpgradeUtil.uploadOrDeleteAdminConfigs(hardwareLayoutPath, partitionLayoutPath, zkLayoutPath, CLUSTER_NAME_PREFIX, dcStr, false, new String[] { ClusterMapUtils.PARTITION_OVERRIDE_STR }, adminConfigFilePath);
        fail("should fail because input partition id is not numeric");
    } catch (NumberFormatException e) {
    // expected
    }
    // success case: mark 1/10 partitions as RO
    Collections.shuffle(writablePartitions);
    int readOnlyCount = writablePartitions.size() / 10;
    StringBuilder sb = new StringBuilder();
    Set<String> readOnlyInFile = new HashSet<>();
    for (int i = 0; i < readOnlyCount; ++i) {
        sb.append(writablePartitions.get(i).toPathString()).append(",");
        readOnlyInFile.add(writablePartitions.get(i).toPathString());
    }
    Utils.writeStringToFile(sb.toString(), adminConfigFilePath);
    HelixBootstrapUpgradeUtil.uploadOrDeleteAdminConfigs(hardwareLayoutPath, partitionLayoutPath, zkLayoutPath, CLUSTER_NAME_PREFIX, dcStr, false, new String[] { ClusterMapUtils.PARTITION_OVERRIDE_STR }, adminConfigFilePath);
    // verify overridden partitions in Helix
    for (ZkInfo zkInfo : dcsToZkInfo.values()) {
        HelixPropertyStore<ZNRecord> propertyStore = CommonUtils.createHelixPropertyStore("localhost:" + zkInfo.getPort(), propertyStoreConfig, Collections.singletonList(propertyStoreConfig.rootPath));
        ZNRecord zNRecord = propertyStore.get(ClusterMapUtils.PARTITION_OVERRIDE_ZNODE_PATH, null, AccessOption.PERSISTENT);
        if (!activeDcSet.contains(zkInfo.getDcName())) {
            assertNull(zNRecord);
        } else {
            assertNotNull(zNRecord);
            Map<String, Map<String, String>> overridePartition = zNRecord.getMapFields();
            Set<String> readOnlyInDc = new HashSet<>();
            for (Map.Entry<String, Map<String, String>> entry : overridePartition.entrySet()) {
                if (entry.getValue().get(ClusterMapUtils.PARTITION_STATE).equals(ClusterMapUtils.READ_ONLY_STR)) {
                    readOnlyInDc.add(entry.getKey());
                }
            }
            // Verify ReadOnly partitions in DC match that in static file
            assertEquals("Mismatch in ReadOnly partitions for static file and propertyStore", readOnlyInFile, readOnlyInDc);
        }
    }
}
Also used : ArrayList(java.util.ArrayList) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ZNRecord(org.apache.helix.zookeeper.datamodel.ZNRecord) HashSet(java.util.HashSet) Test(org.junit.Test)

Aggregations

ZNRecord (org.apache.helix.zookeeper.datamodel.ZNRecord)37 HashMap (java.util.HashMap)19 Test (org.junit.Test)18 Map (java.util.Map)10 ArrayList (java.util.ArrayList)8 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)8 VerifiableProperties (com.github.ambry.config.VerifiableProperties)6 HashSet (java.util.HashSet)6 InstanceConfig (org.apache.helix.model.InstanceConfig)6 MetricRegistry (com.codahale.metrics.MetricRegistry)5 Properties (java.util.Properties)5 Stat (org.apache.zookeeper.data.Stat)5 ClusterMapConfig (com.github.ambry.config.ClusterMapConfig)4 HelixPropertyStoreConfig (com.github.ambry.config.HelixPropertyStoreConfig)4 IOException (java.io.IOException)4 JSONObject (org.json.JSONObject)4 List (java.util.List)3 Random (java.util.Random)3 PropertyKey (org.apache.helix.PropertyKey)3 IdealState (org.apache.helix.model.IdealState)3