You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sm...@apache.org on 2018/05/30 15:02:51 UTC

[ambari] branch trunk updated: [AMBARI-23941] Updating serviceLevelParams and clusterLevelParams in server-side metadata holder both when adding and removing a service/property (#1366)

This is an automated email from the ASF dual-hosted git repository.

smolnar pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ambari.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 02da908  [AMBARI-23941] Updating serviceLevelParams and clusterLevelParams in server-side metadata holder both when adding and removing a service/property (#1366)
02da908 is described below

commit 02da908795aa0ba3ee151352b4346911d1a5481e
Author: Sandor Molnar <sm...@apache.org>
AuthorDate: Wed May 30 17:02:47 2018 +0200

    [AMBARI-23941] Updating serviceLevelParams and clusterLevelParams in server-side metadata holder both when adding and removing a service/property (#1366)
    
    * AMBARI-23941. Updating serviceLevelParams and clusterLevelParams in server-side metadata holder both when adding and removing a service/property
    
    * AMBARI-23941. Eliminated code duplication and applied locking when updating service/cluster level parameters
    
    * AMBARI-23941. Preparing the code for partial configuration updates (i.e. service or cluster level params should not be touched) and for the case when service level params are updated for a single service only (in case of cluter level params we always use full metadata)
    
    * AMBARI-23941. Locking service/cluster level metadata maps properly
---
 .../ambari/server/agent/stomp/MetadataHolder.java  |   2 +-
 .../server/agent/stomp/dto/MetadataCluster.java    |  97 +++++++++-----
 .../controller/AmbariManagementControllerImpl.java |  64 ++-------
 .../ambari/server/events/MetadataUpdateEvent.java  |   3 +-
 .../agent/stomp/dto/MetadataClusterTest.java       | 144 +++++++++++++++++++++
 5 files changed, 225 insertions(+), 85 deletions(-)

diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/MetadataHolder.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/MetadataHolder.java
index 3d8ee35..8fd8951 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/MetadataHolder.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/MetadataHolder.java
@@ -88,7 +88,7 @@ public class MetadataHolder extends AgentClusterDataHolder<MetadataUpdateEvent>
             if (cluster.updateClusterLevelParams(updatedCluster.getClusterLevelParams())) {
               changed = true;
             }
-            if (cluster.updateServiceLevelParams(updatedCluster.getServiceLevelParams())) {
+            if (cluster.updateServiceLevelParams(updatedCluster.getServiceLevelParams(), updatedCluster.isFullServiceLevelMetadata())) {
               changed = true;
             }
             if (CollectionUtils.isNotEmpty(updatedCluster.getStatusCommandsToRun())
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/dto/MetadataCluster.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/dto/MetadataCluster.java
index b22ee60..5619adc 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/dto/MetadataCluster.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/stomp/dto/MetadataCluster.java
@@ -18,41 +18,56 @@
 package org.apache.ambari.server.agent.stomp.dto;
 
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.SortedMap;
 import java.util.TreeMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
 
 import org.apache.ambari.server.state.SecurityType;
-import org.apache.commons.lang.StringUtils;
 
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
 @JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class MetadataCluster {
-  @JsonProperty("status_commands_to_run")
-  private Set<String> statusCommandsToRun = new HashSet<>();
-  private SortedMap<String, MetadataServiceInfo> serviceLevelParams = new TreeMap<>();
-  private SortedMap<String, String> clusterLevelParams = new TreeMap<>();
+  private final Lock lock = new ReentrantLock();
 
-  private SortedMap<String, SortedMap<String,String>> agentConfigs = new TreeMap<>();
+  @JsonProperty("status_commands_to_run")
+  private final Set<String> statusCommandsToRun;
+  private final boolean fullServiceLevelMetadata; //this is true in case serviceLevelParams has all parameters for all services
+  private SortedMap<String, MetadataServiceInfo> serviceLevelParams;
+  private SortedMap<String, String> clusterLevelParams;
+  private SortedMap<String, SortedMap<String,String>> agentConfigs;
 
-  public MetadataCluster(SecurityType securityType, SortedMap<String,MetadataServiceInfo> serviceLevelParams,
+  public MetadataCluster(SecurityType securityType, SortedMap<String,MetadataServiceInfo> serviceLevelParams, boolean fullServiceLevelMetadata,
                          SortedMap<String, String> clusterLevelParams, SortedMap<String, SortedMap<String,String>> agentConfigs) {
+    this.statusCommandsToRun  = new HashSet<>();
     if (securityType != null) {
       this.statusCommandsToRun.add("STATUS");
       if (SecurityType.KERBEROS.equals(securityType)) {
         this.statusCommandsToRun.add("SECURITY_STATUS");
       }
     }
+    this.fullServiceLevelMetadata = fullServiceLevelMetadata;
     this.serviceLevelParams = serviceLevelParams;
     this.clusterLevelParams = clusterLevelParams;
     this.agentConfigs = agentConfigs;
   }
 
   public static MetadataCluster emptyMetadataCluster() {
-    return new MetadataCluster(null, null, null, null);
+    return new MetadataCluster(null, null, false, null, null);
+  }
+
+  public static MetadataCluster serviceLevelParamsMetadataCluster(SecurityType securityType, SortedMap<String, MetadataServiceInfo> serviceLevelParams,
+      boolean fullServiceLevelMetadata) {
+    return new MetadataCluster(securityType, serviceLevelParams, fullServiceLevelMetadata, null, null);
+  }
+
+  public static MetadataCluster clusterLevelParamsMetadataCluster(SecurityType securityType, SortedMap<String, String> clusterLevelParams) {
+    return new MetadataCluster(securityType, null, false, clusterLevelParams, null);
   }
 
   public Set<String> getStatusCommandsToRun() {
@@ -67,43 +82,63 @@ public class MetadataCluster {
     return clusterLevelParams;
   }
 
-  public void setClusterLevelParams(SortedMap<String, String> clusterLevelParams) {
-    this.clusterLevelParams = clusterLevelParams;
-  }
-
   public SortedMap<String, SortedMap<String, String>> getAgentConfigs() {
     return agentConfigs;
   }
 
-  public void setAgentConfigs(SortedMap<String, SortedMap<String, String>> agentConfigs) {
-    this.agentConfigs = agentConfigs;
+  public boolean isFullServiceLevelMetadata() {
+    return fullServiceLevelMetadata;
   }
 
-  public boolean updateServiceLevelParams(SortedMap<String, MetadataServiceInfo> update) {
-    boolean changed = false;
-    for (String key : update.keySet()) {
-      if (!serviceLevelParams.containsKey(key) || !serviceLevelParams.get(key).equals(update.get(key))) {
-        changed = true;
-        break;
+  public boolean updateServiceLevelParams(SortedMap<String, MetadataServiceInfo> update, boolean fullMetadataInUpdatedMap) {
+    if (update != null) {
+      try {
+        lock.lock();
+        if (this.serviceLevelParams == null) {
+          this.serviceLevelParams = new TreeMap<>();
+        }
+        return updateMapIfNeeded(this.serviceLevelParams, update, fullMetadataInUpdatedMap);
+      } finally {
+        lock.unlock();
       }
     }
-    if (changed) {
-      serviceLevelParams.putAll(update);
-    }
-    return changed;
+
+    return false;
   }
 
   public boolean updateClusterLevelParams(SortedMap<String, String> update) {
-    boolean changed = false;
-    for (String key : update.keySet()) {
-      if (!clusterLevelParams.containsKey(key) || !StringUtils.equals(clusterLevelParams.get(key), update.get(key))) {
-        changed = true;
-        break;
+    if (update != null) {
+      try {
+        lock.lock();
+        if (this.clusterLevelParams == null) {
+          this.clusterLevelParams = new TreeMap<>();
+        }
+        return updateMapIfNeeded(this.clusterLevelParams, update, true);
+      } finally {
+        lock.unlock();
       }
     }
-    if (changed) {
-      clusterLevelParams.putAll(update);
+
+    return false;
+  }
+
+  private <T> boolean updateMapIfNeeded(Map<String, T> currentMap, Map<String, T> updatedMap, boolean fullMetadataInUpdatedMap) {
+    boolean changed = false;
+    if (fullMetadataInUpdatedMap) { // we have full metadata in updatedMap (i.e. in case of service removal we have full metadata in updatedMap)
+      changed = !Objects.equals(currentMap, updatedMap);
+      if (changed) {
+        currentMap.clear();
+        currentMap.putAll(updatedMap);
+      }
+    } else { // to support backward compatibility we fall back to previous version where we only added non-existing services/properties in current metadata
+      for (String key : updatedMap.keySet()) {
+        if (!currentMap.containsKey(key) || !currentMap.get(key).equals(updatedMap.get(key))) {
+          currentMap.put(key, updatedMap.get(key));
+          changed = true;
+        }
+      }
     }
+
     return changed;
   }
 
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index 0960384..da5523b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -5583,10 +5583,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
 
       SecurityType securityType = cl.getSecurityType();
 
-      MetadataCluster metadataCluster = new MetadataCluster(securityType,
-          getMetadataServiceLevelParams(cl),
-          getMetadataClusterLevelParams(cl, stackId),
-          null);
+      MetadataCluster metadataCluster = new MetadataCluster(securityType, getMetadataServiceLevelParams(cl), true, getMetadataClusterLevelParams(cl, stackId), null);
       metadataClusters.put(Long.toString(cl.getClusterId()), metadataCluster);
     }
 
@@ -5596,50 +5593,23 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   }
 
   public MetadataUpdateEvent getClusterMetadata(Cluster cl) throws AmbariException {
-    TreeMap<String, MetadataCluster> metadataClusters = new TreeMap<>();
-    StackId stackId = cl.getDesiredStackVersion();
-
-    SecurityType securityType = cl.getSecurityType();
-
-    MetadataCluster metadataCluster = new MetadataCluster(securityType,
-        getMetadataServiceLevelParams(cl),
-        getMetadataClusterLevelParams(cl, stackId),
-        null);
+    final TreeMap<String, MetadataCluster> metadataClusters = new TreeMap<>();
+    MetadataCluster metadataCluster = new MetadataCluster(cl.getSecurityType(), getMetadataServiceLevelParams(cl), true, getMetadataClusterLevelParams(cl, cl.getDesiredStackVersion()), null);
     metadataClusters.put(Long.toString(cl.getClusterId()), metadataCluster);
-
-    MetadataUpdateEvent metadataUpdateEvent = new MetadataUpdateEvent(metadataClusters,
-        null, getMetadataAgentConfigs(), UpdateEventType.UPDATE);
-    return metadataUpdateEvent;
+    return new MetadataUpdateEvent(metadataClusters, null, getMetadataAgentConfigs(), UpdateEventType.UPDATE);
   }
 
   @Override
   public MetadataUpdateEvent getClusterMetadataOnConfigsUpdate(Cluster cl) throws AmbariException {
-    TreeMap<String, MetadataCluster> metadataClusters = new TreeMap<>();
-    StackId stackId = cl.getDesiredStackVersion();
-
-    MetadataCluster metadataCluster = new MetadataCluster(null,
-        new TreeMap<>(),
-        getMetadataClusterLevelConfigsParams(cl, stackId),
-        null);
-    metadataClusters.put(Long.toString(cl.getClusterId()), metadataCluster);
-
-    MetadataUpdateEvent metadataUpdateEvent = new MetadataUpdateEvent(metadataClusters,
-        null, getMetadataAgentConfigs(), UpdateEventType.UPDATE);
-    return metadataUpdateEvent;
+    final TreeMap<String, MetadataCluster> metadataClusters = new TreeMap<>();
+    metadataClusters.put(Long.toString(cl.getClusterId()), MetadataCluster.clusterLevelParamsMetadataCluster(null, getMetadataClusterLevelParams(cl, cl.getDesiredStackVersion())));
+    return new MetadataUpdateEvent(metadataClusters, null, getMetadataAgentConfigs(), UpdateEventType.UPDATE);
   }
 
   public MetadataUpdateEvent getClusterMetadataOnRepoUpdate(Cluster cl) throws AmbariException {
     TreeMap<String, MetadataCluster> metadataClusters = new TreeMap<>();
-
-    MetadataCluster metadataCluster = new MetadataCluster(null,
-        getMetadataServiceLevelParams(cl),
-        new TreeMap<>(),
-        null);
-    metadataClusters.put(Long.toString(cl.getClusterId()), metadataCluster);
-
-    MetadataUpdateEvent metadataUpdateEvent = new MetadataUpdateEvent(metadataClusters,
-        null, getMetadataAgentConfigs(), UpdateEventType.UPDATE);
-    return metadataUpdateEvent;
+    metadataClusters.put(Long.toString(cl.getClusterId()), MetadataCluster.serviceLevelParamsMetadataCluster(null, getMetadataServiceLevelParams(cl), true));
+    return new MetadataUpdateEvent(metadataClusters, null, getMetadataAgentConfigs(), UpdateEventType.UPDATE);
   }
 
   public MetadataUpdateEvent getClusterMetadataOnServiceInstall(Cluster cl, String serviceName) throws AmbariException {
@@ -5647,17 +5617,9 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
   }
 
   public MetadataUpdateEvent getClusterMetadataOnServiceCredentialStoreUpdate(Cluster cl, String serviceName) throws AmbariException {
-    TreeMap<String, MetadataCluster> metadataClusters = new TreeMap<>();
-
-    MetadataCluster metadataCluster = new MetadataCluster(null,
-        getMetadataServiceLevelParams(cl.getService(serviceName)),
-        new TreeMap<>(),
-        null);
-    metadataClusters.put(Long.toString(cl.getClusterId()), metadataCluster);
-
-    MetadataUpdateEvent metadataUpdateEvent = new MetadataUpdateEvent(metadataClusters,
-        null, getMetadataAgentConfigs(), UpdateEventType.UPDATE);
-    return metadataUpdateEvent;
+    final TreeMap<String, MetadataCluster> metadataClusters = new TreeMap<>();
+    metadataClusters.put(Long.toString(cl.getClusterId()), MetadataCluster.serviceLevelParamsMetadataCluster(null, getMetadataServiceLevelParams(cl), false));
+    return new MetadataUpdateEvent(metadataClusters, null, getMetadataAgentConfigs(), UpdateEventType.UPDATE);
   }
 
   private String getClientsToUpdateConfigs(ComponentInfo componentInfo) {
@@ -5779,7 +5741,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
     return clusterLevelParams;
   }
 
-  public TreeMap<String, String> getMetadataClusterLevelConfigsParams(Cluster cluster, StackId stackId) throws AmbariException {
+  private TreeMap<String, String> getMetadataClusterLevelConfigsParams(Cluster cluster, StackId stackId) throws AmbariException {
     TreeMap<String, String> clusterLevelParams = new TreeMap<>();
 
     Map<String, DesiredConfig> desiredConfigs = cluster.getDesiredConfigs(false);
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/events/MetadataUpdateEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/events/MetadataUpdateEvent.java
index c9be4a6..8724f1a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/events/MetadataUpdateEvent.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/events/MetadataUpdateEvent.java
@@ -19,7 +19,6 @@ package org.apache.ambari.server.events;
 
 import java.util.Map;
 import java.util.SortedMap;
-import java.util.TreeMap;
 
 import org.apache.ambari.server.agent.stomp.dto.Hashable;
 import org.apache.ambari.server.agent.stomp.dto.MetadataCluster;
@@ -64,7 +63,7 @@ public class MetadataUpdateEvent extends STOMPEvent implements Hashable {
     super(Type.METADATA);
     this.metadataClusters = metadataClusters;
     if (ambariLevelParams != null) {
-      this.metadataClusters.put(AMBARI_LEVEL_CLUSTER_ID, new MetadataCluster(null, new TreeMap<>(), ambariLevelParams, metadataAgentConfigs));
+      this.metadataClusters.put(AMBARI_LEVEL_CLUSTER_ID, new MetadataCluster(null, null, false, ambariLevelParams, metadataAgentConfigs));
     }
     this.eventType = eventType;
   }
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/agent/stomp/dto/MetadataClusterTest.java b/ambari-server/src/test/java/org/apache/ambari/server/agent/stomp/dto/MetadataClusterTest.java
new file mode 100644
index 0000000..1e5db3b
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/agent/stomp/dto/MetadataClusterTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.agent.stomp.dto;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.junit.Test;
+
+public class MetadataClusterTest {
+
+  @Test
+  public void shouldReturnFalseWhenUpdatingServiceLevelParamsWithoutNewOrRemovedServices() throws Exception {
+    final SortedMap<String, MetadataServiceInfo> current = new TreeMap<>();
+    current.put("service1", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    current.put("service2", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    current.put("service3", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    final MetadataCluster metadataCluster = MetadataCluster.serviceLevelParamsMetadataCluster(null, current, true);
+    final SortedMap<String, MetadataServiceInfo> updated = new TreeMap<>(current);
+    assertFalse(metadataCluster.updateServiceLevelParams(updated, true));
+    assertEquals(current, metadataCluster.getServiceLevelParams());
+  }
+
+  @Test
+  public void shouldReturnTrueWhenUpdatingServiceLevelParamsUponServiceAddition() throws Exception {
+    final SortedMap<String, MetadataServiceInfo> current = new TreeMap<>();
+    current.put("service1", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    current.put("service2", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    final MetadataCluster metadataCluster = MetadataCluster.serviceLevelParamsMetadataCluster(null, current, true);
+    final SortedMap<String, MetadataServiceInfo> updated = new TreeMap<>(current);
+    updated.put("service3", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    assertTrue(metadataCluster.updateServiceLevelParams(updated, true));
+    assertEquals(updated, metadataCluster.getServiceLevelParams());
+  }
+
+  @Test
+  public void shouldReturnTrueWhenUpdatingServiceLevelParamsUponServiceRemoval() throws Exception {
+    final SortedMap<String, MetadataServiceInfo> current = new TreeMap<>();
+    current.put("service1", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    current.put("service2", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    current.put("service3", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    final MetadataCluster metadataCluster = MetadataCluster.serviceLevelParamsMetadataCluster(null, current, true);
+    final SortedMap<String, MetadataServiceInfo> updated = new TreeMap<>(current);
+    updated.remove("service2");
+    assertTrue(metadataCluster.updateServiceLevelParams(updated, true));
+    assertEquals(updated, metadataCluster.getServiceLevelParams());
+  }
+
+  @Test
+  public void shouldReturnFalseWhenNullServiceLevelParamsArePassedBecauseOfPartialConfigurationUpdate() throws Exception {
+    final SortedMap<String, MetadataServiceInfo> current = new TreeMap<>();
+    current.put("service1", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    current.put("service2", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    current.put("service3", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    final MetadataCluster metadataCluster = MetadataCluster.serviceLevelParamsMetadataCluster(null, current, true);
+    assertFalse(metadataCluster.updateServiceLevelParams(null, true));
+    assertEquals(current, metadataCluster.getServiceLevelParams());
+  }
+
+  @Test
+  public void shouldReturnTrueWhenUpdatingServiceLevelParamsWithoutFullServiceLevelMetadata() throws Exception {
+    final SortedMap<String, MetadataServiceInfo> current = new TreeMap<>();
+    current.put("service1", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    current.put("service2", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    current.put("service3", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    final MetadataCluster metadataCluster = MetadataCluster.serviceLevelParamsMetadataCluster(null, current, true);
+    final SortedMap<String, MetadataServiceInfo> updated = new TreeMap<>();
+    updated.put("service3", new MetadataServiceInfo("v2", Boolean.TRUE, null, 2L, "servicePackageFolder2"));
+    updated.put("service4", new MetadataServiceInfo("v1", Boolean.FALSE, null, 1L, "servicePackageFolder"));
+    assertTrue(metadataCluster.updateServiceLevelParams(updated, false));
+    final SortedMap<String, MetadataServiceInfo> expected = current;
+    expected.putAll(updated);
+    assertEquals(expected, metadataCluster.getServiceLevelParams());
+  }
+
+  @Test
+  public void shouldReturnFalseWhenUpdatingClusterLevelParamsWithoutClusterLevelParameterAdditionOrRemoval() throws Exception {
+    final SortedMap<String, String> current = new TreeMap<>();
+    current.put("param1", "value1");
+    current.put("param2", "value2");
+    current.put("param3", "value3");
+    final MetadataCluster metadataCluster = MetadataCluster.clusterLevelParamsMetadataCluster(null, current);
+    final SortedMap<String, String> updated = new TreeMap<>(current);
+    assertFalse(metadataCluster.updateClusterLevelParams(updated));
+    assertEquals(current, metadataCluster.getClusterLevelParams());
+  }
+
+  @Test
+  public void shouldReturnTrueWhenUpdatingClusterLevelParamsUponClusterLevelParameterAddition() throws Exception {
+    final SortedMap<String, String> current = new TreeMap<>();
+    current.put("param1", "value1");
+    current.put("param2", "value2");
+    final MetadataCluster metadataCluster = MetadataCluster.clusterLevelParamsMetadataCluster(null, current);
+    final SortedMap<String, String> updated = new TreeMap<>(current);
+    updated.put("param3", "value3");
+    assertTrue(metadataCluster.updateClusterLevelParams(updated));
+    assertEquals(updated, metadataCluster.getClusterLevelParams());
+  }
+
+  @Test
+  public void shouldReturnTrueWhenUpdatingClusterLevelParamsUponClusterLevelParameterRemoval() throws Exception {
+    final SortedMap<String, String> current = new TreeMap<>();
+    current.put("param1", "value1");
+    current.put("param2", "value2");
+    current.put("param3", "value3");
+    final MetadataCluster metadataCluster = MetadataCluster.clusterLevelParamsMetadataCluster(null, current);
+    final SortedMap<String, String> updated = new TreeMap<>(current);
+    updated.remove("param2");
+    assertTrue(metadataCluster.updateClusterLevelParams(updated));
+    assertEquals(updated, metadataCluster.getClusterLevelParams());
+  }
+
+  @Test
+  public void shouldReturnFalseWhenNullClusterLevelParamsArePassedBecauseOfPartialConfigurationUpdate() throws Exception {
+    final SortedMap<String, String> current = new TreeMap<>();
+    current.put("param1", "value1");
+    current.put("param2", "value2");
+    current.put("param3", "value3");
+    final MetadataCluster metadataCluster = MetadataCluster.clusterLevelParamsMetadataCluster(null, current);
+    assertFalse(metadataCluster.updateClusterLevelParams(null));
+    assertEquals(current, metadataCluster.getClusterLevelParams());
+  }
+
+}

-- 
To stop receiving notification emails like this one, please contact
smolnar@apache.org.