/*
 * 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.configuration;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy;
import static org.powermock.api.easymock.PowerMock.mockStatic;
import static org.powermock.api.easymock.PowerMock.replayAll;
import static org.powermock.api.easymock.PowerMock.verifyAll;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;

import org.apache.ambari.annotations.ConfigurationMarkdown;
import org.apache.ambari.annotations.Markdown;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.configuration.Configuration.ConfigurationProperty;
import org.apache.ambari.server.configuration.Configuration.ConnectionPoolType;
import org.apache.ambari.server.configuration.Configuration.DatabaseType;
import org.apache.ambari.server.controller.metrics.ThreadPoolEnabledPropertyProvider;
import org.apache.ambari.server.security.authentication.kerberos.AmbariKerberosAuthenticationProperties;
import org.apache.ambari.server.state.services.MetricsRetrievalService;
import org.apache.ambari.server.utils.PasswordUtils;
import org.apache.ambari.server.utils.StageUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.api.support.membermodification.MemberMatcher;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import com.google.common.base.Charsets;

import junit.framework.Assert;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ Configuration.class, PasswordUtils.class })
@PowerMockIgnore( {"javax.management.*", "javax.crypto.*"})
public class ConfigurationTest {
  public TemporaryFolder temp = new TemporaryFolder();

  @Before
  public void setup() throws Exception {
    temp.create();
  }

  @After
  public void teardown() throws AmbariException {
    temp.delete();
  }

  /**
   * ambari.properties doesn't contain "security.agent.hostname.validate" option
   */
  @Test
  public void testValidateAgentHostnames() {
    Assert.assertTrue(new Configuration().validateAgentHostnames());
  }

  /**
   * ambari.properties contains "security.agent.hostname.validate=true" option
   */
  @Test
  public void testValidateAgentHostnamesOn() {
    Properties ambariProperties = new Properties();
    ambariProperties.setProperty(Configuration.SRVR_AGENT_HOSTNAME_VALIDATE.getKey(), "true");
    Configuration conf = new Configuration(ambariProperties);
    Assert.assertTrue(conf.validateAgentHostnames());
    Assert.assertEquals("true", conf.getConfigsMap().get(Configuration.SRVR_AGENT_HOSTNAME_VALIDATE.getKey()));
  }

  /**
   * ambari.properties contains "security.agent.hostname.validate=false" option
   */
  @Test
  public void testValidateAgentHostnamesOff() {
    Properties ambariProperties = new Properties();
    ambariProperties.setProperty(Configuration.SRVR_AGENT_HOSTNAME_VALIDATE.getKey(), "false");
    Configuration conf = new Configuration(ambariProperties);
    Assert.assertFalse(conf.validateAgentHostnames());
    Assert.assertEquals("false", conf.getConfigsMap().get(Configuration.SRVR_AGENT_HOSTNAME_VALIDATE.getKey()));
  }

  /**
   * ambari.properties doesn't contain "security.server.two_way_ssl" option
   * @throws Exception
   */
  @Test
  public void testDefaultTwoWayAuthNotSet() throws Exception {
    Assert.assertFalse(new Configuration().isTwoWaySsl());
  }

  /**
   * ambari.properties contains "security.server.two_way_ssl=true" option
   * @throws Exception
   */
  @Test
  public void testTwoWayAuthTurnedOn() throws Exception {
    Properties ambariProperties = new Properties();
    ambariProperties.setProperty("security.server.two_way_ssl", "true");
    Configuration conf = new Configuration(ambariProperties);
    Assert.assertTrue(conf.isTwoWaySsl());
  }

  /**
   * ambari.properties contains "security.server.two_way_ssl=false" option
   * @throws Exception
   */
  @Test
  public void testTwoWayAuthTurnedOff() throws Exception {
    Properties ambariProperties = new Properties();
    ambariProperties.setProperty("security.server.two_way_ssl", "false");
    Configuration conf = new Configuration(ambariProperties);
    Assert.assertFalse(conf.isTwoWaySsl());
  }

  @Test
  public void testGetClientSSLApiPort() throws Exception {
    Properties ambariProperties = new Properties();
    ambariProperties.setProperty(Configuration.CLIENT_API_SSL_PORT.getKey(), "6666");
    Configuration conf = new Configuration(ambariProperties);
    Assert.assertEquals(6666, conf.getClientSSLApiPort());
    conf = new Configuration();
    Assert.assertEquals(8443, conf.getClientSSLApiPort());
  }

  @Test
  public void testGetMpacksV2StagingPath() {
    Properties ambariProperties = new Properties();
    ambariProperties.setProperty(Configuration.MPACKS_V2_STAGING_DIR_PATH.getKey(), "/var/lib/ambari-server/resources/mpacks-v2/");
    Configuration conf = new Configuration(ambariProperties);
    Assert.assertEquals("/var/lib/ambari-server/resources/mpacks-v2/", conf.getMpacksV2StagingPath());
    conf = new Configuration();
    Assert.assertEquals(null, conf.getMpacksV2StagingPath());
  }

  @Test
  public void testGetClientHTTPSSettings() throws IOException {

    File passFile = File.createTempFile("https.pass.", "txt");
    passFile.deleteOnExit();

    String password = "pass12345";

    FileUtils.writeStringToFile(passFile, password, Charset.defaultCharset());

    Properties ambariProperties = new Properties();
    ambariProperties.setProperty(Configuration.API_USE_SSL.getKey(), "true");
    ambariProperties.setProperty(
        Configuration.CLIENT_API_SSL_KSTR_DIR_NAME.getKey(),
        passFile.getParent());
    ambariProperties.setProperty(
        Configuration.CLIENT_API_SSL_CRT_PASS_FILE_NAME.getKey(),
        passFile.getName());


    String oneWayPort = RandomStringUtils.randomNumeric(4);
    String twoWayPort = RandomStringUtils.randomNumeric(4);

    ambariProperties.setProperty(Configuration.SRVR_TWO_WAY_SSL_PORT.getKey(), twoWayPort.toString());
    ambariProperties.setProperty(Configuration.SRVR_ONE_WAY_SSL_PORT.getKey(), oneWayPort.toString());

    Configuration conf = new Configuration(ambariProperties);
    Assert.assertTrue(conf.getApiSSLAuthentication());

    //Different certificates for two-way SSL and HTTPS
    Assert.assertFalse(conf.getConfigsMap().get(Configuration.KSTR_NAME.getKey()).
      equals(conf.getConfigsMap().get(Configuration.CLIENT_API_SSL_KSTR_NAME.getKey())));

    Assert.assertEquals("keystore.p12", conf.getConfigsMap().get(
        Configuration.KSTR_NAME.getKey()));
    Assert.assertEquals("PKCS12", conf.getConfigsMap().get(
        Configuration.KSTR_TYPE.getKey()));
    Assert.assertEquals("keystore.p12", conf.getConfigsMap().get(
        Configuration.TSTR_NAME.getKey()));
    Assert.assertEquals("PKCS12", conf.getConfigsMap().get(
        Configuration.TSTR_TYPE.getKey()));

    Assert.assertEquals("https.keystore.p12", conf.getConfigsMap().get(
      Configuration.CLIENT_API_SSL_KSTR_NAME.getKey()));
    Assert.assertEquals("PKCS12", conf.getConfigsMap().get(
        Configuration.CLIENT_API_SSL_KSTR_TYPE.getKey()));
    Assert.assertEquals("https.keystore.p12", conf.getConfigsMap().get(
        Configuration.CLIENT_API_SSL_TSTR_NAME.getKey()));
    Assert.assertEquals("PKCS12", conf.getConfigsMap().get(
        Configuration.CLIENT_API_SSL_TSTR_TYPE.getKey()));
    Assert.assertEquals(passFile.getName(), conf.getConfigsMap().get(
      Configuration.CLIENT_API_SSL_CRT_PASS_FILE_NAME.getKey()));
    Assert.assertEquals(password, conf.getConfigsMap().get(Configuration.CLIENT_API_SSL_CRT_PASS.getKey()));
    Assert.assertEquals(Integer.parseInt(twoWayPort), conf.getTwoWayAuthPort());
    Assert.assertEquals(Integer.parseInt(oneWayPort), conf.getOneWayAuthPort());

  }

  @Test
  public void testLoadSSLParams_unencrypted() throws IOException {
    Properties ambariProperties = new Properties();
    String unencrypted = "fake-unencrypted-password";
    String encrypted = "fake-encrypted-password";
    ambariProperties.setProperty(Configuration.SSL_TRUSTSTORE_PASSWORD.getKey(), unencrypted);
    Configuration conf = spy(new Configuration(ambariProperties));
    PowerMock.stub(PowerMock.method(PasswordUtils.class, "readPasswordFromStore", String.class, Configuration.class)).toReturn(null);
    conf.loadSSLParams();
    Assert.assertEquals(System.getProperty(Configuration.JAVAX_SSL_TRUSTSTORE_PASSWORD, "unknown"), unencrypted);
  }

  @Test
  public void testLoadSSLParams_encrypted() throws IOException {
    Properties ambariProperties = new Properties();
    String unencrypted = "fake-unencrypted-password";
    String encrypted = "fake-encrypted-password";
    ambariProperties.setProperty(Configuration.SSL_TRUSTSTORE_PASSWORD.getKey(), unencrypted);
    Configuration conf = spy(new Configuration(ambariProperties));
    PowerMock.stub(PowerMock.method(PasswordUtils.class, "readPasswordFromStore", String.class, Configuration.class)).toReturn(encrypted);
    conf.loadSSLParams();
    Assert.assertEquals(System.getProperty(Configuration.JAVAX_SSL_TRUSTSTORE_PASSWORD, "unknown"), encrypted);
  }

  @Test
  public void testGetRcaDatabasePassword_fromStore() {
    String serverJdbcRcaUserPasswdKey = "key";
    String encrypted = "password";

    Properties properties = new Properties();
    properties.setProperty(Configuration.SERVER_JDBC_RCA_USER_PASSWD.getKey(), serverJdbcRcaUserPasswdKey);
    Configuration conf = spy(new Configuration(properties));
    PowerMock.stub(PowerMock.method(PasswordUtils.class, "readPassword")).toReturn(encrypted);

    Assert.assertEquals(encrypted, conf.getRcaDatabasePassword());
  }

  @Test
  public void testGetRcaDatabasePassword_fromFile() {
    Configuration conf = spy(new Configuration(new Properties()));
    Assert.assertEquals("mapred", conf.getRcaDatabasePassword());
  }

  @Test
  public void testGetLocalDatabaseUrl() {
    Properties ambariProperties = new Properties();
    ambariProperties.setProperty("server.jdbc.database_name", "ambaritestdatabase");
    Configuration conf = new Configuration(ambariProperties);
    Assert.assertEquals(conf.getLocalDatabaseUrl(), Configuration.JDBC_LOCAL_URL.concat("ambaritestdatabase"));
  }

  @Test
  public void testNoNewlineInPassword() throws Exception {
    Properties ambariProperties = new Properties();
    File f = temp.newFile("password.dat");
    FileOutputStream fos = new FileOutputStream(f);
    fos.write("ambaritest\r\n".getBytes());
    fos.close();
    String passwordFile = temp.getRoot().getAbsolutePath()
      + System.getProperty("file.separator") + "password.dat";

    ambariProperties.setProperty(Configuration.SERVER_JDBC_USER_PASSWD.getKey(),
      passwordFile);

    Configuration conf = new Configuration(ambariProperties);
    PowerMock.stub(PowerMock.method(PasswordUtils.class,"readPasswordFromStore", String.class, Configuration.class)).toReturn(null);

    Assert.assertEquals("ambaritest", conf.getDatabasePassword());
  }

  @Test
  public void testGetAmbariProperties() throws Exception {
    Properties ambariProperties = new Properties();
    ambariProperties.setProperty("name", "value");
    Configuration conf = new Configuration(ambariProperties);
    mockStatic(Configuration.class);
    Method[] methods = MemberMatcher.methods(Configuration.class, "readConfigFile");
    PowerMock.expectPrivate(Configuration.class, methods[0]).andReturn(ambariProperties);
    replayAll();
    Map<String, String> props = conf.getAmbariProperties();
    verifyAll();
    Assert.assertEquals("value", props.get("name"));
  }

  @Test
  public void testGetAmbariBlacklistFile() {
    Properties ambariProperties = new Properties();
    Configuration conf = new Configuration(ambariProperties);
    Assert.assertEquals(null, conf.getAmbariBlacklistFile());
    ambariProperties = new Properties();
    ambariProperties.setProperty(Configuration.PROPERTY_MASK_FILE.getKey(), "ambari-blacklist.properties");
    conf = new Configuration(ambariProperties);
    Assert.assertEquals("ambari-blacklist.properties", conf.getAmbariBlacklistFile());
  }

  @Rule
  public ExpectedException exception = ExpectedException.none();

  @Test()
  public void testGetLocalDatabaseUrlThrowException() {
    Properties ambariProperties = new Properties();
    Configuration conf = new Configuration(ambariProperties);
    exception.expect(RuntimeException.class);
    exception.expectMessage("Server DB Name is not configured!");
    conf.getLocalDatabaseUrl();
  }

  @Test()
  public void testServerPoolSizes() {
    Properties ambariProperties = new Properties();
    Configuration conf = new Configuration(ambariProperties);

    Assert.assertEquals(25, conf.getClientThreadPoolSize());
    Assert.assertEquals(25, conf.getAgentThreadPoolSize());

    Assert.assertEquals(10, conf.getViewExtractionThreadPoolCoreSize());
    Assert.assertEquals(20, conf.getViewExtractionThreadPoolMaxSize());
    Assert.assertEquals(100000L, conf.getViewExtractionThreadPoolTimeout());

    ambariProperties = new Properties();
    ambariProperties.setProperty("client.threadpool.size.max", "4");
    ambariProperties.setProperty("agent.threadpool.size.max", "82");

    ambariProperties.setProperty("view.extraction.threadpool.size.core", "83");
    ambariProperties.setProperty("view.extraction.threadpool.size.max", "56");
    ambariProperties.setProperty("view.extraction.threadpool.timeout", "6000");

    conf = new Configuration(ambariProperties);

    Assert.assertEquals(4, conf.getClientThreadPoolSize());
    Assert.assertEquals(82, conf.getAgentThreadPoolSize());

    Assert.assertEquals(83, conf.getViewExtractionThreadPoolCoreSize());
    Assert.assertEquals(56, conf.getViewExtractionThreadPoolMaxSize());
    Assert.assertEquals(6000L, conf.getViewExtractionThreadPoolTimeout());
  }

  @Test()
  public void testGetDefaultAgentTaskTimeout() {
    Properties ambariProperties = new Properties();
    Configuration conf = new Configuration(ambariProperties);

    Assert.assertEquals("900", conf.getDefaultAgentTaskTimeout(false));
    Assert.assertEquals("1800", conf.getDefaultAgentTaskTimeout(true));

    ambariProperties = new Properties();
    ambariProperties.setProperty("agent.task.timeout", "4");
    ambariProperties.setProperty("agent.package.install.task.timeout", "82");

    conf = new Configuration(ambariProperties);

    Assert.assertEquals("4", conf.getDefaultAgentTaskTimeout(false));
    Assert.assertEquals("82", conf.getDefaultAgentTaskTimeout(true));
  }


  @Test
  public void testGetDefaultServerTaskTimeout() {
    Properties ambariProperties = new Properties();
    Configuration conf = new Configuration(ambariProperties);

    Assert.assertEquals(Integer.valueOf(1200), conf.getDefaultServerTaskTimeout());

    ambariProperties = new Properties();
    ambariProperties.setProperty(Configuration.SERVER_TASK_TIMEOUT.getKey(), "3600");

    conf = new Configuration(ambariProperties);

    Assert.assertEquals(Integer.valueOf(3600), conf.getDefaultServerTaskTimeout());
  }

  @Test
  public void testIsViewValidationEnabled() throws Exception {
    final Properties ambariProperties = new Properties();
    Configuration configuration = new Configuration(ambariProperties);
    Assert.assertFalse(configuration.isViewValidationEnabled());

    ambariProperties.setProperty(Configuration.VIEWS_VALIDATE.getKey(), "false");
    configuration = new Configuration(ambariProperties);
    Assert.assertFalse(configuration.isViewValidationEnabled());

    ambariProperties.setProperty(Configuration.VIEWS_VALIDATE.getKey(), "true");
    configuration = new Configuration(ambariProperties);
    Assert.assertTrue(configuration.isViewValidationEnabled());
  }

  @Test
  public void testIsViewRemoveUndeployedEnabled() throws Exception {
    final Properties ambariProperties = new Properties();
    Configuration configuration = new Configuration(ambariProperties);
    Assert.assertFalse(configuration.isViewRemoveUndeployedEnabled());

    ambariProperties.setProperty(Configuration.VIEWS_REMOVE_UNDEPLOYED.getKey(), "false");
    configuration = new Configuration(ambariProperties);
    Assert.assertFalse(configuration.isViewRemoveUndeployedEnabled());

    ambariProperties.setProperty(Configuration.VIEWS_REMOVE_UNDEPLOYED.getKey(), "true");
    configuration = new Configuration(ambariProperties);
    Assert.assertTrue(configuration.isViewRemoveUndeployedEnabled());

    ambariProperties.setProperty(Configuration.VIEWS_REMOVE_UNDEPLOYED.getKey(),
        Configuration.VIEWS_REMOVE_UNDEPLOYED.getDefaultValue());

    configuration = new Configuration(ambariProperties);
    Assert.assertFalse(configuration.isViewRemoveUndeployedEnabled());
  }

  @Test
  public void testConnectionPoolingProperties() throws Exception {
    // test defaults
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);
    Assert.assertEquals(ConnectionPoolType.INTERNAL, configuration.getConnectionPoolType());
    Assert.assertEquals(5, configuration.getConnectionPoolAcquisitionSize());
    Assert.assertEquals(7200, configuration.getConnectionPoolIdleTestInternval());
    Assert.assertEquals(0, configuration.getConnectionPoolMaximumAge());
    Assert.assertEquals(0, configuration.getConnectionPoolMaximumExcessIdle());
    Assert.assertEquals(14400, configuration.getConnectionPoolMaximumIdle());
    Assert.assertEquals(32, configuration.getConnectionPoolMaximumSize());
    Assert.assertEquals(5, configuration.getConnectionPoolMinimumSize());
    Assert.assertEquals(30, configuration.getConnectionPoolAcquisitionRetryAttempts());
    Assert.assertEquals(1000, configuration.getConnectionPoolAcquisitionRetryDelay());

    ambariProperties.setProperty(Configuration.SERVER_JDBC_CONNECTION_POOL.getKey(), ConnectionPoolType.C3P0.getName());
    ambariProperties.setProperty(Configuration.SERVER_JDBC_CONNECTION_POOL_MIN_SIZE.getKey(), "1");
    ambariProperties.setProperty(Configuration.SERVER_JDBC_CONNECTION_POOL_MAX_SIZE.getKey(), "2");
    ambariProperties.setProperty(Configuration.SERVER_JDBC_CONNECTION_POOL_AQUISITION_SIZE.getKey(), "3");
    ambariProperties.setProperty(Configuration.SERVER_JDBC_CONNECTION_POOL_MAX_AGE.getKey(), "4");
    ambariProperties.setProperty(Configuration.SERVER_JDBC_CONNECTION_POOL_MAX_IDLE_TIME.getKey(), "5");
    ambariProperties.setProperty(Configuration.SERVER_JDBC_CONNECTION_POOL_MAX_IDLE_TIME_EXCESS.getKey(), "6");
    ambariProperties.setProperty(Configuration.SERVER_JDBC_CONNECTION_POOL_IDLE_TEST_INTERVAL.getKey(), "7");
    ambariProperties.setProperty(Configuration.SERVER_JDBC_CONNECTION_POOL_ACQUISITION_RETRY_ATTEMPTS.getKey(), "8");
    ambariProperties.setProperty(Configuration.SERVER_JDBC_CONNECTION_POOL_ACQUISITION_RETRY_DELAY.getKey(), "9");


    Assert.assertEquals(ConnectionPoolType.C3P0, configuration.getConnectionPoolType());
    Assert.assertEquals(3, configuration.getConnectionPoolAcquisitionSize());
    Assert.assertEquals(7, configuration.getConnectionPoolIdleTestInternval());
    Assert.assertEquals(4, configuration.getConnectionPoolMaximumAge());
    Assert.assertEquals(6, configuration.getConnectionPoolMaximumExcessIdle());
    Assert.assertEquals(5, configuration.getConnectionPoolMaximumIdle());
    Assert.assertEquals(2, configuration.getConnectionPoolMaximumSize());
    Assert.assertEquals(1, configuration.getConnectionPoolMinimumSize());
    Assert.assertEquals(8, configuration.getConnectionPoolAcquisitionRetryAttempts());
    Assert.assertEquals(9, configuration.getConnectionPoolAcquisitionRetryDelay());
  }

  @Test
  public void testDatabaseType() throws Exception {
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);

    ambariProperties.setProperty(Configuration.SERVER_JDBC_URL.getKey(), "jdbc:oracle://server");
    Assert.assertEquals( DatabaseType.ORACLE, configuration.getDatabaseType() );

    ambariProperties.setProperty(Configuration.SERVER_JDBC_URL.getKey(), "jdbc:postgres://server");
    Assert.assertEquals( DatabaseType.POSTGRES, configuration.getDatabaseType() );

    ambariProperties.setProperty(Configuration.SERVER_JDBC_URL.getKey(), "jdbc:mysql://server");
    Assert.assertEquals( DatabaseType.MYSQL, configuration.getDatabaseType() );

    ambariProperties.setProperty(Configuration.SERVER_JDBC_URL.getKey(), "jdbc:derby://server");
    Assert.assertEquals( DatabaseType.DERBY, configuration.getDatabaseType() );

    ambariProperties.setProperty(Configuration.SERVER_JDBC_URL.getKey(), "jdbc:sqlserver://server");
    Assert.assertEquals( DatabaseType.SQL_SERVER, configuration.getDatabaseType() );
  }

  @Test
  public void testGetAgentPackageParallelCommandsLimit() throws Exception {
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);

    Assert.assertEquals(100, configuration.getAgentPackageParallelCommandsLimit());

    ambariProperties.setProperty(Configuration.AGENT_PACKAGE_PARALLEL_COMMANDS_LIMIT.getKey(), "5");
    Assert.assertEquals(5, configuration.getAgentPackageParallelCommandsLimit());

    ambariProperties.setProperty(Configuration.AGENT_PACKAGE_PARALLEL_COMMANDS_LIMIT.getKey(), "0");
    Assert.assertEquals(1, configuration.getAgentPackageParallelCommandsLimit());
  }

  @Test
  public void testGetExecutionSchedulerWait() throws Exception {
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);

    //default
    Assert.assertEquals(new Long(1000L), configuration.getExecutionSchedulerWait());

    ambariProperties.setProperty(Configuration.EXECUTION_SCHEDULER_WAIT.getKey(), "5");
    Assert.assertEquals(new Long(5000L), configuration.getExecutionSchedulerWait());
    // > 60 secs
    ambariProperties.setProperty(Configuration.EXECUTION_SCHEDULER_WAIT.getKey(), "100");
    Assert.assertEquals(new Long(60000L), configuration.getExecutionSchedulerWait());
    //not a number
    ambariProperties.setProperty(Configuration.EXECUTION_SCHEDULER_WAIT.getKey(), "100m");
    Assert.assertEquals(new Long(1000L), configuration.getExecutionSchedulerWait());
  }

  @Test
  public void testServerLocksProfilingEnabled() throws Exception {
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);

    Assert.assertFalse(configuration.isServerLocksProfilingEnabled());

    ambariProperties.setProperty(Configuration.SERVER_LOCKS_PROFILING.getKey(), Boolean.TRUE.toString());

    Assert.assertTrue(configuration.isServerLocksProfilingEnabled());
  }

  @Test
  public void testAlertCaching() throws Exception {
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);

    Assert.assertFalse(configuration.isAlertCacheEnabled());

    ambariProperties.setProperty(Configuration.ALERTS_CACHE_ENABLED.getKey(), Boolean.TRUE.toString());
    ambariProperties.setProperty(Configuration.ALERTS_CACHE_FLUSH_INTERVAL.getKey(), "60");
    ambariProperties.setProperty(Configuration.ALERTS_CACHE_SIZE.getKey(), "1000");

    Assert.assertTrue(configuration.isAlertCacheEnabled());
    Assert.assertEquals(60, configuration.getAlertCacheFlushInterval());
    Assert.assertEquals(1000, configuration.getAlertCacheSize());
  }

  @Test
  public void testPropertyProviderThreadPoolSizes() throws Exception {
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);

    Assert.assertEquals(2 * Runtime.getRuntime().availableProcessors(), configuration.getPropertyProvidersThreadPoolCoreSize());
    Assert.assertEquals(4 * Runtime.getRuntime().availableProcessors(), configuration.getPropertyProvidersThreadPoolMaxSize());

    ambariProperties.setProperty(Configuration.PROPERTY_PROVIDER_THREADPOOL_MAX_SIZE.getKey(), "44");
    ambariProperties.setProperty(Configuration.PROPERTY_PROVIDER_THREADPOOL_CORE_SIZE.getKey(), "22");

    Assert.assertEquals(22, configuration.getPropertyProvidersThreadPoolCoreSize());
    Assert.assertEquals(44, configuration.getPropertyProvidersThreadPoolMaxSize());
  }


  public void testGetHostRoleCommandStatusSummaryCacheSize() throws  Exception {
    // Given
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);
    ambariProperties.setProperty(Configuration.SERVER_HRC_STATUS_SUMMARY_CACHE_SIZE.getKey(), "3000");

    // When
    long actualCacheSize = configuration.getHostRoleCommandStatusSummaryCacheSize();

    // Then
    Assert.assertEquals(actualCacheSize, 3000L);
  }

  @Test
  public void testGetHostRoleCommandStatusSummaryCacheSizeDefault() throws  Exception {
    // Given
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);

    // When
    Long actualCacheSize = configuration.getHostRoleCommandStatusSummaryCacheSize();

    // Then
    Assert.assertEquals(actualCacheSize, Configuration.SERVER_HRC_STATUS_SUMMARY_CACHE_SIZE.getDefaultValue());
  }

  @Test
  public void testGetHostRoleCommandStatusSummaryCacheExpiryDuration() throws  Exception {
    // Given
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);
    ambariProperties.setProperty(Configuration.SERVER_HRC_STATUS_SUMMARY_CACHE_EXPIRY_DURATION.getKey(), "60");

    // When
    long actualCacheExpiryDuration = configuration.getHostRoleCommandStatusSummaryCacheExpiryDuration();

    // Then
    Assert.assertEquals(actualCacheExpiryDuration, 60L);
  }

  @Test
  public void testGetHostRoleCommandStatusSummaryCacheExpiryDurationDefault() throws  Exception {
    // Given
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);

    // When
    Long actualCacheExpiryDuration = configuration.getHostRoleCommandStatusSummaryCacheExpiryDuration();

    // Then
    Assert.assertEquals(actualCacheExpiryDuration, Configuration.SERVER_HRC_STATUS_SUMMARY_CACHE_EXPIRY_DURATION.getDefaultValue());
  }

  @Test
  public void testGetHostRoleCommandStatusSummaryCacheEnabled() throws  Exception {
    // Given
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);
    ambariProperties.setProperty(Configuration.SERVER_HRC_STATUS_SUMMARY_CACHE_ENABLED.getKey(), "true");

    // When
    boolean actualCacheEnabledConfig = configuration.getHostRoleCommandStatusSummaryCacheEnabled();

    // Then
    Assert.assertEquals(actualCacheEnabledConfig, true);
  }

  @Test
  public void testGetHostRoleCommandStatusSummaryCacheDisabled() throws  Exception {
    // Given
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);
    ambariProperties.setProperty(Configuration.SERVER_HRC_STATUS_SUMMARY_CACHE_ENABLED.getKey(), "false");

    // When
    boolean actualCacheEnabledConfig = configuration.getHostRoleCommandStatusSummaryCacheEnabled();

    // Then
    Assert.assertEquals(actualCacheEnabledConfig, false);
  }

  @Test
  public void testGetHostRoleCommandStatusSummaryCacheEnabledDefault() throws  Exception {
    // Given
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);

    // When
    Boolean actualCacheEnabledConfig = configuration.getHostRoleCommandStatusSummaryCacheEnabled();

    // Then
    Assert.assertEquals(actualCacheEnabledConfig, Configuration.SERVER_HRC_STATUS_SUMMARY_CACHE_ENABLED.getDefaultValue());
  }

  @Test
  public void testCustomDatabaseProperties() throws Exception {
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);
    ambariProperties.setProperty("server.jdbc.properties.foo", "fooValue");
    ambariProperties.setProperty("server.jdbc.properties.bar", "barValue");

    Properties properties = configuration.getDatabaseCustomProperties();
    Assert.assertEquals(2, properties.size());
    Assert.assertEquals("fooValue", properties.getProperty("eclipselink.jdbc.property.foo"));
    Assert.assertEquals("barValue", properties.getProperty("eclipselink.jdbc.property.bar"));
  }

  @Test
  public void testCustomPersistenceProperties() throws Exception {
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);
    ambariProperties.setProperty("server.persistence.properties.eclipselink.cache.coordination.channel", "FooChannel");
    ambariProperties.setProperty("server.persistence.properties.eclipselink.persistence-context.flush-mode", "commit");

    Properties properties = configuration.getPersistenceCustomProperties();
    Assert.assertEquals(2, properties.size());
    Assert.assertEquals("FooChannel", properties.getProperty("eclipselink.cache.coordination.channel"));
    Assert.assertEquals("commit", properties.getProperty("eclipselink.persistence-context.flush-mode"));
  }

  /**
   * Tests the default values for the {@link ThreadPoolEnabledPropertyProvider}.
   *
   * @throws Exception
   */
  @Test
  public void testThreadPoolEnabledPropertyProviderDefaults() throws Exception {
    final int SMALLEST_COMPLETION_SERIVCE_TIMEOUT_MS = 1000;
    final int LARGEST_COMPLETION_SERIVCE_TIMEOUT_MS = 5000;

    int processorCount = Runtime.getRuntime().availableProcessors();
    final Properties ambariProperties = new Properties();
    final Configuration configuration = new Configuration(ambariProperties);

    long completionServiceTimeout = configuration.getPropertyProvidersCompletionServiceTimeout();
    int corePoolSize = configuration.getPropertyProvidersThreadPoolCoreSize();
    int maxPoolSize = configuration.getPropertyProvidersThreadPoolMaxSize();
    int workerQueueSize = configuration.getPropertyProvidersWorkerQueueSize();

    // test defaults
    Assert.assertEquals(5000, completionServiceTimeout);
    Assert.assertEquals(Configuration.PROCESSOR_BASED_THREADPOOL_CORE_SIZE_DEFAULT, corePoolSize);
    Assert.assertEquals(Configuration.PROCESSOR_BASED_THREADPOOL_MAX_SIZE_DEFAULT, maxPoolSize);
    Assert.assertEquals(Integer.MAX_VALUE, workerQueueSize);

    // now let's test to make sure these all make sense
    Assert.assertTrue(completionServiceTimeout >= SMALLEST_COMPLETION_SERIVCE_TIMEOUT_MS);
    Assert.assertTrue(completionServiceTimeout <= LARGEST_COMPLETION_SERIVCE_TIMEOUT_MS);
    Assert.assertTrue(corePoolSize <= maxPoolSize);
    Assert.assertTrue(corePoolSize > 2 && corePoolSize <= 128);
    Assert.assertTrue(maxPoolSize > 2 && maxPoolSize <= processorCount * 4);
    Assert.assertTrue(workerQueueSize > processorCount * 10);
  }

  /**
   * Tests that the Kerberos-authentication properties are read and properly and set in an
