You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by dm...@apache.org on 2015/12/08 13:45:26 UTC
ambari git commit: AMBARI-14250. Add unit test coverage for
ConfigMergeHelper#getConflicts (dlysnichenko)
Repository: ambari
Updated Branches:
refs/heads/trunk 139764681 -> 4bd35dfba
AMBARI-14250. Add unit test coverage for ConfigMergeHelper#getConflicts (dlysnichenko)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/4bd35dfb
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/4bd35dfb
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/4bd35dfb
Branch: refs/heads/trunk
Commit: 4bd35dfbab90d85965caf03e7808fcd5b6054e27
Parents: 1397646
Author: Lisnichenko Dmitro <dl...@hortonworks.com>
Authored: Tue Dec 8 14:46:03 2015 +0200
Committer: Lisnichenko Dmitro <dl...@hortonworks.com>
Committed: Tue Dec 8 14:46:03 2015 +0200
----------------------------------------------------------------------
.../ambari/server/state/ConfigMergeHelper.java | 34 ++-
.../server/state/ConfigMergeHelperTest.java | 245 +++++++++++++++++++
2 files changed, 272 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/4bd35dfb/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigMergeHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigMergeHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigMergeHelper.java
index 0610137..b799bc7 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigMergeHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/ConfigMergeHelper.java
@@ -55,9 +55,10 @@ public class ConfigMergeHelper {
Cluster cluster = m_clusters.get().getCluster(clusterName);
StackId oldStack = cluster.getCurrentStackVersion();
- Map<String, Map<String, String>> oldMap = new HashMap<String, Map<String, String>>();
- Map<String, Map<String, String>> newMap = new HashMap<String, Map<String, String>>();
+ Map<String, Map<String, String>> oldMap = new HashMap<>();
+ Map<String, Map<String, String>> newMap = new HashMap<>();
+ // Collect service-level properties for old and new stack
for (String serviceName : cluster.getServices().keySet()) {
Set<PropertyInfo> oldStackProperties = m_ambariMetaInfo.get().getServiceProperties(
oldStack.getStackName(), oldStack.getStackVersion(), serviceName);
@@ -68,6 +69,7 @@ public class ConfigMergeHelper {
addToMap(newMap, newStackProperties);
}
+ // Collect stack-level properties defined for old and new stack
Set<PropertyInfo> set = m_ambariMetaInfo.get().getStackProperties(
oldStack.getStackName(), oldStack.getStackVersion());
addToMap(oldMap, set);
@@ -79,6 +81,7 @@ public class ConfigMergeHelper {
Map<String, Map<String, ThreeWayValue>> result =
new HashMap<String, Map<String, ThreeWayValue>>();
+ // For every property of every config type, see if it is going to be merged:
for (Entry<String, Map<String, String>> entry : oldMap.entrySet()) {
if (!newMap.containsKey(entry.getKey())) {
LOG.info("Stack {} does not have an equivalent config type {} in {}",
@@ -91,6 +94,10 @@ public class ConfigMergeHelper {
Collection<String> customValueKeys = null;
Config config = cluster.getDesiredConfigByType(entry.getKey());
+
+ // The conflict occurs, if current property is not defined at stack
+ // metainfo, but is present in current cluster configs,
+ // and a new value is different from current value
if (null != config) {
Set<String> valueKeys = config.getProperties().keySet();
@@ -116,6 +123,13 @@ public class ConfigMergeHelper {
}
}
+ // Also, conflict occurs if all four coditions are met:
+ // a) property is defined both in old and in new stack
+ // b) property value in new stack differs from current
+ // the property value
+ // c) current property value is not the same as in new stack
+ // d) current property value is not the same as in old stack
+
Collection<String> common = CollectionUtils.intersection(newPairs.keySet(),
oldPairs.keySet());
@@ -127,10 +141,7 @@ public class ConfigMergeHelper {
savedVal = config.getProperties().get(prop);
}
- // If values are not defined in stack (null), we skip them
- // Or if values in old stack and in new stack are the same, and value
- // in current config is different, skip it
- if (!(newStackVal == null && oldStackVal == null)
+ if (!(newStackVal == null || oldStackVal == null)
&& !newStackVal.equals(savedVal) &&
(!oldStackVal.equals(newStackVal) || !oldStackVal.equals(savedVal))) {
ThreeWayValue twv = new ThreeWayValue();
@@ -161,6 +172,7 @@ public class ConfigMergeHelper {
}
}
+
/**
* Represents the three different config values for merging.
*/
@@ -179,7 +191,15 @@ public class ConfigMergeHelper {
public String savedValue;
}
- private static String normalizeValue(String templateValue, String newRawValue) {
+ /**
+ * If template looks like Java heap size, then format raw value to comply
+ * with size unit specified in template
+ * @param templateValue
+ * @param newRawValue
+ * @return raw value formatted like template (if template looks like Java
+ * heap size), raw value as is otherwise.
+ */
+ static String normalizeValue(String templateValue, String newRawValue) {
if (null == templateValue) {
return newRawValue;
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/4bd35dfb/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigMergeHelperTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigMergeHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigMergeHelperTest.java
new file mode 100644
index 0000000..ba9eb3c
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/state/ConfigMergeHelperTest.java
@@ -0,0 +1,245 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.state;
+
+import com.google.inject.Binder;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Module;
+import com.google.inject.persist.PersistService;
+import com.google.inject.util.Modules;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.orm.GuiceJpaInitializer;
+import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static org.easymock.EasyMock.anyString;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.junit.Assert.assertEquals;
+import static org.apache.ambari.server.state.ConfigMergeHelper.ThreeWayValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests the {@link ConfigMergeHelper} class
+ */
+public class ConfigMergeHelperTest {
+
+ private static final StackId currentStackId = new StackId("HDP-2.1.1");
+ private static final StackId newStackId = new StackId("HPD-2.2.0");
+
+ private Injector injector;
+ private Clusters clustersMock;
+ private AmbariMetaInfo ambariMetaInfoMock;
+
+ @Before
+ public void before() throws Exception {
+ clustersMock = createNiceMock(Clusters.class);
+ ambariMetaInfoMock = createNiceMock(AmbariMetaInfo.class);
+
+ final InMemoryDefaultTestModule injectorModule = new InMemoryDefaultTestModule() {
+ @Override
+ protected void configure() {
+ super.configure();
+ }
+ };
+
+ MockModule mockModule = new MockModule();
+ // create an injector which will inject the mocks
+ injector = Guice.createInjector(Modules.override(injectorModule).with(mockModule));
+ injector.getInstance(GuiceJpaInitializer.class);
+ }
+
+ @After
+ public void teardown() {
+ injector.getInstance(PersistService.class).stop();
+ }
+
+ @Test
+ public void testGetConflicts() throws Exception {
+ Cluster clusterMock = createNiceMock(Cluster.class);
+
+ expect(clustersMock.getCluster(anyString())).andReturn(clusterMock);
+
+ expect(clusterMock.getCurrentStackVersion()).andReturn(currentStackId);
+ expect(clusterMock.getServices()).andReturn(new HashMap<String, Service>() {{
+ put("HDFS", createNiceMock(Service.class));
+ put("ZK", createNiceMock(Service.class));
+ }});
+
+
+ Set<PropertyInfo> currentHDFSProperties = new HashSet<PropertyInfo>() {{
+ add(createPropertyInfo("hdfs-env.xml", "equal.key", "equal-value"));
+ }};
+
+ Set<PropertyInfo> currentZKProperties = new HashSet<PropertyInfo>() {{
+ add(createPropertyInfo("zk-env.xml", "different.key", "different-value-1"));
+ }};
+
+ Set<PropertyInfo> currentStackProperties = new HashSet<PropertyInfo>() {{
+ add(createPropertyInfo("hadoop-env.xml", "equal.key", "modified.value"));
+ }};
+
+ expect(ambariMetaInfoMock.getServiceProperties(currentStackId.getStackName(),
+ currentStackId.getStackVersion(), "HDFS")).andReturn(currentHDFSProperties);
+ expect(ambariMetaInfoMock.getServiceProperties(currentStackId.getStackName(),
+ currentStackId.getStackVersion(), "ZK")).andReturn(currentZKProperties);
+ expect(ambariMetaInfoMock.getStackProperties(currentStackId.getStackName(),
+ currentStackId.getStackVersion())).andReturn(currentStackProperties);
+
+ Set<PropertyInfo> newHDFSProperties = new HashSet<PropertyInfo>() {{
+ add(createPropertyInfo("hdfs-env.xml", "equal.key", "equal-value"));
+ add(createPropertyInfo("new-hdfs-config.xml", "equal.key", "equal-value"));
+ }};
+
+ Set<PropertyInfo> newZKProperties = new HashSet<PropertyInfo>() {{
+ add(createPropertyInfo("zk-env.xml", "equal.key", "different-value-2"));
+ add(createPropertyInfo("zk-env.xml", "new.key", "new-value-2"));
+ }};
+
+ Set<PropertyInfo> newStackProperties = new HashSet<PropertyInfo>() {{
+ add(createPropertyInfo("hadoop-env.xml", "equal.key", "another.value"));
+ }};
+
+ expect(ambariMetaInfoMock.getServiceProperties(newStackId.getStackName(),
+ newStackId.getStackVersion(), "HDFS")).andReturn(newHDFSProperties);
+ expect(ambariMetaInfoMock.getServiceProperties(newStackId.getStackName(),
+ newStackId.getStackVersion(), "ZK")).andReturn(newZKProperties);
+ expect(ambariMetaInfoMock.getStackProperties(newStackId.getStackName(),
+ newStackId.getStackVersion())).andReturn(newStackProperties);
+
+ // desired config of hdfs-env.xml
+ Map<String, String> desiredHdfsEnvProperties = new HashMap<String, String>() {{
+
+ }};
+ expect(clusterMock.getDesiredConfigByType("hdfs-env.xml")).andReturn(
+ createConfigMock(desiredHdfsEnvProperties)
+ );
+
+ // desired config of zk-env.xml
+ Map<String, String> desiredZkEnvProperties = new HashMap<String, String>() {{
+
+ }};
+ expect(clusterMock.getDesiredConfigByType("hdfs-env.xml")).andReturn(
+ createConfigMock(desiredZkEnvProperties)
+ );
+
+ // desired config of hadoop-env.xml
+ Map<String, String> desiredHadoopEnvProperties = new HashMap<String, String>() {{
+
+ }};
+ expect(clusterMock.getDesiredConfigByType("hadoop-env.xml")).andReturn(
+ createConfigMock(desiredHadoopEnvProperties)
+ );
+
+ replay(clusterMock, clustersMock, ambariMetaInfoMock);
+
+ ConfigMergeHelper configMergeHelper = injector.getInstance(ConfigMergeHelper.class);
+
+ Map<String, Map<String, ThreeWayValue>> conflicts = configMergeHelper.getConflicts(
+ "clustername", newStackId);
+
+ assertNotNull(conflicts);
+ assertEquals(2, conflicts.size());
+ for (String key : conflicts.keySet()) {
+ if (key.equals("hdfs-env")) {
+ Map<String, ThreeWayValue> stringThreeWayValueMap = conflicts.get(key);
+ assertEquals(1, stringThreeWayValueMap.size());
+ assertEquals("equal-value", stringThreeWayValueMap.get("equal.key").oldStackValue);
+ assertEquals("equal-value", stringThreeWayValueMap.get("equal.key").newStackValue);
+ assertEquals("", stringThreeWayValueMap.get("equal.key").savedValue);
+ } else if (key.equals("hadoop-env")) {
+ Map<String, ThreeWayValue> stringThreeWayValueMap = conflicts.get(key);
+ assertEquals(1, stringThreeWayValueMap.size());
+ assertEquals("modified.value", stringThreeWayValueMap.get("equal.key").oldStackValue);
+ assertEquals("another.value", stringThreeWayValueMap.get("equal.key").newStackValue);
+ assertEquals("", stringThreeWayValueMap.get("equal.key").savedValue);
+ } else {
+ fail("Unexpected key");
+ }
+ }
+ assertEquals(2, conflicts.size());
+ }
+
+ private PropertyInfo createPropertyInfo(String fileName, String name, String value) {
+ PropertyInfo result = new PropertyInfo();
+ result.setFilename(fileName);
+ result.setName(name);
+ result.setValue(value);
+ return result;
+ }
+
+ /**
+ * Generates config that returns properties
+ * @param properties properties that should be returned by config mock
+ * @return mock
+ */
+ private Config createConfigMock(Map<String, String> properties) {
+ Config result = createNiceMock(Config.class);
+ expect(result.getProperties()).andReturn(properties);
+ return result;
+ }
+
+ @Test
+ public void testNormalizeValue() throws Exception{
+ // If template not defined
+ String normalizedValue = ConfigMergeHelper.normalizeValue(null, "2048m");
+ assertEquals("2048m", normalizedValue);
+
+ // Template does not define heap
+ normalizedValue = ConfigMergeHelper.normalizeValue("3k", "2048");
+ assertEquals("2048", normalizedValue);
+
+ // Template - megabytes
+ normalizedValue = ConfigMergeHelper.normalizeValue("1024m", "2048");
+ assertEquals("2048m", normalizedValue);
+
+ normalizedValue = ConfigMergeHelper.normalizeValue("1024M", "2048");
+ assertEquals("2048M", normalizedValue);
+
+ // Template - gigabytes
+ normalizedValue = ConfigMergeHelper.normalizeValue("4g", "2");
+ assertEquals("2g", normalizedValue);
+
+ normalizedValue = ConfigMergeHelper.normalizeValue("4G", "2");
+ assertEquals("2G", normalizedValue);
+ }
+
+
+
+ private class MockModule implements Module {
+
+ @Override
+ public void configure(Binder binder) {
+ binder.bind(Clusters.class).toInstance(clustersMock);
+ binder.bind(AmbariMetaInfo.class).toInstance(ambariMetaInfoMock);
+ }
+ }
+}