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

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
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.createNiceMock;
import static org.easymock.EasyMock.createStrictMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.newCapture;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.ConfigGroupRequest;
import org.apache.ambari.server.controller.ConfigGroupResponse;
import org.apache.ambari.server.controller.RequestStatusResponse;
import org.apache.ambari.server.controller.spi.NoSuchResourceException;
import org.apache.ambari.server.controller.spi.Predicate;
import org.apache.ambari.server.controller.spi.Request;
import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
import org.apache.ambari.server.controller.spi.ResourceProvider;
import org.apache.ambari.server.controller.spi.SystemException;
import org.apache.ambari.server.controller.utilities.PredicateBuilder;
import org.apache.ambari.server.controller.utilities.PropertyHelper;
import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
import org.apache.ambari.server.orm.dao.HostDAO;
import org.apache.ambari.server.orm.entities.HostEntity;
import org.apache.ambari.server.security.TestAuthenticationFactory;
import org.apache.ambari.server.security.authorization.AuthorizationException;
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.configgroup.ConfigGroup;
import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
import org.easymock.Capture;
import org.easymock.EasyMock;
import org.easymock.IAnswer;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.util.Modules;

public class ConfigGroupResourceProviderTest {

  private HostDAO hostDAO = null;

  @Before
  public void setup() throws Exception {
    // Clear authenticated user so that authorization checks will pass
    SecurityContextHolder.getContext().setAuthentication(null);

    hostDAO = createStrictMock(HostDAO.class);

    // Create injector after all mocks have been initialized
    Guice.createInjector(Modules.override(
        new InMemoryDefaultTestModule()).with(new MockModule()));
  }

  private ConfigGroupResourceProvider getConfigGroupResourceProvider
      (AmbariManagementController managementController) throws NoSuchFieldException, IllegalAccessException {
    Resource.Type type = Resource.Type.ConfigGroup;

    ConfigGroupResourceProvider configGroupResourceProvider =
        (ConfigGroupResourceProvider) AbstractControllerResourceProvider.getResourceProvider(
        type,
        managementController);

    Provider<ConfigHelper> configHelperProvider = createNiceMock(Provider.class);
    expect(configHelperProvider.get()).andReturn(createNiceMock(ConfigHelper.class));

    replay(configHelperProvider);

    Field m_configHelper = ConfigGroupResourceProvider.class.getDeclaredField("m_configHelper");
    m_configHelper.setAccessible(true);
    m_configHelper.set(configGroupResourceProvider, configHelperProvider);

    return configGroupResourceProvider;
  }


  private class MockModule implements Module {
    @Override
    public void configure(Binder binder) {
      binder.bind(HostDAO.class).toInstance(hostDAO);
    }
  }

  @Test
  public void testCreateConfigGroupAsAmbariAdministrator() throws Exception {
    testCreateConfigGroup(TestAuthenticationFactory.createAdministrator());
  }

  @Test
  public void testCreateConfigGroupAsClusterAdministrator() throws Exception {
    testCreateConfigGroup(TestAuthenticationFactory.createClusterAdministrator());
  }

  @Test
  public void testCreateConfigGroupAsClusterOperator() throws Exception {
    testCreateConfigGroup(TestAuthenticationFactory.createClusterOperator());
  }

  @Test
  public void testCreateConfigGroupAsServiceAdministrator() throws Exception {
    testCreateConfigGroup(TestAuthenticationFactory.createServiceAdministrator());
  }

  @Test(expected = AuthorizationException.class)
  public void testCreateConfigGroupAsServiceOperator() throws Exception {
    testCreateConfigGroup(TestAuthenticationFactory.createServiceOperator());
  }

  @Test(expected = AuthorizationException.class)
  public void testCreateConfigGroupAsClusterUser() throws Exception {
    testCreateConfigGroup(TestAuthenticationFactory.createClusterUser());
  }

  private void testCreateConfigGroup(Authentication authentication) throws Exception {
    AmbariManagementController managementController = createMock(AmbariManagementController.class);
    RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
    Clusters clusters = createNiceMock(Clusters.class);
    Cluster cluster = createNiceMock(Cluster.class);
    Host h1 = createNiceMock(Host.class);
    Host h2 = createNiceMock(Host.class);
    HostEntity hostEntity1 = createMock(HostEntity.class);
    HostEntity hostEntity2 = createMock(HostEntity.class);
    ConfigGroupFactory configGroupFactory = createNiceMock(ConfigGroupFactory.class);
    ConfigGroup configGroup = createNiceMock(ConfigGroup.class);

    expect(managementController.getClusters()).andReturn(clusters).anyTimes();
    expect(clusters.getCluster("Cluster100")).andReturn(cluster).anyTimes();
    expect(clusters.getHost("h1")).andReturn(h1);
    expect(clusters.getHost("h2")).andReturn(h2);
    expect(cluster.getClusterName()).andReturn("Cluster100").anyTimes();
    expect(cluster.isConfigTypeExists(anyString())).andReturn(true).anyTimes();
    expect(managementController.getConfigGroupFactory()).andReturn(configGroupFactory);
    expect(managementController.getAuthName()).andReturn("admin").anyTimes();
    expect(hostDAO.findByName("h1")).andReturn(hostEntity1).atLeastOnce();
    expect(hostDAO.findByName("h2")).andReturn(hostEntity2).atLeastOnce();
    expect(hostEntity1.getHostId()).andReturn(1L).atLeastOnce();
    expect(hostEntity2.getHostId()).andReturn(2L).atLeastOnce();

    Capture<Cluster> clusterCapture = newCapture();
    Capture<String> serviceName = newCapture();
    Capture<String> captureName = newCapture();
    Capture<String> captureDesc = newCapture();
    Capture<String> captureTag = newCapture();
    Capture<Map<String, Config>> captureConfigs = newCapture();
    Capture<Map<Long, Host>> captureHosts = newCapture();

    expect(configGroupFactory.createNew(capture(clusterCapture), capture(serviceName),
        capture(captureName), capture(captureTag), capture(captureDesc),
        capture(captureConfigs), capture(captureHosts))).andReturn(configGroup);

    replay(managementController, clusters, cluster, configGroupFactory,
        configGroup, response, hostDAO, hostEntity1, hostEntity2);

    ResourceProvider provider = getConfigGroupResourceProvider
        (managementController);

    Set<Map<String, Object>> propertySet = new LinkedHashSet<>();
    Map<String, Object> properties = new LinkedHashMap<>();

    Set<Map<String, Object>> hostSet = new HashSet<>();
    Map<String, Object> host1 = new HashMap<>();
    host1.put(ConfigGroupResourceProvider.HOST_NAME, "h1");
    hostSet.add(host1);
    Map<String, Object> host2 = new HashMap<>();
    host2.put(ConfigGroupResourceProvider.HOST_NAME, "h2");
    hostSet.add(host2);

    Set<Map<String, Object>> configSet = new HashSet<>();
    Map<String, String> configMap = new HashMap<>();
    Map<String, Object> configs = new HashMap<>();
    configs.put("type", "core-site");
    configs.put("tag", "version100");
    configMap.put("key1", "value1");
    configs.put("properties", configMap);
    configSet.add(configs);

    properties.put(ConfigGroupResourceProvider
        .CLUSTER_NAME, "Cluster100");
    properties.put(ConfigGroupResourceProvider.GROUP_NAME,
        "test-1");
    properties.put(ConfigGroupResourceProvider.TAG,
        "tag-1");
    properties.put(ConfigGroupResourceProvider.HOSTS,
        hostSet);
    properties.put(ConfigGroupResourceProvider.DESIRED_CONFIGS,
        configSet);

    propertySet.add(properties);

    Request request = PropertyHelper.getCreateRequest(propertySet, null);

    SecurityContextHolder.getContext().setAuthentication(authentication);

    provider.createResources(request);

    verify(managementController, clusters, cluster, configGroupFactory,
        configGroup, response, hostDAO, hostEntity1, hostEntity2);

    assertEquals("version100", captureConfigs.getValue().get("core-site")
        .getTag());
    assertTrue(captureHosts.getValue().containsKey(1L));
    assertTrue(captureHosts.getValue().containsKey(2L));
  }

  @Test
  public void testDuplicateNameConfigGroupAsAmbariAdministrator() throws Exception {
    testDuplicateNameConfigGroup(TestAuthenticationFactory.createAdministrator());
  }

  @Test
  public void testDuplicateNameConfigGroupAsClusterAdministrator() throws Exception {
    testDuplicateNameConfigGroup(TestAuthenticationFactory.createClusterAdministrator());
  }

  @Test
  public void testDuplicateNameConfigGroupAsClusterOperator() throws Exception {
    testDuplicateNameConfigGroup(TestAuthenticationFactory.createClusterOperator());
  }

  @Test
  public void testDuplicateNameConfigGroupAsServiceAdministrator() throws Exception {
    testDuplicateNameConfigGroup(TestAuthenticationFactory.createServiceAdministrator());
  }

  @Test(expected = AuthorizationException.class)
  public void testDuplicateNameConfigGroupAsServiceOperator() throws Exception {
    testDuplicateNameConfigGroup(TestAuthenticationFactory.createServiceOperator());
  }

  @Test(expected = AuthorizationException.class)
  public void testDuplicateNameConfigGroupAsClusterUser() throws Exception {
    testDuplicateNameConfigGroup(TestAuthenticationFactory.createClusterUser());
  }

  private void testDuplicateNameConfigGroup(Authentication authentication) throws Exception {
    AmbariManagementController managementController = createMock(AmbariManagementController.class);
    RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
    Clusters clusters = createNiceMock(Clusters.class);
    Cluster cluster = createNiceMock(Cluster.class);
    ConfigGroupFactory configGroupFactory = createNiceMock(ConfigGroupFactory.class);
    ConfigGroup configGroup = createNiceMock(ConfigGroup.class);
    Map<Long, ConfigGroup> configGroupMap = new HashMap<>();
    configGroupMap.put(1L, configGroup);

    expect(managementController.getClusters()).andReturn(clusters).anyTimes();
    expect(clusters.getCluster("Cluster100")).andReturn(cluster).anyTimes();
    expect(managementController.getConfigGroupFactory()).andReturn
        (configGroupFactory).anyTimes();
    expect(managementController.getAuthName()).andReturn("admin").anyTimes();
    expect(cluster.getConfigGroups()).andReturn(configGroupMap);

    expect(configGroupFactory.createNew((Cluster) anyObject(), (String) anyObject(), (String) anyObject(),
        (String) anyObject(), (String) anyObject(), EasyMock.anyObject(),
        EasyMock.anyObject())).andReturn(configGroup).anyTimes();

    expect(configGroup.getClusterName()).andReturn("Cluster100").anyTimes();
    expect(configGroup.getName()).andReturn("test-1").anyTimes();
    expect(configGroup.getTag()).andReturn("tag-1").anyTimes();

    replay(managementController, clusters, cluster, configGroupFactory,
        configGroup, response);

    ResourceProvider provider = getConfigGroupResourceProvider
        (managementController);

    Map<String, Object> properties = new LinkedHashMap<>();
    Set<Map<String, Object>> propertySet = new LinkedHashSet<>();

    properties.put(ConfigGroupResourceProvider
        .CLUSTER_NAME, "Cluster100");
    properties.put(ConfigGroupResourceProvider.GROUP_NAME,
        "test-1");
    properties.put(ConfigGroupResourceProvider.TAG,
        "tag-1");

    propertySet.add(properties);
    Request request = PropertyHelper.getCreateRequest(propertySet, null);

    SecurityContextHolder.getContext().setAuthentication(authentication);

    Exception exception = null;
    try {
      provider.createResources(request);
    } catch (AuthorizationException e) {
      throw e;
    } catch (Exception e) {
      exception = e;
    }

    verify(managementController, clusters, cluster, configGroupFactory,
        configGroup, response);

    assertNotNull(exception);
    assertTrue(exception instanceof ResourceAlreadyExistsException);
  }

  @Test
  public void testUpdateConfigGroupWithWrongConfigType() throws Exception {
    AmbariManagementController managementController = createMock(AmbariManagementController.class);
    RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
    ConfigHelper configHelper = createNiceMock(ConfigHelper.class);
    Clusters clusters = createNiceMock(Clusters.class);
    Cluster cluster = createNiceMock(Cluster.class);
    Host h1 = createNiceMock(Host.class);
    Host h2 = createNiceMock(Host.class);
    HostEntity hostEntity1 = createMock(HostEntity.class);
    HostEntity hostEntity2 = createMock(HostEntity.class);

    final ConfigGroup configGroup = createNiceMock(ConfigGroup.class);
    ConfigGroupResponse configGroupResponse = createNiceMock
        (ConfigGroupResponse.class);

    expect(cluster.isConfigTypeExists("core-site")).andReturn(false).anyTimes();
    expect(managementController.getClusters()).andReturn(clusters).anyTimes();
    expect(managementController.getAuthName()).andReturn("admin").anyTimes();
    expect(clusters.getCluster("Cluster100")).andReturn(cluster).anyTimes();
    expect(clusters.getHost("h1")).andReturn(h1);
    expect(clusters.getHost("h2")).andReturn(h2);
    expect(hostDAO.findByName("h1")).andReturn(hostEntity1).anyTimes();
    expect(hostDAO.findById(1L)).andReturn(hostEntity1).anyTimes();
    expect(hostDAO.findByName("h2")).andReturn(hostEntity2).anyTimes();
    expect(hostDAO.findById(2L)).andReturn(hostEntity2).anyTimes();
    expect(hostEntity1.getHostId()).andReturn(1L).atLeastOnce();
    expect(hostEntity2.getHostId()).andReturn(2L).atLeastOnce();
    expect(h1.getHostId()).andReturn(1L).anyTimes();
    expect(h2.getHostId()).andReturn(2L).anyTimes();

    expect(configGroup.getName()).andReturn("test-1").anyTimes();
    expect(configGroup.getId()).andReturn(25L).anyTimes();
    expect(configGroup.getTag()).andReturn("tag-1").anyTimes();

    expect(configGroup.convertToResponse()).andReturn(configGroupResponse).anyTimes();
    expect(configGroupResponse.getClusterName()).andReturn("Cluster100").anyTimes();
    expect(configGroupResponse.getId()).andReturn(25L).anyTimes();

    expect(cluster.getConfigGroups()).andStubAnswer(new IAnswer<Map<Long, ConfigGroup>>() {
      @Override
      public Map<Long, ConfigGroup> answer() throws Throwable {
        Map<Long, ConfigGroup> configGroupMap = new HashMap<>();
        configGroupMap.put(configGroup.getId(), configGroup);
        return configGroupMap;
      }
    });

    replay(managementController, clusters, cluster,
        configGroup, response, configGroupResponse, configHelper, hostDAO, hostEntity1, hostEntity2, h1, h2);

    ResourceProvider provider = getConfigGroupResourceProvider
        (managementController);

    Map<String, Object> properties = new LinkedHashMap<>();

    Set<Map<String, Object>> hostSet = new HashSet<>();
    Map<String, Object> host1 = new HashMap<>();
    host1.put(ConfigGroupResourceProvider.HOST_NAME, "h1");
    hostSet.add(host1);
    Map<String, Object> host2 = new HashMap<>();
    host2.put(ConfigGroupResourceProvider.HOST_NAME, "h2");
    hostSet.add(host2);

    Set<Map<String, Object>> configSet = new HashSet<>();
    Map<String, String> configMap = new HashMap<>();
    Map<String, Object> configs = new HashMap<>();
    configs.put("type", "core-site");
    configs.put("tag", "version100");
    configMap.put("key1", "value1");
    configs.put("properties", configMap);
    configSet.add(configs);

    properties.put(ConfigGroupResourceProvider
        .CLUSTER_NAME, "Cluster100");
    properties.put(ConfigGroupResourceProvider.GROUP_NAME,
        "test-1");
    properties.put(ConfigGroupResourceProvider.TAG,
        "tag-1");
    properties.put(ConfigGroupResourceProvider.HOSTS,
        hostSet);
    properties.put(ConfigGroupResourceProvider.DESIRED_CONFIGS,
        configSet);

    Map<String, String> mapRequestProps = new HashMap<>();
    mapRequestProps.put("context", "Called from a test");

    Request request = PropertyHelper.getUpdateRequest(properties, mapRequestProps);

    Predicate predicate = new PredicateBuilder().property
        (ConfigGroupResourceProvider.CLUSTER_NAME).equals
        ("Cluster100").and().
        property(ConfigGroupResourceProvider.ID).equals
        (25L).toPredicate();

    SecurityContextHolder.getContext().setAuthentication(TestAuthenticationFactory.createAdministrator());

    SystemException systemException = null;
    try {
      provider.updateResources(request, predicate);
    } catch (SystemException e) {
      systemException = e;
    }
    assertNotNull(systemException);
    verify(managementController, clusters, cluster,
        configGroup, response, configGroupResponse, configHelper, hostDAO, hostEntity1, hostEntity2, h1, h2);
  }

  @Test
  public void testUpdateConfigGroupAsAmbariAdministrator() throws Exception {
    testUpdateConfigGroup(TestAuthenticationFactory.createAdministrator());
  }

  @Test
  public void testUpdateConfigGroupAsClusterAdministrator() throws Exception {
    testUpdateConfigGroup(TestAuthenticationFactory.createClusterAdministrator());
  }

  @Test
  public void testUpdateConfigGroupAsClusterOperator() throws Exception {
    testUpdateConfigGroup(TestAuthenticationFactory.createClusterOperator());
  }

  @Test
  public void testUpdateConfigGroupAsServiceAdministrator() throws Exception {
    testUpdateConfigGroup(TestAuthenticationFactory.createServiceAdministrator());
  }

  @Test(expected = AuthorizationException.class)
  public void testUpdateConfigGroupAsServiceOperator() throws Exception {
    testUpdateConfigGroup(TestAuthenticationFactory.createServiceOperator());
  }

  @Test(expected = AuthorizationException.class)
  public void testUpdateConfigGroupAsClusterUser() throws Exception {
    testUpdateConfigGroup(TestAuthenticationFactory.createClusterUser());
  }

  private void testUpdateConfigGroup(Authentication authentication) throws Exception {
    AmbariManagementController managementController = createMock(AmbariManagementController.class);
    RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);
    ConfigHelper configHelper = createNiceMock(ConfigHelper.class);
    Clusters clusters = createNiceMock(Clusters.class);
    Cluster cluster = createNiceMock(Cluster.class);
    Host h1 = createNiceMock(Host.class);
    Host h2 = createNiceMock(Host.class);
    HostEntity hostEntity1 = createMock(HostEntity.class);
    HostEntity hostEntity2 = createMock(HostEntity.class);

    final ConfigGroup configGroup = createNiceMock(ConfigGroup.class);
    ConfigGroupResponse configGroupResponse = createNiceMock
        (ConfigGroupResponse.class);

    expect(cluster.isConfigTypeExists("core-site")).andReturn(true).anyTimes();
    expect(managementController.getClusters()).andReturn(clusters).anyTimes();
    expect(managementController.getAuthName()).andReturn("admin").anyTimes();
    expect(clusters.getCluster("Cluster100")).andReturn(cluster).anyTimes();
    expect(clusters.getHost("h1")).andReturn(h1);
    expect(clusters.getHost("h2")).andReturn(h2);
    expect(hostDAO.findByName("h1")).andReturn(hostEntity1).anyTimes();
    expect(hostDAO.findById(1L)).andReturn(hostEntity1).anyTimes();
    expect(hostDAO.findByName("h2")).andReturn(hostEntity2).anyTimes();
    expect(hostDAO.findById(2L)).andReturn(hostEntity2).anyTimes();
    expect(hostEntity1.getHostId()).andReturn(1L).atLeastOnce();
    expect(hostEntity2.getHostId()).andReturn(2L).atLeastOnce();
    expect(h1.getHostId()).andReturn(1L).anyTimes();
    expect(h2.getHostId()).andReturn(2L).anyTimes();
    expect(managementController.getConfigGroupUpdateResults((ConfigGroupRequest)anyObject())).
            andReturn(new ConfigGroupResponse(1L, "", "", "", "", new HashSet<>(), new HashSet<>())).atLeastOnce();

    expect(configGroup.getName()).andReturn("test-1").anyTimes();
    expect(configGroup.getId()).andReturn(25L).anyTimes();
    expect(configGroup.getTag()).andReturn("tag-1").anyTimes();

    expect(configGroup.convertToResponse()).andReturn(configGroupResponse).anyTimes();
    expect(configGroupResponse.getClusterName()).andReturn("Cluster100").anyTimes();
    expect(configGroupResponse.getId()).andReturn(25L).anyTimes();

    expect(cluster.getConfigGroups()).andStubAnswer(new IAnswer<Map<Long, ConfigGroup>>() {
      @Override
      public Map<Long, ConfigGroup> answer() throws Throwable {
        Map<Long, ConfigGroup> configGroupMap = new HashMap<>();
        configGroupMap.put(configGroup.getId(), configGroup);
        return configGroupMap;
      }
    });

    replay(managementController, clusters, cluster,
        configGroup, response, configGroupResponse, configHelper, hostDAO, hostEntity1, hostEntity2, h1, h2);

    ResourceProvider provider = getConfigGroupResourceProvider
        (managementController);

    Map<String, Object> properties = new LinkedHashMap<>();

    Set<Map<String, Object>> hostSet = new HashSet<>();
    Map<String, Object> host1 = new HashMap<>();
    host1.put(ConfigGroupResourceProvider.HOST_NAME, "h1");
    hostSet.add(host1);
    Map<String, Object> host2 = new HashMap<>();
    host2.put(ConfigGroupResourceProvider.HOST_NAME, "h2");
    hostSet.add(host2);

    Set<Map<String, Object>> configSet = new HashSet<>();
    Map<String, String> configMap = new HashMap<>();
    Map<String, Object> configs = new HashMap<>();
    configs.put("type", "core-site");
    configs.put("tag", "version100");
    configMap.put("key1", "value1");
    configs.put("properties", configMap);
    configSet.add(configs);

    properties.put(ConfigGroupResourceProvider
        .CLUSTER_NAME, "Cluster100");
    properties.put(ConfigGroupResourceProvider.GROUP_NAME,
        "test-1");
    properties.put(ConfigGroupResourceProvider.TAG,
        "tag-1");
    properties.put(ConfigGroupResourceProvider.HOSTS,
        hostSet);
    properties.put(ConfigGroupResourceProvider.DESIRED_CONFIGS,
        configSet);

    Map<String, String> mapRequestProps = new HashMap<>();
    mapRequestProps.put("context", "Called from a test");

    Request request = PropertyHelper.getUpdateRequest(properties, mapRequestProps);

    Predicate predicate = new PredicateBuilder().property
        (ConfigGroupResourceProvider.CLUSTER_NAME).equals
        ("Cluster100").and().
        property(ConfigGroupResourceProvider.ID).equals
        (25L).toPredicate();

    SecurityContextHolder.getContext().setAuthentication(authentication);

    provider.updateResources(request, predicate);

    verify(managementController, clusters, cluster,
        configGroup, response, configGroupResponse, configHelper, hostDAO, hostEntity1, hostEntity2, h1, h2);
  }

  @Test
  public void testGetConfigGroupAsAmbariAdministrator() throws Exception {
    testGetConfigGroup(TestAuthenticationFactory.createAdministrator());
  }

  @Test
  public void testGetConfigGroupAsClusterAdministrator() throws Exception {
    testGetConfigGroup(TestAuthenticationFactory.createClusterAdministrator());
  }

  @Test
  public void testGetConfigGroupAsClusterOperator() throws Exception {
    testGetConfigGroup(TestAuthenticationFactory.createClusterOperator());
  }

  @Test
  public void testGetConfigGroupAsServiceAdministrator() throws Exception {
    testGetConfigGroup(TestAuthenticationFactory.createServiceAdministrator());
  }

  @Test
  public void testGetConfigGroupAsServiceOperator() throws Exception {
    testGetConfigGroup(TestAuthenticationFactory.createServiceOperator());
  }

  @Test
  public void testGetConfigGroupAsClusterUser() throws Exception {
    testGetConfigGroup(TestAuthenticationFactory.createClusterUser());
  }

  @SuppressWarnings("unchecked")
  private void testGetConfigGroup(Authentication authentication) throws Exception {
    AmbariManagementController managementController = createMock(AmbariManagementController.class);
    Clusters clusters = createNiceMock(Clusters.class);
    Cluster cluster = createNiceMock(Cluster.class);
    Host h1 = createNiceMock(Host.class);
    final Long host1Id = 1L;
    List<Long> hostIds = new ArrayList<Long>() {{
      add(host1Id);
    }};
    List<String> hostNames = new ArrayList<String>() {{
      add("h1");
    }};
    HostEntity hostEntity1 = createMock(HostEntity.class);

    expect(hostDAO.getHostNamesByHostIds(hostIds)).andReturn(hostNames).atLeastOnce();
    expect(hostDAO.findByName("h1")).andReturn(hostEntity1).anyTimes();
    expect(hostEntity1.getHostId()).andReturn(host1Id).anyTimes();

    ConfigGroup configGroup1 = createNiceMock(ConfigGroup.class);
    ConfigGroup configGroup2 = createNiceMock(ConfigGroup.class);
    ConfigGroup configGroup3 = createNiceMock(ConfigGroup.class);
    ConfigGroup configGroup4 = createNiceMock(ConfigGroup.class);
    ConfigGroupResponse response1 = createNiceMock(ConfigGroupResponse.class);
    ConfigGroupResponse response2 = createNiceMock(ConfigGroupResponse.class);
    ConfigGroupResponse response3 = createNiceMock(ConfigGroupResponse.class);
    ConfigGroupResponse response4 = createNiceMock(ConfigGroupResponse.class);

    Map<Long, ConfigGroup> configGroupMap = new HashMap<>();
    configGroupMap.put(1L, configGroup1);
    configGroupMap.put(2L, configGroup2);
    configGroupMap.put(3L, configGroup3);
    configGroupMap.put(4L, configGroup4);

    Map<Long, ConfigGroup> configGroupByHostname = new HashMap<>();
    configGroupByHostname.put(4L, configGroup4);

    expect(configGroup1.convertToResponse()).andReturn(response1).anyTimes();
    expect(configGroup2.convertToResponse()).andReturn(response2).anyTimes();
    expect(configGroup3.convertToResponse()).andReturn(response3).anyTimes();
    expect(configGroup4.convertToResponse()).andReturn(response4).anyTimes();

    expect(managementController.getClusters()).andReturn(clusters).anyTimes();
    expect(clusters.getCluster("Cluster100")).andReturn(cluster).anyTimes();
    expect(cluster.getConfigGroups()).andReturn(configGroupMap).anyTimes();
    expect(cluster.getClusterName()).andReturn("Cluster100").anyTimes();

    expect(configGroup1.getName()).andReturn("g1").anyTimes();
    expect(configGroup2.getName()).andReturn("g2").anyTimes();
    expect(configGroup3.getName()).andReturn("g3").anyTimes();
    expect(configGroup4.getName()).andReturn("g4").anyTimes();
    expect(configGroup1.getTag()).andReturn("t1").anyTimes();
    expect(configGroup2.getTag()).andReturn("t2").anyTimes();
    expect(configGroup3.getTag()).andReturn("t3").anyTimes();
    expect(configGroup4.getTag()).andReturn("t4").anyTimes();

    Map<Long, Host> hostMap = new HashMap<>();
    hostMap.put(host1Id, h1);
    expect(configGroup4.getHosts()).andReturn(hostMap).anyTimes();


    expect(response1.getClusterName()).andReturn("Cluster100").anyTimes();
    expect(response2.getClusterName()).andReturn("Cluster100").anyTimes();
    expect(response3.getClusterName()).andReturn("Cluster100").anyTimes();
    expect(response4.getClusterName()).andReturn("Cluster100").anyTimes();
    expect(response1.getId()).andReturn(1L).anyTimes();
    expect(response2.getId()).andReturn(2L).anyTimes();
    expect(response3.getId()).andReturn(3L).anyTimes();
    expect(response4.getId()).andReturn(4L).anyTimes();
    expect(response2.getGroupName()).andReturn("g2").anyTimes();
    expect(response3.getTag()).andReturn("t3").anyTimes();
    expect(cluster.getConfigGroupsByHostname("h1")).andReturn(configGroupByHostname).anyTimes();

    Set<Map<String, Object>> hostObj = new HashSet<>();
    Map<String, Object> hostnames = new HashMap<>();
    hostnames.put("host_name", "h1");
    hostObj.add(hostnames);
    expect(response4.getHosts()).andReturn(hostObj).anyTimes();

    replay(managementController, clusters, cluster, hostDAO, hostEntity1,
        configGroup1, configGroup2, configGroup3, configGroup4, response1, response2, response3, response4);

    SecurityContextHolder.getContext().setAuthentication(authentication);

    ResourceProvider resourceProvider = getConfigGroupResourceProvider(managementController);

    Set<String> propertyIds = new HashSet<>();

    propertyIds.add(ConfigGroupResourceProvider.CLUSTER_NAME);
    propertyIds.add(ConfigGroupResourceProvider.ID);

    // Read all
    Predicate predicate = new PredicateBuilder().property
        (ConfigGroupResourceProvider.CLUSTER_NAME)
        .equals("Cluster100").toPredicate();
    Request request = PropertyHelper.getReadRequest(propertyIds);

    Set<Resource> resources = resourceProvider.getResources(request, predicate);

    assertEquals(4, resources.size());

    // Read by id
    predicate = new PredicateBuilder().property(ConfigGroupResourceProvider
        .ID).equals(1L).and().property
        (ConfigGroupResourceProvider.CLUSTER_NAME)
        .equals("Cluster100").toPredicate();

    resources = resourceProvider.getResources(request, predicate);

    assertEquals(1, resources.size());
    assertEquals(1L, resources.iterator().next().getPropertyValue
        (ConfigGroupResourceProvider.ID));

    // Read by Name
    predicate = new PredicateBuilder().property(ConfigGroupResourceProvider
        .CLUSTER_NAME).equals("Cluster100").and()
        .property(ConfigGroupResourceProvider.GROUP_NAME)
        .equals("g2").toPredicate();

    resources = resourceProvider.getResources(request, predicate);

    assertEquals(1, resources.size());
    assertEquals("g2", resources.iterator().next().getPropertyValue
        (ConfigGroupResourceProvider.GROUP_NAME));

    // Read by tag
    predicate = new PredicateBuilder().property(ConfigGroupResourceProvider
        .CLUSTER_NAME).equals("Cluster100").and()
        .property(ConfigGroupResourceProvider.TAG)
        .equals("t3").toPredicate();

    resources = resourceProvider.getResources(request, predicate);

    assertEquals(1, resources.size());
    assertEquals("t3", resources.iterator().next().getPropertyValue
        (ConfigGroupResourceProvider.TAG));

    // Read by hostname (hosts=h1)
    predicate = new PredicateBuilder().property(ConfigGroupResourceProvider
        .CLUSTER_NAME).equals("Cluster100").and()
        .property(ConfigGroupResourceProvider.HOSTS)
        .equals("h1").toPredicate();

    resources = resourceProvider.getResources(request, predicate);

