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

import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.DB_DRIVER_FILENAME;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.HOST_SYS_PREPPED;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.JAVA_VERSION;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.NOT_MANAGED_HDFS_PATH_LIST;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_NAME;
import static org.apache.ambari.server.agent.ExecutionCommand.KeyNames.STACK_VERSION;
import static org.easymock.EasyMock.anyBoolean;
import static org.easymock.EasyMock.anyLong;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.captureBoolean;
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.partialMockBuilder;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reset;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import jakarta.persistence.RollbackException;

import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.ClusterNotFoundException;
import org.apache.ambari.server.HostNotFoundException;
import org.apache.ambari.server.ParentObjectNotFoundException;
import org.apache.ambari.server.ServiceComponentHostNotFoundException;
import org.apache.ambari.server.ServiceComponentNotFoundException;
import org.apache.ambari.server.ServiceNotFoundException;
import org.apache.ambari.server.actionmanager.ActionDBAccessorImpl;
import org.apache.ambari.server.actionmanager.ActionManager;
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.configuration.Configuration;
import org.apache.ambari.server.controller.internal.RequestStageContainer;
import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.mpack.MpackManagerFactory;
import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
import org.apache.ambari.server.orm.entities.LdapSyncSpecEntity;
import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
import org.apache.ambari.server.security.authorization.Users;
import org.apache.ambari.server.security.authorization.internal.InternalAuthenticationToken;
import org.apache.ambari.server.security.encryption.CredentialStoreService;
import org.apache.ambari.server.security.encryption.CredentialStoreType;
import org.apache.ambari.server.security.ldap.AmbariLdapDataPopulator;
import org.apache.ambari.server.security.ldap.LdapBatchDto;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.state.ComponentInfo;
import org.apache.ambari.server.state.Config;
import org.apache.ambari.server.state.ConfigHelper;
import org.apache.ambari.server.state.DesiredConfig;
import org.apache.ambari.server.state.Host;
import org.apache.ambari.server.state.MaintenanceState;
import org.apache.ambari.server.state.Module;
import org.apache.ambari.server.state.Mpack;
import org.apache.ambari.server.state.PropertyInfo;
import org.apache.ambari.server.state.RepositoryInfo;
import org.apache.ambari.server.state.SecurityType;
import org.apache.ambari.server.state.Service;
import org.apache.ambari.server.state.ServiceComponent;
import org.apache.ambari.server.state.ServiceComponentHost;
import org.apache.ambari.server.state.ServiceInfo;
import org.apache.ambari.server.state.ServiceOsSpecific;
import org.apache.ambari.server.state.StackId;
import org.apache.ambari.server.state.StackInfo;
import org.apache.ambari.server.state.State;
import org.apache.ambari.server.state.stack.OsFamily;
import org.easymock.Capture;
import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.security.core.context.SecurityContextHolder;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Provider;
import com.google.inject.util.Modules;

import junit.framework.Assert;

/**
 * AmbariManagementControllerImpl unit tests
 */
public class AmbariManagementControllerImplTest {

  // Mocks
  private static final AmbariLdapDataPopulator ldapDataPopulator = createMock(AmbariLdapDataPopulator.class);
  private static final Clusters clusters = createNiceMock(Clusters.class);
  private static final ActionDBAccessorImpl actionDBAccessor = createNiceMock(ActionDBAccessorImpl.class);
  private static final AmbariMetaInfo ambariMetaInfo = createMock(AmbariMetaInfo.class);
  private static final Users users = createMock(Users.class);
  private static final AmbariSessionManager sessionManager = createNiceMock(AmbariSessionManager.class);

  @BeforeClass
  public static void setupAuthentication() {
    // Set authenticated user so that authorization checks will pass
    InternalAuthenticationToken authenticationToken = new InternalAuthenticationToken("admin");
    authenticationToken.setAuthenticated(true);
    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
  }

  @Before
  public void before() throws Exception {
    reset(ldapDataPopulator, clusters, actionDBAccessor, ambariMetaInfo, users, sessionManager);
  }

  @Test
  public void testgetAmbariServerURI() throws Exception {
    // create mocks
    Injector injector = createStrictMock(Injector.class);
    Capture<AmbariManagementController> controllerCapture = EasyMock.newCapture();

    // set expectations
    constructorInit(injector, controllerCapture, createNiceMock(KerberosHelper.class));

    //replay
    replay(injector);


    AmbariManagementControllerImpl controller = new AmbariManagementControllerImpl(null, null, injector);

    class AmbariConfigsSetter {
      public void setConfigs(AmbariManagementController controller, String masterProtocol, String masterHostname, Integer masterPort) throws Exception {
        // masterProtocol
        Class<?> c = controller.getClass();
        Field f = c.getDeclaredField("masterProtocol");
        f.setAccessible(true);
        f.set(controller, masterProtocol);

        // masterHostname
        f = c.getDeclaredField("masterHostname");
        f.setAccessible(true);
        f.set(controller, masterHostname);

        // masterPort
        f = c.getDeclaredField("masterPort");
        f.setAccessible(true);
        f.set(controller, masterPort);
      }
    }

    AmbariConfigsSetter ambariConfigsSetter = new AmbariConfigsSetter();

    ambariConfigsSetter.setConfigs(controller, "http", "hostname", 8080);
    assertEquals("http://hostname:8080/jdk_path", controller.getAmbariServerURI("/jdk_path"));

    ambariConfigsSetter.setConfigs(controller, "https", "somesecuredhost", 8443);
    assertEquals("https://somesecuredhost:8443/mysql_path", controller.getAmbariServerURI("/mysql_path"));

    ambariConfigsSetter.setConfigs(controller, "https", "othersecuredhost", 8443);
    assertEquals("https://othersecuredhost:8443/oracle/ojdbc/", controller.getAmbariServerURI("/oracle/ojdbc/"));

    ambariConfigsSetter.setConfigs(controller, "http", "hostname", 8080);
    assertEquals("http://hostname:8080/jdk_path?query", controller.getAmbariServerURI("/jdk_path?query"));

    verify(injector);
  }

  @Test
  public void testGetClusters() throws Exception {
    // member state mocks
    Injector injector = createStrictMock(Injector.class);
    Capture<AmbariManagementController> controllerCapture = EasyMock.newCapture();

    ClusterRequest request1 = new ClusterRequest(null, "cluster1", "1", Collections.emptySet());
    Cluster cluster = createNiceMock(Cluster.class);
    ClusterResponse response = createNiceMock(ClusterResponse.class);

    Set<ClusterRequest> setRequests = new HashSet<>();
    setRequests.add(request1);

    // expectations
    // constructor init
    constructorInit(injector, controllerCapture, createNiceMock(KerberosHelper.class));

    // getCluster
    expect(clusters.getCluster("cluster1")).andReturn(cluster);
    expect(cluster.convertToResponse()).andReturn(response);

    CredentialStoreService credentialStoreService = createNiceMock(CredentialStoreService.class);
    expect(credentialStoreService.isInitialized(anyObject(CredentialStoreType.class))).andReturn(true).anyTimes();

    // replay mocks
    replay(injector, clusters, cluster, response, credentialStoreService);

    // test
    AmbariManagementController controller = new AmbariManagementControllerImpl(null, clusters, injector);

    Field f = controller.getClass().getDeclaredField("credentialStoreService");
    f.setAccessible(true);
    f.set(controller, credentialStoreService);

    Set<ClusterResponse> setResponses = controller.getClusters(setRequests);

    // assert and verify
    assertEquals(1, setResponses.size());
    assertTrue(setResponses.contains(response));

    verify(injector, clusters, cluster, response, credentialStoreService);
  }

  @Test
  public void testGetClientHostForRunningAction_componentIsNull() throws Exception {
    Injector injector = createNiceMock(Injector.class);

    Cluster cluster = createNiceMock(Cluster.class);
    Service service = createNiceMock(Service.class);
    ServiceComponent component = null;

    replay(cluster, service, injector);

    AmbariManagementControllerImpl controller = new AmbariManagementControllerImpl(null, clusters, injector);
    String host = controller.getClientHostForRunningAction(cluster, service, component);

    assertNull(host);
    verify(cluster, service, injector);
  }

  @Test
  public void testGetClientHostForRunningAction_componentMapIsEmpty() throws Exception {
    Injector injector = createNiceMock(Injector.class);

    Cluster cluster = createNiceMock(Cluster.class);
    Service service = createNiceMock(Service.class);
    ServiceComponent component = createNiceMock(ServiceComponent.class);
    Map<String, ServiceComponentHost> hostMap = new HashMap<>();
    expect(component.getServiceComponentHosts()).andReturn(hostMap);

    replay(cluster, service, component, injector);

    AmbariManagementControllerImpl controller = new AmbariManagementControllerImpl(null, clusters, injector);
    String host = controller.getClientHostForRunningAction(cluster, service, component);

    verify(cluster, service, component, injector);
    assertNull(host);
  }

  @Test
  public void testGetClientHostForRunningAction_returnsHelathyHost() throws Exception {
    Injector injector = createNiceMock(Injector.class);
    ActionManager actionManager = createNiceMock(ActionManager.class);

    Cluster cluster = createNiceMock(Cluster.class);
    Service service = createNiceMock(Service.class);
    ServiceComponent component = createNiceMock(ServiceComponent.class);
    Map<String, ServiceComponentHost> hostMap = createNiceMock(Map.class);
    Set<String> hostsSet = createNiceMock(Set.class);
    expect(hostMap.isEmpty()).andReturn(false);
    expect(hostMap.keySet()).andReturn(hostsSet);
    expect(component.getServiceComponentHosts()).andReturn(hostMap).times(2);

    replay(cluster, service, component, injector, actionManager, hostMap, hostsSet);

    AmbariManagementControllerImpl controller = createMockBuilder(AmbariManagementControllerImpl.class)
        .addMockedMethod("filterHostsForAction")
        .addMockedMethod("getHealthyHost")
        .withConstructor(actionManager, clusters, injector)
        .createMock();
    expect(controller.getHealthyHost(hostsSet)).andReturn("healthy_host");
    controller.filterHostsForAction(hostsSet, service, cluster, Resource.Type.Cluster);
    expectLastCall().once();

    replay(controller);
    String host = controller.getClientHostForRunningAction(cluster, service, component);

    assertEquals("healthy_host", host);
    verify(controller, cluster, service, component, injector, hostMap);
  }

  @Test
  public void testGetClientHostForRunningAction_clientComponent() throws Exception {
    Injector injector = createNiceMock(Injector.class);
    Cluster cluster = createNiceMock(Cluster.class);
    Service service = createNiceMock(Service.class);
    StackId stackId = createNiceMock(StackId.class);
    ServiceComponent component = createNiceMock(ServiceComponent.class);

    expect(service.getName()).andReturn("service");
    expect(service.getServiceComponent("component")).andReturn(component);
    expect(service.getDesiredStackId()).andReturn(stackId);
    expect(stackId.getStackName()).andReturn("stack");
    expect(stackId.getStackVersion()).andReturn("1.0");

    ServiceInfo serviceInfo = createNiceMock(ServiceInfo.class);
    ComponentInfo compInfo = createNiceMock(ComponentInfo.class);
    expect(serviceInfo.getClientComponent()).andReturn(compInfo);
    expect(compInfo.getName()).andReturn("component");
    expect(component.getServiceComponentHosts()).andReturn(Collections.singletonMap("host", null));
    expect(ambariMetaInfo.getService("stack", "1.0", "service")).andReturn(serviceInfo);

    replay(injector, cluster, service, component, serviceInfo, compInfo, ambariMetaInfo, stackId);

    AmbariManagementControllerImpl controller = new AmbariManagementControllerImpl(null, clusters, injector);
    setAmbariMetaInfo(ambariMetaInfo, controller);
    ServiceComponent resultComponent = controller.getClientComponentForRunningAction(cluster, service);

    assertNotNull(resultComponent);
    assertEquals(component, resultComponent);
    verify(injector, cluster, service, component, serviceInfo, compInfo, ambariMetaInfo, stackId);
  }

  @Test
  public void testGetClientHostForRunningAction_clientComponentThrowsException() throws Exception {
    Injector injector = createNiceMock(Injector.class);
    Cluster cluster = createNiceMock(Cluster.class);
    Service service = createNiceMock(Service.class);
    StackId stackId = createNiceMock(StackId.class);
    ServiceComponent component1 = createNiceMock(ServiceComponent.class);
    ServiceComponent component2 = createNiceMock(ServiceComponent.class);

    expect(service.getName()).andReturn("service");
    expect(service.getServiceComponent("component")).andThrow(
      new ServiceComponentNotFoundException("cluster", "service", "component"));
    expect(service.getDesiredStackId()).andReturn(stackId);
    expect(stackId.getStackName()).andReturn("stack");
    expect(stackId.getStackVersion()).andReturn("1.0");
    Map<String, ServiceComponent> componentsMap = new HashMap<>();
    componentsMap.put("component1", component1);
    componentsMap.put("component2", component2);
    expect(service.getServiceComponents()).andReturn(componentsMap);
    expect(component1.getServiceComponentHosts()).andReturn(Collections.emptyMap());
    expect(component2.getServiceComponentHosts()).andReturn(
      Collections.singletonMap("anyHost", null));

    ServiceInfo serviceInfo = createNiceMock(ServiceInfo.class);
    ComponentInfo compInfo = createNiceMock(ComponentInfo.class);
    expect(serviceInfo.getClientComponent()).andReturn(compInfo);
    expect(compInfo.getName()).andReturn("component");
    expect(ambariMetaInfo.getService("stack", "1.0", "service")).andReturn(serviceInfo);

    replay(injector, cluster, service, component1, component2, serviceInfo, compInfo, ambariMetaInfo, stackId);

    AmbariManagementControllerImpl controller = new AmbariManagementControllerImpl(null, clusters, injector);
    setAmbariMetaInfo(ambariMetaInfo, controller);
    ServiceComponent resultComponent = controller.getClientComponentForRunningAction(cluster, service);

    assertNotNull(resultComponent);
    assertEquals(component2, resultComponent);
    verify(injector, cluster, service, component1, component2, serviceInfo, compInfo, ambariMetaInfo, stackId);
  }

  @Test
  public void testGetClientHostForRunningAction_noClientComponent() throws Exception {
    Injector injector = createNiceMock(Injector.class);
    Cluster cluster = createNiceMock(Cluster.class);
    Service service = createNiceMock(Service.class);
    StackId stackId = createNiceMock(StackId.class);
    ServiceComponent component1 = createNiceMock(ServiceComponent.class);
    ServiceComponent component2 = createNiceMock(ServiceComponent.class);

    expect(service.getName()).andReturn("service");
    expect(service.getDesiredStackId()).andReturn(stackId);
    expect(stackId.getStackName()).andReturn("stack");
    expect(stackId.getStackVersion()).andReturn("1.0");
    Map<String, ServiceComponent> componentsMap = new HashMap<>();
    componentsMap.put("component1", component1);
    componentsMap.put("component2", component2);
    expect(service.getServiceComponents()).andReturn(componentsMap);
    expect(component1.getServiceComponentHosts()).andReturn(Collections.emptyMap());
    expect(component2.getServiceComponentHosts()).andReturn(
      Collections.singletonMap("anyHost", null));

    ServiceInfo serviceInfo = createNiceMock(ServiceInfo.class);
    expect(serviceInfo.getClientComponent()).andReturn(null);
    expect(ambariMetaInfo.getService("stack", "1.0", "service")).andReturn(serviceInfo);

    replay(injector, cluster, service, component1, component2, serviceInfo, ambariMetaInfo, stackId);

    AmbariManagementControllerImpl controller = new AmbariManagementControllerImpl(null, clusters, injector);
    setAmbariMetaInfo(ambariMetaInfo, controller);
    ServiceComponent resultComponent = controller.getClientComponentForRunningAction(cluster, service);

    assertNotNull(resultComponent);
    assertEquals(component2, resultComponent);
    verify(injector, cluster, service, component1, component2, serviceInfo, ambariMetaInfo, stackId);
  }

  /**
   * Ensure that ClusterNotFoundException is propagated in case where there is a single request.
   */
  @Test
  public void testGetClusters___ClusterNotFoundException() throws Exception {
    // member state mocks
    Injector injector = createStrictMock(Injector.class);
    Capture<AmbariManagementController> controllerCapture = EasyMock.newCapture();

    // requests
    ClusterRequest request1 = new ClusterRequest(null, "cluster1", "1", Collections.emptySet());

    Set<ClusterRequest> setRequests = new HashSet<>();
    setRequests.add(request1);

    // expectations
    // constructor init
    constructorInit(injector, controllerCapture, createNiceMock(KerberosHelper.class));

    // getCluster
    expect(clusters.getCluster("cluster1")).andThrow(new ClusterNotFoundException("cluster1"));

    // replay mocks
    replay(injector, clusters);

    //test
    AmbariManagementController controller = new AmbariManagementControllerImpl(null, clusters, injector);

    // assert that exception is thrown in case where there is a single request
    try {
      controller.getClusters(setRequests);
      fail("expected ClusterNotFoundException");
    } catch (ClusterNotFoundException e) {
      // expected
    }

    verify(injector, clusters);
  }

  /**
   * Ensure that ClusterNotFoundException is handled where there are multiple requests as would be the
   * case when an OR predicate is provided in the query.
   */
  @Test
  public void testGetClusters___OR_Predicate_ClusterNotFoundException() throws Exception {
    // member state mocks
    Injector injector = createStrictMock(Injector.class);
    Capture<AmbariManagementController> controllerCapture = EasyMock.newCapture();

    Cluster cluster = createNiceMock(Cluster.class);
    Cluster cluster2 = createNiceMock(Cluster.class);
    ClusterResponse response = createNiceMock(ClusterResponse.class);
    ClusterResponse response2 = createNiceMock(ClusterResponse.class);

    // requests
    ClusterRequest request1 = new ClusterRequest(null, "cluster1", "1", Collections.emptySet());
    ClusterRequest request2 = new ClusterRequest(null, "cluster2", "1", Collections.emptySet());
    ClusterRequest request3 = new ClusterRequest(null, "cluster3", "1", Collections.emptySet());
    ClusterRequest request4 = new ClusterRequest(null, "cluster4", "1", Collections.emptySet());

    Set<ClusterRequest> setRequests = new HashSet<>();
    setRequests.add(request1);
    setRequests.add(request2);
    setRequests.add(request3);
    setRequests.add(request4);

    // expectations
    // constructor init
    constructorInit(injector, controllerCapture, createNiceMock(KerberosHelper.class));

    // getCluster
    expect(clusters.getCluster("cluster1")).andThrow(new ClusterNotFoundException("cluster1"));
    expect(clusters.getCluster("cluster2")).andReturn(cluster);
    expect(clusters.getCluster("cluster3")).andReturn(cluster2);
    expect(clusters.getCluster("cluster4")).andThrow(new ClusterNotFoundException("cluster4"));

    expect(cluster.convertToResponse()).andReturn(response);
    expect(cluster2.convertToResponse()).andReturn(response2);

    CredentialStoreService credentialStoreService = createNiceMock(CredentialStoreService.class);
    expect(credentialStoreService.isInitialized(anyObject(CredentialStoreType.class))).andReturn(true).anyTimes();

    // replay mocks
    replay(injector, clusters, cluster, cluster2, response, response2, credentialStoreService);

    //test
    AmbariManagementController controller = new AmbariManagementControllerImpl(null, clusters, injector);

    Field f = controller.getClass().getDeclaredField("credentialStoreService");
    f.setAccessible(true);
    f.set(controller, credentialStoreService);

    Set<ClusterResponse> setResponses = controller.getClusters(setRequests);

    // assert and verify
    assertSame(controller, controllerCapture.getValue());
    assertEquals(2, setResponses.size());
    assertTrue(setResponses.contains(response));
    assertTrue(setResponses.contains(response2));

    verify(injector, clusters, cluster, cluster2, response, response2, credentialStoreService);
  }

  /**
   * Ensure that validateClusterName(String clusterName) work as expected.
   * Character Requirements
   * <p>
   * A through Z
   * a through z
   * 0 through 9
   * _ (underscore)
   * - (dash)
   * Length Requirements
   * <p>
   * Minimum: 1 character
   * Maximum: 100 characters
   */
  @Test
  public void testValidateClusterName() throws Exception {
    AmbariManagementControllerImpl.validateClusterName("clustername");
    AmbariManagementControllerImpl.validateClusterName("CLUSTERNAME");
    AmbariManagementControllerImpl.validateClusterName("clustername123");
    AmbariManagementControllerImpl.validateClusterName("cluster-name");
    AmbariManagementControllerImpl.validateClusterName("cluster_name");
    try {
      AmbariManagementControllerImpl.validateClusterName(null);
      Assert.fail("IllegalArgumentException not thrown");
    } catch (IllegalArgumentException e) {
      // This is expected
    }
    try {
      AmbariManagementControllerImpl.validateClusterName("clusternameclusternameclusternameclusternameclusternameclusternameclusternameclusternameclusternameclustername");
      Assert.fail("IllegalArgumentException not thrown");
    } catch (IllegalArgumentException e) {
      // This is expected
    }
    try {
      AmbariManagementControllerImpl.validateClusterName("clustername@#$%");
      Assert.fail("IllegalArgumentException not thrown");
    } catch (IllegalArgumentException e) {
      // This is expected
    }
    try {
      AmbariManagementControllerImpl.validateClusterName("");
      Assert.fail("IllegalArgumentException not thrown");
    } catch (IllegalArgumentException e) {
      // This is expected
    }
  }

  /**
   * Ensure that when the cluster id is provided and the given cluster name is different from the cluster's name
   * then the cluster rename logic is executed.
   */
  @Test
  public void testUpdateClusters() throws Exception {
    // member state mocks
    Capture<AmbariManagementController> controllerCapture = EasyMock.newCapture();
    Injector injector = createStrictMock(Injector.class);
    Cluster cluster = createNiceMock(Cluster.class);
    ActionManager actionManager = createNiceMock(ActionManager.class);
    ClusterRequest clusterRequest = createNiceMock(ClusterRequest.class);
    ConfigurationRequest configurationRequest = createNiceMock(ConfigurationRequest.class);

    // requests
    Set<ClusterRequest> setRequests = new HashSet<>();
    setRequests.add(clusterRequest);

    List<ConfigurationRequest> configRequests = new ArrayList<>();
    configRequests.add(configurationRequest);

    KerberosHelper kerberosHelper = createStrictMock(KerberosHelper.class);
    Provider<MetadataHolder> m_metadataHolder = createMock(Provider.class);
    MetadataHolder metadataHolder = createMock(MetadataHolder.class);
    Provider<AgentConfigsHolder> m_agentConfigsHolder = createMock(Provider.class);
    AgentConfigsHolder agentConfigsHolder = createMockBuilder(AgentConfigsHolder.class)
        .addMockedMethod("updateData").createMock();
    // expectations
    constructorInit(injector, controllerCapture, null, null,
        kerberosHelper, m_metadataHolder, m_agentConfigsHolder);

    expect(m_metadataHolder.get()).andReturn(metadataHolder).anyTimes();
    expect(metadataHolder.updateData(anyObject())).andReturn(true).anyTimes();

    expect(m_agentConfigsHolder.get()).andReturn(agentConfigsHolder).anyTimes();
    agentConfigsHolder.updateData(anyLong(), anyObject(List.class));
    expectLastCall().anyTimes();

    expect(clusterRequest.getClusterName()).andReturn("clusterNew").times(5);
    expect(clusterRequest.getClusterId()).andReturn(1L).times(4);
    expect(clusterRequest.getDesiredConfig()).andReturn(configRequests);
    expect(configurationRequest.getVersionTag()).andReturn(null).times(1);
    expect(clusters.getClusterById(1L)).andReturn(cluster).times(1);
    expect(cluster.getClusterName()).andReturn("clusterOld").times(1);

    cluster.setClusterName("clusterNew");
    expectLastCall();

    configurationRequest.setVersionTag(EasyMock.anyObject(String.class));
    expectLastCall();

    // replay mocks
    replay(actionManager, cluster, clusters, injector, clusterRequest, sessionManager, configurationRequest,
        m_metadataHolder, metadataHolder, m_agentConfigsHolder, agentConfigsHolder);

    // test
    AmbariManagementController controller = partialMockBuilder(AmbariManagementControllerImpl.class)
        .withConstructor(actionManager, clusters, injector)
        .addMockedMethod("getClusterMetadataOnConfigsUpdate")
        .createMock();
    controller.updateClusters(setRequests, null);

    // assert and verify
    assertSame(controller, controllerCapture.getValue());
    verify(actionManager, cluster, clusters, injector, clusterRequest, sessionManager, configurationRequest,
        m_metadataHolder, metadataHolder, m_agentConfigsHolder, agentConfigsHolder);
  }

  /**
   * Ensure that processing update request does not fail on configuration
   * properties with no value specified (no value = null reference value)
   * TODO disabled for now as tests nothing, check what exactly should be tested here
   * updateCluster request was noop due to equality on cluster and request configs (both contained null)
   * mocks are too limited to pass further these base checks
   */
  @Test
  @Ignore
  public void testUpdateClustersWithNullConfigPropertyValues() throws Exception {
    // member state mocks
    Capture<AmbariManagementController> controllerCapture = EasyMock.newCapture();
    Injector injector = createStrictMock(Injector.class);
    Cluster cluster = createNiceMock(Cluster.class);
    ActionManager actionManager = createNiceMock(ActionManager.class);
    ClusterRequest clusterRequest = createNiceMock(ClusterRequest.class);
    Config config = createNiceMock(Config.class);

    // requests
    Set<ClusterRequest> setRequests = Collections.singleton(clusterRequest);

    KerberosHelper kerberosHelper = createStrictMock(KerberosHelper.class);
    // expectations
    constructorInit(injector, controllerCapture, kerberosHelper);

    expect(clusterRequest.getClusterName()).andReturn("clusterNew").anyTimes();
    expect(clusterRequest.getClusterId()).andReturn(1L).anyTimes();

    ConfigurationRequest configReq = new ConfigurationRequest();
    final Map<String, String> configReqProps = Maps.newHashMap();
    configReqProps.put("p1", null);
    configReq.setProperties(configReqProps);

    expect(clusterRequest.getDesiredConfig()).andReturn(ImmutableList.of(configReq)).anyTimes();
    expect(clusters.getClusterById(1L)).andReturn(cluster).anyTimes();
    expect(cluster.getClusterName()).andReturn("clusterOld").anyTimes();
    expect(cluster.getConfigPropertiesTypes(anyObject(String.class))).andReturn(Maps.newHashMap()).anyTimes();

    expect(config.getType()).andReturn("config-type").anyTimes();
    expect(config.getProperties()).andReturn(configReqProps).anyTimes();
    expect(config.getPropertiesAttributes()).andReturn(new HashMap<>()).anyTimes();
    expect(cluster.getDesiredConfigByType(anyObject(String.class))).andReturn(config).anyTimes();

    cluster.addSessionAttributes(EasyMock.anyObject());
    expectLastCall().once();

    cluster.setClusterName("clusterNew");
    expectLastCall();

    // replay mocks
    replay(actionManager, cluster, clusters, config, injector, clusterRequest, sessionManager);

    // test
    AmbariManagementController controller = new AmbariManagementControllerImpl(actionManager, clusters, injector);
    controller.updateClusters(setRequests, null);

    // assert and verify
    assertSame(controller, controllerCapture.getValue());
    verify(actionManager, cluster, clusters, config, injector, clusterRequest, sessionManager);
  }

  /**
   * Ensure that when the cluster is updated KerberosHandler.toggleKerberos is not invoked unless
   * the security type is altered
   */
  @Test
  public void testUpdateClustersToggleKerberosNotInvoked() throws Exception {
    // member state mocks
    Capture<AmbariManagementController> controllerCapture = EasyMock.newCapture();
    Injector injector = createStrictMock(Injector.class);
    Cluster cluster = createNiceMock(Cluster.class);
    ActionManager actionManager = createNiceMock(ActionManager.class);
    ClusterRequest clusterRequest = createNiceMock(ClusterRequest.class);

    // requests
    Set<ClusterRequest> setRequests = Collections.singleton(clusterRequest);

    KerberosHelper kerberosHelper = createStrictMock(KerberosHelper.class);
    Provider<MetadataHolder> m_metadataHolder = createMock(Provider.class);
    MetadataHolder metadataHolder = createMock(MetadataHolder.class);
    Provider<AgentConfigsHolder> m_agentConfigsHolder = createMock(Provider.class);
    AgentConfigsHolder agentConfigsHolder = createMockBuilder(AgentConfigsHolder.class)
        .addMockedMethod("updateData").createMock();
    // expectations
