content: /*
   * 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.easymock.EasyMock.createMock;
  import static org.easymock.EasyMock.createNiceMock;
  import static org.easymock.EasyMock.replay;
  
  import java.util.Arrays;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Map;
  import java.util.Set;
  
  import org.apache.ambari.server.controller.AmbariManagementController;
  import org.apache.ambari.server.controller.ClusterRequest;
  import org.apache.ambari.server.controller.ConfigurationRequest;
  import org.apache.ambari.server.controller.GroupRequest;
  import org.apache.ambari.server.controller.HostRequest;
  import org.apache.ambari.server.controller.MaintenanceStateHelper;
  import org.apache.ambari.server.controller.MemberRequest;
  import org.apache.ambari.server.controller.RequestStatusResponse;
  import org.apache.ambari.server.controller.ServiceComponentHostRequest;
  import org.apache.ambari.server.controller.StackConfigurationDependencyRequest;
  import org.apache.ambari.server.controller.StackConfigurationRequest;
  import org.apache.ambari.server.controller.StackLevelConfigurationRequest;
  import org.apache.ambari.server.controller.UserRequest;
  import org.apache.ambari.server.controller.predicate.AlwaysPredicate;
  import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
  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.RequestStatus;
  import org.apache.ambari.server.controller.spi.Resource;
  import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
  import org.apache.ambari.server.controller.spi.SystemException;
  import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
  import org.apache.ambari.server.controller.utilities.PredicateBuilder;
  import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
  import org.apache.ambari.server.state.SecurityType;
  import org.easymock.EasyMock;
  import org.easymock.IArgumentMatcher;
  import org.junit.Assert;
  import org.junit.Test;
  
  /**
   * Resource provider tests.
   */
  public class AbstractResourceProviderTest {
  
    @Test
    public void testCheckPropertyIds() {
      Set<String> propertyIds = new HashSet<>();
      propertyIds.add("foo");
      propertyIds.add("cat1/foo");
      propertyIds.add("cat2/bar");
      propertyIds.add("cat2/baz");
      propertyIds.add("cat3/sub1/bam");
      propertyIds.add("cat4/sub2/sub3/bat");
      propertyIds.add("cat5/subcat5/map");
  
      Map<Resource.Type, String> keyPropertyIds = new HashMap<>();
  
      AmbariManagementController managementController = createMock(AmbariManagementController.class);
  
      AbstractResourceProvider provider = new HostComponentProcessResourceProvider(managementController);
  
      Set<String> unsupported = provider.checkPropertyIds(Collections.singleton("HostComponentProcess/host_name"));
      Assert.assertTrue(unsupported.isEmpty());
  
      // note that key is not in the set of known property ids.  We allow it if its parent is a known property.
      // this allows for Map type properties where we want to treat the entries as individual properties
      Assert.assertTrue(provider.checkPropertyIds(Collections.singleton("HostComponentProcess/host_name/foo")).isEmpty());
  
      unsupported = provider.checkPropertyIds(Collections.singleton("bar"));
      Assert.assertEquals(1, unsupported.size());
      Assert.assertTrue(unsupported.contains("bar"));
  
      unsupported = provider.checkPropertyIds(Collections.singleton("HostComponentProcess/status"));
      Assert.assertTrue(unsupported.isEmpty());
  
      unsupported = provider.checkPropertyIds(Collections.singleton("HostComponentProcess"));
      Assert.assertTrue(unsupported.isEmpty());
    }
  
    @Test
    public void testGetPropertyIds() {
      Set<String> propertyIds = new HashSet<>();
      propertyIds.add("HostComponentProcess/name");
      propertyIds.add("HostComponentProcess/status");
      propertyIds.add("HostComponentProcess/cluster_name");
      propertyIds.add("HostComponentProcess/host_name");
      propertyIds.add("HostComponentProcess/component_name");
  
      AmbariManagementController managementController = createMock(AmbariManagementController.class);
      MaintenanceStateHelper maintenanceStateHelper = createNiceMock(MaintenanceStateHelper.class);
      RepositoryVersionDAO repositoryVersionDAO = createNiceMock(RepositoryVersionDAO.class);
      replay(maintenanceStateHelper, repositoryVersionDAO);
  
      AbstractResourceProvider provider = new HostComponentProcessResourceProvider(managementController);
  
      Set<String> supportedPropertyIds = provider.getPropertyIds();
      Assert.assertTrue(supportedPropertyIds.containsAll(propertyIds));
    }
  
    @Test
    public void testGetRequestStatus() {
      AmbariManagementController managementController = createMock(AmbariManagementController.class);
      MaintenanceStateHelper maintenanceStateHelper = createNiceMock(MaintenanceStateHelper.class);
      RepositoryVersionDAO repositoryVersionDAO = createNiceMock(RepositoryVersionDAO.class);
      replay(maintenanceStateHelper, repositoryVersionDAO);
  
      AbstractResourceProvider provider = new ServiceResourceProvider(managementController,
          maintenanceStateHelper, repositoryVersionDAO);
  
      RequestStatus status = provider.getRequestStatus(null);
  
      Assert.assertNull(status.getRequestResource());
      Assert.assertEquals(Collections.emptySet(), status.getAssociatedResources());
  
      RequestStatusResponse response = new RequestStatusResponse(99L);
  
      status = provider.getRequestStatus(response);
      Resource resource = status.getRequestResource();
  
      Assert.assertEquals(99L, resource.getPropertyValue("Requests/id"));
      Assert.assertEquals(Collections.emptySet(), status.getAssociatedResources());
  
  
      status = provider.getRequestStatus(response, null);
      resource = status.getRequestResource();
  
      Assert.assertEquals(99L, resource.getPropertyValue("Requests/id"));
      Assert.assertEquals(Collections.emptySet(), status.getAssociatedResources());
  
  
      Resource associatedResource = new ResourceImpl(Resource.Type.Service);
  
      Set<Resource> associatedResources = Collections.singleton(associatedResource);
      status = provider.getRequestStatus(response, associatedResources);
      resource = status.getRequestResource();
  
      Assert.assertEquals(99L, resource.getPropertyValue("Requests/id"));
      Assert.assertEquals(associatedResources, status.getAssociatedResources());
    }
  
    @Test
    public void testGetPropertyMaps() throws Exception {
      AbstractResourceProvider provider = new TestResourceProvider();
  
      Map<String, Object> updatePropertyMap = new HashMap<>();
      updatePropertyMap.put("SomeProperty", "SomeUpdateValue");
      updatePropertyMap.put("SomeOtherProperty", 99);
  
      // get the property map to update resource
      // where ClusterName=c1 and ResourceName=r1
      PredicateBuilder pb = new PredicateBuilder();
      Predicate predicate = pb.property("ClusterName").equals("c1").and().property("ResourceName").equals("r1").toPredicate();
  
      Set<Map<String, Object>> propertyMaps = provider.getPropertyMaps(updatePropertyMap, predicate);
  
      Assert.assertEquals(1, propertyMaps.size());
  
      Map<String, Object> map = propertyMaps.iterator().next();
  
      Assert.assertEquals(4, map.size());
      Assert.assertEquals("c1", map.get("ClusterName"));
      Assert.assertEquals("r1", map.get("ResourceName"));
      Assert.assertEquals("SomeUpdateValue", map.get("SomeProperty"));
      Assert.assertEquals(99, map.get("SomeOtherProperty"));
  
      // get the property maps to update resources
      // where ClusterName=c1 and (ResourceName=r1 or ResourceName=r2)
      pb = new PredicateBuilder();
      predicate = pb.property("ClusterName").equals("c1").and().
          begin().
            property("ResourceName").equals("r1").or().property("ResourceName").equals("r2").
          end().toPredicate();
  
      propertyMaps = provider.getPropertyMaps(updatePropertyMap, predicate);
  
      Assert.assertEquals(2, propertyMaps.size());
  
      for (Map<String, Object> map2 : propertyMaps) {
        Assert.assertEquals(4, map2.size());
        Assert.assertEquals("c1", map2.get("ClusterName"));
        Object resourceName = map2.get("ResourceName");
        Assert.assertTrue(resourceName.equals("r1") || resourceName.equals("r2"));
        Assert.assertEquals("SomeUpdateValue", map2.get("SomeProperty"));
        Assert.assertEquals(99, map2.get("SomeOtherProperty"));
      }
  
      // get the property maps to update all resources
      predicate = new AlwaysPredicate();
  
      propertyMaps = provider.getPropertyMaps(updatePropertyMap, predicate);
  
      Assert.assertEquals(4, propertyMaps.size());
  
      for (Map<String, Object> map2 : propertyMaps) {
        Assert.assertEquals(4, map2.size());
        Assert.assertEquals("c1", map2.get("ClusterName"));
        Object resourceName = map2.get("ResourceName");
        Assert.assertTrue(resourceName.equals("r1") || resourceName.equals("r2")||
            resourceName.equals("r3") || resourceName.equals("r4"));
        Assert.assertEquals("SomeUpdateValue", map2.get("SomeProperty"));
        Assert.assertEquals(99, map2.get("SomeOtherProperty"));
      }
    }
  
    @Test
    public void testGetQueryParameterValue() {
  
      String queryParameterId1 = "qp/variable1";
      String queryParameterValue1 = "value1";
      String queryParameterId2 = "qp/variable2";
      String queryParameterValue2 = "value2";
  
      //Array of predicates
      Predicate  predicate = new PredicateBuilder().property(queryParameterId1).equals(queryParameterValue1).
          and().property(queryParameterId2).equals(queryParameterValue2).toPredicate();
  
      Assert.assertEquals(queryParameterValue1, AbstractResourceProvider.getQueryParameterValue(queryParameterId1, predicate));
      Assert.assertFalse(queryParameterValue2.equals(AbstractResourceProvider.getQueryParameterValue(queryParameterId1, predicate)));
      Assert.assertNull(AbstractResourceProvider.getQueryParameterValue("queryParameterIdNotFound", predicate));
  
      String queryParameterId3 = "qp/variable3";
      String queryParameterValue3 = "value3";
  
      // tests ServiceInfo/state=INSTALLED&params/run_smoke_test=true
      //Array of arrays of predicates
      predicate = new PredicateBuilder().property(queryParameterId3).equals(queryParameterValue3).
          and().begin().property(queryParameterId1).equals(queryParameterValue1).
          and().property(queryParameterId2).equals(queryParameterValue2).end().toPredicate();
  
      Assert.assertEquals(queryParameterValue1, AbstractResourceProvider.
          getQueryParameterValue(queryParameterId1, predicate));
      Assert.assertFalse(queryParameterValue2.equals(AbstractResourceProvider.
          getQueryParameterValue(queryParameterId1, predicate)));
      Assert.assertNull(AbstractResourceProvider.
          getQueryParameterValue("queryParameterIdNotFound", predicate));
  
      Assert.assertEquals(queryParameterValue3, AbstractResourceProvider.
          getQueryParameterValue(queryParameterId3, predicate));
  
    }
  
  
    // ----- helper methods ----------------------------------------------------
  
    /**
     * Equals check that accounts for nulls.
     *
     * @param left   the left object
     * @param right  the right object
     *
     * @return true if the left and right object are equal or both null
     */
    private static boolean eq(Object left, Object right) {
      return  left == null ? right == null : right != null && left.equals(right);
    }
  
  
    // ----- inner classes -----------------------------------------------------
  
    /**
     * Utility class for getting various AmbariManagmentController request related matchers.
     */
    public static class Matcher
    {
      public static ClusterRequest getClusterRequest(
          Long clusterId, String clusterName, String stackVersion, Set<String> hostNames)
      {
        EasyMock.reportMatcher(new ClusterRequestMatcher(clusterId, clusterName, stackVersion, hostNames));
        return null;
      }
  
      public static Set<ClusterRequest> getClusterRequestSet(
          Long clusterId, String clusterName, String provisioningState, SecurityType securityType, String stackVersion, Set<String> hostNames)
      {
        EasyMock.reportMatcher(new ClusterRequestSetMatcher(clusterId, clusterName, provisioningState, securityType, stackVersion, hostNames));
        return null;
      }
  
      public static ConfigurationRequest getConfigurationRequest(
          String clusterName, String type, String tag, Map<String, String> configs, Map<String, Map<String, String>> configAttributes)
      {
        EasyMock.reportMatcher(new ConfigurationRequestMatcher(clusterName, type, tag, configs, configAttributes));
        return null;
      }
  
      public static Set<HostRequest> getHostRequestSet(String hostname, String clusterName,
                                                       Map<String, String> hostAttributes)
      {
        EasyMock.reportMatcher(new HostRequestSetMatcher(hostname, clusterName, hostAttributes));
        return null;
      }
  
      public static Set<ServiceComponentHostRequest> getHostComponentRequestSet(
          String clusterName, String serviceName, String componentName, String hostName,
          Map<String, String> configVersions, String desiredState)
      {
        EasyMock.reportMatcher(new HostComponentRequestSetMatcher(
            clusterName, serviceName, componentName, hostName, configVersions, desiredState));
        return null;
      }
  
      public static Set<UserRequest> getUserRequestSet(String name)
      {
        EasyMock.reportMatcher(new UserRequestSetMatcher(name));
        return null;
      }
  
      public static Set<GroupRequest> getGroupRequestSet(String name)
      {
        EasyMock.reportMatcher(new GroupRequestSetMatcher(name));
        return null;
      }
  
      public static Set<MemberRequest> getMemberRequestSet(String groupname, String username)
      {
        EasyMock.reportMatcher(new MemberRequestSetMatcher(groupname, username));
        return null;
      }
  
      public static Set<StackConfigurationRequest> getStackConfigurationRequestSet(String stackName, String stackVersion,
          String serviceName, String propertyName)
      {
        EasyMock.reportMatcher(new StackConfigurationRequestSetMatcher(stackName, stackVersion, serviceName, propertyName));
        return null;
      }
  
      public static Set<StackConfigurationDependencyRequest> getStackConfigurationDependencyRequestSet(String stackName, String stackVersion,
          String serviceName, String propertyName, String dependencyName)
      {
        EasyMock.reportMatcher(new StackConfigurationDependencyRequestSetMatcher(stackName, stackVersion, serviceName, propertyName, dependencyName));
        return null;
      }
  
      public static Set<StackLevelConfigurationRequest> getStackLevelConfigurationRequestSet(String stackName, String stackVersion,
          String propertyName)
      {
        EasyMock.reportMatcher(new StackLevelConfigurationRequestSetMatcher(stackName, stackVersion, propertyName));
        return null;
      }
    }
  
    /**
     * Matcher for a ClusterRequest.
     */
    public static class ClusterRequestMatcher extends ClusterRequest implements IArgumentMatcher {
  
      public ClusterRequestMatcher(Long clusterId, String clusterName, String stackVersion, Set<String> hostNames) {
        super(clusterId, clusterName, stackVersion, hostNames);
      }
  
      @Override
      public boolean matches(Object o) {
        return o instanceof ClusterRequest &&
            eq(((ClusterRequest) o).getClusterId(), getClusterId()) &&
            eq(((ClusterRequest) o).getClusterName(), getClusterName()) &&
            eq(((ClusterRequest) o).getStackVersion(), getStackVersion()) &&
            eq(((ClusterRequest) o).getHostNames(), getHostNames());
      }
  
      @Override
      public void appendTo(StringBuffer stringBuffer) {
        stringBuffer.append("ClusterRequestMatcher(").append(super.toString()).append(")");
      }
    }
  
    /**
     * Matcher for a ClusterRequest set.
     */
    public static class ClusterRequestSetMatcher extends ClusterRequest implements IArgumentMatcher {
  
      public ClusterRequestSetMatcher(Long clusterId, String clusterName, String provisioningState,
                                      SecurityType securityType, String stackVersion, Set<String> hostNames) {
        super(clusterId, clusterName, provisioningState, securityType, stackVersion, hostNames);
      }
  
      @Override
      public boolean matches(Object o) {
        if (!(o instanceof Set)) {
          return false;
        }
  
        Set set = (Set) o;
  
        if (set.size() != 1) {
          return false;
        }
  
        Object request = set.iterator().next();
  
        return eq(((ClusterRequest) request).getClusterId(), getClusterId()) &&
            eq(((ClusterRequest) request).getClusterName(), getClusterName()) &&
            eq(((ClusterRequest) request).getStackVersion(), getStackVersion()) &&
            eq(((ClusterRequest) request).getHostNames(), getHostNames());
      }
  
      @Override
      public void appendTo(StringBuffer stringBuffer) {
        stringBuffer.append("ClusterRequestSetMatcher(").append(super.toString()).append(")");
      }
    }
  
    /**
     * Matcher for a ConfigurationRequest.
     */
    public static class ConfigurationRequestMatcher extends ConfigurationRequest implements IArgumentMatcher {
  
      public ConfigurationRequestMatcher(String clusterName, String type, String tag, Map<String, String> configs, Map<String, Map<String, String>> configsAttributes) {
        super(clusterName, type, tag, configs, configsAttributes);
      }
  
      @Override
      public boolean matches(Object o) {
        return o instanceof ConfigurationRequest &&
            eq(((ConfigurationRequest) o).getClusterName(), getClusterName()) &&
            eq(((ConfigurationRequest) o).getType(), getType()) &&
            eq(((ConfigurationRequest) o).getVersionTag(), getVersionTag()) &&
            eq(((ConfigurationRequest) o).getProperties(), getProperties()) &&
            eq(((ConfigurationRequest) o).getPropertiesAttributes(), getPropertiesAttributes());
      }
  
      @Override
      public void appendTo(StringBuffer stringBuffer) {
        stringBuffer.append("ConfigurationRequestMatcher(").append(super.toString()).append(")");
      }
    }
  
  
    /**
     * Matcher for a HostRequest set containing a single request.
     */
    public static class HostRequestSetMatcher extends HashSet<HostRequest> implements IArgumentMatcher {
  
      private final HostRequest hostRequest;
  
      public HostRequestSetMatcher(String hostname, String clusterName, Map<String, String> hostAttributes) {
        hostRequest = new HostRequest(hostname, clusterName);
        add(hostRequest);
      }
  
      @Override
      public boolean matches(Object o) {
        if (!(o instanceof Set)) {
          return false;
        }
  
        Set set = (Set) o;
  
        if (set.size() != 1) {
          return false;
        }
  
        Object request = set.iterator().next();
  
        return request instanceof HostRequest &&
            eq(((HostRequest) request).getClusterName(), hostRequest.getClusterName()) &&
            eq(((HostRequest) request).getHostname(), hostRequest.getHostname());
      }
  
      @Override
      public void appendTo(StringBuffer stringBuffer) {
        stringBuffer.append("HostRequestSetMatcher(").append(hostRequest).append(")");
      }
    }
  
    /**
     * Matcher for a ServiceComponentHostRequest set containing a single request.
     */
    public static class HostComponentRequestSetMatcher extends HashSet<ServiceComponentHostRequest>
        implements IArgumentMatcher {
  
      private final ServiceComponentHostRequest hostComponentRequest;
  
      public HostComponentRequestSetMatcher(String clusterName, String serviceName, String componentName, String hostName,
                                        Map<String, String> configVersions, String desiredState) {
        hostComponentRequest =
            new ServiceComponentHostRequest(clusterName, serviceName, componentName,
                hostName, desiredState);
        add(hostComponentRequest);
      }
  
      @Override
      public boolean matches(Object o) {
  
        if (!(o instanceof Set)) {
          return false;
        }
  
        Set set = (Set) o;
  
        if (set.size() != 1) {
          return false;
        }
  
        Object request = set.iterator().next();
  
        return request instanceof ServiceComponentHostRequest &&
            eq(((ServiceComponentHostRequest) request).getClusterName(), hostComponentRequest.getClusterName()) &&
            eq(((ServiceComponentHostRequest) request).getServiceName(), hostComponentRequest.getServiceName()) &&
            eq(((ServiceComponentHostRequest) request).getComponentName(), hostComponentRequest.getComponentName()) &&
            eq(((ServiceComponentHostRequest) request).getHostname(), hostComponentRequest.getHostname()) &&
            eq(((ServiceComponentHostRequest) request).getDesiredState(), hostComponentRequest.getDesiredState());
      }
  
      @Override
      public void appendTo(StringBuffer stringBuffer) {
        stringBuffer.append("HostComponentRequestSetMatcher(").append(hostComponentRequest).append(")");
      }
    }
  
    /**
     * Matcher for a UserRequest set containing a single request.
     */
    public static class UserRequestSetMatcher extends HashSet<UserRequest> implements IArgumentMatcher {
  
      private final UserRequest userRequest;
  
      public UserRequestSetMatcher(String name) {
        userRequest = new UserRequest(name);
        add(userRequest);
      }
  
      @Override
      public boolean matches(Object o) {
  
        if (!(o instanceof Set)) {
          return false;
        }
  
        Set set = (Set) o;
  
        if (set.size() != 1) {
          return false;
        }
  
        Object request = set.iterator().next();
  
        return request instanceof UserRequest &&
            eq(((UserRequest) request).getUsername(), userRequest.getUsername());
      }
  
      @Override
      public void appendTo(StringBuffer stringBuffer) {
        stringBuffer.append("UserRequestSetMatcher(").append(userRequest).append(")");
      }
    }
  
    /**
     * Matcher for a GroupRequest set containing a single request.
     */
    public static class GroupRequestSetMatcher extends HashSet<GroupRequest> implements IArgumentMatcher {
  
      private final GroupRequest groupRequest;
  
      public GroupRequestSetMatcher(String name) {
        groupRequest = new GroupRequest(name);
        add(groupRequest);
      }
  
      @Override
      public boolean matches(Object o) {
  
        if (!(o instanceof Set)) {
          return false;
        }
  
        Set set = (Set) o;
  
        if (set.size() != 1) {
          return false;
        }
  
        Object request = set.iterator().next();
  
        return request instanceof GroupRequest &&
            eq(((GroupRequest) request).getGroupName(), groupRequest.getGroupName());
      }
  
      @Override
      public void appendTo(StringBuffer stringBuffer) {
        stringBuffer.append("GroupRequestSetMatcher(").append(groupRequest).append(")");
      }
    }
  
    /**
     * Matcher for a MemberRequest set containing a single request.
     */
    public static class MemberRequestSetMatcher extends HashSet<MemberRequest> implements IArgumentMatcher {
  
      private final MemberRequest memberRequest;
  
      public MemberRequestSetMatcher(String groupname, String username) {
        memberRequest = new MemberRequest(groupname, username);
        add(memberRequest);
      }
  
      @Override
      public boolean matches(Object o) {
  
        if (!(o instanceof Set)) {
          return false;
        }
  
        Set set = (Set) o;
  
        if (set.size() != 1) {
          return false;
        }
  
        Object request = set.iterator().next();
  
        return request instanceof MemberRequest &&
            eq(((MemberRequest) request).getGroupName(), memberRequest.getGroupName()) &&
            eq(((MemberRequest) request).getUserName(), memberRequest.getUserName());
      }
  
      @Override
      public void appendTo(StringBuffer stringBuffer) {
        stringBuffer.append("MemberRequestSetMatcher(").append(memberRequest).append(")");
      }
    }
  
    /**
     * Matcher for a Stack set containing a single request.
     */
    public static class StackConfigurationRequestSetMatcher extends HashSet<StackConfigurationRequest> implements IArgumentMatcher {
  
      private final StackConfigurationRequest stackConfigurationRequest;
  
      public StackConfigurationRequestSetMatcher(String stackName, String stackVersion,
          String serviceName, String propertyName) {
        stackConfigurationRequest = new StackConfigurationRequest(stackName, stackVersion, serviceName, propertyName);
        add(stackConfigurationRequest);
      }
  
      @Override
      public boolean matches(Object o) {
  
        if (!(o instanceof Set)) {
          return false;
        }
  
        Set set = (Set) o;
  
        if (set.size() != 1) {
          return false;
        }
  
        Object request = set.iterator().next();
  
        return request instanceof StackConfigurationRequest &&
            eq(((StackConfigurationRequest) request).getPropertyName(), stackConfigurationRequest.getPropertyName()) &&
            eq(((StackConfigurationRequest) request).getServiceName(), stackConfigurationRequest.getServiceName()) &&
            eq(((StackConfigurationRequest) request).getStackName(), stackConfigurationRequest.getStackName()) &&
            eq(((StackConfigurationRequest) request).getStackVersion(), stackConfigurationRequest.getStackVersion());
      }
  
      @Override
      public void appendTo(StringBuffer stringBuffer) {
        stringBuffer.append("StackConfigurationRequestSetMatcher(").append(stackConfigurationRequest).append(")");
      }
    }
  
    /**
     * Matcher for a StackConfigurationDependency set containing a single request.
     */
    public static class StackConfigurationDependencyRequestSetMatcher extends HashSet<StackConfigurationRequest> implements IArgumentMatcher {
  
      private final StackConfigurationDependencyRequest stackConfigurationDependencyRequest;
  
      public StackConfigurationDependencyRequestSetMatcher(String stackName, String stackVersion,
          String serviceName, String propertyName, String dependencyName) {
        stackConfigurationDependencyRequest = new StackConfigurationDependencyRequest(stackName, stackVersion, serviceName, propertyName, dependencyName);
        add(stackConfigurationDependencyRequest);
      }
  
      @Override
      public boolean matches(Object o) {
  
        if (!(o instanceof Set)) {
          return false;
        }
  
        Set set = (Set) o;
  
        if (set.size() != 1) {
          return false;
        }
  
        Object request = set.iterator().next();
  
        return request instanceof StackConfigurationRequest &&
            eq(((StackConfigurationRequest) request).getPropertyName(), stackConfigurationDependencyRequest.getPropertyName()) &&
            eq(((StackConfigurationRequest) request).getServiceName(), stackConfigurationDependencyRequest.getServiceName()) &&
            eq(((StackConfigurationRequest) request).getStackName(), stackConfigurationDependencyRequest.getStackName()) &&
            eq(((StackConfigurationRequest) request).getStackVersion(), stackConfigurationDependencyRequest.getStackVersion());
      }
  
      @Override
      public void appendTo(StringBuffer stringBuffer) {
        stringBuffer.append("StackConfigurationRequestSetMatcher(").append(stackConfigurationDependencyRequest).append(")");
      }
    }
  
    public static class StackLevelConfigurationRequestSetMatcher extends HashSet<StackLevelConfigurationRequest> implements IArgumentMatcher {
  
      private final StackLevelConfigurationRequest stackLevelConfigurationRequest;
  
      public StackLevelConfigurationRequestSetMatcher(String stackName, String stackVersion,
          String propertyName) {
        stackLevelConfigurationRequest = new StackLevelConfigurationRequest(stackName, stackVersion, propertyName);
        add(stackLevelConfigurationRequest);
      }
  
      @Override
      public boolean matches(Object o) {
  
        if (!(o instanceof Set)) {
          return false;
        }
  
        Set set = (Set) o;
  
        if (set.size() != 1) {
          return false;
        }
  
        Object request = set.iterator().next();
  
        return request instanceof StackLevelConfigurationRequest &&
            eq(((StackLevelConfigurationRequest) request).getPropertyName(), stackLevelConfigurationRequest.getPropertyName()) &&
            eq(((StackLevelConfigurationRequest) request).getStackName(), stackLevelConfigurationRequest.getStackName()) &&
            eq(((StackLevelConfigurationRequest) request).getStackVersion(), stackLevelConfigurationRequest.getStackVersion());
      }
  
      @Override
      public void appendTo(StringBuffer stringBuffer) {
        stringBuffer.append("StackLevelConfigurationRequestSetMatcher(").append(stackLevelConfigurationRequest).append(")");
      }
    }
  
    /**
     * A test observer that records the last event.
     */
    public static class TestObserver implements ResourceProviderObserver {
  
      ResourceProviderEvent lastEvent = null;
  
      @Override
      public void update(ResourceProviderEvent event) {
        lastEvent = event;
      }
  
      public ResourceProviderEvent getLastEvent() {
        return lastEvent;
      }
    }
  
  
    // ----- Test resource adapter ---------------------------------------------
  
    private static Resource.Type testResourceType = new Resource.Type("testResource");
  
    private static Set<String> pkPropertyIds =
      new HashSet<>(Arrays.asList(new String[]{
        "ClusterName",
        "ResourceName"}));
  
    private static Set<String> propertyIds =
      new HashSet<>(Arrays.asList(new String[]{
        "ClusterName",
        "ResourceName",
        "SomeProperty",
        "SomeOtherProperty"}));
  
    private static Map<Resource.Type, String> keyPropertyIds =
      new HashMap<>();
  
    static {
      keyPropertyIds.put(Resource.Type.Cluster, "ClusterName");
      keyPropertyIds.put(testResourceType, "ResourceName" );
    }
  
    private static Set<Resource> allResources = new HashSet<>();
  
    static {
      Resource resource = new ResourceImpl(testResourceType);
      resource.setProperty("ClusterName", "c1");
      resource.setProperty("ResourceName", "r1");
      resource.setProperty("SomeProperty", "SomeValue1");
      resource.setProperty("SomeOtherProperty", 10);
      allResources.add(resource);
  
      resource = new ResourceImpl(testResourceType);
      resource.setProperty("ClusterName", "c1");
      resource.setProperty("ResourceName", "r2");
      resource.setProperty("SomeProperty", "SomeValue2");
      resource.setProperty("SomeOtherProperty", 100);
      allResources.add(resource);
  
      resource = new ResourceImpl(testResourceType);
      resource.setProperty("ClusterName", "c1");
      resource.setProperty("ResourceName", "r3");
      resource.setProperty("SomeProperty", "SomeValue3");
      resource.setProperty("SomeOtherProperty", 1000);
      allResources.add(resource);
  
      resource = new ResourceImpl(testResourceType);
      resource.setProperty("ClusterName", "c1");
      resource.setProperty("ResourceName", "r4");
      resource.setProperty("SomeProperty", "SomeValue4");
      resource.setProperty("SomeOtherProperty", 9999);
      allResources.add(resource);
    }
  
    public static class TestResourceProvider extends AbstractResourceProvider {
  
      protected TestResourceProvider() {
        super(propertyIds, AbstractResourceProviderTest.keyPropertyIds);
      }
  
      @Override
      protected Set<String> getPKPropertyIds() {
        return pkPropertyIds;
  
      }
  
      @Override
      public RequestStatus createResources(Request request)
          throws SystemException, UnsupportedPropertyException, ResourceAlreadyExistsException, NoSuchParentResourceException {
        return new RequestStatusImpl(null);
      }
  
      @Override
      public Set<Resource> getResources(Request request, Predicate predicate)
          throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
  
        Set<Resource> resources = new HashSet<>();
  
        for(Resource resource : allResources) {
          if (predicate.evaluate(resource)) {
            resources.add(new ResourceImpl(resource, request.getPropertyIds()));
          }
        }
        return resources;
      }
  
      @Override
      public RequestStatus updateResources(Request request, Predicate predicate)
          throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
        return new RequestStatusImpl(null);
      }
  
      @Override
      public RequestStatus deleteResources(Request request, Predicate predicate)
          throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
        return new RequestStatusImpl(null);
      }
    }
  }
  