You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by am...@apache.org on 2017/11/16 15:36:53 UTC

[30/50] [abbrv] ambari git commit: AMBARI-22347. Simplify Ambari configuration tables from AMBARI-21307 (rlevas)

http://git-wip-us.apache.org/repos/asf/ambari/blob/a631d0ed/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AmbariConfigurationResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AmbariConfigurationResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AmbariConfigurationResourceProviderTest.java
index c2a1421..a2ecb27 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AmbariConfigurationResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/AmbariConfigurationResourceProviderTest.java
@@ -14,238 +14,364 @@
 
 package org.apache.ambari.server.controller.internal;
 
+import static org.apache.ambari.server.controller.internal.AmbariConfigurationResourceProvider.AMBARI_CONFIGURATION_CATEGORY_PROPERTY_ID;
+import static org.apache.ambari.server.controller.internal.AmbariConfigurationResourceProvider.AMBARI_CONFIGURATION_PROPERTIES_PROPERTY_ID;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.newCapture;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
+
+import javax.persistence.EntityManager;
 
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceProvider;
 import org.apache.ambari.server.controller.utilities.PredicateBuilder;
-import org.apache.ambari.server.events.AmbariLdapConfigChangedEvent;
+import org.apache.ambari.server.events.AmbariConfigurationChangedEvent;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.dao.AmbariConfigurationDAO;
 import org.apache.ambari.server.orm.entities.AmbariConfigurationEntity;
-import org.apache.ambari.server.orm.entities.ConfigurationBaseEntity;
+import org.apache.ambari.server.security.TestAuthenticationFactory;
+import org.apache.ambari.server.security.authorization.AuthorizationException;
 import org.easymock.Capture;
-import org.easymock.EasyMock;
-import org.easymock.EasyMockRule;
 import org.easymock.EasyMockSupport;
-import org.easymock.Mock;
-import org.easymock.TestSubject;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Rule;
+import org.junit.After;
 import org.junit.Test;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
 
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
 
 public class AmbariConfigurationResourceProviderTest extends EasyMockSupport {
 
-  @Rule
-  public EasyMockRule mocks = new EasyMockRule(this);
+  private static final String CATEGORY_NAME_1 = "test-category-1";
+  private static final String CATEGORY_NAME_2 = "test-category-2";
 
-  @Mock
-  private Request requestMock;
+  @After
+  public void clearAuthentication() {
+    SecurityContextHolder.getContext().setAuthentication(null);
+  }
 
-  @Mock
-  private AmbariConfigurationDAO ambariConfigurationDAO;
+  @Test
+  public void testCreateResources_Administrator() throws Exception {
+    testCreateResources(TestAuthenticationFactory.createAdministrator());
+  }
 
-  @Mock
-  private AmbariEventPublisher publisher;
+  @Test(expected = AuthorizationException.class)
+  public void testCreateResources_ClusterAdministrator() throws Exception {
+    testCreateResources(TestAuthenticationFactory.createClusterAdministrator());
+  }
 
-  private Capture<AmbariConfigurationEntity> ambariConfigurationEntityCapture;
+  @Test(expected = AuthorizationException.class)
+  public void testCreateResources_ClusterOperator() throws Exception {
+    testCreateResources(TestAuthenticationFactory.createClusterOperator());
+  }
 
-  private Gson gson;
+  @Test(expected = AuthorizationException.class)
+  public void testCreateResources_ServiceAdministrator() throws Exception {
+    testCreateResources(TestAuthenticationFactory.createServiceAdministrator());
+  }
 
-  private static final String DATA_MOCK_STR = "[\n" +
-    "      {\n" +
-    "        \"authentication.ldap.baseDn\" : \"dc=ambari,dc=apache,dc=org\",\n" +
-    "        \"authentication.ldap.primaryUrl\" : \"localhost:33389\",\n" +
-    "        \"authentication.ldap.secondaryUrl\" : \"localhost:333\"\n" +
-    "      }\n" +
-    "    ]";
+  @Test(expected = AuthorizationException.class)
+  public void testCreateResources_ServiceOperator() throws Exception {
+    testCreateResources(TestAuthenticationFactory.createServiceOperator());
+  }
 
-  private static final Long PK_LONG = Long.valueOf(1);
-  private static final String PK_STRING = String.valueOf(1);
-  private static final String VERSION_TAG = "test version";
-  private static final String VERSION = "1";
-  private static final String TYPE = "AmbariConfiguration";
+  private void testCreateResources(Authentication authentication) throws Exception {
+    Injector injector = createInjector();
 
-  @TestSubject
-  private AmbariConfigurationResourceProvider ambariConfigurationResourceProvider = new AmbariConfigurationResourceProvider();
+    ResourceProvider resourceProvider = injector.getInstance(AmbariConfigurationResourceProvider.class);
 
-  @Before
-  public void setup() {
-    ambariConfigurationEntityCapture = Capture.newInstance();
-    gson = new GsonBuilder().create();
-  }
+    Set<Map<String, Object>> propertySets = new HashSet<>();
 
-  @Test
-  public void testCreateAmbariConfigurationRequestResultsInTheProperPersistenceCall() throws Exception {
-
-    // GIVEN
-    // configuration properties parsed from the request
-    Set<Map<String, Object>> resourcePropertiesSet = Sets.newHashSet(
-      new PropertiesMapBuilder()
-        .withId(PK_LONG)
-        .withVersion(VERSION)
-        .withVersionTag(VERSION_TAG)
-        .withData(DATA_MOCK_STR)
-        .withType(TYPE)
-        .build());
-
-    // mock the request to return the properties
-    EasyMock.expect(requestMock.getProperties()).andReturn(resourcePropertiesSet);
-
-    // capture the entity the DAO gets called with
-    ambariConfigurationDAO.create(EasyMock.capture(ambariConfigurationEntityCapture));
-    publisher.publish(EasyMock.anyObject(AmbariLdapConfigChangedEvent.class));
+    Map<String, String> properties1 = new HashMap<>();
+    properties1.put("property1a", "value1");
+    properties1.put("property2a", "value2");
+    propertySets.add(toRequestProperties(CATEGORY_NAME_1, properties1));
+
+    Map<String, String> properties2 = new HashMap<>();
+    properties2.put("property1b", "value1");
+    properties2.put("property2b", "value2");
+    propertySets.add(toRequestProperties(CATEGORY_NAME_2, properties2));
+
+    Request request = createMock(Request.class);
+    expect(request.getProperties()).andReturn(propertySets).once();
+
+    Capture<Map<String, String>> capturedProperties1 = newCapture();
+    Capture<Map<String, String>> capturedProperties2 = newCapture();
+
+    AmbariConfigurationDAO dao = injector.getInstance(AmbariConfigurationDAO.class);
+    expect(dao.reconcileCategory(eq(CATEGORY_NAME_1), capture(capturedProperties1), eq(true)))
+        .andReturn(true)
+        .once();
+    expect(dao.reconcileCategory(eq(CATEGORY_NAME_2), capture(capturedProperties2), eq(true)))
+        .andReturn(true)
+        .once();
+
+    AmbariEventPublisher publisher = injector.getInstance(AmbariEventPublisher.class);
+    publisher.publish(anyObject(AmbariConfigurationChangedEvent.class));
+    expectLastCall().times(2);
 
     replayAll();
 
-    // WHEN
-    ambariConfigurationResourceProvider.createResourcesAuthorized(requestMock);
+    SecurityContextHolder.getContext().setAuthentication(authentication);
 
-    // THEN
-    AmbariConfigurationEntity capturedAmbariConfigurationEntity = ambariConfigurationEntityCapture.getValue();
-    Assert.assertNotNull(capturedAmbariConfigurationEntity);
-    Assert.assertNull("The entity identifier should be null", capturedAmbariConfigurationEntity.getId());
-    Assert.assertEquals("The entity version is not the expected", Integer.valueOf(VERSION),
-      capturedAmbariConfigurationEntity.getConfigurationBaseEntity().getVersion());
-    Assert.assertEquals("The entity version tag is not the expected", VERSION_TAG,
-      capturedAmbariConfigurationEntity.getConfigurationBaseEntity().getVersionTag());
-    Assert.assertEquals("The entity data is not the expected", DATA_MOCK_STR,
-      gson.fromJson(capturedAmbariConfigurationEntity.getConfigurationBaseEntity().getConfigurationData(), String.class));
+    resourceProvider.createResources(request);
+
+    verifyAll();
+
+    validateCapturedProperties(properties1, capturedProperties1);
+    validateCapturedProperties(properties2, capturedProperties2);
   }
 
   @Test
-  public void testRemoveAmbariConfigurationRequestResultsInTheProperPersistenceCall() throws Exception {
-    // GIVEN
-    Predicate predicate = new PredicateBuilder().property(
-      AmbariConfigurationResourceProvider.ResourcePropertyId.ID.getPropertyId()).equals("1").toPredicate();
+  public void testDeleteResources_Administrator() throws Exception {
+    testDeleteResources(TestAuthenticationFactory.createAdministrator());
+  }
 
-    Capture<Long> pkCapture = Capture.newInstance();
-    ambariConfigurationDAO.removeByPK(EasyMock.capture(pkCapture));
-    publisher.publish(EasyMock.anyObject(AmbariLdapConfigChangedEvent.class));
+  @Test(expected = AuthorizationException.class)
+  public void testDeleteResources_ClusterAdministrator() throws Exception {
+    testDeleteResources(TestAuthenticationFactory.createClusterAdministrator());
+  }
 
-    replayAll();
+  @Test(expected = AuthorizationException.class)
+  public void testDeleteResources_ClusterOperator() throws Exception {
+    testDeleteResources(TestAuthenticationFactory.createClusterOperator());
+  }
 
-    // WHEN
-    ambariConfigurationResourceProvider.deleteResourcesAuthorized(requestMock, predicate);
+  @Test(expected = AuthorizationException.class)
+  public void testDeleteResources_ServiceAdministrator() throws Exception {
+    testDeleteResources(TestAuthenticationFactory.createServiceAdministrator());
+  }
 
-    // THEN
-    Assert.assertEquals("The pk of the entity to be removed doen't match the expected id", Long.valueOf(1), pkCapture.getValue());
+  @Test(expected = AuthorizationException.class)
+  public void testDeleteResources_ServiceOperator() throws Exception {
+    testDeleteResources(TestAuthenticationFactory.createServiceOperator());
   }
 
+  private void testDeleteResources(Authentication authentication) throws Exception {
+    Injector injector = createInjector();
 
-  @Test
-  public void testRetrieveAmbariConfigurationShouldResultsInTheProperDAOCall() throws Exception {
-    // GIVEN
-    Predicate predicate = new PredicateBuilder().property(
-      AmbariConfigurationResourceProvider.ResourcePropertyId.ID.getPropertyId()).equals("1").toPredicate();
+    ResourceProvider resourceProvider = injector.getInstance(AmbariConfigurationResourceProvider.class);
+
+    Predicate predicate = new PredicateBuilder()
+        .property(AMBARI_CONFIGURATION_CATEGORY_PROPERTY_ID)
+        .equals(CATEGORY_NAME_1)
+        .toPredicate();
+
+    Request request = createMock(Request.class);
+
+    AmbariConfigurationDAO dao = injector.getInstance(AmbariConfigurationDAO.class);
+    expect(dao.removeByCategory(CATEGORY_NAME_1)).andReturn(1).once();
+
+    AmbariEventPublisher publisher = injector.getInstance(AmbariEventPublisher.class);
+    publisher.publish(anyObject(AmbariConfigurationChangedEvent.class));
+    expectLastCall().once();
 
-    EasyMock.expect(ambariConfigurationDAO.findAll()).andReturn(Lists.newArrayList(createDummyAmbariConfigurationEntity()));
     replayAll();
 
-    // WHEN
-    Set<Resource> resourceSet = ambariConfigurationResourceProvider.getResourcesAuthorized(requestMock, predicate);
+    SecurityContextHolder.getContext().setAuthentication(authentication);
+
+    resourceProvider.deleteResources(request, predicate);
 
-    // THEN
-    Assert.assertNotNull(resourceSet);
-    Assert.assertFalse(resourceSet.isEmpty());
+    verifyAll();
   }
 
   @Test
-  public void testUpdateAmbariConfigurationShouldResultInTheProperDAOCalls() throws Exception {
-    // GIVEN
+  public void testGetResources_Administrator() throws Exception {
+    testGetResources(TestAuthenticationFactory.createAdministrator());
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testGetResources_ClusterAdministrator() throws Exception {
+    testGetResources(TestAuthenticationFactory.createClusterAdministrator());
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testGetResources_ClusterOperator() throws Exception {
+    testGetResources(TestAuthenticationFactory.createClusterOperator());
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testGetResources_ServiceAdministrator() throws Exception {
+    testGetResources(TestAuthenticationFactory.createServiceAdministrator());
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testGetResources_ServiceOperator() throws Exception {
+    testGetResources(TestAuthenticationFactory.createServiceOperator());
+  }
+
+  private void testGetResources(Authentication authentication) throws Exception {
+    Injector injector = createInjector();
+
+    ResourceProvider resourceProvider = injector.getInstance(AmbariConfigurationResourceProvider.class);
 
-    Predicate predicate = new PredicateBuilder().property(
-      AmbariConfigurationResourceProvider.ResourcePropertyId.ID.getPropertyId()).equals("1").toPredicate();
+    Predicate predicate = new PredicateBuilder()
+        .property(AMBARI_CONFIGURATION_CATEGORY_PROPERTY_ID)
+        .equals(CATEGORY_NAME_1)
+        .toPredicate();
 
-    // properteies in the request, representing the updated configuration
-    Set<Map<String, Object>> resourcePropertiesSet = Sets.newHashSet(new PropertiesMapBuilder()
-      .withId(PK_LONG)
-      .withVersion("2")
-      .withVersionTag("version-2")
-      .withData(DATA_MOCK_STR)
-      .withType(TYPE)
-      .build());
+    Request request = createMock(Request.class);
+    expect(request.getPropertyIds()).andReturn(null).anyTimes();
 
-    EasyMock.expect(requestMock.getProperties()).andReturn(resourcePropertiesSet);
+    Map<String, String> properties = new HashMap<>();
+    properties.put("property1a", "value1");
+    properties.put("property2a", "value2");
 
-    AmbariConfigurationEntity persistedEntity = createDummyAmbariConfigurationEntity();
-    EasyMock.expect(ambariConfigurationDAO.findByPK(PK_LONG)).andReturn(persistedEntity);
-    ambariConfigurationDAO.update(EasyMock.capture(ambariConfigurationEntityCapture));
-    publisher.publish(EasyMock.anyObject(AmbariLdapConfigChangedEvent.class));
+    AmbariConfigurationDAO dao = injector.getInstance(AmbariConfigurationDAO.class);
+    expect(dao.findByCategory(CATEGORY_NAME_1)).andReturn(createEntities(CATEGORY_NAME_1, properties)).once();
 
     replayAll();
 
-    // WHEN
-    ambariConfigurationResourceProvider.updateResourcesAuthorized(requestMock, predicate);
+    SecurityContextHolder.getContext().setAuthentication(authentication);
 
-    // the captured entity should be the updated one
-    AmbariConfigurationEntity updatedEntity = ambariConfigurationEntityCapture.getValue();
+    Set<Resource> response = resourceProvider.getResources(request, predicate);
 
-    // THEN
-    Assert.assertNotNull(updatedEntity);
-    Assert.assertEquals("The updated version is wrong", Integer.valueOf(2), updatedEntity.getConfigurationBaseEntity().getVersion());
-  }
+    verifyAll();
 
-  private class PropertiesMapBuilder {
+    junit.framework.Assert.assertNotNull(response);
+    junit.framework.Assert.assertEquals(1, response.size());
 
-    private Map<String, Object> resourcePropertiesMap = Maps.newHashMap();
+    Resource resource = response.iterator().next();
+    junit.framework.Assert.assertEquals(Resource.Type.AmbariConfiguration, resource.getType());
 
-    private PropertiesMapBuilder() {
-    }
+    Map<String, Map<String, Object>> propertiesMap = resource.getPropertiesMap();
+    junit.framework.Assert.assertEquals(2, propertiesMap.size());
 
-    public PropertiesMapBuilder withId(Long id) {
-      resourcePropertiesMap.put(AmbariConfigurationResourceProvider.ResourcePropertyId.ID.getPropertyId(), id);
-      return this;
-    }
+    junit.framework.Assert.assertEquals(CATEGORY_NAME_1, propertiesMap.get(Resource.Type.AmbariConfiguration.name()).get("category"));
 
-    private PropertiesMapBuilder withVersion(String version) {
-      resourcePropertiesMap.put(AmbariConfigurationResourceProvider.ResourcePropertyId.VERSION.getPropertyId(), version);
-      return this;
-    }
+    Map<String, Object> retrievedProperties = propertiesMap.get(Resource.Type.AmbariConfiguration.name() + "/properties");
+    junit.framework.Assert.assertEquals(2, retrievedProperties.size());
 
-    private PropertiesMapBuilder withVersionTag(String versionTag) {
-      resourcePropertiesMap.put(AmbariConfigurationResourceProvider.ResourcePropertyId.VERSION_TAG.getPropertyId(), versionTag);
-      return this;
+    for (Map.Entry<String, String> entry : properties.entrySet()) {
+      junit.framework.Assert.assertEquals(entry.getValue(), retrievedProperties.get(entry.getKey()));
     }
+  }
 
-    private PropertiesMapBuilder withData(String dataJson) {
-      resourcePropertiesMap.put(AmbariConfigurationResourceProvider.ResourcePropertyId.DATA.getPropertyId(), dataJson);
-      return this;
-    }
+  @Test
+  public void testUpdateResources_Administrator() throws Exception {
+    testUpdateResources(TestAuthenticationFactory.createAdministrator());
+  }
 
-    private PropertiesMapBuilder withType(String type) {
-      resourcePropertiesMap.put(AmbariConfigurationResourceProvider.ResourcePropertyId.TYPE.getPropertyId(), type);
-      return this;
-    }
+  @Test(expected = AuthorizationException.class)
+  public void testUpdateResources_ClusterAdministrator() throws Exception {
+    testUpdateResources(TestAuthenticationFactory.createClusterAdministrator());
+  }
 
+  @Test(expected = AuthorizationException.class)
+  public void testUpdateResources_ClusterOperator() throws Exception {
+    testUpdateResources(TestAuthenticationFactory.createClusterOperator());
+  }
 
-    public Map<String, Object> build() {
-      return this.resourcePropertiesMap;
-    }
+  @Test(expected = AuthorizationException.class)
+  public void testUpdateResources_ServiceAdministrator() throws Exception {
+    testUpdateResources(TestAuthenticationFactory.createServiceAdministrator());
+  }
+
+  @Test(expected = AuthorizationException.class)
+  public void testUpdateResources_ServiceOperator() throws Exception {
+    testUpdateResources(TestAuthenticationFactory.createServiceOperator());
+  }
+
+  private void testUpdateResources(Authentication authentication) throws Exception {
+    Injector injector = createInjector();
+
+    ResourceProvider resourceProvider = injector.getInstance(AmbariConfigurationResourceProvider.class);
+
+    Predicate predicate = new PredicateBuilder()
+        .property(AMBARI_CONFIGURATION_CATEGORY_PROPERTY_ID)
+        .equals(CATEGORY_NAME_1)
+        .toPredicate();
+
+    Set<Map<String, Object>> propertySets = new HashSet<>();
 
+    Map<String, String> properties1 = new HashMap<>();
+    properties1.put("property1a", "value1");
+    properties1.put("property2a", "value2");
+    propertySets.add(toRequestProperties(CATEGORY_NAME_1, properties1));
+
+    Request request = createMock(Request.class);
+    expect(request.getProperties()).andReturn(propertySets).once();
+
+    Capture<Map<String, String>> capturedProperties1 = newCapture();
+
+    AmbariConfigurationDAO dao = injector.getInstance(AmbariConfigurationDAO.class);
+    expect(dao.reconcileCategory(eq(CATEGORY_NAME_1), capture(capturedProperties1), eq(false)))
+        .andReturn(true)
+        .once();
+
+    AmbariEventPublisher publisher = injector.getInstance(AmbariEventPublisher.class);
+    publisher.publish(anyObject(AmbariConfigurationChangedEvent.class));
+    expectLastCall().times(1);
+
+    replayAll();
+
+    SecurityContextHolder.getContext().setAuthentication(authentication);
+
+    resourceProvider.updateResources(request, predicate);
+
+    verifyAll();
+
+    validateCapturedProperties(properties1, capturedProperties1);
   }
 
-  private AmbariConfigurationEntity createDummyAmbariConfigurationEntity() {
-    AmbariConfigurationEntity acEntity = new AmbariConfigurationEntity();
-    ConfigurationBaseEntity configurationBaseEntity = new ConfigurationBaseEntity();
-    acEntity.setConfigurationBaseEntity(configurationBaseEntity);
-    acEntity.setId(PK_LONG);
-    acEntity.getConfigurationBaseEntity().setConfigurationData(DATA_MOCK_STR);
-    acEntity.getConfigurationBaseEntity().setVersion(Integer.valueOf(VERSION));
-    acEntity.getConfigurationBaseEntity().setVersionTag(VERSION_TAG);
-    acEntity.getConfigurationBaseEntity().setType("ldap-config");
+  private List<AmbariConfigurationEntity> createEntities(String categoryName, Map<String, String> properties) {
+    List<AmbariConfigurationEntity> entities = new ArrayList<>();
 
-    return acEntity;
+    for (Map.Entry<String, String> property : properties.entrySet()) {
+      AmbariConfigurationEntity entity = new AmbariConfigurationEntity();
+      entity.setCategoryName(categoryName);
+      entity.setPropertyName(property.getKey());
+      entity.setPropertyValue(property.getValue());
+      entities.add(entity);
+    }
+
+    return entities;
+  }
+
+  private Map<String, Object> toRequestProperties(String categoryName1, Map<String, String> properties) {
+    Map<String, Object> requestProperties = new HashMap<>();
+    requestProperties.put(AMBARI_CONFIGURATION_CATEGORY_PROPERTY_ID, categoryName1);
+    for (Map.Entry<String, String> entry : properties.entrySet()) {
+      requestProperties.put(AMBARI_CONFIGURATION_PROPERTIES_PROPERTY_ID + "/" + entry.getKey(), entry.getValue());
+    }
+    return requestProperties;
   }
 
+  private void validateCapturedProperties(Map<String, String> expectedProperties, Capture<Map<String, String>> capturedProperties) {
+    junit.framework.Assert.assertTrue(capturedProperties.hasCaptured());
 
+    Map<String, String> properties = capturedProperties.getValue();
+    junit.framework.Assert.assertNotNull(properties);
+
+    // Convert the Map to a TreeMap to help with comparisons
+    expectedProperties = new TreeMap<>(expectedProperties);
+    properties = new TreeMap<>(properties);
+    junit.framework.Assert.assertEquals(expectedProperties, properties);
+  }
+
+  private Injector createInjector() throws Exception {
+    return Guice.createInjector(new AbstractModule() {
+      @Override
+      protected void configure() {
+        bind(EntityManager.class).toInstance(createNiceMock(EntityManager.class));
+        bind(AmbariConfigurationDAO.class).toInstance(createMock(AmbariConfigurationDAO.class));
+        bind(AmbariEventPublisher.class).toInstance(createMock(AmbariEventPublisher.class));
+      }
+    });
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/a631d0ed/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AmbariConfigurationDAOTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AmbariConfigurationDAOTest.java b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AmbariConfigurationDAOTest.java
new file mode 100644
index 0000000..f801fd6
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/orm/dao/AmbariConfigurationDAOTest.java
@@ -0,0 +1,298 @@
+/*
+ * 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.orm.dao;
+
+import static org.easymock.EasyMock.capture;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.newCapture;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.persistence.EntityManager;
+
+import org.apache.ambari.server.orm.entities.AmbariConfigurationEntity;
+import org.easymock.Capture;
+import org.easymock.CaptureType;
+import org.easymock.EasyMockSupport;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.inject.Provider;
+
+import junit.framework.Assert;
+
+public class AmbariConfigurationDAOTest extends EasyMockSupport {
+
+  private static final String CATEGORY_NAME = "test-category";
+  private static Method methodMerge;
+  private static Method methodRemove;
+  private static Method methodCreate;
+  private static Method methodFindByCategory;
+
+  private static Field fieldEntityManagerProvider;
+
+  @BeforeClass
+  public static void beforeKDCKerberosOperationHandlerTest() throws Exception {
+    methodMerge = AmbariConfigurationDAO.class.getMethod("merge", AmbariConfigurationEntity.class);
+    methodRemove = CrudDAO.class.getMethod("remove", Object.class);
+    methodCreate = AmbariConfigurationDAO.class.getMethod("create", AmbariConfigurationEntity.class);
+    methodFindByCategory = AmbariConfigurationDAO.class.getMethod("findByCategory", String.class);
+
+    fieldEntityManagerProvider = CrudDAO.class.getDeclaredField("entityManagerProvider");
+  }
+
+  @Test
+  public void testReconcileCategoryNewCategory() throws Exception {
+    Capture<AmbariConfigurationEntity> capturedEntities = newCapture(CaptureType.ALL);
+
+    AmbariConfigurationDAO dao = createDao();
+
+    expect(dao.findByCategory(CATEGORY_NAME)).andReturn(null).once();
+
+    dao.create(capture(capturedEntities));
+    expectLastCall().anyTimes();
+
+    replayAll();
+
+    Map<String, String> properties;
+    properties = new HashMap<>();
+    properties.put("property1", "value1");
+    properties.put("property2", "value2");
+    dao.reconcileCategory(CATEGORY_NAME, properties, true);
+
+    verifyAll();
+
+    validateCapturedEntities(CATEGORY_NAME, properties, capturedEntities);
+  }
+
+  @Test
+  public void testReconcileCategoryReplaceCategory() throws Exception {
+
+    Map<String, String> existingProperties;
+    existingProperties = new HashMap<>();
+    existingProperties.put("property1", "value1");
+    existingProperties.put("property2", "value2");
+
+    Capture<AmbariConfigurationEntity> capturedCreatedEntities = newCapture(CaptureType.ALL);
+    Capture<AmbariConfigurationEntity> capturedRemovedEntities = newCapture(CaptureType.ALL);
+
+    AmbariConfigurationDAO dao = createDao();
+
+    expect(dao.findByCategory(CATEGORY_NAME)).andReturn(toEntities(CATEGORY_NAME, existingProperties)).once();
+
+    dao.remove(capture(capturedRemovedEntities));
+    expectLastCall().anyTimes();
+
+    dao.create(capture(capturedCreatedEntities));
+    expectLastCall().anyTimes();
+
+    replayAll();
+
+    Map<String, String> newProperties;
+    newProperties = new HashMap<>();
+    newProperties.put("property1_new", "value1");
+    newProperties.put("property2_new", "value2");
+    dao.reconcileCategory(CATEGORY_NAME, newProperties, true);
+
+    verifyAll();
+
+    validateCapturedEntities(CATEGORY_NAME, newProperties, capturedCreatedEntities);
+    validateCapturedEntities(CATEGORY_NAME, existingProperties, capturedRemovedEntities);
+  }
+
+  @Test
+  public void testReconcileCategoryUpdateCategoryKeepNotSpecified() throws Exception {
+
+    Map<String, String> existingProperties;
+    existingProperties = new HashMap<>();
+    existingProperties.put("property1", "value1");
+    existingProperties.put("property2", "value2");
+
+    Capture<AmbariConfigurationEntity> capturedCreatedEntities = newCapture(CaptureType.ALL);
+    Capture<AmbariConfigurationEntity> capturedMergedEntities = newCapture(CaptureType.ALL);
+
+    AmbariConfigurationDAO dao = createDao();
+
+    expect(dao.findByCategory(CATEGORY_NAME)).andReturn(toEntities(CATEGORY_NAME, existingProperties)).once();
+
+    expect(dao.merge(capture(capturedMergedEntities))).andReturn(createNiceMock(AmbariConfigurationEntity.class)).anyTimes();
+
+    dao.create(capture(capturedCreatedEntities));
+    expectLastCall().anyTimes();
+
+    replayAll();
+
+    Map<String, String> newProperties;
+    newProperties = new HashMap<>();
+    newProperties.put("property1", "new_value1");
+    newProperties.put("property2_new", "value2");
+    newProperties.put("property3", "value3");
+    dao.reconcileCategory(CATEGORY_NAME, newProperties, false);
+
+    verifyAll();
+
+    Map<String, String> expectedProperties;
+
+    expectedProperties = new HashMap<>();
+    expectedProperties.put("property2_new", "value2");
+    expectedProperties.put("property3", "value3");
+    validateCapturedEntities(CATEGORY_NAME, expectedProperties, capturedCreatedEntities);
+
+    expectedProperties = new HashMap<>();
+    expectedProperties.put("property1", "new_value1");
+    validateCapturedEntities(CATEGORY_NAME, expectedProperties, capturedMergedEntities);
+  }
+
+  @Test
+  public void testReconcileCategoryUpdateCategoryRemoveNotSpecified() throws Exception {
+
+    Map<String, String> existingProperties;
+    existingProperties = new HashMap<>();
+    existingProperties.put("property1", "value1");
+    existingProperties.put("property2", "value2");
+
+    Capture<AmbariConfigurationEntity> capturedCreatedEntities = newCapture(CaptureType.ALL);
+    Capture<AmbariConfigurationEntity> capturedRemovedEntities = newCapture(CaptureType.ALL);
+    Capture<AmbariConfigurationEntity> capturedMergedEntities = newCapture(CaptureType.ALL);
+
+    AmbariConfigurationDAO dao = createDao();
+
+    expect(dao.findByCategory(CATEGORY_NAME)).andReturn(toEntities(CATEGORY_NAME, existingProperties)).once();
+
+    expect(dao.merge(capture(capturedMergedEntities))).andReturn(createNiceMock(AmbariConfigurationEntity.class)).anyTimes();
+
+    dao.remove(capture(capturedRemovedEntities));
+    expectLastCall().anyTimes();
+
+    dao.create(capture(capturedCreatedEntities));
+    expectLastCall().anyTimes();
+
+    replayAll();
+
+    Map<String, String> newProperties;
+    newProperties = new HashMap<>();
+    newProperties.put("property1", "new_value1");
+    newProperties.put("property2_new", "value2");
+    newProperties.put("property3", "value3");
+    dao.reconcileCategory(CATEGORY_NAME, newProperties, true);
+
+    verifyAll();
+
+    Map<String, String> expectedProperties;
+
+    expectedProperties = new HashMap<>();
+    expectedProperties.put("property2_new", "value2");
+    expectedProperties.put("property3", "value3");
+    validateCapturedEntities(CATEGORY_NAME, expectedProperties, capturedCreatedEntities);
+
+    expectedProperties = new HashMap<>();
+    expectedProperties.put("property2", "value2");
+    validateCapturedEntities(CATEGORY_NAME, expectedProperties, capturedRemovedEntities);
+
+    expectedProperties = new HashMap<>();
+    expectedProperties.put("property1", "new_value1");
+    validateCapturedEntities(CATEGORY_NAME, expectedProperties, capturedMergedEntities);
+  }
+
+  @Test
+  public void testReconcileCategoryAppendCategory() throws Exception {
+
+    Map<String, String> existingProperties;
+    existingProperties = new HashMap<>();
+    existingProperties.put("property1", "value1");
+    existingProperties.put("property2", "value2");
+
+    Capture<AmbariConfigurationEntity> capturedCreatedEntities = newCapture(CaptureType.ALL);
+
+    AmbariConfigurationDAO dao = createDao();
+
+    expect(dao.findByCategory(CATEGORY_NAME)).andReturn(toEntities(CATEGORY_NAME, existingProperties)).once();
+
+    dao.create(capture(capturedCreatedEntities));
+    expectLastCall().anyTimes();
+
+    replayAll();
+
+    Map<String, String> newProperties;
+    newProperties = new HashMap<>();
+    newProperties.put("property3", "value3");
+    newProperties.put("property4", "value3");
+    dao.reconcileCategory(CATEGORY_NAME, newProperties, false);
+
+    verifyAll();
+
+    validateCapturedEntities(CATEGORY_NAME, newProperties, capturedCreatedEntities);
+  }
+
+  private AmbariConfigurationDAO createDao() throws IllegalAccessException {
+    AmbariConfigurationDAO dao = createMockBuilder(AmbariConfigurationDAO.class)
+        .addMockedMethods(methodMerge, methodRemove, methodCreate, methodFindByCategory)
+        .createMock();
+
+    EntityManager entityManager = createMock(EntityManager.class);
+    entityManager.flush();
+    expectLastCall().anyTimes();
+
+    Provider<EntityManager> entityManagerProvider = createMock(Provider.class);
+    expect(entityManagerProvider.get()).andReturn(entityManager).anyTimes();
+
+    fieldEntityManagerProvider.set(dao, entityManagerProvider);
+
+    return dao;
+  }
+
+  private List<AmbariConfigurationEntity> toEntities(String categoryName, Map<String, String> properties) {
+    List<AmbariConfigurationEntity> entities = new ArrayList<>();
+
+    for (Map.Entry<String, String> property : properties.entrySet()) {
+      AmbariConfigurationEntity entity = new AmbariConfigurationEntity();
+      entity.setCategoryName(categoryName);
+      entity.setPropertyName(property.getKey());
+      entity.setPropertyValue(property.getValue());
+      entities.add(entity);
+    }
+
+    return entities;
+  }
+
+  private void validateCapturedEntities(String expectedCategoryName, Map<String, String> expectedProperties, Capture<AmbariConfigurationEntity> capturedEntities) {
+    Assert.assertTrue(capturedEntities.hasCaptured());
+
+    List<AmbariConfigurationEntity> entities = capturedEntities.getValues();
+    Assert.assertNotNull(entities);
+
+    Map<String, String> capturedProperties = new TreeMap<>();
+    for (AmbariConfigurationEntity entity : entities) {
+      Assert.assertEquals(expectedCategoryName, entity.getCategoryName());
+      capturedProperties.put(entity.getPropertyName(), entity.getPropertyValue());
+    }
+
+    // Convert the Map to a TreeMap to help with comparisons
+    expectedProperties = new TreeMap<>(expectedProperties);
+    Assert.assertEquals(expectedProperties, capturedProperties);
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/a631d0ed/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog300Test.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog300Test.java b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog300Test.java
index bd8f5cb..747f99b 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog300Test.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/upgrade/UpgradeCatalog300Test.java
@@ -17,6 +17,10 @@
  */
 package org.apache.ambari.server.upgrade;
 
+import static org.apache.ambari.server.upgrade.UpgradeCatalog300.AMBARI_CONFIGURATION_CATEGORY_NAME_COLUMN;
+import static org.apache.ambari.server.upgrade.UpgradeCatalog300.AMBARI_CONFIGURATION_PROPERTY_NAME_COLUMN;
+import static org.apache.ambari.server.upgrade.UpgradeCatalog300.AMBARI_CONFIGURATION_PROPERTY_VALUE_COLUMN;
+import static org.apache.ambari.server.upgrade.UpgradeCatalog300.AMBARI_CONFIGURATION_TABLE;
 import static org.apache.ambari.server.upgrade.UpgradeCatalog300.COMPONENT_DESIRED_STATE_TABLE;
 import static org.apache.ambari.server.upgrade.UpgradeCatalog300.COMPONENT_STATE_TABLE;
 import static org.apache.ambari.server.upgrade.UpgradeCatalog300.SECURITY_STATE_COLUMN;
@@ -42,6 +46,7 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import javax.persistence.EntityManager;
@@ -186,6 +191,15 @@ public class UpgradeCatalog300Test {
     dbAccessor.dropColumn(SERVICE_DESIRED_STATE_TABLE, SECURITY_STATE_COLUMN);
     expectLastCall().once();
 
+    // Ambari configuration table addition...
+    Capture<List<DBAccessor.DBColumnInfo>> ambariConfigurationTableColumns = newCapture();
+
+    dbAccessor.createTable(eq(AMBARI_CONFIGURATION_TABLE), capture(ambariConfigurationTableColumns));
+    expectLastCall().once();
+    dbAccessor.addPKConstraint(AMBARI_CONFIGURATION_TABLE, "PK_ambari_configuration", AMBARI_CONFIGURATION_CATEGORY_NAME_COLUMN, AMBARI_CONFIGURATION_PROPERTY_NAME_COLUMN);
+    expectLastCall().once();
+    // Ambari configuration table addition...
+
     replay(dbAccessor, configuration);
 
     Injector injector = Guice.createInjector(module);
@@ -197,6 +211,35 @@ public class UpgradeCatalog300Test {
     Assert.assertEquals(null, capturedOpsDisplayNameColumn.getDefaultValue());
     Assert.assertEquals(String.class, capturedOpsDisplayNameColumn.getType());
 
+    // Ambari configuration table addition...
+    Assert.assertTrue(ambariConfigurationTableColumns.hasCaptured());
+    List<DBAccessor.DBColumnInfo> columns = ambariConfigurationTableColumns.getValue();
+    Assert.assertEquals(3, columns.size());
+
+    for (DBAccessor.DBColumnInfo column : columns) {
+      String columnName = column.getName();
+
+      if (AMBARI_CONFIGURATION_CATEGORY_NAME_COLUMN.equals(columnName)) {
+        Assert.assertEquals(String.class, column.getType());
+        Assert.assertEquals(Integer.valueOf(100), column.getLength());
+        Assert.assertEquals(null, column.getDefaultValue());
+        Assert.assertFalse(column.isNullable());
+      } else if (AMBARI_CONFIGURATION_PROPERTY_NAME_COLUMN.equals(columnName)) {
+        Assert.assertEquals(String.class, column.getType());
+        Assert.assertEquals(Integer.valueOf(100), column.getLength());
+        Assert.assertEquals(null, column.getDefaultValue());
+        Assert.assertFalse(column.isNullable());
+      } else if (AMBARI_CONFIGURATION_PROPERTY_VALUE_COLUMN.equals(columnName)) {
+        Assert.assertEquals(String.class, column.getType());
+        Assert.assertEquals(Integer.valueOf(255), column.getLength());
+        Assert.assertEquals(null, column.getDefaultValue());
+        Assert.assertTrue(column.isNullable());
+      } else {
+        Assert.fail("Unexpected column name: " + columnName);
+      }
+    }
+    // Ambari configuration table addition...
+
     verify(dbAccessor);
   }