/*
 * 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 org.apache.ambari.server.controller.internal.HostComponentResourceProvider.STALE_CONFIGS;
import static org.apache.ambari.server.security.TestAuthenticationFactory.createAdministrator;
import static org.apache.ambari.server.security.TestAuthenticationFactory.createViewUser;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.capture;
import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.newCapture;
import static org.powermock.api.easymock.PowerMock.createMock;
import static org.powermock.api.easymock.PowerMock.createNiceMock;
import static org.powermock.api.easymock.PowerMock.replay;
import static org.powermock.api.easymock.PowerMock.replayAll;
import static org.powermock.api.easymock.PowerMock.reset;
import static org.powermock.api.easymock.PowerMock.resetAll;
import static org.powermock.api.easymock.PowerMock.verify;
import static org.powermock.api.easymock.PowerMock.verifyAll;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.actionmanager.ActionManager;
import org.apache.ambari.server.actionmanager.HostRoleCommand;
import org.apache.ambari.server.actionmanager.HostRoleStatus;
import org.apache.ambari.server.actionmanager.Stage;
import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.api.services.BaseRequest;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.AmbariServer;
import org.apache.ambari.server.controller.ExecuteActionRequest;
import org.apache.ambari.server.controller.RequestStatusResponse;
import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
import org.apache.ambari.server.controller.spi.Predicate;
import org.apache.ambari.server.controller.spi.QueryResponse;
import org.apache.ambari.server.controller.spi.Request;
import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.controller.spi.ResourceProvider;
import org.apache.ambari.server.controller.utilities.ClusterControllerHelper;
import org.apache.ambari.server.controller.utilities.PredicateBuilder;
import org.apache.ambari.server.controller.utilities.PredicateHelper;
import org.apache.ambari.server.controller.utilities.PropertyHelper;
import org.apache.ambari.server.customactions.ActionDefinition;
import org.apache.ambari.server.orm.dao.HostRoleCommandDAO;
import org.apache.ambari.server.orm.dao.HostRoleCommandStatusSummaryDTO;
import org.apache.ambari.server.orm.dao.RequestDAO;
import org.apache.ambari.server.orm.entities.RequestEntity;
import org.apache.ambari.server.security.TestAuthenticationFactory;
import org.apache.ambari.server.security.authorization.AuthorizationException;
import org.apache.ambari.server.security.authorization.AuthorizationHelperInitializer;
import org.apache.ambari.server.security.authorization.RoleAuthorization;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.topology.Blueprint;
import org.apache.ambari.server.topology.ClusterTopology;
import org.apache.ambari.server.topology.HostGroup;
import org.apache.ambari.server.topology.HostGroupInfo;
import org.apache.ambari.server.topology.HostRequest;
import org.apache.ambari.server.topology.LogicalRequest;
import org.apache.ambari.server.topology.TopologyManager;
import org.apache.ambari.server.topology.TopologyRequest;
import org.apache.ambari.server.utils.SecretReference;
import org.easymock.Capture;
import org.easymock.EasyMock;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

/**
 * RequestResourceProvider tests.
 */
@RunWith(PowerMockRunner.class)
@PrepareForTest({ClusterControllerHelper.class})
public class RequestResourceProviderTest {

  private RequestDAO requestDAO;
  private HostRoleCommandDAO hrcDAO;
  private TopologyManager topologyManager;

  @Before
  public void before() throws Exception {

    requestDAO = createNiceMock(RequestDAO.class);
    hrcDAO = createNiceMock(HostRoleCommandDAO.class);
    topologyManager = createNiceMock(TopologyManager.class);

    reset(topologyManager);

    //todo: add assertions for topology manager interactions
    expect(topologyManager.getStageSummaries(EasyMock.<Long>anyObject())).andReturn(
      Collections.emptyMap()).anyTimes();

    expect(topologyManager.getRequests(EasyMock.anyObject())).andReturn(
      Collections.emptyList()).anyTimes();

    replay(topologyManager);


    // !!! don't mess with injectors for this test
    Field field = RequestResourceProvider.class.getDeclaredField("s_requestDAO");
    field.setAccessible(true);
    field.set(null, requestDAO);

    field = RequestResourceProvider.class.getDeclaredField("s_hostRoleCommandDAO");
    field.setAccessible(true);
    field.set(null, hrcDAO);

    field = RequestResourceProvider.class.getDeclaredField("topologyManager");
    field.setAccessible(true);
    field.set(null, topologyManager);

    field = SecretReference.class.getDeclaredField("gson");
    field.setAccessible(true);
    field.set(null, new Gson());

    AuthorizationHelperInitializer.viewInstanceDAOReturningNull();
  }

  @After
  public void cleanAuthentication() {
    SecurityContextHolder.getContext().setAuthentication(null);
  }

  @Test
  public void testCreateResources() throws Exception {
    Resource.Type type = Resource.Type.Request;

    AmbariManagementController managementController = createMock(AmbariManagementController.class);
    RequestStatusResponse response = createNiceMock(RequestStatusResponse.class);


    // replay
    replay(managementController, response);

    ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
      type,
      managementController);

    // add the property map to a set for the request.  add more maps for multiple creates
    Set<Map<String, Object>> propertySet = new LinkedHashSet<>();

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

    // add properties to the request map
    properties.put(RequestResourceProvider.REQUEST_ID_PROPERTY_ID, "Request100");

    propertySet.add(properties);

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

    try {
      provider.createResources(request);
      Assert.fail("Expected an UnsupportedOperationException");
    } catch (UnsupportedOperationException e) {
      // expected
    }

    // verify
    verify(managementController, response);
  }

  @Test
  public void testGetResourcesWithRequestInfo() throws Exception {
    Resource.Type type = Resource.Type.Request;

    expect(requestDAO.findByPks(Collections.emptyList(), true)).andReturn(Collections.emptyList()).anyTimes();

    prepareGetAuthorizationExpectations();

    ActionManager actionManager = createNiceMock(ActionManager.class);

    Cluster cluster = createNiceMock(Cluster.class);
    expect(cluster.getClusterId()).andReturn(1L).anyTimes();
    expect(cluster.getResourceId()).andReturn(4L).anyTimes();

    Clusters clusters = createNiceMock(Clusters.class);
    expect(clusters.getCluster("foo_cluster")).andReturn(cluster).anyTimes();

    AmbariManagementController managementController = createMock(AmbariManagementController.class);
    expect(managementController.getActionManager()).andReturn(actionManager).anyTimes();
    expect(managementController.getClusters()).andReturn(clusters).anyTimes();
    replay(managementController, clusters, cluster);

    ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(type, managementController);

    Map<String, String> requestInfoProperties = new HashMap<>();
    Request request;
    Predicate predicate = new PredicateBuilder()
      .property(RequestResourceProvider.REQUEST_CLUSTER_NAME_PROPERTY_ID)
      .equals("foo_cluster")
      .and().property(RequestResourceProvider.REQUEST_ID_PROPERTY_ID)
      .equals(null)
      .and().property(RequestResourceProvider.REQUEST_STATUS_PROPERTY_ID)
      .equals(null)
      .toPredicate();

    request = PropertyHelper.getReadRequest(new HashSet<>(),
      requestInfoProperties, null, null, null);

    expect(requestDAO.findAllRequestIds(BaseRequest.DEFAULT_PAGE_SIZE, false, 1L)).andReturn(Collections.emptyList()).anyTimes();
    replay(requestDAO);

    provider.getResources(request, predicate);
    verify(requestDAO);

    requestInfoProperties.put(BaseRequest.PAGE_SIZE_PROPERTY_KEY, "20");
    request = PropertyHelper.getReadRequest(new HashSet<>(),
      requestInfoProperties, null, null, null);
    provider.getResources(request, predicate);
    verify(requestDAO);

    reset(requestDAO);

    requestInfoProperties.put(BaseRequest.ASC_ORDER_PROPERTY_KEY, "true");
    request = PropertyHelper.getReadRequest(new HashSet<>(),
      requestInfoProperties, null, null, null);
    expect(requestDAO.findByPks(Collections.emptyList(), true)).andReturn(Collections.emptyList()).anyTimes();
    expect(requestDAO.findAllRequestIds(BaseRequest.DEFAULT_PAGE_SIZE, true, 1L)).andReturn(Collections.emptyList()).anyTimes();
    replay(requestDAO);

    provider.getResources(request, predicate);
    verify(requestDAO);
  }

  private void prepareGetAuthorizationExpectations() {
    prepareGetAuthorizationExpectations(true);
  }

  private void prepareGetAuthorizationExpectations(boolean allowedToAuthorize) {
    SecurityContextHolder.getContext().setAuthentication(allowedToAuthorize ? createAdministrator() : createViewUser(1L));
  }

  @Test
  public void testGetResources() throws Exception {
    Resource.Type type = Resource.Type.Request;

    String storedInputs = "{" +
        " \"hosts\": \"host1\"," +
        " \"check_execute_list\": \"last_agent_env_check,installed_packages,existing_repos,transparentHugePage\"," +
        " \"jdk_location\": \"http://ambari_server.home:8080/resources/\"," +
        " \"threshold\": \"20\"," +
        " \"password\": \"for your eyes only\"," +
        " \"foo_password\": \"for your eyes only\"," +
        " \"passwd\": \"for your eyes only\"," +
        " \"foo_passwd\": \"for your eyes only\"" +
        " }";
    String cleanedInputs = SecretReference.maskPasswordInPropertyMap(storedInputs);

    // Make sure SecretReference.maskPasswordInPropertyMap properly masked the password fields in cleanedInputs...
    Gson gson = new Gson();
    Map<String, String> map = gson.fromJson(cleanedInputs, new TypeToken<Map<String, String>>() {}.getType());
    for (Map.Entry<String, String> entry : map.entrySet()) {
      String name = entry.getKey();
      if (name.contains("password") || name.contains("passwd")) {
        Assert.assertEquals("SECRET", entry.getValue());
      }
      else {
        Assert.assertFalse("SECRET".equals(entry.getValue()));
      }
    }

    AmbariManagementController managementController = createMock(AmbariManagementController.class);
    ActionManager actionManager = createNiceMock(ActionManager.class);
    RequestEntity requestMock = createNiceMock(RequestEntity.class);

    expect(requestMock.getRequestContext()).andReturn("this is a context").anyTimes();
    expect(requestMock.getRequestId()).andReturn(100L).anyTimes();
    expect(requestMock.getInputs()).andReturn(storedInputs).anyTimes();

    Capture<Collection<Long>> requestIdsCapture = newCapture();

    // set expectations
    expect(managementController.getActionManager()).andReturn(actionManager);
    expect(requestDAO.findByPks(capture(requestIdsCapture), eq(true))).andReturn(Collections.singletonList(requestMock)).anyTimes();
    expect(hrcDAO.findAggregateCounts((Long) anyObject())).andReturn(new HashMap<Long, HostRoleCommandStatusSummaryDTO>(){{
      put(1L, HostRoleCommandStatusSummaryDTO.create().inProgress(1));
    }}).anyTimes();

    prepareGetAuthorizationExpectations();

    // replay
    replay(managementController, actionManager, requestDAO, hrcDAO, requestMock);

    ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
      type,
      managementController);

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

    propertyIds.add(RequestResourceProvider.REQUEST_ID_PROPERTY_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_STATUS_PROPERTY_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_INPUTS_ID);

    Predicate predicate = new PredicateBuilder().property(RequestResourceProvider.REQUEST_ID_PROPERTY_ID).equals("100").
      toPredicate();
    Request request = PropertyHelper.getReadRequest(propertyIds);
    Set<Resource> resources = provider.getResources(request, predicate);

    Assert.assertEquals(1, resources.size());
    for (Resource resource : resources) {
      Assert.assertEquals(100L, (long) (Long) resource.getPropertyValue(RequestResourceProvider.REQUEST_ID_PROPERTY_ID));
      Assert.assertEquals("IN_PROGRESS", resource.getPropertyValue(RequestResourceProvider.REQUEST_STATUS_PROPERTY_ID));
      Assert.assertEquals(cleanedInputs, resource.getPropertyValue(RequestResourceProvider.REQUEST_INPUTS_ID));
    }

    // verify
    verify(managementController, actionManager, requestDAO, hrcDAO);
  }

  @Test
  public void testGetResourcesWithRequestSchedule() throws Exception {
    Resource.Type type = Resource.Type.Request;

    AmbariManagementController managementController = createMock(AmbariManagementController.class);
    ActionManager actionManager = createNiceMock(ActionManager.class);

    RequestEntity requestMock = createNiceMock(RequestEntity.class);
    expect(requestMock.getRequestContext()).andReturn("this is a context").anyTimes();
    expect(requestMock.getRequestId()).andReturn(100L).anyTimes();
    expect(requestMock.getRequestScheduleId()).andReturn(11L).anyTimes();

    Capture<Collection<Long>> requestIdsCapture = newCapture();

    // set expectations
    expect(managementController.getActionManager()).andReturn(actionManager);
    expect(requestDAO.findByPks(capture(requestIdsCapture), eq(true))).andReturn(Collections.singletonList(requestMock)).anyTimes();
    expect(hrcDAO.findAggregateCounts((Long) anyObject())).andReturn(new HashMap<Long, HostRoleCommandStatusSummaryDTO>(){{
      put(1L, HostRoleCommandStatusSummaryDTO.create().inProgress(1));
    }}).anyTimes();

    prepareGetAuthorizationExpectations();

    // replay
    replay(managementController, actionManager, requestDAO, hrcDAO, requestMock);

    ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
      type,
      managementController);

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

    propertyIds.add(RequestResourceProvider.REQUEST_ID_PROPERTY_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_STATUS_PROPERTY_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_SOURCE_SCHEDULE);


    Predicate predicate = new PredicateBuilder().property(RequestResourceProvider.REQUEST_ID_PROPERTY_ID).equals("100").
      toPredicate();
    Request request = PropertyHelper.getReadRequest(propertyIds);
    Set<Resource> resources = provider.getResources(request, predicate);

    Assert.assertEquals(1, resources.size());
    for (Resource resource : resources) {
      Assert.assertEquals(100L, (long) (Long) resource.getPropertyValue(RequestResourceProvider.REQUEST_ID_PROPERTY_ID));
      Assert.assertEquals("IN_PROGRESS", resource.getPropertyValue(RequestResourceProvider.REQUEST_STATUS_PROPERTY_ID));
      Assert.assertEquals(11L, (long) (Long) resource.getPropertyValue(RequestResourceProvider.REQUEST_SOURCE_SCHEDULE_ID));
    }

    // verify
    verify(managementController, actionManager, requestDAO, hrcDAO);
  }

  @Test
  public void testGetResourcesWithoutRequestSchedule() throws Exception {
    Resource.Type type = Resource.Type.Request;

    AmbariManagementController managementController = createMock(AmbariManagementController.class);
    ActionManager actionManager = createNiceMock(ActionManager.class);
    RequestEntity requestMock = createNiceMock(RequestEntity.class);

    expect(requestMock.getRequestContext()).andReturn("this is a context").anyTimes();
    expect(requestMock.getRequestId()).andReturn(100L).anyTimes();
    expect(requestMock.getRequestScheduleId()).andReturn(null).anyTimes();

    Capture<Collection<Long>> requestIdsCapture = newCapture();

    // set expectations
    expect(managementController.getActionManager()).andReturn(actionManager);
    expect(requestDAO.findByPks(capture(requestIdsCapture), eq(true))).andReturn(Collections.singletonList(requestMock)).anyTimes();
    expect(hrcDAO.findAggregateCounts((Long) anyObject())).andReturn(new HashMap<Long, HostRoleCommandStatusSummaryDTO>(){{
      put(1L, HostRoleCommandStatusSummaryDTO.create().inProgress(1));
    }}).anyTimes();

    prepareGetAuthorizationExpectations();

    // replay
    replay(managementController, actionManager, requestMock, requestDAO, hrcDAO);

    ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
      type,
      managementController);

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

    propertyIds.add(RequestResourceProvider.REQUEST_ID_PROPERTY_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_STATUS_PROPERTY_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_SOURCE_SCHEDULE);


    Predicate predicate = new PredicateBuilder().property(RequestResourceProvider.REQUEST_ID_PROPERTY_ID).equals("100").
      toPredicate();
    Request request = PropertyHelper.getReadRequest(propertyIds);
    Set<Resource> resources = provider.getResources(request, predicate);

    Assert.assertEquals(1, resources.size());
    for (Resource resource : resources) {
      Assert.assertEquals(100L, (long) (Long) resource.getPropertyValue(RequestResourceProvider.REQUEST_ID_PROPERTY_ID));
      Assert.assertEquals("IN_PROGRESS", resource.getPropertyValue(RequestResourceProvider.REQUEST_STATUS_PROPERTY_ID));
      Assert.assertEquals(null, resource.getPropertyValue(RequestResourceProvider.REQUEST_SOURCE_SCHEDULE));
    }

    // verify
    verify(managementController, actionManager, requestMock, requestDAO, hrcDAO);
  }

  @Test
  public void testGetResourcesWithCluster() throws Exception {
    Resource.Type type = Resource.Type.Request;

    AmbariManagementController managementController = createMock(AmbariManagementController.class);
    ActionManager actionManager = createNiceMock(ActionManager.class);
    Clusters clusters = createNiceMock(Clusters.class);
    Cluster cluster = createNiceMock(Cluster.class);

    expect(cluster.getClusterId()).andReturn(50L).anyTimes();

    RequestEntity requestMock = createNiceMock(RequestEntity.class);
    expect(requestMock.getRequestContext()).andReturn("this is a context").anyTimes();
    expect(requestMock.getClusterId()).andReturn(50L).anyTimes();
    expect(requestMock.getRequestId()).andReturn(100L).anyTimes();

    Capture<Collection<Long>> requestIdsCapture = newCapture();

    // set expectations
    expect(managementController.getActionManager()).andReturn(actionManager).anyTimes();
    expect(managementController.getClusters()).andReturn(clusters).anyTimes();
    expect(clusters.getCluster("c1")).andReturn(cluster).anyTimes();
    expect(clusters.getCluster("bad-cluster")).andThrow(new AmbariException("bad cluster!")).anyTimes();
    expect(requestDAO.findByPks(capture(requestIdsCapture), eq(true))).andReturn(Collections.singletonList(requestMock));
    expect(hrcDAO.findAggregateCounts((Long) anyObject())).andReturn(new HashMap<Long, HostRoleCommandStatusSummaryDTO>(){{
      put(1L, HostRoleCommandStatusSummaryDTO.create().inProgress(1));
    }}).anyTimes();

    prepareGetAuthorizationExpectations();

    // replay
    replay(managementController, actionManager, clusters, cluster, requestMock, requestDAO, hrcDAO);

    ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
      type,
      managementController);

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

    propertyIds.add(RequestResourceProvider.REQUEST_ID_PROPERTY_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_STATUS_PROPERTY_ID);

    Predicate predicate = new PredicateBuilder().
      property(RequestResourceProvider.REQUEST_CLUSTER_NAME_PROPERTY_ID).equals("c1").and().
      property(RequestResourceProvider.REQUEST_ID_PROPERTY_ID).equals("100").
      toPredicate();
    Request request = PropertyHelper.getReadRequest(propertyIds);
    Set<Resource> resources = provider.getResources(request, predicate);

    Assert.assertEquals(1, resources.size());
    for (Resource resource : resources) {
      Assert.assertEquals(100L, (long) (Long) resource.getPropertyValue(RequestResourceProvider.REQUEST_ID_PROPERTY_ID));
      Assert.assertEquals("IN_PROGRESS", resource.getPropertyValue(RequestResourceProvider.REQUEST_STATUS_PROPERTY_ID));
    }

    // try again with a bad cluster name
    predicate = new PredicateBuilder().
      property(RequestResourceProvider.REQUEST_CLUSTER_NAME_PROPERTY_ID).equals("bad-cluster").and().
      property(RequestResourceProvider.REQUEST_ID_PROPERTY_ID).equals("100").
      toPredicate();
    try {
      provider.getResources(request, predicate);
    } catch (NoSuchParentResourceException e) {
      e.printStackTrace();
    }

    // verify
    verify(managementController, actionManager, clusters, cluster, requestMock, requestDAO, hrcDAO);
  }

  @Test
  public void testGetResourcesOrPredicate() throws Exception {
    Resource.Type type = Resource.Type.Request;

    AmbariManagementController managementController = createMock(AmbariManagementController.class);
    ActionManager actionManager = createNiceMock(ActionManager.class);

    RequestEntity requestMock = createNiceMock(RequestEntity.class);
    expect(requestMock.getRequestContext()).andReturn("this is a context").anyTimes();
    expect(requestMock.getRequestId()).andReturn(100L).anyTimes();

    RequestEntity requestMock1 = createNiceMock(RequestEntity.class);
    expect(requestMock1.getRequestContext()).andReturn("this is a context").anyTimes();
    expect(requestMock1.getRequestId()).andReturn(101L).anyTimes();

    Capture<Collection<Long>> requestIdsCapture = newCapture();

    // set expectations
    expect(managementController.getActionManager()).andReturn(actionManager).anyTimes();
    expect(requestDAO.findByPks(capture(requestIdsCapture), eq(true))).
      andReturn(Arrays.asList(requestMock, requestMock1)).anyTimes();
    expect(hrcDAO.findAggregateCounts((Long) anyObject())).andReturn(new HashMap<Long, HostRoleCommandStatusSummaryDTO>(){{
      put(1L, HostRoleCommandStatusSummaryDTO.create().inProgress(1));
    }}).anyTimes();

    prepareGetAuthorizationExpectations();

    // replay
    replay(managementController, actionManager, requestMock, requestMock1, requestDAO, hrcDAO);

    ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
      type,
      managementController);

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

    propertyIds.add(RequestResourceProvider.REQUEST_ID_PROPERTY_ID);

    Predicate predicate = new PredicateBuilder().property(RequestResourceProvider.REQUEST_ID_PROPERTY_ID).equals("100").
      or().property(RequestResourceProvider.REQUEST_ID_PROPERTY_ID).equals("101").
      toPredicate();
    Request request = PropertyHelper.getReadRequest(propertyIds);
    Set<Resource> resources = provider.getResources(request, predicate);

    Assert.assertEquals(2, resources.size());
    for (Resource resource : resources) {
      long id = (Long) resource.getPropertyValue(RequestResourceProvider.REQUEST_ID_PROPERTY_ID);
      Assert.assertTrue(id == 100L || id == 101L);
    }

    // verify
    verify(managementController, actionManager, requestMock, requestMock1, requestDAO, hrcDAO);
  }

  @Test
  public void testGetResourcesCompleted() throws Exception {
    Resource.Type type = Resource.Type.Request;

    AmbariManagementController managementController = createMock(AmbariManagementController.class);
    ActionManager actionManager = createNiceMock(ActionManager.class);

    RequestEntity requestMock0 = createNiceMock(RequestEntity.class);
    expect(requestMock0.getRequestContext()).andReturn("this is a context").anyTimes();
    expect(requestMock0.getRequestId()).andReturn(100L).anyTimes();

    RequestEntity requestMock1 = createNiceMock(RequestEntity.class);
    expect(requestMock1.getRequestContext()).andReturn("this is a context").anyTimes();
    expect(requestMock1.getRequestId()).andReturn(101L).anyTimes();

    Capture<Collection<Long>> requestIdsCapture = newCapture();

    // set expectations
    expect(managementController.getActionManager()).andReturn(actionManager).anyTimes();
    expect(requestDAO.findByPks(capture(requestIdsCapture), eq(true))).andReturn(Arrays.asList(requestMock0));
    expect(requestDAO.findByPks(capture(requestIdsCapture), eq(true))).andReturn(Arrays.asList(requestMock1));
    expect(hrcDAO.findAggregateCounts((Long) anyObject())).andReturn(new HashMap<Long, HostRoleCommandStatusSummaryDTO>(){{
      put(1L, HostRoleCommandStatusSummaryDTO.create().completed(2));
    }}).anyTimes();

    prepareGetAuthorizationExpectations();

    // replay
    replay(managementController, actionManager, requestMock0, requestMock1, requestDAO, hrcDAO);

    ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
      type,
      managementController);

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

    propertyIds.add(RequestResourceProvider.REQUEST_ID_PROPERTY_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_STATUS_PROPERTY_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_TASK_CNT_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_COMPLETED_TASK_CNT_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_FAILED_TASK_CNT_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_PROGRESS_PERCENT_ID);

    Predicate predicate = new PredicateBuilder().property(RequestResourceProvider.REQUEST_ID_PROPERTY_ID).equals("100").or().
      property(RequestResourceProvider.REQUEST_ID_PROPERTY_ID).equals("101").toPredicate();
    Request request = PropertyHelper.getReadRequest(propertyIds);
    Set<Resource> resources = provider.getResources(request, predicate);

    Assert.assertEquals(2, resources.size());
    for (Resource resource : resources) {
      long id = (Long) resource.getPropertyValue(RequestResourceProvider.REQUEST_ID_PROPERTY_ID);
      Assert.assertTrue(id == 100L || id == 101L);
      Assert.assertEquals("COMPLETED", resource.getPropertyValue(RequestResourceProvider.REQUEST_STATUS_PROPERTY_ID));
      Assert.assertEquals(2, resource.getPropertyValue(RequestResourceProvider.REQUEST_TASK_CNT_ID));
      Assert.assertEquals(0, resource.getPropertyValue(RequestResourceProvider.REQUEST_FAILED_TASK_CNT_ID));
      Assert.assertEquals(2, resource.getPropertyValue(RequestResourceProvider.REQUEST_COMPLETED_TASK_CNT_ID));

      Assert.assertEquals(100.0, resource.getPropertyValue(RequestResourceProvider.REQUEST_PROGRESS_PERCENT_ID));
    }

    // verify
    verify(managementController, actionManager, requestMock0, requestMock1, requestDAO, hrcDAO);
  }

  @Test
  public void testGetResourcesInProgress() throws Exception {
    Resource.Type type = Resource.Type.Request;

    AmbariManagementController managementController = createMock(AmbariManagementController.class);
    ActionManager actionManager = createNiceMock(ActionManager.class);

    RequestEntity requestMock0 = createNiceMock(RequestEntity.class);
    expect(requestMock0.getRequestContext()).andReturn("this is a context").anyTimes();
    expect(requestMock0.getRequestId()).andReturn(100L).anyTimes();

    RequestEntity requestMock1 = createNiceMock(RequestEntity.class);
    expect(requestMock1.getRequestContext()).andReturn("this is a context").anyTimes();
    expect(requestMock1.getRequestId()).andReturn(101L).anyTimes();

    Capture<Collection<Long>> requestIdsCapture = EasyMock.newCapture();

    // set expectations
    expect(managementController.getActionManager()).andReturn(actionManager).anyTimes();
    expect(requestDAO.findByPks(capture(requestIdsCapture), eq(true))).andReturn(Arrays.asList(requestMock0));
    expect(requestDAO.findByPks(capture(requestIdsCapture), eq(true))).andReturn(Arrays.asList(requestMock1));

    // IN_PROGRESS and PENDING
    expect(hrcDAO.findAggregateCounts(100L)).andReturn(new HashMap<Long, HostRoleCommandStatusSummaryDTO>() {{
      put(1L, HostRoleCommandStatusSummaryDTO.create().inProgress(1).pending(1));
    }}).once();

    // IN_PROGRESS and QUEUED
    expect(hrcDAO.findAggregateCounts(101L)).andReturn(new HashMap<Long, HostRoleCommandStatusSummaryDTO>(){{
      put(1L, HostRoleCommandStatusSummaryDTO.create().inProgress(1).queued(1));
    }}).once();

    prepareGetAuthorizationExpectations();

    // replay
    replay(managementController, actionManager, requestMock0, requestMock1, requestDAO, hrcDAO);

    ResourceProvider provider = AbstractControllerResourceProvider.getResourceProvider(
      type,
      managementController);

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

    propertyIds.add(RequestResourceProvider.REQUEST_ID_PROPERTY_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_STATUS_PROPERTY_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_TASK_CNT_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_COMPLETED_TASK_CNT_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_FAILED_TASK_CNT_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_QUEUED_TASK_CNT_ID);
    propertyIds.add(RequestResourceProvider.REQUEST_PROGRESS_PERCENT_ID);

    Predicate predicate = new PredicateBuilder().property(RequestResourceProvider.REQUEST_ID_PROPERTY_ID).equals("100").or().
      property(RequestResourceProvider.REQUEST_ID_PROPERTY_ID).equals("101").toPredicate();
    Request request = PropertyHelper.getReadRequest(propertyIds);
    Set<Resource> resources = provider.getResources(request, predicate);

    Assert.assertEquals(2, resources.size());
    for (Resource resource : resources) {
      long id = (Long) resource.getPropertyValue(RequestResourceProvider.REQUEST_ID_PROPERTY_ID);
      Assert.assertTrue(id == 100L || id == 101L);
      Assert.assertEquals("IN_PROGRESS", resource.getPropertyValue(RequestResourceProvider.REQUEST_STATUS_PROPERTY_ID));
      Assert.assertEquals(2, resource.getPropertyValue(RequestResourceProvider.REQUEST_TASK_CNT_ID));
      Assert.assertEquals(0, resource.getPropertyValue(RequestResourceProvider.REQUEST_FAILED_TASK_CNT_ID));

      if (id == 100L) {
        Assert.assertEquals(0, resource.getPropertyValue(RequestResourceProvider.REQUEST_QUEUED_TASK_CNT_ID));
