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

import static org.apache.ambari.server.upgrade.UpgradeCatalog270.ADMINPRIVILEGE_PERMISSION_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.ADMINPRIVILEGE_PRINCIPAL_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.ADMINPRIVILEGE_PRIVILEGE_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.ADMINPRIVILEGE_RESOURCE_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.ADMINPRIVILEGE_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_CONFIGURATION_CATEGORY_NAME_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_CONFIGURATION_PROPERTY_NAME_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_CONFIGURATION_PROPERTY_VALUE_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_CONFIGURATION_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_INFRA_NEW_NAME;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_INFRA_OLD_NAME;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_SEQUENCES_SEQUENCE_NAME_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_SEQUENCES_SEQUENCE_VALUE_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.AMBARI_SEQUENCES_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.COMPONENT_DESIRED_STATE_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.COMPONENT_NAME_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.COMPONENT_STATE_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.FK_HOSTCOMPONENTDESIREDSTATE_COMPONENT_NAME;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.FK_HOSTCOMPONENTSTATE_COMPONENT_NAME;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.FK_KKP_HOST_ID;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.FK_KKP_KEYTAB_PATH;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.FK_KKP_PRINCIPAL_NAME;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.FK_KKP_SERVICE_PRINCIPAL;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.FK_SERVICECOMPONENTDESIREDSTATE_SERVICE_NAME;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.HOSTS_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.HOST_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.KERBEROS_KEYTAB_PRINCIPAL_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.KERBEROS_KEYTAB_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.KERBEROS_PRINCIPAL_HOST_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.KERBEROS_PRINCIPAL_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.KEYTAB_PATH_FIELD;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.KKP_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.KKP_MAPPING_SERVICE_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.MEMBERS_GROUP_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.MEMBERS_MEMBER_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.MEMBERS_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.MEMBERS_USER_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.PK_KERBEROS_KEYTAB;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.PK_KKP;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.PK_KKP_MAPPING_SERVICE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.PRINCIPAL_NAME_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_APPLICABLE_SERVICES_FOREIGN_KEY;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_APPLICABLE_SERVICES_REPO_DEFINITION_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_APPLICABLE_SERVICES_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_BASE_URL_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_COMPONENTS_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_DISTRIBUTION_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_FOREIGN_KEY;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_MIRRORS_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_PRIMARY_KEY;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_REPO_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_REPO_NAME_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_REPO_OS_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_DEFINITION_UNIQUE_REPO_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_OS_AMBARI_MANAGED_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_OS_FAMILY_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_OS_FOREIGN_KEY;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_OS_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_OS_PRIMARY_KEY;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_OS_REPO_VERSION_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_OS_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_TAGS_FOREIGN_KEY;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_TAGS_REPO_DEFINITION_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_TAGS_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_TAGS_TAG_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_VERSION_REPOSITORIES_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_VERSION_REPO_VERSION_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REPO_VERSION_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REQUEST_DISPLAY_STATUS_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REQUEST_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.REQUEST_USER_NAME_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.SECURITY_STATE_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.SERVICE_COMPONENT_DESIRED_STATE_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.SERVICE_DESIRED_STATE_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.SERVICE_NAME_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.STAGE_DISPLAY_STATUS_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.STAGE_STATUS_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.STAGE_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.UNIQUE_USERS_0_INDEX;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.UNI_KKP;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USERS_CONSECUTIVE_FAILURES_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USERS_CREATE_TIME_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USERS_DISPLAY_NAME_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USERS_LDAP_USER_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USERS_LOCAL_USERNAME_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USERS_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USERS_USER_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USERS_USER_NAME_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USERS_USER_PASSWORD_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USERS_USER_TYPE_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USERS_VERSION_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USER_AUTHENTICATION_AUTHENTICATION_KEY_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USER_AUTHENTICATION_AUTHENTICATION_TYPE_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USER_AUTHENTICATION_CREATE_TIME_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USER_AUTHENTICATION_PRIMARY_KEY;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USER_AUTHENTICATION_TABLE;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USER_AUTHENTICATION_UPDATE_TIME_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USER_AUTHENTICATION_USER_AUTHENTICATION_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USER_AUTHENTICATION_USER_AUTHENTICATION_USERS_FOREIGN_KEY;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.USER_AUTHENTICATION_USER_ID_COLUMN;
import static org.apache.ambari.server.upgrade.UpgradeCatalog270.WIDGET_TABLE;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.anyString;
import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.createMockBuilder;
import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.createStrictMock;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.mock;
import static org.easymock.EasyMock.newCapture;
import static org.easymock.EasyMock.niceMock;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reset;
import static org.easymock.EasyMock.startsWith;
import static org.easymock.EasyMock.verify;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyInt;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManager;

import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.actionmanager.ActionDBAccessor;
import org.apache.ambari.server.actionmanager.ActionDBAccessorImpl;
import org.apache.ambari.server.actionmanager.ActionManager;
import org.apache.ambari.server.actionmanager.HostRoleCommandFactory;
import org.apache.ambari.server.actionmanager.HostRoleCommandFactoryImpl;
import org.apache.ambari.server.actionmanager.HostRoleStatus;
import org.apache.ambari.server.actionmanager.StageFactory;
import org.apache.ambari.server.actionmanager.StageFactoryImpl;
import org.apache.ambari.server.agent.stomp.AgentConfigsHolder;
import org.apache.ambari.server.agent.stomp.MetadataHolder;
import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.audit.AuditLogger;
import org.apache.ambari.server.audit.AuditLoggerDefaultImpl;
import org.apache.ambari.server.configuration.AmbariServerConfigurationCategory;
import org.apache.ambari.server.configuration.AmbariServerConfigurationKey;
import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.controller.AbstractRootServiceResponseFactory;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.AmbariManagementControllerImpl;
import org.apache.ambari.server.controller.AmbariServer;
import org.apache.ambari.server.controller.ConfigurationRequest;
import org.apache.ambari.server.controller.KerberosHelper;
import org.apache.ambari.server.controller.KerberosHelperImpl;
import org.apache.ambari.server.controller.MaintenanceStateHelper;
import org.apache.ambari.server.controller.RootServiceResponseFactory;
import org.apache.ambari.server.controller.ServiceConfigVersionResponse;
import org.apache.ambari.server.hooks.HookService;
import org.apache.ambari.server.hooks.users.UserHookService;
import org.apache.ambari.server.metadata.CachedRoleCommandOrderProvider;
import org.apache.ambari.server.metadata.RoleCommandOrderProvider;
import org.apache.ambari.server.mpack.MpackManagerFactory;
import org.apache.ambari.server.orm.DBAccessor;
import org.apache.ambari.server.orm.dao.AmbariConfigurationDAO;
import org.apache.ambari.server.orm.dao.ArtifactDAO;
import org.apache.ambari.server.orm.entities.ArtifactEntity;
import org.apache.ambari.server.scheduler.ExecutionScheduler;
import org.apache.ambari.server.security.SecurityHelper;
import org.apache.ambari.server.security.encryption.CredentialStoreService;
import org.apache.ambari.server.serveraction.kerberos.PrepareKerberosIdentitiesServerAction;
import org.apache.ambari.server.stack.StackManagerFactory;
import org.apache.ambari.server.stack.upgrade.orchestrate.UpgradeContextFactory;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.state.Config;
import org.apache.ambari.server.state.ConfigHelper;
import org.apache.ambari.server.state.Host;
import org.apache.ambari.server.state.SecurityType;
import org.apache.ambari.server.state.Service;
import org.apache.ambari.server.state.ServiceComponentHostFactory;
import org.apache.ambari.server.state.ServiceFactory;
import org.apache.ambari.server.state.ServiceImpl;
import org.apache.ambari.server.state.StackId;
import org.apache.ambari.server.state.State;
import org.apache.ambari.server.state.cluster.ClusterFactory;
import org.apache.ambari.server.state.cluster.ClusterImpl;
import org.apache.ambari.server.state.cluster.ClustersImpl;
import org.apache.ambari.server.state.host.HostFactory;
import org.apache.ambari.server.state.host.HostImpl;
import org.apache.ambari.server.state.stack.OsFamily;
import org.apache.ambari.server.testutils.PartialNiceMockBinder;
import org.apache.ambari.server.topology.PersistedState;
import org.apache.ambari.server.topology.PersistedStateImpl;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.easymock.Capture;
import org.easymock.CaptureType;
import org.easymock.EasyMock;
import org.easymock.EasyMockRunner;
import org.easymock.EasyMockSupport;
import org.easymock.Mock;
import org.easymock.MockType;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.StandardPasswordEncoder;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.persist.UnitOfWork;

@RunWith(EasyMockRunner.class)
public class UpgradeCatalog270Test {
  public static final Gson GSON = new Gson();
  @Rule
  public ExpectedException expectedException = ExpectedException.none();

  @Mock(type = MockType.STRICT)
  private Provider<EntityManager> entityManagerProvider;

  @Mock(type = MockType.NICE)
  private Injector injector;

  @Mock(type = MockType.NICE)
  private EntityManager entityManager;

  @Mock(type = MockType.DEFAULT)
  private DBAccessor dbAccessor;

  @Mock(type = MockType.NICE)
  private OsFamily osFamily;

  @Mock(type = MockType.NICE)
  private Config config;

  @Mock(type = MockType.NICE)
  private ActionManager actionManager;

  @Mock(type = MockType.NICE)
  private Clusters clusters;

  @Mock(type = MockType.NICE)
  private Cluster cluster;

  @Mock(type = MockType.NICE)
  AmbariConfigurationDAO ambariConfigurationDao;

  @Mock(type = MockType.NICE)
  ArtifactDAO artifactDAO;

  @Mock(type = MockType.NICE)
  private AmbariManagementController ambariManagementController;

  @Before
  public void init() {
    reset(entityManagerProvider, injector);

    expect(entityManagerProvider.get()).andReturn(entityManager).anyTimes();

    expect(injector.getInstance(Gson.class)).andReturn(null).anyTimes();
    expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(null).anyTimes();

    replay(entityManagerProvider, injector);
  }

  @After
  public void tearDown() {
  }

  @Test
  public void testExecuteDMLUpdates() throws Exception {
    Method addNewConfigurationsFromXml = AbstractUpgradeCatalog.class.getDeclaredMethod("addNewConfigurationsFromXml");
    Method showHcatDeletedUserMessage = UpgradeCatalog270.class.getDeclaredMethod("showHcatDeletedUserMessage");
    Method setStatusOfStagesAndRequests = UpgradeCatalog270.class.getDeclaredMethod("setStatusOfStagesAndRequests");
    Method updateLogSearchConfigs = UpgradeCatalog270.class.getDeclaredMethod("updateLogSearchConfigs");
    Method updateKerberosConfigurations = UpgradeCatalog270.class.getDeclaredMethod("updateKerberosConfigurations");
    Method upgradeLdapConfiguration = UpgradeCatalog270.class.getDeclaredMethod("moveAmbariPropertiesToAmbariConfiguration");
    Method createRoleAuthorizations = UpgradeCatalog270.class.getDeclaredMethod("createRoleAuthorizations");
    Method addUserAuthenticationSequence = UpgradeCatalog270.class.getDeclaredMethod("addUserAuthenticationSequence");
    Method renameAmbariInfra = UpgradeCatalog270.class.getDeclaredMethod("renameAmbariInfra");
    Method updateKerberosDescriptorArtifacts = UpgradeCatalog270.class.getSuperclass().getDeclaredMethod("updateKerberosDescriptorArtifacts");
    Method updateSolrConfigurations = UpgradeCatalog270.class.getDeclaredMethod("updateSolrConfigurations");
    Method updateAmsConfigurations = UpgradeCatalog270.class.getDeclaredMethod("updateAmsConfigs");
    Method updateStormConfigurations = UpgradeCatalog270.class.getDeclaredMethod("updateStormConfigs");
    Method clearHadoopMetrics2Content = UpgradeCatalog270.class.getDeclaredMethod("clearHadoopMetrics2Content");

    UpgradeCatalog270 upgradeCatalog270 = createMockBuilder(UpgradeCatalog270.class)
        .addMockedMethod(showHcatDeletedUserMessage)
        .addMockedMethod(addNewConfigurationsFromXml)
        .addMockedMethod(setStatusOfStagesAndRequests)
        .addMockedMethod(updateLogSearchConfigs)
        .addMockedMethod(updateKerberosConfigurations)
        .addMockedMethod(upgradeLdapConfiguration)
        .addMockedMethod(createRoleAuthorizations)
        .addMockedMethod(addUserAuthenticationSequence)
        .addMockedMethod(renameAmbariInfra)
        .addMockedMethod(updateKerberosDescriptorArtifacts)
        .addMockedMethod(updateSolrConfigurations)
        .addMockedMethod(updateAmsConfigurations)
        .addMockedMethod(updateStormConfigurations)
        .addMockedMethod(clearHadoopMetrics2Content)
        .createMock();


    upgradeCatalog270.addNewConfigurationsFromXml();
    expectLastCall().once();

    upgradeCatalog270.showHcatDeletedUserMessage();
    expectLastCall().once();

    upgradeCatalog270.createRoleAuthorizations();
    expectLastCall().once();

    upgradeCatalog270.setStatusOfStagesAndRequests();
    expectLastCall().once();

    upgradeCatalog270.updateLogSearchConfigs();

    upgradeCatalog270.updateKerberosConfigurations();
    expectLastCall().once();

    upgradeCatalog270.moveAmbariPropertiesToAmbariConfiguration();
    expectLastCall().once();

    upgradeCatalog270.addUserAuthenticationSequence();
    expectLastCall().once();

    upgradeCatalog270.renameAmbariInfra();
    expectLastCall().once();

    upgradeCatalog270.updateKerberosDescriptorArtifacts();
    expectLastCall().once();

    upgradeCatalog270.updateSolrConfigurations();
    expectLastCall().once();

    upgradeCatalog270.updateAmsConfigs();
    expectLastCall().once();

    upgradeCatalog270.updateStormConfigs();
    expectLastCall().once();

    upgradeCatalog270.clearHadoopMetrics2Content();
    expectLastCall().once();

    replay(upgradeCatalog270);

    upgradeCatalog270.executeDMLUpdates();

    verify(upgradeCatalog270);
  }

  @Test
  public void testExecuteDDLUpdates() throws Exception {
    // dropBrokenFKs
    dbAccessor.dropFKConstraint(COMPONENT_DESIRED_STATE_TABLE, FK_HOSTCOMPONENTDESIREDSTATE_COMPONENT_NAME);
    expectLastCall().once();
    dbAccessor.dropFKConstraint(COMPONENT_STATE_TABLE, FK_HOSTCOMPONENTSTATE_COMPONENT_NAME);
    expectLastCall().once();
    dbAccessor.dropFKConstraint(SERVICE_COMPONENT_DESIRED_STATE_TABLE, FK_SERVICECOMPONENTDESIREDSTATE_SERVICE_NAME);
    expectLastCall().once();

    // updateStageTable
    Capture<DBAccessor.DBColumnInfo> updateStageTableCaptures = newCapture(CaptureType.ALL);
    dbAccessor.addColumn(eq(STAGE_TABLE), capture(updateStageTableCaptures));
    expectLastCall().once();
    dbAccessor.addColumn(eq(STAGE_TABLE), capture(updateStageTableCaptures));
    expectLastCall().once();
    dbAccessor.addColumn(eq(REQUEST_TABLE), capture(updateStageTableCaptures));
    expectLastCall().once();

    // updateRequestTable
    Capture<DBAccessor.DBColumnInfo> updateRequestTableCapture = newCapture(CaptureType.ALL);
    dbAccessor.addColumn(eq(REQUEST_TABLE), capture(updateRequestTableCapture));
    expectLastCall().once();

    // updateWidgetTable
    Capture<DBAccessor.DBColumnInfo> updateWidgetTableCapture = newCapture(CaptureType.ALL);
    dbAccessor.addColumn(eq(WIDGET_TABLE), capture(updateWidgetTableCapture));
    expectLastCall().once();

    // addOpsDisplayNameColumnToHostRoleCommand
    Capture<DBAccessor.DBColumnInfo> hrcOpsDisplayNameColumn = newCapture();
    dbAccessor.addColumn(eq(UpgradeCatalog270.HOST_ROLE_COMMAND_TABLE), capture(hrcOpsDisplayNameColumn));
    expectLastCall().once();

    Capture<DBAccessor.DBColumnInfo> lastValidColumn = newCapture();
    dbAccessor.addColumn(eq(UpgradeCatalog270.COMPONENT_STATE_TABLE), capture(lastValidColumn));

    // removeSecurityState
    dbAccessor.dropColumn(COMPONENT_DESIRED_STATE_TABLE, SECURITY_STATE_COLUMN);
    expectLastCall().once();
    dbAccessor.dropColumn(COMPONENT_STATE_TABLE, SECURITY_STATE_COLUMN);
    expectLastCall().once();
    dbAccessor.dropColumn(SERVICE_DESIRED_STATE_TABLE, SECURITY_STATE_COLUMN);
    expectLastCall().once();

    // addAmbariConfigurationTable
    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();

    //upgradeUserTable - converting users.create_time to long
    Capture<DBAccessor.DBColumnInfo> temporaryColumnCreationCapture = newCapture(CaptureType.ALL);
    Capture<DBAccessor.DBColumnInfo> temporaryColumnRenameCapture = newCapture(CaptureType.ALL);

    // upgradeUserTable - create user_authentication table
    Capture<List<DBAccessor.DBColumnInfo>> createUserAuthenticationTableCaptures = newCapture(CaptureType.ALL);
    Capture<List<DBAccessor.DBColumnInfo>> createMembersTableCaptures = newCapture(CaptureType.ALL);
    Capture<List<DBAccessor.DBColumnInfo>> createAdminPrincipalTableCaptures = newCapture(CaptureType.ALL);
    Capture<DBAccessor.DBColumnInfo> updateUserTableCaptures = newCapture(CaptureType.ALL);
    Capture<DBAccessor.DBColumnInfo> alterUserTableCaptures = newCapture(CaptureType.ALL);

    Capture<List<DBAccessor.DBColumnInfo>> addRepoOsTableCapturedColumns = newCapture(CaptureType.ALL);
    Capture<List<DBAccessor.DBColumnInfo>> addRepoDefinitionTableCapturedColumns = newCapture(CaptureType.ALL);
    Capture<List<DBAccessor.DBColumnInfo>> addRepoTagsTableCapturedColumns = newCapture(CaptureType.ALL);
    Capture<List<DBAccessor.DBColumnInfo>> addRepoApplicableServicesTableCapturedColumns = newCapture(CaptureType.ALL);
    Capture<String[]> insertRepoOsTableRowColumns = newCapture(CaptureType.ALL);
    Capture<String[]> insertRepoOsTableRowValues = newCapture(CaptureType.ALL);
    Capture<String[]> insertAmbariSequencesRowColumns = newCapture(CaptureType.ALL);
    Capture<String[]> insertAmbariSequencesRowValues = newCapture(CaptureType.ALL);

    // Any return value will work here as long as a SQLException is not thrown.
    expect(dbAccessor.getColumnType(USERS_TABLE, USERS_USER_TYPE_COLUMN)).andReturn(0).anyTimes();

    prepareConvertingUsersCreationTime(dbAccessor, temporaryColumnCreationCapture, temporaryColumnRenameCapture);
    prepareCreateUserAuthenticationTable(dbAccessor, createUserAuthenticationTableCaptures);
    prepareUpdateGroupMembershipRecords(dbAccessor, createMembersTableCaptures);
    prepareUpdateAdminPrivilegeRecords(dbAccessor, createAdminPrincipalTableCaptures);
    prepareUpdateUsersTable(dbAccessor, updateUserTableCaptures, alterUserTableCaptures);
    prepareUpdateRepoTables(dbAccessor, addRepoOsTableCapturedColumns, addRepoDefinitionTableCapturedColumns, addRepoTagsTableCapturedColumns,
      addRepoApplicableServicesTableCapturedColumns, insertRepoOsTableRowColumns, insertRepoOsTableRowValues, insertAmbariSequencesRowColumns, insertAmbariSequencesRowValues);

    // upgradeKerberosTables
    Capture<List<DBAccessor.DBColumnInfo>> kerberosKeytabColumnsCapture = newCapture();
    dbAccessor.createTable(eq(KERBEROS_KEYTAB_TABLE), capture(kerberosKeytabColumnsCapture));
    expectLastCall().once();
    dbAccessor.addPKConstraint(KERBEROS_KEYTAB_TABLE, PK_KERBEROS_KEYTAB, KEYTAB_PATH_FIELD);
    expectLastCall().once();

    Capture<List<DBAccessor.DBColumnInfo>> kerberosKeytabPrincipalColumnsCapture = newCapture();
    dbAccessor.createTable(eq(KERBEROS_KEYTAB_PRINCIPAL_TABLE), capture(kerberosKeytabPrincipalColumnsCapture));
    expectLastCall().once();
    dbAccessor.addPKConstraint(KERBEROS_KEYTAB_PRINCIPAL_TABLE, PK_KKP, KKP_ID_COLUMN);
    expectLastCall().once();
    dbAccessor.addUniqueConstraint(KERBEROS_KEYTAB_PRINCIPAL_TABLE, UNI_KKP, KEYTAB_PATH_FIELD, PRINCIPAL_NAME_COLUMN, HOST_ID_COLUMN);
    expectLastCall().once();

    Capture<List<DBAccessor.DBColumnInfo>> mappingColumnsCapture = newCapture();
    dbAccessor.createTable(eq(KKP_MAPPING_SERVICE_TABLE), capture(mappingColumnsCapture));
    expectLastCall().once();
    dbAccessor.addPKConstraint(KKP_MAPPING_SERVICE_TABLE, PK_KKP_MAPPING_SERVICE, KKP_ID_COLUMN, SERVICE_NAME_COLUMN, COMPONENT_NAME_COLUMN);
    expectLastCall().once();

    dbAccessor.addFKConstraint(KERBEROS_KEYTAB_PRINCIPAL_TABLE, FK_KKP_KEYTAB_PATH, KEYTAB_PATH_FIELD, KERBEROS_KEYTAB_TABLE, KEYTAB_PATH_FIELD, false);
    expectLastCall().once();
    dbAccessor.addFKConstraint(KERBEROS_KEYTAB_PRINCIPAL_TABLE, FK_KKP_HOST_ID,HOST_ID_COLUMN, HOSTS_TABLE, HOST_ID_COLUMN, false);
    expectLastCall().once();
    dbAccessor.addFKConstraint(KERBEROS_KEYTAB_PRINCIPAL_TABLE, FK_KKP_PRINCIPAL_NAME, PRINCIPAL_NAME_COLUMN, KERBEROS_PRINCIPAL_TABLE, PRINCIPAL_NAME_COLUMN, false);
    expectLastCall().once();
    dbAccessor.addFKConstraint(KKP_MAPPING_SERVICE_TABLE, FK_KKP_SERVICE_PRINCIPAL, KKP_ID_COLUMN, KERBEROS_KEYTAB_PRINCIPAL_TABLE, KKP_ID_COLUMN, false);
    expectLastCall().once();

    Connection c = niceMock(Connection.class);
    Statement s = niceMock(Statement.class);
    expect(s.executeQuery(anyString())).andReturn(null).once();
    expect(c.createStatement()).andReturn(s).once();
    expect(dbAccessor.getConnection()).andReturn(c).once();

    dbAccessor.dropTable(KERBEROS_PRINCIPAL_HOST_TABLE);

    replay(dbAccessor);

    Injector injector = Guice.createInjector(getTestGuiceModule());
    UpgradeCatalog270 upgradeCatalog270 = injector.getInstance(UpgradeCatalog270.class);
    upgradeCatalog270.executeDDLUpdates();

    // Validate updateStageTableCaptures
    Assert.assertTrue(updateStageTableCaptures.hasCaptured());
    validateColumns(updateStageTableCaptures.getValues(),
        Arrays.asList(
            new DBAccessor.DBColumnInfo(STAGE_STATUS_COLUMN, String.class, 255, HostRoleStatus.PENDING, false),
            new DBAccessor.DBColumnInfo(STAGE_DISPLAY_STATUS_COLUMN, String.class, 255, HostRoleStatus.PENDING, false),
            new DBAccessor.DBColumnInfo(REQUEST_DISPLAY_STATUS_COLUMN, String.class, 255, HostRoleStatus.PENDING, false))
    );

    // Validate updateRequestTableCapture
    Assert.assertTrue(updateRequestTableCapture.hasCaptured());
    validateColumns(updateRequestTableCapture.getValues(),
            Arrays.asList(new DBAccessor.DBColumnInfo(REQUEST_USER_NAME_COLUMN, String.class, 255))
    );

    DBAccessor.DBColumnInfo capturedOpsDisplayNameColumn = hrcOpsDisplayNameColumn.getValue();
    Assert.assertEquals(UpgradeCatalog270.HRC_OPS_DISPLAY_NAME_COLUMN, capturedOpsDisplayNameColumn.getName());
    Assert.assertEquals(null, capturedOpsDisplayNameColumn.getDefaultValue());
    Assert.assertEquals(String.class, capturedOpsDisplayNameColumn.getType());

    // Ambari configuration table addition...
    Assert.assertTrue(ambariConfigurationTableColumns.hasCaptured());
    validateColumns(ambariConfigurationTableColumns.getValue(),
        Arrays.asList(
            new DBAccessor.DBColumnInfo(AMBARI_CONFIGURATION_CATEGORY_NAME_COLUMN, String.class, 100, null, false),
            new DBAccessor.DBColumnInfo(AMBARI_CONFIGURATION_PROPERTY_NAME_COLUMN, String.class, 100, null, false),
            new DBAccessor.DBColumnInfo(AMBARI_CONFIGURATION_PROPERTY_VALUE_COLUMN, String.class, 2048, null, true))
    );

    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(2048), column.getLength());
        Assert.assertEquals(null, column.getDefaultValue());
        Assert.assertTrue(column.isNullable());
      } else {
        Assert.fail("Unexpected column name: " + columnName);
      }
    }
    // Ambari configuration table addition...

    DBAccessor.DBColumnInfo capturedLastValidColumn = lastValidColumn.getValue();
    Assert.assertEquals(upgradeCatalog270.COMPONENT_LAST_STATE_COLUMN, capturedLastValidColumn.getName());
    Assert.assertEquals(State.UNKNOWN, capturedLastValidColumn.getDefaultValue());
    Assert.assertEquals(String.class, capturedLastValidColumn.getType());

    validateConvertingUserCreationTime(temporaryColumnCreationCapture,temporaryColumnRenameCapture);
    validateCreateUserAuthenticationTable(createUserAuthenticationTableCaptures);
    validateUpdateGroupMembershipRecords(createMembersTableCaptures);
    validateUpdateAdminPrivilegeRecords(createAdminPrincipalTableCaptures);
    validateUpdateUsersTable(updateUserTableCaptures, alterUserTableCaptures);
    validateCreateRepoOsTable(addRepoOsTableCapturedColumns, addRepoDefinitionTableCapturedColumns, addRepoTagsTableCapturedColumns,
        insertRepoOsTableRowColumns, insertRepoOsTableRowValues, insertAmbariSequencesRowColumns, insertAmbariSequencesRowValues);

    verify(dbAccessor);
  }

  private Module getTestGuiceModule() {
    Module module = new AbstractModule() {
      @Override
      public void configure() {
        PartialNiceMockBinder.newBuilder().addConfigsBindings().addPasswordEncryptorBindings().addLdapBindings().addFactoriesInstallBinding().build().configure(binder());

        bind(DBAccessor.class).toInstance(dbAccessor);
        bind(OsFamily.class).toInstance(osFamily);
        bind(EntityManager.class).toInstance(entityManager);
        bind(AmbariConfigurationDAO.class).toInstance(ambariConfigurationDao);
        bind(PersistedState.class).toInstance(mock(PersistedStateImpl.class));
        bind(Clusters.class).toInstance(mock(ClustersImpl.class));
        bind(SecurityHelper.class).toInstance(mock(SecurityHelper.class));
        bind(HostRoleCommandFactory.class).to(HostRoleCommandFactoryImpl.class);
        bind(ActionDBAccessor.class).toInstance(createNiceMock(ActionDBAccessorImpl.class));
        bind(UnitOfWork.class).toInstance(createNiceMock(UnitOfWork.class));
        bind(RoleCommandOrderProvider.class).to(CachedRoleCommandOrderProvider.class);
        bind(StageFactory.class).to(StageFactoryImpl.class);
        bind(AuditLogger.class).toInstance(createNiceMock(AuditLoggerDefaultImpl.class));
        bind(PasswordEncoder.class).toInstance(new StandardPasswordEncoder());
        bind(HookService.class).to(UserHookService.class);
        bind(ServiceComponentHostFactory.class).toInstance(createNiceMock(ServiceComponentHostFactory.class));
        bind(AbstractRootServiceResponseFactory.class).to(RootServiceResponseFactory.class);
        bind(CredentialStoreService.class).toInstance(createNiceMock(CredentialStoreService.class));
        bind(AmbariManagementController.class).toInstance(createNiceMock(AmbariManagementControllerImpl.class));
        bind(ExecutionScheduler.class).toInstance(createNiceMock(ExecutionScheduler.class));
        bind(AmbariMetaInfo.class).toInstance(createNiceMock(AmbariMetaInfo.class));
        bind(KerberosHelper.class).toInstance(createNiceMock(KerberosHelperImpl.class));
        bind(MpackManagerFactory.class).toInstance(createNiceMock(MpackManagerFactory.class));
        bind(StackManagerFactory.class).toInstance(createNiceMock(StackManagerFactory.class));

        install(new FactoryModuleBuilder().implement(
            Host.class, HostImpl.class).build(HostFactory.class));
        install(new FactoryModuleBuilder().implement(
            Cluster.class, ClusterImpl.class).build(ClusterFactory.class));
        install(new FactoryModuleBuilder().build(UpgradeContextFactory.class));
        install(new FactoryModuleBuilder().implement(
            Service.class, ServiceImpl.class).build(ServiceFactory.class));
//        binder.bind(Configuration.class).toInstance(configuration);
//        binder.bind(AmbariManagementController.class).toInstance(ambariManagementController);
      }
    };
    return module;
  }

  private void prepareConvertingUsersCreationTime(DBAccessor dbAccessor, Capture<DBAccessor.DBColumnInfo> temporaryColumnCreationCapture,
      Capture<DBAccessor.DBColumnInfo> temporaryColumnRenameCapture) throws SQLException {
    expect(dbAccessor.getColumnType(USERS_TABLE, USERS_CREATE_TIME_COLUMN)).andReturn(Types.TIMESTAMP).once();
    final String temporaryColumnName = USERS_CREATE_TIME_COLUMN + "_numeric";
    expect(dbAccessor.tableHasColumn(USERS_TABLE, temporaryColumnName)).andReturn(Boolean.FALSE);
    dbAccessor.addColumn(eq(USERS_TABLE), capture(temporaryColumnCreationCapture));
    expect(dbAccessor.tableHasColumn(USERS_TABLE, USERS_CREATE_TIME_COLUMN)).andReturn(Boolean.TRUE);

    final Connection connectionMock = niceMock(Connection.class);
    expect(dbAccessor.getConnection()).andReturn(connectionMock).once();
    final PreparedStatement preparedStatementMock = niceMock(PreparedStatement.class);
    expect(connectionMock.prepareStatement(anyString())).andReturn(preparedStatementMock);
    final ResultSet resultSetMock = niceMock(ResultSet.class);
    expect(preparedStatementMock.executeQuery()).andReturn(resultSetMock);
    expect(resultSetMock.next()).andReturn(Boolean.TRUE).once();
    expect(resultSetMock.getInt(1)).andReturn(1).anyTimes();
    expect(resultSetMock.getTimestamp(2)).andReturn(new Timestamp(1l)).anyTimes();
    replay(connectionMock, preparedStatementMock, resultSetMock);

    expect(dbAccessor.updateTable(eq(USERS_TABLE), eq(temporaryColumnName), eq(1l), anyString())).andReturn(anyInt());

    dbAccessor.dropColumn(USERS_TABLE, USERS_CREATE_TIME_COLUMN);
    expectLastCall().once();

    dbAccessor.renameColumn(eq(USERS_TABLE), eq(temporaryColumnName), capture(temporaryColumnRenameCapture));
  }

  private void prepareCreateUserAuthenticationTable(DBAccessor dbAccessor, Capture<List<DBAccessor.DBColumnInfo>> capturedData)
      throws SQLException {

    String temporaryTableName = USER_AUTHENTICATION_TABLE + "_tmp";

    dbAccessor.dropTable(eq(temporaryTableName));
    expectLastCall().times(2);
    dbAccessor.createTable(eq(temporaryTableName), capture(capturedData));
    expectLastCall().once();

    expect(dbAccessor.executeUpdate(startsWith("insert into " + temporaryTableName))).andReturn(1).once();
    expect(dbAccessor.executeUpdate(startsWith("update " + temporaryTableName))).andReturn(1).once();

    dbAccessor.createTable(eq(USER_AUTHENTICATION_TABLE), capture(capturedData));
    expectLastCall().once();
    dbAccessor.addPKConstraint(USER_AUTHENTICATION_TABLE, USER_AUTHENTICATION_PRIMARY_KEY, USER_AUTHENTICATION_USER_AUTHENTICATION_ID_COLUMN);
    expectLastCall().once();
    dbAccessor.addFKConstraint(USER_AUTHENTICATION_TABLE, USER_AUTHENTICATION_USER_AUTHENTICATION_USERS_FOREIGN_KEY, USER_AUTHENTICATION_USER_ID_COLUMN, USERS_TABLE, USERS_USER_ID_COLUMN, false);
    expectLastCall().once();

    expect(dbAccessor.executeUpdate(startsWith("insert into " + USER_AUTHENTICATION_TABLE))).andReturn(1).once();
  }

  private void validateConvertingUserCreationTime(Capture<DBAccessor.DBColumnInfo> temporaryColumnCreationCapture, Capture<DBAccessor.DBColumnInfo> temporaryColumnRenameCapture) {
    Assert.assertTrue(temporaryColumnCreationCapture.hasCaptured());
    Assert.assertTrue(temporaryColumnRenameCapture.hasCaptured());
    assertEquals(new DBAccessor.DBColumnInfo(USERS_CREATE_TIME_COLUMN, Long.class, null, null, false), temporaryColumnRenameCapture.getValue());
  }

  private void validateCreateUserAuthenticationTable(Capture<List<DBAccessor.DBColumnInfo>> capturedData) {
    Assert.assertTrue(capturedData.hasCaptured());
    List<List<DBAccessor.DBColumnInfo>> capturedValues = capturedData.getValues();
    Assert.assertEquals(2, capturedValues.size());
    for (List<DBAccessor.DBColumnInfo> capturedValue : capturedValues) {
      validateColumns(capturedValue,
          Arrays.asList(
              new DBAccessor.DBColumnInfo(USER_AUTHENTICATION_USER_AUTHENTICATION_ID_COLUMN, Long.class, null, null, false),
              new DBAccessor.DBColumnInfo(USER_AUTHENTICATION_USER_ID_COLUMN, Integer.class, null, null, false),
              new DBAccessor.DBColumnInfo(USER_AUTHENTICATION_AUTHENTICATION_TYPE_COLUMN, String.class, 50, null, false),
              new DBAccessor.DBColumnInfo(USER_AUTHENTICATION_AUTHENTICATION_KEY_COLUMN, String.class, 2048, null, true),
              new DBAccessor.DBColumnInfo(USER_AUTHENTICATION_CREATE_TIME_COLUMN, Long.class, null, null, true),
              new DBAccessor.DBColumnInfo(USER_AUTHENTICATION_UPDATE_TIME_COLUMN, Long.class, null, null, true)
          )
      );
    }
  }

  private void prepareUpdateGroupMembershipRecords(DBAccessor dbAccessor, Capture<List<DBAccessor.DBColumnInfo>> capturedData)
      throws SQLException {
    String temporaryTableName = MEMBERS_TABLE + "_tmp";

    dbAccessor.dropTable(eq(temporaryTableName));
    expectLastCall().times(2);
    dbAccessor.createTable(eq(temporaryTableName), capture(capturedData));
    expectLastCall().once();

    expect(dbAccessor.executeUpdate(startsWith("insert into " + temporaryTableName))).andReturn(1).once();

    dbAccessor.truncateTable(MEMBERS_TABLE);
    expectLastCall().once();

    expect(dbAccessor.executeUpdate(startsWith("insert into " + MEMBERS_TABLE))).andReturn(1).once();
  }

  private void validateUpdateGroupMembershipRecords(Capture<List<DBAccessor.DBColumnInfo>> capturedData) {
    Assert.assertTrue(capturedData.hasCaptured());
    List<List<DBAccessor.DBColumnInfo>> capturedValues = capturedData.getValues();
    Assert.assertEquals(1, capturedValues.size());
    for (List<DBAccessor.DBColumnInfo> capturedValue : capturedValues) {
      validateColumns(capturedValue,
          Arrays.asList(
              new DBAccessor.DBColumnInfo(MEMBERS_MEMBER_ID_COLUMN, Long.class, null, null, false),
              new DBAccessor.DBColumnInfo(MEMBERS_USER_ID_COLUMN, Long.class, null, null, false),
              new DBAccessor.DBColumnInfo(MEMBERS_GROUP_ID_COLUMN, Long.class, null, null, false)
          )
      );
    }
  }

  private void prepareUpdateAdminPrivilegeRecords(DBAccessor dbAccessor, Capture<List<DBAccessor.DBColumnInfo>> capturedData)
      throws SQLException {
    String temporaryTableName = ADMINPRIVILEGE_TABLE + "_tmp";

    dbAccessor.dropTable(eq(temporaryTableName));
    expectLastCall().times(2);
    dbAccessor.createTable(eq(temporaryTableName), capture(capturedData));
    expectLastCall().once();

    expect(dbAccessor.executeUpdate(startsWith("insert into " + temporaryTableName))).andReturn(1).once();

    dbAccessor.truncateTable(ADMINPRIVILEGE_TABLE);
    expectLastCall().once();

    expect(dbAccessor.executeUpdate(startsWith("insert into " + ADMINPRIVILEGE_TABLE))).andReturn(1).once();
  }

  private void validateUpdateAdminPrivilegeRecords(Capture<List<DBAccessor.DBColumnInfo>> capturedData) {
    Assert.assertTrue(capturedData.hasCaptured());
    List<List<DBAccessor.DBColumnInfo>> capturedValues = capturedData.getValues();
    Assert.assertEquals(1, capturedValues.size());
    for (List<DBAccessor.DBColumnInfo> capturedValue : capturedValues) {
      validateColumns(capturedValue,
          Arrays.asList(
              new DBAccessor.DBColumnInfo(ADMINPRIVILEGE_PRIVILEGE_ID_COLUMN, Long.class, null, null, false),
              new DBAccessor.DBColumnInfo(ADMINPRIVILEGE_PERMISSION_ID_COLUMN, Long.class, null, null, false),
              new DBAccessor.DBColumnInfo(ADMINPRIVILEGE_RESOURCE_ID_COLUMN, Long.class, null, null, false),
              new DBAccessor.DBColumnInfo(ADMINPRIVILEGE_PRINCIPAL_ID_COLUMN, Long.class, null, null, false)
          )
      );
    }
  }

  private void prepareUpdateUsersTable(DBAccessor dbAccessor, Capture<DBAccessor.DBColumnInfo> updateUserTableCaptures, Capture<DBAccessor.DBColumnInfo> alterUserTableCaptures)
      throws SQLException {

    expect(dbAccessor.executeUpdate(startsWith("delete from " + USERS_TABLE))).andReturn(1).once();

    dbAccessor.dropUniqueConstraint(USERS_TABLE, UNIQUE_USERS_0_INDEX);
    expectLastCall().once();
    dbAccessor.dropColumn(USERS_TABLE, USERS_USER_TYPE_COLUMN);
    expectLastCall().once();
    dbAccessor.dropColumn(USERS_TABLE, USERS_LDAP_USER_COLUMN);
    expectLastCall().once();
    dbAccessor.dropColumn(USERS_TABLE, USERS_USER_PASSWORD_COLUMN);
    expectLastCall().once();

    dbAccessor.addColumn(eq(USERS_TABLE), capture(updateUserTableCaptures));
    expectLastCall().atLeastOnce();

    expect(dbAccessor.executeUpdate(startsWith("update " + USERS_TABLE))).andReturn(1).once();


    dbAccessor.alterColumn(eq(USERS_TABLE), capture(alterUserTableCaptures));
    expectLastCall().atLeastOnce();

    dbAccessor.addUniqueConstraint(USERS_TABLE, UNIQUE_USERS_0_INDEX, USERS_USER_NAME_COLUMN);
    expectLastCall().once();
  }

  private void prepareUpdateRepoTables(DBAccessor dbAccessor,
                                       Capture<List<DBAccessor.DBColumnInfo>> addRepoOsTableCapturedColumns,
                                       Capture<List<DBAccessor.DBColumnInfo>> addRepoDefinitionTableCapturedColumns,
                                       Capture<List<DBAccessor.DBColumnInfo>> addRepoTagsTableCapturedColumns,
                                       Capture<List<DBAccessor.DBColumnInfo>> addRepoApplicableServicesTableCapturedColumns,
                                       Capture<String[]> insertRepoOsTableRowColumns,
                                       Capture<String[]> insertRepoOsTableRowValues,
                                       Capture<String[]> insertAmbariSequencesRowColumns,
                                       Capture<String[]> insertAmbariSequencesRowValues)
      throws SQLException {

    dbAccessor.createTable(eq(REPO_OS_TABLE), capture(addRepoOsTableCapturedColumns));
    expectLastCall().once();
    dbAccessor.addPKConstraint(REPO_OS_TABLE, REPO_OS_PRIMARY_KEY, REPO_OS_ID_COLUMN);
    expectLastCall().once();
    dbAccessor.addFKConstraint(REPO_OS_TABLE, REPO_OS_FOREIGN_KEY, REPO_OS_REPO_VERSION_ID_COLUMN, REPO_VERSION_TABLE, REPO_VERSION_REPO_VERSION_ID_COLUMN, false);
    expectLastCall().once();

    dbAccessor.createTable(eq(REPO_DEFINITION_TABLE), capture(addRepoDefinitionTableCapturedColumns));
    expectLastCall().once();
    dbAccessor.addPKConstraint(REPO_DEFINITION_TABLE, REPO_DEFINITION_PRIMARY_KEY, REPO_DEFINITION_ID_COLUMN);
    expectLastCall().once();
    dbAccessor.addFKConstraint(REPO_DEFINITION_TABLE, REPO_DEFINITION_FOREIGN_KEY, REPO_DEFINITION_REPO_OS_ID_COLUMN, REPO_OS_TABLE, REPO_OS_ID_COLUMN, false);
    expectLastCall().once();

    dbAccessor.createTable(eq(REPO_TAGS_TABLE), capture(addRepoTagsTableCapturedColumns));
    expectLastCall().once();
    dbAccessor.addFKConstraint(REPO_TAGS_TABLE, REPO_TAGS_FOREIGN_KEY, REPO_TAGS_REPO_DEFINITION_ID_COLUMN, REPO_DEFINITION_TABLE, REPO_DEFINITION_ID_COLUMN, false);
    expectLastCall().once();

    dbAccessor.createTable(eq(REPO_APPLICABLE_SERVICES_TABLE), capture(addRepoApplicableServicesTableCapturedColumns));
    expectLastCall().once();
    dbAccessor.addFKConstraint(REPO_APPLICABLE_SERVICES_TABLE, REPO_APPLICABLE_SERVICES_FOREIGN_KEY, REPO_APPLICABLE_SERVICES_REPO_DEFINITION_ID_COLUMN, REPO_DEFINITION_TABLE, REPO_DEFINITION_ID_COLUMN, false);
    expectLastCall().once();

    expect(dbAccessor.tableHasColumn(eq(REPO_VERSION_TABLE), eq(REPO_VERSION_REPOSITORIES_COLUMN))).andReturn(true).once();
    final Map<Long, String> repoMap = new HashMap<>();
    repoMap.put(1L, getSampleRepositoryData());
    expect(dbAccessor.getKeyToStringColumnMap(eq(REPO_VERSION_TABLE), eq(REPO_VERSION_REPO_VERSION_ID_COLUMN), eq(REPO_VERSION_REPOSITORIES_COLUMN), eq(null), eq(null), eq(true))).andReturn(repoMap).once();
    expect(dbAccessor.insertRowIfMissing(eq(REPO_OS_TABLE), capture(insertRepoOsTableRowColumns), capture(insertRepoOsTableRowValues), eq(false))).andReturn(true).once();

    expect(dbAccessor.insertRowIfMissing(eq(AMBARI_SEQUENCES_TABLE),
        capture(insertAmbariSequencesRowColumns),
        capture(insertAmbariSequencesRowValues),
        eq(false))).andReturn(true).once();
    expect(dbAccessor.insertRowIfMissing(eq(AMBARI_SEQUENCES_TABLE),
        capture(insertAmbariSequencesRowColumns),
        capture(insertAmbariSequencesRowValues),
        eq(false))).andReturn(true).once();

    dbAccessor.dropColumn(eq(REPO_VERSION_TABLE), eq(REPO_VERSION_REPOSITORIES_COLUMN));
    expectLastCall().once();
  }

  /**
   * @return sample JSON data from repo_version data (no repositories defined) where 'OperatingSystems/ambari_managed_repositories' is missing
   */
  private String getSampleRepositoryData() {
    return "[{\"repositories\":[],\"OperatingSystems/os_type\":\"redhat7\"}]";
  }

  private void validateUpdateUsersTable(Capture<DBAccessor.DBColumnInfo> updateUserTableCaptures, Capture<DBAccessor.DBColumnInfo> alterUserTableCaptures) {
    Assert.assertTrue(updateUserTableCaptures.hasCaptured());
    validateColumns(updateUserTableCaptures.getValues(),
        Arrays.asList(
            new DBAccessor.DBColumnInfo(USERS_CONSECUTIVE_FAILURES_COLUMN, Integer.class, null, 0, false),
            new DBAccessor.DBColumnInfo(USERS_DISPLAY_NAME_COLUMN, String.class, 255, null, true),
            new DBAccessor.DBColumnInfo(USERS_LOCAL_USERNAME_COLUMN, String.class, 255, null, true),
            new DBAccessor.DBColumnInfo(USERS_VERSION_COLUMN, Long.class, null, 0, false)
        )
    );

    Assert.assertTrue(alterUserTableCaptures.hasCaptured());
    validateColumns(alterUserTableCaptures.getValues(),
        Arrays.asList(
            new DBAccessor.DBColumnInfo(USERS_DISPLAY_NAME_COLUMN, String.class, 255, null, false),
            new DBAccessor.DBColumnInfo(USERS_LOCAL_USERNAME_COLUMN, String.class, 255, null, false)
        )
    );
  }

  private void validateCreateRepoOsTable(Capture<List<DBAccessor.DBColumnInfo>> addRepoOsTableCapturedColumns,
                                         Capture<List<DBAccessor.DBColumnInfo>> addRepoDefinitionTableCapturedColumns,
                                         Capture<List<DBAccessor.DBColumnInfo>> addRepoTagsTableCapturedColumns,
                                         Capture<String[]> insertRepoOsTableRowColumns, Capture<String[]> insertRepoOsTableRowValues,
                                         Capture<String[]> insertAmbariSequencesRowColumns, Capture<String[]> insertAmbariSequencesRowValues) {
    Assert.assertTrue(addRepoOsTableCapturedColumns.hasCaptured());
    validateColumns(addRepoOsTableCapturedColumns.getValue(),
        Arrays.asList(
            new DBAccessor.DBColumnInfo(REPO_OS_ID_COLUMN, Long.class, null, null, false),
            new DBAccessor.DBColumnInfo(REPO_OS_REPO_VERSION_ID_COLUMN, Long.class, null, null, false),
            new DBAccessor.DBColumnInfo(REPO_OS_FAMILY_COLUMN, String.class, 255, null, false),
            new DBAccessor.DBColumnInfo(REPO_OS_AMBARI_MANAGED_COLUMN, Integer.class, null, 1, true)
        )
    );

    Assert.assertTrue(addRepoDefinitionTableCapturedColumns.hasCaptured());
    validateColumns(addRepoDefinitionTableCapturedColumns.getValue(),
        Arrays.asList(
            new DBAccessor.DBColumnInfo(REPO_DEFINITION_ID_COLUMN, Long.class, null, null, false),
            new DBAccessor.DBColumnInfo(REPO_DEFINITION_REPO_OS_ID_COLUMN, Long.class, null, null, false),
            new DBAccessor.DBColumnInfo(REPO_DEFINITION_REPO_NAME_COLUMN, String.class, 255, null, false),
            new DBAccessor.DBColumnInfo(REPO_DEFINITION_REPO_ID_COLUMN, String.class, 255, null, false),
            new DBAccessor.DBColumnInfo(REPO_DEFINITION_BASE_URL_COLUMN, String.class, 2048, null, true),
            new DBAccessor.DBColumnInfo(REPO_DEFINITION_DISTRIBUTION_COLUMN, String.class, 2048, null, true),
            new DBAccessor.DBColumnInfo(REPO_DEFINITION_COMPONENTS_COLUMN, String.class, 2048, null, true),
            new DBAccessor.DBColumnInfo(REPO_DEFINITION_UNIQUE_REPO_COLUMN, Integer.class, 1, 1, true),
            new DBAccessor.DBColumnInfo(REPO_DEFINITION_MIRRORS_COLUMN, String.class, 2048, null, true)
        )
    );

    Assert.assertTrue(addRepoTagsTableCapturedColumns.hasCaptured());
    validateColumns(addRepoTagsTableCapturedColumns.getValue(),
        Arrays.asList(
            new DBAccessor.DBColumnInfo(REPO_TAGS_REPO_DEFINITION_ID_COLUMN, Long.class, null, null, false),
            new DBAccessor.DBColumnInfo(REPO_TAGS_TAG_COLUMN, String.class, 255, null, false)
        )
    );

    List<String[]> values;

    Assert.assertTrue(insertRepoOsTableRowColumns.hasCaptured());
    values = insertRepoOsTableRowColumns.getValues();
    Assert.assertEquals(1, values.size());
    Assert.assertArrayEquals(new String[] {REPO_OS_ID_COLUMN, REPO_OS_REPO_VERSION_ID_COLUMN, REPO_OS_AMBARI_MANAGED_COLUMN, REPO_OS_FAMILY_COLUMN}, values.get(0));

    Assert.assertTrue(insertRepoOsTableRowValues.hasCaptured());
    values = insertRepoOsTableRowValues.getValues();
    Assert.assertEquals(1, values.size());
    Assert.assertArrayEquals(new String[] {"1", "1", "1", "'redhat7'"}, values.get(0));

    Assert.assertTrue(insertAmbariSequencesRowColumns.hasCaptured());
    values = insertAmbariSequencesRowColumns.getValues();
    Assert.assertEquals(2, values.size());
    Assert.assertArrayEquals(new String[]{AMBARI_SEQUENCES_SEQUENCE_NAME_COLUMN, AMBARI_SEQUENCES_SEQUENCE_VALUE_COLUMN}, values.get(0));
    Assert.assertArrayEquals(new String[]{AMBARI_SEQUENCES_SEQUENCE_NAME_COLUMN, AMBARI_SEQUENCES_SEQUENCE_VALUE_COLUMN}, values.get(1));

    Assert.assertTrue(insertAmbariSequencesRowValues.hasCaptured());
    values = insertAmbariSequencesRowValues.getValues();
    Assert.assertEquals(2, values.size());
    Assert.assertArrayEquals(new String[]{"'repo_os_id_seq'", "2"}, values.get(0));
    Assert.assertArrayEquals(new String[]{"'repo_definition_id_seq'", "1"}, values.get(1));


  }

  private void validateColumns(List<DBAccessor.DBColumnInfo> capturedColumns, List<DBAccessor.DBColumnInfo> expectedColumns) {
    Assert.assertEquals(expectedColumns.size(), capturedColumns.size());

    // copy these so we can alter them...
    expectedColumns = new ArrayList<>(expectedColumns);
    capturedColumns = new ArrayList<>(capturedColumns);

    Iterator<DBAccessor.DBColumnInfo> capturedColumnIterator = capturedColumns.iterator();
    while (capturedColumnIterator.hasNext()) {
      DBAccessor.DBColumnInfo capturedColumnInfo = capturedColumnIterator.next();

      Iterator<DBAccessor.DBColumnInfo> expectedColumnIterator = expectedColumns.iterator();
      while (expectedColumnIterator.hasNext()) {
        DBAccessor.DBColumnInfo expectedColumnInfo = expectedColumnIterator.next();

        if (expectedColumnInfo.equals(capturedColumnInfo)) {
          expectedColumnIterator.remove();
          capturedColumnIterator.remove();
          break;
        }
      }
    }

    assertTrue("Not all captured columns were expected", capturedColumns.isEmpty());
    assertTrue("Not all expected columns were captured", expectedColumns.isEmpty());
  }


  @Test
  public void testLogSearchUpdateConfigs() throws Exception {
    reset(clusters, cluster);
    expect(clusters.getClusters()).andReturn(ImmutableMap.of("normal", cluster)).once();

    EasyMockSupport easyMockSupport = new EasyMockSupport();

    Injector injector2 = easyMockSupport.createNiceMock(Injector.class);
    AmbariManagementControllerImpl controller = createMockBuilder(AmbariManagementControllerImpl.class)
        .addMockedMethod("createConfiguration", ConfigurationRequest.class)
        .addMockedMethod("getClusters", new Class[]{})
        .addMockedMethod("createConfig", Cluster.class, StackId.class, String.class, Map.class,
            String.class, Map.class)
        .createNiceMock();
    ConfigHelper configHelper = createMockBuilder(ConfigHelper.class)
        .addMockedMethod("createConfigType", Cluster.class, StackId.class, AmbariManagementController.class,
            String.class, Map.class, String.class, String.class)
        .createMock();

    expect(injector2.getInstance(AmbariManagementController.class)).andReturn(controller).anyTimes();
    expect(injector2.getInstance(ConfigHelper.class)).andReturn(configHelper).anyTimes();
    expect(injector2.getInstance(DBAccessor.class)).andReturn(dbAccessor).anyTimes();
    expect(controller.getClusters()).andReturn(clusters).anyTimes();

    configHelper.createConfigType(anyObject(Cluster.class), anyObject(StackId.class), eq(controller),
        eq("logsearch-common-properties"), eq(Collections.emptyMap()), eq("ambari-upgrade"),
        eq("Updated logsearch-common-properties during Ambari Upgrade from 2.6.0 to 3.0.0"));
    expectLastCall().once();

    Map<String, String> oldLogSearchProperties = ImmutableMap.of(
        "logsearch.logfeeder.include.default.level", "FATAL,ERROR,WARN"
    );

    Map<String, String> expectedLogFeederProperties = ImmutableMap.of(
        "logfeeder.include.default.level", "FATAL,ERROR,WARN"
    );

    Config logFeederPropertiesConf = easyMockSupport.createNiceMock(Config.class);
    expect(cluster.getDesiredConfigByType("logfeeder-properties")).andReturn(logFeederPropertiesConf).times(2);
    expect(logFeederPropertiesConf.getProperties()).andReturn(Collections.emptyMap()).once();
    Capture<Map<String, String>> logFeederPropertiesCapture = EasyMock.newCapture();
    expect(controller.createConfig(anyObject(Cluster.class), anyObject(StackId.class), eq("logfeeder-properties"), capture(logFeederPropertiesCapture),
        anyString(), EasyMock.anyObject())).andReturn(config).once();

    Config logSearchPropertiesConf = easyMockSupport.createNiceMock(Config.class);
    expect(cluster.getDesiredConfigByType("logsearch-properties")).andReturn(logSearchPropertiesConf).times(2);
    expect(logSearchPropertiesConf.getProperties()).andReturn(oldLogSearchProperties).times(2);
    Capture<Map<String, String>> logSearchPropertiesCapture = EasyMock.newCapture();
    expect(controller.createConfig(anyObject(Cluster.class), anyObject(StackId.class), eq("logsearch-properties"), capture(logSearchPropertiesCapture),
        anyString(), EasyMock.anyObject())).andReturn(config).once();

    Map<String, String> oldLogFeederLog4j = ImmutableMap.of(
        "content", "<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">");

    Map<String, String> expectedLogFeederLog4j = ImmutableMap.of(
        "content", "<!DOCTYPE log4j:configuration SYSTEM \"http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd\">");

    Config logFeederLog4jConf = easyMockSupport.createNiceMock(Config.class);
    expect(cluster.getDesiredConfigByType("logfeeder-log4j")).andReturn(logFeederLog4jConf).atLeastOnce();
    expect(logFeederLog4jConf.getProperties()).andReturn(oldLogFeederLog4j).anyTimes();
    Capture<Map<String, String>> logFeederLog4jCapture = EasyMock.newCapture();
    expect(controller.createConfig(anyObject(Cluster.class), anyObject(StackId.class), anyString(), capture(logFeederLog4jCapture), anyString(),
        EasyMock.anyObject())).andReturn(config).once();

    Map<String, String> oldLogSearchLog4j = ImmutableMap.of(
        "content", "<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">");

    Map<String, String> expectedLogSearchLog4j = ImmutableMap.of(
        "content", "<!DOCTYPE log4j:configuration SYSTEM \"http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd\">");

    Config logSearchLog4jConf = easyMockSupport.createNiceMock(Config.class);
    expect(cluster.getDesiredConfigByType("logsearch-log4j")).andReturn(logSearchLog4jConf).atLeastOnce();
    expect(logSearchLog4jConf.getProperties()).andReturn(oldLogSearchLog4j).anyTimes();
    Capture<Map<String, String>> logSearchLog4jCapture = EasyMock.newCapture();
    expect(controller.createConfig(anyObject(Cluster.class), anyObject(StackId.class), anyString(), capture(logSearchLog4jCapture), anyString(),
        EasyMock.anyObject())).andReturn(config).once();

    Map<String, String> oldLogSearchServiceLogsConf = ImmutableMap.of(
        "content", "<before/><requestHandler name=\"/admin/\"   class=\"solr.admin.AdminHandlers\" /><after/>");

    Map<String, String> expectedLogSearchServiceLogsConf = ImmutableMap.of(
        "content", "<before/><after/>");

    Config logSearchServiceLogsConf = easyMockSupport.createNiceMock(Config.class);
    expect(cluster.getDesiredConfigByType("logsearch-service_logs-solrconfig")).andReturn(logSearchServiceLogsConf).atLeastOnce();
    expect(logSearchServiceLogsConf.getProperties()).andReturn(oldLogSearchServiceLogsConf).anyTimes();
    Capture<Map<String, String>> logSearchServiceLogsConfCapture = EasyMock.newCapture();
    expect(controller.createConfig(anyObject(Cluster.class), anyObject(StackId.class), anyString(), capture(logSearchServiceLogsConfCapture), anyString(),
        EasyMock.anyObject())).andReturn(config).once();

    Map<String, String> oldLogSearchAuditLogsConf = ImmutableMap.of(
        "content", "<before/><requestHandler name=\"/admin/\"   class=\"solr.admin.AdminHandlers\" /><after/>");

    Map<String, String> expectedLogSearchAuditLogsConf = ImmutableMap.of(
        "content", "<before/><after/>");

    Config logSearchAuditLogsConf = easyMockSupport.createNiceMock(Config.class);
    expect(cluster.getDesiredConfigByType("logsearch-audit_logs-solrconfig")).andReturn(logSearchAuditLogsConf).atLeastOnce();
    expect(logSearchAuditLogsConf.getProperties()).andReturn(oldLogSearchAuditLogsConf).anyTimes();
    Capture<Map<String, String>> logSearchAuditLogsConfCapture = EasyMock.newCapture();
    expect(controller.createConfig(anyObject(Cluster.class), anyObject(StackId.class), anyString(), capture(logSearchAuditLogsConfCapture), anyString(),
        EasyMock.anyObject())).andReturn(config).once();

    Map<String, String> oldLogFeederOutputConf = ImmutableMap.of(
        "content",
        "      \"zk_connect_string\":\"{{logsearch_solr_zk_quorum}}{{logsearch_solr_zk_znode}}\",\n" +
            "      \"collection\":\"{{logsearch_solr_collection_service_logs}}\",\n" +
            "      \"number_of_shards\": \"{{logsearch_collection_service_logs_numshards}}\",\n" +
            "      \"splits_interval_mins\": \"{{logsearch_service_logs_split_interval_mins}}\",\n" +
            "\n" +
            "      \"zk_connect_string\":\"{{logsearch_solr_zk_quorum}}{{logsearch_solr_zk_znode}}\",\n" +
            "      \"collection\":\"{{logsearch_solr_collection_audit_logs}}\",\n" +
            "      \"number_of_shards\": \"{{logsearch_collection_audit_logs_numshards}}\",\n" +
            "      \"splits_interval_mins\": \"{{logsearch_audit_logs_split_interval_mins}}\",\n"
    );

    Map<String, String> expectedLogFeederOutputConf = ImmutableMap.of(
        "content",
        "      \"zk_connect_string\":\"{{logsearch_solr_zk_quorum}}{{logsearch_solr_zk_znode}}\",\n" +
            "      \"type\": \"service\",\n" +
            "\n" +
            "      \"zk_connect_string\":\"{{logsearch_solr_zk_quorum}}{{logsearch_solr_zk_znode}}\",\n" +
            "      \"type\": \"audit\",\n"
    );

    Config logFeederOutputConf = easyMockSupport.createNiceMock(Config.class);
    expect(cluster.getDesiredConfigByType("logfeeder-output-config")).andReturn(logFeederOutputConf).atLeastOnce();
    expect(logFeederOutputConf.getProperties()).andReturn(oldLogFeederOutputConf).anyTimes();
    Capture<Map<String, String>> logFeederOutputConfCapture = EasyMock.newCapture();
    expect(controller.createConfig(anyObject(Cluster.class), anyObject(StackId.class), anyString(), capture(logFeederOutputConfCapture), anyString(),
        EasyMock.anyObject())).andReturn(config).once();

    String serviceConfigMapping = "serviceconfigmapping";
    String clusterConfig = "clusterconfig";
    dbAccessor.executeQuery(startsWith("DELETE FROM "+ serviceConfigMapping));
    expectLastCall().once();
    dbAccessor.executeQuery(startsWith("DELETE FROM "+ clusterConfig));
    expectLastCall().once();

    replay(clusters, cluster, dbAccessor);
    replay(controller, injector2);
    replay(logSearchPropertiesConf, logFeederPropertiesConf);
    replay(logFeederLog4jConf, logSearchLog4jConf);
    replay(logSearchServiceLogsConf, logSearchAuditLogsConf);
    replay(logFeederOutputConf);
    new UpgradeCatalog270(injector2).updateLogSearchConfigs();
    easyMockSupport.verifyAll();

    Map<String, String> newLogFeederProperties = logFeederPropertiesCapture.getValue();
    assertTrue(Maps.difference(expectedLogFeederProperties, newLogFeederProperties).areEqual());

    Map<String, String> newLogSearchProperties = logSearchPropertiesCapture.getValue();
    assertTrue(Maps.difference(Collections.emptyMap(), newLogSearchProperties).areEqual());

    Map<String, String> updatedLogFeederLog4j = logFeederLog4jCapture.getValue();
    assertTrue(Maps.difference(expectedLogFeederLog4j, updatedLogFeederLog4j).areEqual());

    Map<String, String> updatedLogSearchLog4j = logSearchLog4jCapture.getValue();
    assertTrue(Maps.difference(expectedLogSearchLog4j, updatedLogSearchLog4j).areEqual());

    Map<String, String> updatedServiceLogsConf = logSearchServiceLogsConfCapture.getValue();
    assertTrue(Maps.difference(expectedLogSearchServiceLogsConf, updatedServiceLogsConf).areEqual());

    Map<String, String> updatedAuditLogsConf = logSearchAuditLogsConfCapture.getValue();
    assertTrue(Maps.difference(expectedLogSearchAuditLogsConf, updatedAuditLogsConf).areEqual());

    Map<String, String> updatedLogFeederOutputConf = logFeederOutputConfCapture.getValue();
    assertTrue(Maps.difference(expectedLogFeederOutputConf, updatedLogFeederOutputConf).areEqual());
  }

  @Test
  public void testUpdateKerberosConfigurations() throws AmbariException, NoSuchFieldException, IllegalAccessException {
    StackId stackId = new StackId("HDP", "2.6.0.0");

    Map<String, Cluster> clusterMap = new HashMap<>();

    Map<String, String> propertiesWithGroup = new HashMap<>();
    propertiesWithGroup.put("group", "ambari_managed_identities");
    propertiesWithGroup.put("kdc_host", "host1.example.com");
    propertiesWithGroup.put("realm", "example.com");

    Config newConfig = createMock(Config.class);
    expect(newConfig.getTag()).andReturn("version2").atLeastOnce();
    expect(newConfig.getType()).andReturn("kerberos-env").atLeastOnce();

    ServiceConfigVersionResponse response = createMock(ServiceConfigVersionResponse.class);

    Config configWithGroup = createMock(Config.class);
    expect(configWithGroup.getProperties()).andReturn(propertiesWithGroup).atLeastOnce();
    expect(configWithGroup.getPropertiesAttributes()).andReturn(Collections.emptyMap()).atLeastOnce();
    expect(configWithGroup.getTag()).andReturn("version1").atLeastOnce();

    Cluster cluster1 = createMock(Cluster.class);
    expect(cluster1.getDesiredConfigByType("kerberos-env")).andReturn(configWithGroup).atLeastOnce();
    expect(cluster1.getConfigsByType("kerberos-env")).andReturn(Collections.singletonMap("v1", configWithGroup)).atLeastOnce();
    expect(cluster1.getServiceByConfigType("kerberos-env")).andReturn("KERBEROS").atLeastOnce();
    expect(cluster1.getClusterName()).andReturn("c1").atLeastOnce();
    expect(cluster1.getDesiredStackVersion()).andReturn(stackId).atLeastOnce();
    expect(cluster1.getConfig(eq("kerberos-env"), anyString())).andReturn(newConfig).atLeastOnce();
    expect(cluster1.addDesiredConfig("ambari-upgrade", Collections.singleton(newConfig), "Updated kerberos-env during Ambari Upgrade from 2.6.2 to 2.7.0.")).andReturn(response).once();

    Map<String, String> propertiesWithoutGroup = new HashMap<>();
    propertiesWithoutGroup.put("kdc_host", "host2.example.com");
    propertiesWithoutGroup.put("realm", "example.com");

    Config configWithoutGroup = createMock(Config.class);
    expect(configWithoutGroup.getProperties()).andReturn(propertiesWithoutGroup).atLeastOnce();

    Cluster cluster2 = createMock(Cluster.class);
    expect(cluster2.getDesiredConfigByType("kerberos-env")).andReturn(configWithoutGroup).atLeastOnce();

    Cluster cluster3 = createMock(Cluster.class);
    expect(cluster3.getDesiredConfigByType("kerberos-env")).andReturn(null).atLeastOnce();

    clusterMap.put("c1", cluster1);
    clusterMap.put("c2", cluster2);
    clusterMap.put("c3", cluster3);

    Clusters clusters = createMock(Clusters.class);
    expect(clusters.getClusters()).andReturn(clusterMap).anyTimes();

    Capture<Map<String, String>> capturedProperties = newCapture();

    AmbariManagementControllerImpl controller = createMockBuilder(AmbariManagementControllerImpl.class)
        .addMockedMethod("createConfiguration", ConfigurationRequest.class)
        .addMockedMethod("getClusters", new Class[]{})
        .addMockedMethod("createConfig", Cluster.class, StackId.class, String.class, Map.class,
            String.class, Map.class)
        .addMockedMethod("getClusterMetadataOnConfigsUpdate", Cluster.class)
        .createMock();
    expect(controller.getClusters()).andReturn(clusters).anyTimes();
    expect(controller.createConfig(eq(cluster1), eq(stackId), eq("kerberos-env"), capture(capturedProperties), anyString(), anyObject(Map.class))).andReturn(newConfig).once();


    Injector injector = createNiceMock(Injector.class);
    ConfigHelper configHelper = createStrictMock(ConfigHelper.class);
    expect(injector.getInstance(AmbariManagementController.class)).andReturn(controller).anyTimes();
    expect(injector.getInstance(MetadataHolder.class)).andReturn(createNiceMock(MetadataHolder.class)).anyTimes();
    expect(injector.getInstance(AgentConfigsHolder.class)).andReturn(createNiceMock(AgentConfigsHolder.class)).anyTimes();
    expect(injector.getInstance(AmbariServer.class)).andReturn(createNiceMock(AmbariServer.class)).anyTimes();
    expect(injector.getInstance(ConfigHelper.class)).andReturn(configHelper).anyTimes();
    KerberosHelper kerberosHelperMock = createNiceMock(KerberosHelper.class);
    expect(kerberosHelperMock.createTemporaryDirectory()).andReturn(new File("/invalid/file/path")).times(2);
    expect(injector.getInstance(KerberosHelper.class)).andReturn(kerberosHelperMock).anyTimes();

    configHelper.updateAgentConfigs(anyObject(Set.class));
    expectLastCall();

    replay(controller, clusters, cluster1, cluster2, configWithGroup, configWithoutGroup, newConfig, response, injector, kerberosHelperMock, configHelper);

    Field field = AbstractUpgradeCatalog.class.getDeclaredField("configuration");

    UpgradeCatalog270 upgradeCatalog270 = createMockBuilder(UpgradeCatalog270.class).addMockedMethod("getPrepareIdentityServerAction").addMockedMethod("executeInTransaction").createMock();
    PrepareKerberosIdentitiesServerAction mockAction = createNiceMock(PrepareKerberosIdentitiesServerAction.class);
    expect(upgradeCatalog270.getPrepareIdentityServerAction()).andReturn(mockAction).times(2);
    upgradeCatalog270.executeInTransaction(anyObject());
    expectLastCall().times(2);
    upgradeCatalog270.injector = injector;

    replay(upgradeCatalog270);

    field.set(upgradeCatalog270, createNiceMock(Configuration.class));
    upgradeCatalog270.updateKerberosConfigurations();

    verify(controller, clusters, cluster1, cluster2, configWithGroup, configWithoutGroup, newConfig, response, injector, upgradeCatalog270, configHelper);


    Assert.assertEquals(1, capturedProperties.getValues().size());

    Map<String, String> properties = capturedProperties.getValue();
    Assert.assertEquals(3, properties.size());
    Assert.assertEquals("ambari_managed_identities", properties.get("ipa_user_group"));
    Assert.assertEquals("host1.example.com", properties.get("kdc_host"));
    Assert.assertEquals("example.com", properties.get("realm"));

    Assert.assertEquals(3, propertiesWithGroup.size());
    Assert.assertEquals("ambari_managed_identities", propertiesWithGroup.get("group"));
    Assert.assertEquals("host1.example.com", propertiesWithGroup.get("kdc_host"));
    Assert.assertEquals("example.com", propertiesWithGroup.get("realm"));
  }

  @Test
  public void shouldSaveLdapConfigurationIfPropertyIsSetInAmbariProperties() throws Exception {
    final Module module = getTestGuiceModule();

    expect(entityManager.find(anyObject(), anyObject())).andReturn(null).anyTimes();
    final Map<String, String> properties = new HashMap<>();
    properties.put(AmbariServerConfigurationKey.LDAP_ENABLED.key(), "true");
    properties.put(AmbariServerConfigurationKey.AMBARI_MANAGES_LDAP_CONFIGURATION.key(), "true");
    properties.put(AmbariServerConfigurationKey.LDAP_ENABLED_SERVICES.key(), "AMBARI");

    expect(ambariConfigurationDao.reconcileCategory(AmbariServerConfigurationCategory.LDAP_CONFIGURATION.getCategoryName(), properties, false)).andReturn(true).once();
    replay(entityManager, ambariConfigurationDao);

    final Injector injector = Guice.createInjector(module);
    injector.getInstance(Configuration.class).setProperty("ambari.ldap.isConfigured", "true");
    final UpgradeCatalog270 upgradeCatalog270 = new UpgradeCatalog270(injector);
    upgradeCatalog270.moveAmbariPropertiesToAmbariConfiguration();
    verify(entityManager, ambariConfigurationDao);
  }

  @Test
  public void shouldNotSaveLdapConfigurationIfPropertyIsNotSetInAmbariProperties() throws Exception {
    final Module module = getTestGuiceModule();
    expect(entityManager.find(anyObject(), anyObject())).andReturn(null).anyTimes();
    final Map<String, String> properties = new HashMap<>();
    properties.put(AmbariServerConfigurationKey.LDAP_ENABLED.key(), "true");
    expect(ambariConfigurationDao.reconcileCategory(AmbariServerConfigurationCategory.LDAP_CONFIGURATION.getCategoryName(), properties, false)).andReturn(true).once();
    replay(entityManager, ambariConfigurationDao);

    final Injector injector = Guice.createInjector(module);
    final UpgradeCatalog270 upgradeCatalog270 = new UpgradeCatalog270(injector);
    upgradeCatalog270.moveAmbariPropertiesToAmbariConfiguration();

    expectedException.expect(AssertionError.class);
    expectedException.expectMessage("Expectation failure on verify");
    verify(entityManager, ambariConfigurationDao);
  }

  @Test
  public void testupdateKerberosDescriptorArtifact() throws Exception {
    String kerberosDescriptorJson = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("org/apache/ambari/server/upgrade/kerberos_descriptor.json"), "UTF-8");

    //there is HIVE -> WEBHCAT_SERVER -> configurations -> core-site -> hadoop.proxyuser.HTTP.hosts
    assertTrue(kerberosDescriptorJson.contains("${clusterHostInfo/webhcat_server_host|append(core-site/hadoop.proxyuser.HTTP.hosts, \\\\\\\\,, true)}"));
    assertTrue(kerberosDescriptorJson.contains("${clusterHostInfo/rm_host}"));

    ArtifactEntity artifactEntity = new ArtifactEntity();
    artifactEntity.setArtifactName("kerberos_descriptor");
    artifactEntity.setArtifactData(GSON.<Map<String, Object>>fromJson(kerberosDescriptorJson, Map.class));

    UpgradeCatalog270 upgradeCatalog270 = createMockBuilder(UpgradeCatalog270.class).createMock();

    expect(artifactDAO.merge(artifactEntity)).andReturn(artifactEntity);

    replay(upgradeCatalog270);

    upgradeCatalog270.updateKerberosDescriptorArtifact(artifactDAO, artifactEntity);

    final String newKerberosDescriptorJson = GSON.toJson(artifactEntity.getArtifactData());

    int oldCount = substringCount(kerberosDescriptorJson, AMBARI_INFRA_OLD_NAME);
    int newCount = substringCount(newKerberosDescriptorJson, AMBARI_INFRA_NEW_NAME);
    assertThat(newCount, is(oldCount));

    assertTrue(newKerberosDescriptorJson.contains("${clusterHostInfo/webhcat_server_hosts|append(core-site/hadoop.proxyuser.HTTP.hosts, \\\\,, true)}"));
    assertTrue(newKerberosDescriptorJson.contains("${clusterHostInfo/resourcemanager_hosts}"));

    verify(upgradeCatalog270);
  }

  private int substringCount(String source, String substring) {
    int count = 0;
    int i = -1;
    while ((i = source.indexOf(substring, i + 1)) != -1) {
      ++count;
    }
    return count;
  }

  @Test
  public void testupdateLuceneMatchVersion() throws Exception {
    String solrConfigXml = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("org/apache/ambari/server/upgrade/solrconfig-v500.xml.j2"), "UTF-8");

    UpgradeCatalog270 upgradeCatalog270 = createMockBuilder(UpgradeCatalog270.class)
            .createMock();

    replay(upgradeCatalog270);

    String updated = upgradeCatalog270.updateLuceneMatchVersion(solrConfigXml,"7.3.1");

    assertThat(updated.contains("<luceneMatchVersion>7.3.1</luceneMatchVersion>"), is(true));
    assertThat(updated.contains("<luceneMatchVersion>5.0.0</luceneMatchVersion>"), is(false));
    verify(upgradeCatalog270);
  }

  @Test
  public void testupdateMergeFactor() throws Exception {
    String solrConfigXml = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("org/apache/ambari/server/upgrade/solrconfig-v500.xml.j2"), "UTF-8");

    UpgradeCatalog270 upgradeCatalog270 = createMockBuilder(UpgradeCatalog270.class)
            .createMock();

    replay(upgradeCatalog270);

    String updated = upgradeCatalog270.updateMergeFactor(solrConfigXml, "logsearch_service_logs_merge_factor");

    assertThat(updated.contains("<int name=\"maxMergeAtOnce\">{{logsearch_service_logs_merge_factor}}</int>"), is(true));
    assertThat(updated.contains("<int name=\"segmentsPerTier\">{{logsearch_service_logs_merge_factor}}</int>"), is(true));
    assertThat(updated.contains("<mergeFactor>{{logsearch_service_logs_merge_factor}}</mergeFactor>"), is(false));
    verify(upgradeCatalog270);
  }

  @Test
  public void testupdateInfraSolrEnv() {
    String solrConfigXml = "#SOLR_HOST=\"192.168.1.1\"\n" +
            "SOLR_HOST=\"192.168.1.1\"\n" +
            "SOLR_KERB_NAME_RULES=\"{{infra_solr_kerberos_name_rules}}\"\n" +
            "SOLR_AUTHENTICATION_CLIENT_CONFIGURER=\"org.apache.solr.client.solrj.impl.Krb5HttpClientConfigurer\"";

    UpgradeCatalog270 upgradeCatalog270 = createMockBuilder(UpgradeCatalog270.class)
            .createMock();

    replay(upgradeCatalog270);

    String updated = upgradeCatalog270.updateInfraSolrEnv(solrConfigXml);

    assertThat(updated, is("SOLR_HOST=`hostname -f`\nSOLR_HOST=`hostname -f`\n\nSOLR_AUTH_TYPE=\"kerberos\""));
    verify(upgradeCatalog270);
  }

  @Test
  public void testRemoveAdminHandlers() {
    UpgradeCatalog270 upgradeCatalog270 = createMockBuilder(UpgradeCatalog270.class)
            .createMock();

    replay(upgradeCatalog270);

    String updated = upgradeCatalog270.removeAdminHandlers("<requestHandler name=\"/admin/\"\n" +
            "                  class=\"solr.admin.AdminHandlers\"/>");

    assertThat(updated, is(""));
    verify(upgradeCatalog270);
  }

  @Test
  public void testUpdateAmsConfigs() throws Exception {

    Map<String, String> oldProperties = new HashMap<String, String>() {
      {
        put("timeline.metrics.service.default.result.limit", "15840");
        put("timeline.container-metrics.ttl", "2592000");
        put("timeline.metrics.cluster.aggregate.splitpoints", "cpu_user,mem_free");
        put("timeline.metrics.host.aggregate.splitpoints", "kafka.metric,nimbus.metric");
        put("timeline.metrics.downsampler.topn.metric.patterns", "dfs.NNTopUserOpCounts.windowMs=60000.op=__%.user=%," +
          "dfs.NNTopUserOpCounts.windowMs=300000.op=__%.user=%,dfs.NNTopUserOpCounts.windowMs=1500000.op=__%.user=%");
      }
    };
    Map<String, String> newProperties = new HashMap<String, String>() {
      {
        put("timeline.metrics.service.default.result.limit", "5760");
        put("timeline.container-metrics.ttl", "1209600");
        put("timeline.metrics.downsampler.topn.metric.patterns", StringUtils.EMPTY);
      }
    };

    Map<String, String> oldAmsHBaseSiteProperties = new HashMap<String, String>() {
      {
        put("hbase.snapshot.enabled", "false");
      }
    };

    Map<String, String> newAmsHBaseSiteProperties = new HashMap<String, String>() {
      {
        put("hbase.snapshot.enabled", "true");
      }
    };

    EasyMockSupport easyMockSupport = new EasyMockSupport();

    Clusters clusters = easyMockSupport.createNiceMock(Clusters.class);
    final Cluster cluster = easyMockSupport.createNiceMock(Cluster.class);
    Config mockAmsSite = easyMockSupport.createNiceMock(Config.class);

    expect(clusters.getClusters()).andReturn(new HashMap<String, Cluster>() {{
      put("normal", cluster);
    }}).once();
    expect(cluster.getDesiredConfigByType("ams-site")).andReturn(mockAmsSite).atLeastOnce();
    expect(mockAmsSite.getProperties()).andReturn(oldProperties).anyTimes();

    Config mockAmsHbaseSite = easyMockSupport.createNiceMock(Config.class);
    expect(cluster.getDesiredConfigByType("ams-hbase-site")).andReturn(mockAmsHbaseSite).atLeastOnce();
    expect(mockAmsHbaseSite.getProperties()).andReturn(oldAmsHBaseSiteProperties).anyTimes();

    Injector injector = easyMockSupport.createNiceMock(Injector.class);
    expect(injector.getInstance(Gson.class)).andReturn(null).anyTimes();
    expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(null).anyTimes();

    replay(injector, clusters, mockAmsSite, mockAmsHbaseSite, cluster);

    AmbariManagementControllerImpl controller = createMockBuilder(AmbariManagementControllerImpl.class)
      .addMockedMethod("createConfiguration", ConfigurationRequest.class)
      .addMockedMethod("getClusters", new Class[] { })
      .addMockedMethod("createConfig", Cluster.class, StackId.class, String.class, Map.class,
          String.class, Map.class)
      .withConstructor(createNiceMock(ActionManager.class), clusters, injector)
      .createNiceMock();

    Injector injector2 = easyMockSupport.createNiceMock(Injector.class);
    Capture<Map> propertiesCapture = EasyMock.newCapture(CaptureType.ALL);

    expect(injector2.getInstance(AmbariManagementController.class)).andReturn(controller).anyTimes();
    expect(controller.getClusters()).andReturn(clusters).anyTimes();
    expect(controller.createConfig(anyObject(Cluster.class), anyObject(StackId.class), anyString(), capture(propertiesCapture), anyString(),
      anyObject(Map.class))).andReturn(createNiceMock(Config.class)).times(2);

    replay(controller, injector2);
    new UpgradeCatalog270(injector2).updateAmsConfigs();
    easyMockSupport.verifyAll();

    assertEquals(propertiesCapture.getValues().size(), 2);

    Map<String, String> updatedProperties = propertiesCapture.getValues().get(0);
    assertTrue(Maps.difference(newProperties, updatedProperties).areEqual());

    updatedProperties = propertiesCapture.getValues().get(1);
    assertTrue(Maps.difference(newAmsHBaseSiteProperties, updatedProperties).areEqual());

  }

  @Test
  public void testUpdateAmsConfigsWithNoContainerMetrics() throws Exception {

    Map<String, String> oldProperties = new HashMap<String, String>() {
      {
        put("timeline.metrics.service.default.result.limit", "15840");
        put("timeline.metrics.host.aggregate.splitpoints", "kafka.metric,nimbus.metric");
      }
    };
    Map<String, String> newProperties = new HashMap<String, String>() {
      {
        put("timeline.metrics.service.default.result.limit", "5760");
      }
    };

    EasyMockSupport easyMockSupport = new EasyMockSupport();

    Clusters clusters = easyMockSupport.createNiceMock(Clusters.class);
    final Cluster cluster = easyMockSupport.createNiceMock(Cluster.class);
    Config mockAmsSite = easyMockSupport.createNiceMock(Config.class);

    expect(clusters.getClusters()).andReturn(new HashMap<String, Cluster>() {{
      put("normal", cluster);
    }}).once();
    expect(cluster.getDesiredConfigByType("ams-site")).andReturn(mockAmsSite).atLeastOnce();
    expect(mockAmsSite.getProperties()).andReturn(oldProperties).anyTimes();

    Injector injector = easyMockSupport.createNiceMock(Injector.class);
    expect(injector.getInstance(Gson.class)).andReturn(null).anyTimes();
    expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(null).anyTimes();

    replay(injector, clusters, mockAmsSite, cluster);

    AmbariManagementControllerImpl controller = createMockBuilder(AmbariManagementControllerImpl.class)
      .addMockedMethod("createConfiguration", ConfigurationRequest.class)
      .addMockedMethod("getClusters", new Class[] { })
      .addMockedMethod("createConfig", Cluster.class, StackId.class, String.class, Map.class,
          String.class, Map.class)
      .withConstructor(createNiceMock(ActionManager.class), clusters, injector)
      .createNiceMock();

    Injector injector2 = easyMockSupport.createNiceMock(Injector.class);
    Capture<Map> propertiesCapture = EasyMock.newCapture();

    expect(injector2.getInstance(AmbariManagementController.class)).andReturn(controller).anyTimes();
    expect(controller.getClusters()).andReturn(clusters).anyTimes();
    expect(controller.createConfig(anyObject(Cluster.class), anyObject(StackId.class), anyString(), capture(propertiesCapture), anyString(),
      anyObject(Map.class))).andReturn(createNiceMock(Config.class)).once();

    replay(controller, injector2);
    new UpgradeCatalog270(injector2).updateAmsConfigs();
    easyMockSupport.verifyAll();

    Map<String, String> updatedProperties = propertiesCapture.getValue();
    assertTrue(Maps.difference(newProperties, updatedProperties).areEqual());
  }

  @Test
  public void testStormConfigs() throws Exception {

    Map<String, String> stormProperties = new HashMap<String, String>() {
      {
        put("_storm.thrift.nonsecure.transport", "org.apache.storm.security.auth.SimpleTransportPlugin");
        put("_storm.thrift.secure.transport", "org.apache.storm.security.auth.kerberos.KerberosSaslTransportPlugin");
        put("storm.thrift.transport", "{{storm_thrift_transport}}");
        put("storm.zookeeper.port", "2181");
      }
    };
    Map<String, String> newStormProperties = new HashMap<String, String>() {
      {
        put("storm.thrift.transport", "org.apache.storm.security.auth.SimpleTransportPlugin");
        put("storm.zookeeper.port", "2181");
      }
    };

    EasyMockSupport easyMockSupport = new EasyMockSupport();

    Clusters clusters = easyMockSupport.createNiceMock(Clusters.class);
    final Cluster cluster = easyMockSupport.createNiceMock(Cluster.class);
    Config mockStormSite = easyMockSupport.createNiceMock(Config.class);

    expect(clusters.getClusters()).andReturn(new HashMap<String, Cluster>() {{
      put("normal", cluster);
    }}).once();
    expect(cluster.getDesiredConfigByType("storm-site")).andReturn(mockStormSite).atLeastOnce();
    expect(cluster.getSecurityType()).andReturn(SecurityType.NONE).anyTimes();
    expect(mockStormSite.getProperties()).andReturn(stormProperties).anyTimes();

    Injector injector = easyMockSupport.createNiceMock(Injector.class);

    replay(injector, clusters, mockStormSite, cluster);

    AmbariManagementControllerImpl controller = createMockBuilder(AmbariManagementControllerImpl.class)
      .addMockedMethod("getClusters", new Class[] { })
      .addMockedMethod("createConfig", Cluster.class, StackId.class, String.class, Map.class,
          String.class, Map.class)
      .withConstructor(createNiceMock(ActionManager.class), clusters, injector)
      .createNiceMock();

    Injector injector2 = easyMockSupport.createNiceMock(Injector.class);
    Capture<Map> propertiesCapture = EasyMock.newCapture();

    expect(injector2.getInstance(AmbariManagementController.class)).andReturn(controller).anyTimes();
    expect(controller.getClusters()).andReturn(clusters).anyTimes();
    expect(controller.createConfig(anyObject(Cluster.class), anyObject(StackId.class), anyString(), capture(propertiesCapture), anyString(),
      anyObject(Map.class))).andReturn(createNiceMock(Config.class)).once();

    replay(controller, injector2);
    new UpgradeCatalog270(injector2).updateStormConfigs();
    easyMockSupport.verifyAll();

    Map<String, String> updatedProperties = propertiesCapture.getValue();
    assertTrue(Maps.difference(newStormProperties, updatedProperties).areEqual());

  }

  @Test
  public void testStormConfigsWithKerberos() throws Exception {

    Map<String, String> stormProperties = new HashMap<String, String>() {
      {
        put("_storm.thrift.nonsecure.transport", "org.apache.storm.security.auth.SimpleTransportPlugin");
        put("_storm.thrift.secure.transport", "org.apache.storm.security.auth.kerberos.KerberosSaslTransportPlugin");
        put("storm.thrift.transport", "{{storm_thrift_transport}}");
        put("storm.zookeeper.port", "2181");
      }
    };
    Map<String, String> newStormProperties = new HashMap<String, String>() {
      {
        put("storm.thrift.transport", "org.apache.storm.security.auth.kerberos.KerberosSaslTransportPlugin");
        put("storm.zookeeper.port", "2181");
      }
    };

    EasyMockSupport easyMockSupport = new EasyMockSupport();

    Clusters clusters = easyMockSupport.createNiceMock(Clusters.class);
    final Cluster cluster = easyMockSupport.createNiceMock(Cluster.class);
    Config mockStormSite = easyMockSupport.createNiceMock(Config.class);

    expect(clusters.getClusters()).andReturn(new HashMap<String, Cluster>() {{
      put("normal", cluster);
    }}).once();
    expect(cluster.getDesiredConfigByType("storm-site")).andReturn(mockStormSite).atLeastOnce();
    expect(cluster.getSecurityType()).andReturn(SecurityType.KERBEROS).anyTimes();
    expect(mockStormSite.getProperties()).andReturn(stormProperties).anyTimes();

    Injector injector = easyMockSupport.createNiceMock(Injector.class);

    replay(injector, clusters, mockStormSite, cluster);

    AmbariManagementControllerImpl controller = createMockBuilder(AmbariManagementControllerImpl.class)
      .addMockedMethod("getClusters", new Class[] { })
      .addMockedMethod("createConfig", Cluster.class, StackId.class, String.class, Map.class,
          String.class, Map.class)
      .withConstructor(createNiceMock(ActionManager.class), clusters, injector)
      .createNiceMock();

    Injector injector2 = easyMockSupport.createNiceMock(Injector.class);
    Capture<Map> propertiesCapture = EasyMock.newCapture();

    expect(injector2.getInstance(AmbariManagementController.class)).andReturn(controller).anyTimes();
    expect(controller.getClusters()).andReturn(clusters).anyTimes();
    expect(controller.createConfig(anyObject(Cluster.class), anyObject(StackId.class), anyString(), capture(propertiesCapture), anyString(),
      anyObject(Map.class))).andReturn(createNiceMock(Config.class)).once();

    replay(controller, injector2);
    new UpgradeCatalog270(injector2).updateStormConfigs();
    easyMockSupport.verifyAll();

    Map<String, String> updatedProperties = propertiesCapture.getValue();
    assertTrue(Maps.difference(newStormProperties, updatedProperties).areEqual());

  }

  @Test
  public void testClearHadoopMetrics2Content() throws Exception {

    Map<String, String> oldContentProperty = new HashMap<String, String>() {
      {
        put("content", "# Licensed to the Apache Software Foundation (ASF) under one or more...");
      }
    };
    Map<String, String> newContentProperty = new HashMap<String, String>() {
      {
        put("content", "");
      }
    };

    EasyMockSupport easyMockSupport = new EasyMockSupport();

    Clusters clusters = easyMockSupport.createNiceMock(Clusters.class);
    final Cluster cluster = easyMockSupport.createNiceMock(Cluster.class);
    Config mockHadoopMetrics2Properties = easyMockSupport.createNiceMock(Config.class);

    expect(clusters.getClusters()).andReturn(new HashMap<String, Cluster>() {{
      put("normal", cluster);
    }}).once();
    expect(cluster.getDesiredConfigByType("hadoop-metrics2.properties")).andReturn(mockHadoopMetrics2Properties).atLeastOnce();
    expect(mockHadoopMetrics2Properties.getProperties()).andReturn(oldContentProperty).anyTimes();

    Injector injector = easyMockSupport.createNiceMock(Injector.class);

    replay(injector, clusters, mockHadoopMetrics2Properties, cluster);

    AmbariManagementControllerImpl controller = createMockBuilder(AmbariManagementControllerImpl.class)
        .addMockedMethod("getClusters", new Class[] { })
        .addMockedMethod("createConfig", Cluster.class, StackId.class, String.class, Map.class,
            String.class, Map.class)
        .withConstructor(createNiceMock(ActionManager.class), clusters, injector)
        .createNiceMock();

    Injector injector2 = easyMockSupport.createNiceMock(Injector.class);
    Capture<Map> propertiesCapture = EasyMock.newCapture();

    expect(injector2.getInstance(AmbariManagementController.class)).andReturn(controller).anyTimes();
    expect(controller.getClusters()).andReturn(clusters).anyTimes();
    expect(controller.createConfig(anyObject(Cluster.class), anyObject(StackId.class), anyString(), capture(propertiesCapture), anyString(),
        anyObject(Map.class))).andReturn(createNiceMock(Config.class)).once();

    replay(controller, injector2);
    new UpgradeCatalog270(injector2).clearHadoopMetrics2Content();
    easyMockSupport.verifyAll();

    Map<String, String> updatedProperties = propertiesCapture.getValue();
    assertTrue(Maps.difference(newContentProperty, updatedProperties).areEqual());

  }
}
