mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Jean-Noël Rouvignac
02.39.2015 05d69c6f9c226c38e40ca7a105b8ea9791ff4b50
TimeBasedMatchingRuleTest.java:
Added tests for indexing
Removed code duplication
3 files added
1 files modified
703 ■■■■ changed files
opendj-server-legacy/src/test/java/org/opends/server/schema/FakeByteStringIndex.java 154 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/schema/FakeEntryIndex.java 180 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/schema/FakeIndexQueryFactory.java 126 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/schema/TimeBasedMatchingRuleTest.java 243 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/schema/FakeByteStringIndex.java
New file
@@ -0,0 +1,154 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at legal-notices/CDDLv1_0.txt.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *      Copyright 2015 ForgeRock AS
 */
package org.opends.server.schema;
import static org.mockito.Mockito.*;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.forgerock.opendj.ldap.Assertion;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.schema.MatchingRule;
import org.forgerock.opendj.ldap.schema.Schema;
import org.forgerock.opendj.ldap.spi.Indexer;
import org.forgerock.opendj.ldap.spi.IndexingOptions;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.FilterType;
class FakeByteStringIndex
{
  private MatchingRule matchingRule;
  private Indexer indexer;
  private final NavigableMap<ByteString, Set<ByteString>> index = new TreeMap<>();
  FakeByteStringIndex(String mrName) throws DecodeException
  {
    matchingRule = DirectoryServer.getMatchingRule(mrName.toLowerCase());
    IndexingOptions options = mock(IndexingOptions.class);
    indexer = matchingRule.createIndexers(options).iterator().next();
  }
  void addAll(List<ByteString> attrValues) throws DecodeException
  {
    for (ByteString attrValue : attrValues)
    {
      add(attrValue);
    }
  }
  void add(ByteString attrValue) throws DecodeException
  {
    for (ByteString key : index(attrValue))
    {
      Set<ByteString> entries = index.get(key);
      if (entries == null)
      {
        entries = new HashSet<>();
        index.put(key, entries);
      }
      entries.add(attrValue);
    }
  }
  private Collection<ByteString> index(ByteString attrValue) throws DecodeException
  {
    Collection<ByteString> keys = new TreeSet<>();
    indexer.createKeys(Schema.getDefaultSchema(), attrValue, keys);
    return keys;
  }
  public Set<ByteString> evaluateAssertionValue(ByteString assertionValue, FilterType filterType)
      throws DirectoryException, DecodeException
  {
    Assertion assertion = getAssertion(assertionValue, filterType);
    return assertion.createIndexQuery(new FakeIndexQueryFactory<ByteString>(index));
  }
  private Assertion getAssertion(ByteString assertionValue, FilterType filterType) throws DecodeException
  {
    switch (filterType)
    {
    case EQUALITY:
    case EXTENSIBLE_MATCH:
      return matchingRule.getAssertion(assertionValue);
    case LESS_OR_EQUAL:
      return matchingRule.getLessOrEqualAssertion(assertionValue);
    case GREATER_OR_EQUAL:
      return matchingRule.getGreaterOrEqualAssertion(assertionValue);
    default:
      throw new RuntimeException("Not implemented for filter type " + filterType);
    }
  }
  @Override
  public String toString()
  {
    StringBuilder sb = new StringBuilder();
    for (Map.Entry<ByteString, Set<ByteString>> mapEntry : index.entrySet())
    {
      String key = mapEntry.getKey().toHexString();
      Set<ByteString> value = mapEntry.getValue();
      Iterator<ByteString> it = value.iterator();
      if (!it.hasNext())
      {
        continue;
      }
      sb.append(key).append("\t").append(firstLine(it.next())).append("\n");
      while (it.hasNext())
      {
        sb.append(emptyString(key.length())).append("\t").append(firstLine(it.next())).append("\n");
      }
    }
    return sb.toString();
  }
  private String firstLine(ByteString attrValue)
  {
    return attrValue.toString().split("\\n")[0] + " ...";
  }
  private String emptyString(int length)
  {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < length; i++)
    {
      sb.append(" ");
    }
    return sb.toString();
  }
}
opendj-server-legacy/src/test/java/org/opends/server/schema/FakeEntryIndex.java
New file
@@ -0,0 +1,180 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at legal-notices/CDDLv1_0.txt.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *      Copyright 2015 ForgeRock AS
 */
package org.opends.server.schema;
import static org.mockito.Mockito.*;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.forgerock.opendj.ldap.Assertion;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DecodeException;
import org.forgerock.opendj.ldap.schema.MatchingRule;
import org.forgerock.opendj.ldap.schema.Schema;
import org.forgerock.opendj.ldap.spi.Indexer;
import org.forgerock.opendj.ldap.spi.IndexingOptions;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
import org.opends.server.types.SearchFilter;
class FakeEntryIndex
{
  private AttributeType attrType;
  private MatchingRule matchingRule;
  private Indexer indexer;
  private final NavigableMap<ByteString, Set<Entry>> index = new TreeMap<>();
  FakeEntryIndex(String attrName) throws DecodeException
  {
    attrType = DirectoryServer.getAttributeTypeOrNull(attrName);
    if (attrType == null)
    {
      throw new IllegalArgumentException("Cannot find attribute with name \"" + attrName + "\"");
    }
    matchingRule = attrType.getEqualityMatchingRule();
    IndexingOptions options = mock(IndexingOptions.class);
    indexer = matchingRule.createIndexers(options).iterator().next();
  }
  void addAll(List<Entry> entries) throws DecodeException
  {
    for (Entry entry : entries)
    {
      add(entry);
    }
  }
  void add(Entry entry) throws DecodeException
  {
    Attribute attribute = entry.getExactAttribute(attrType, Collections.<String>emptySet());
    for (ByteString key : index(attribute))
    {
      Set<Entry> entries = index.get(key);
      if (entries == null)
      {
        entries = new HashSet<>();
        index.put(key, entries);
      }
      entries.add(entry);
    }
  }
  private Collection<ByteString> index(Attribute attribute) throws DecodeException
  {
    if (attribute == null)
    {
      return Collections.emptySet();
    }
    Collection<ByteString> keys = new TreeSet<>();
    for (ByteString attrValue : attribute)
    {
      indexer.createKeys(Schema.getDefaultSchema(), attrValue, keys);
    }
    return keys;
  }
  public Set<Entry> evaluateFilter(String filterString) throws DirectoryException, DecodeException
  {
    SearchFilter filter = SearchFilter.createFilterFromString(filterString);
    if (!attrType.equals(filter.getAttributeType()))
    {
      throw new IllegalArgumentException("The search filter \"" + filterString
          + "\" should target the same attribute type as this index \"" + attrType.getNameOrOID() + "\"");
    }
    Assertion assertion = getAssertion(filter);
    return assertion.createIndexQuery(new FakeIndexQueryFactory<Entry>(index));
  }
  private Assertion getAssertion(SearchFilter filter) throws DecodeException
  {
    switch (filter.getFilterType())
    {
    case EQUALITY:
      return matchingRule.getAssertion(filter.getAssertionValue());
    case LESS_OR_EQUAL:
      return matchingRule.getLessOrEqualAssertion(filter.getAssertionValue());
    case GREATER_OR_EQUAL:
      return matchingRule.getGreaterOrEqualAssertion(filter.getAssertionValue());
    case EXTENSIBLE_MATCH:
      MatchingRule rule = DirectoryServer.getMatchingRule(filter.getMatchingRuleID());
      return rule.getAssertion(filter.getAssertionValue());
    default:
      throw new RuntimeException("Not implemented for search filter type " + filter.getFilterType());
    }
  }
  @Override
  public String toString()
  {
    StringBuilder sb = new StringBuilder();
    for (Map.Entry<ByteString, Set<Entry>> mapEntry : index.entrySet())
    {
      String key = mapEntry.getKey().toHexString();
      Set<Entry> value = mapEntry.getValue();
      Iterator<Entry> it = value.iterator();
      if (!it.hasNext())
      {
        continue;
      }
      sb.append(key).append("\t").append(firstLine(it.next())).append("\n");
      while (it.hasNext())
      {
        sb.append(emptyString(key.length())).append("\t").append(firstLine(it.next())).append("\n");
      }
    }
    return sb.toString();
  }
  private String firstLine(Entry entry)
  {
    return entry.toString().split("\\n")[0] + " ...";
  }
  private String emptyString(int length)
  {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < length; i++)
    {
      sb.append(" ");
    }
    return sb.toString();
  }
}
opendj-server-legacy/src/test/java/org/opends/server/schema/FakeIndexQueryFactory.java
New file
@@ -0,0 +1,126 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at legal-notices/CDDLv1_0.txt.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *      Copyright 2015 ForgeRock AS
 */
package org.opends.server.schema;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.NavigableMap;
import java.util.Set;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.spi.IndexQueryFactory;
import org.forgerock.opendj.ldap.spi.IndexingOptions;
/**
 * {@link IndexQueryFactory} implementation which evaluates queries instead of creating them.
 * The queries are evaluated against a provided {@code NavigableMap<ByteString, Set>} (SetMultimap)
 * which acts as an index.
 *
 * @param <T> type of the values
 */
final class FakeIndexQueryFactory<T> implements IndexQueryFactory<Set<T>>
{
  private final NavigableMap<ByteString, Set<T>> index;
  FakeIndexQueryFactory(NavigableMap<ByteString, Set<T>> index)
  {
    this.index = index;
  }
  @Override
  public Set<T> createExactMatchQuery(String indexID, ByteSequence key)
  {
    Set<T> results = index.get(key);
    return results != null ? new HashSet<>(results) : Collections.<T> emptySet();
  }
  @Override
  public Set<T> createMatchAllQuery()
  {
    return flatten(index.values());
  }
  @Override
  public Set<T> createRangeMatchQuery(String indexID, ByteSequence lower, ByteSequence upper,
      boolean lowerIncluded, boolean upperIncluded)
  {
    NavigableMap<ByteString, Set<T>> map = index;
    if (lower.length() > 0)
    {
      map = map.tailMap(lower.toByteString(), lowerIncluded);
    }
    if (upper.length() > 0)
    {
      map = map.headMap(upper.toByteString(), upperIncluded);
    }
    return flatten(map.values());
  }
  private Set<T> flatten(Collection<? extends Collection<T>> values)
  {
    Set<T> results = new HashSet<>();
    for (Collection<T> entries : values)
    {
      results.addAll(entries);
    }
    return results;
  }
  @Override
  public Set<T> createIntersectionQuery(Collection<Set<T>> subResults)
  {
    Iterator<Set<T>> it = subResults.iterator();
    if (!it.hasNext())
    {
      return Collections.emptySet();
    }
    Set<T> results = new HashSet<>(it.next());
    while (it.hasNext())
    {
      results.retainAll(it.next());
    }
    return results;
  }
  @Override
  public Set<T> createUnionQuery(Collection<Set<T>> subResults)
  {
    Set<T> results = new HashSet<>();
    for (Collection<T> entries : subResults)
    {
      results.addAll(entries);
    }
    return results;
  }
  @Override
  public IndexingOptions getIndexingOptions()
  {
    return null;
  }
}
opendj-server-legacy/src/test/java/org/opends/server/schema/TimeBasedMatchingRuleTest.java
@@ -26,34 +26,41 @@
 */
package org.opends.server.schema;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Set;
import java.util.TimeZone;
import org.assertj.core.api.Assertions;
import org.forgerock.opendj.ldap.*;
import org.forgerock.opendj.ldap.schema.MatchingRule;
import org.opends.server.TestCaseUtils;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.internal.SearchRequest;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.DN;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.Entry;
import org.opends.server.types.FilterType;
import org.opends.server.types.SearchFilter;
import org.opends.server.util.TimeThread;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.assertj.core.api.Assertions.*;
import static org.opends.server.protocols.internal.InternalClientConnection.*;
import static org.opends.server.protocols.internal.Requests.*;
import static org.opends.server.schema.GeneralizedTimeSyntax.*;
import static org.opends.server.schema.SchemaConstants.*;
import static org.testng.Assert.*;
/**
 * This class tests various time-based matching rules.
 */
/** This class tests various time-based matching rules. */
@SuppressWarnings("javadoc")
public final class TimeBasedMatchingRuleTest
        extends SchemaTestCase
@@ -112,24 +119,33 @@
    assertEquals(0, resultCode);
  }
  @DataProvider
  public Object[][] relativeTime()
  {
    return new Object[][] {
      // relativeTime less than expired events
      { TIME_ATTR + ":" + EXT_OMR_RELATIVE_TIME_LT_OID + ":=-60m", new DN[] { user1, user2, } },
      // relativeTime less than future events
      { TIME_ATTR + ":" + EXT_OMR_RELATIVE_TIME_LT_OID + ":=1d", new DN[] { user1, user2, user3, user5, } },
      // relativeTime greater than expired events
      { TIME_ATTR + ":" + EXT_OMR_RELATIVE_TIME_GT_OID + ":=-1h", new DN[] { user3, user4, user5, } },
      // relativeTime greater than future events
      { TIME_ATTR + ":" + EXT_OMR_RELATIVE_TIME_GT_OID + ":=0s", new DN[] { user3, user4, } },
    };
  }
  /**
   * Test to search using the less-than relative time matching rule for expired events.
   */
  @Test
  public void testRTLessThanExpiredEvents() throws Exception
  /** Test to search using the relative time matching rule. */
  @Test(dataProvider = "relativeTime")
  public void testRelativeTimeUsingSearch(String filterString, DN[] expectedDNs) throws Exception
  {
    try
    {
      populateEntries();
      String filter = TIME_ATTR + ":" + EXT_OMR_RELATIVE_TIME_LT_OID + ":=-60m";
      SearchRequest request = newSearchRequest("dc=example,dc=com", SearchScope.WHOLE_SUBTREE, filter);
      SearchRequest request = newSearchRequest("dc=example,dc=com", SearchScope.WHOLE_SUBTREE, filterString);
      InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
      assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
      List<SearchResultEntry> entries = searchOperation.getSearchEntries();
      assertTrue(dnFoundInEntryList(entries,user1,user2));
      assertThat(toNames(searchOperation.getSearchEntries())).containsOnly(expectedDNs);
    }
    finally
    {
@@ -137,84 +153,45 @@
    }
  }
  /**
   * Test to search using the less-than relative time matching rule for future events.
   */
  @Test
  public void testRTLessThanFutureEvents() throws Exception
  @Test(dataProvider = "relativeTime")
  public void testRelativeTimeUsingAssertion(String filterString, DN[] expectedDNs) throws Exception
  {
    try
    {
      populateEntries();
      String filter = TIME_ATTR + ":" + EXT_OMR_RELATIVE_TIME_LT_OID + ":=1d";
      SearchRequest request = newSearchRequest("dc=example,dc=com", SearchScope.WHOLE_SUBTREE, filter);
      InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
      assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
      List<SearchResultEntry> entries = searchOperation.getSearchEntries();
      assertTrue(entries.size() == 4 && dnFoundInEntryList(entries,user1,user2,user3,user5));
    }
    finally
    {
      TestCaseUtils.clearJEBackend("userRoot");
    }
    SearchFilter filter = SearchFilter.createFilterFromString(filterString);
    assertThat(getMatchingEntryDNs(filter)).containsOnly(expectedDNs);
  }
  /**
   * Test to search using the greater-than relative time matching rule for expired events.
   */
  @Test
  public void testRTGreaterThanExpiredEvents() throws Exception
  private Collection<DN> getMatchingEntryDNs(SearchFilter filter) throws Exception
  {
    try
    {
      populateEntries();
    AttributeType attrType = filter.getAttributeType();
    MatchingRule rule = DirectoryServer.getMatchingRule(filter.getMatchingRuleID());
    Assertion assertion = rule.getAssertion(filter.getAssertionValue());
      String filter = TIME_ATTR + ":" + EXT_OMR_RELATIVE_TIME_GT_OID + ":=-1h";
      SearchRequest request = newSearchRequest("dc=example,dc=com", SearchScope.WHOLE_SUBTREE, filter);
      InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
      assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
      List<SearchResultEntry> entries = searchOperation.getSearchEntries();
      Assertions.assertThat(entries).hasSize(3);
      assertTrue(dnFoundInEntryList(entries, user3, user4, user5));
    }
    finally
    Collection<DN> results = new ArrayList<>();
    for (Entry entry : makeEntries())
    {
      TestCaseUtils.clearJEBackend("userRoot");
      Attribute attribute = entry.getExactAttribute(attrType, Collections.<String> emptySet());
      if (attribute != null)
      {
        ByteString attrValue = rule.normalizeAttributeValue(attribute.iterator().next());
        if (assertion.matches(attrValue).toBoolean())
        {
          results.add(entry.getName());
        }
      }
    }
    return results;
  }
    /**
   * Test to search using the greater-than relative time matching rule for future events.
   */
  @Test
  public void testRTGreaterThanFutureEvents() throws Exception
  /** Test to search using the relative time matching rule with index. */
  @Test(dataProvider = "relativeTime")
  public void testRelativeTimeWithIndex(String filterString, DN[] expectedDNs) throws Exception
  {
    try
    {
      populateEntries();
      String filter = TIME_ATTR + ":" + EXT_OMR_RELATIVE_TIME_GT_OID + ":=0s";
      SearchRequest request = newSearchRequest("dc=example,dc=com", SearchScope.WHOLE_SUBTREE, filter);
      InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
      assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
      List<SearchResultEntry> entries = searchOperation.getSearchEntries();
      assertTrue(entries.size()==2 && dnFoundInEntryList(entries,user3,user4));
    }
    finally
    {
      TestCaseUtils.clearJEBackend("userRoot");
    }
    FakeEntryIndex index = new FakeEntryIndex(TIME_ATTR);
    index.addAll(makeEntries());
    Collection<Entry> entries = index.evaluateFilter(filterString);
    assertThat(toNames(entries)).containsOnly(expectedDNs);
  }
   /**
    * Test to search using the partial date and time matching rule
    * for an assertion value.
@@ -233,8 +210,7 @@
      SearchRequest request = newSearchRequest("dc=example,dc=com", SearchScope.WHOLE_SUBTREE, filter);
      InternalSearchOperation searchOperation = getRootConnection().processSearch(request);
      assertEquals(searchOperation.getResultCode(), ResultCode.SUCCESS);
      List<SearchResultEntry> entries = searchOperation.getSearchEntries();
      assertTrue(entries.size()==1 && dnFoundInEntryList(entries,user6));
      assertThat(toNames(searchOperation.getSearchEntries())).containsOnly(user6);
    }
    finally
    {
@@ -242,25 +218,46 @@
    }
  }
  private List<DN> toNames(Collection<? extends Entry> entries)
  {
    List<DN> results = new ArrayList<>();
    for (Entry entry : entries)
    {
      results.add(entry.getName());
    }
    return results;
  }
  /**
   * Test to match the attribute and the assertion values using a partial date and time
   * matching rule.
   */
  @Test(dataProvider="partialDateTimeValues")
  public void testPartialDateNTimeMatch(long attributeValue,String assertionValue) throws Exception
  public void testPartialDateNTimeMatch(long timeInMillis, String generalizedTime, String assertionValue)
      throws Exception
  {
    MatchingRule partialTimeRule = DirectoryServer.getMatchingRule(
            EXT_PARTIAL_DATE_TIME_NAME.toLowerCase());
    Assertion assertion = partialTimeRule.getAssertion(ByteString.valueOfUtf8(assertionValue));
    assertEquals(assertion.matches(ByteString.valueOfLong(attributeValue)), ConditionResult.TRUE);
    assertEquals(assertion.matches(ByteString.valueOfLong(timeInMillis)), ConditionResult.TRUE);
  }
  @Test(dataProvider="partialDateTimeValues")
  public void testPartialDateNTimeMatchViaIndex(long timeInMillis, String generalizedTime, String assertionValue)
      throws Exception
  {
    ByteString attrValue = ByteString.valueOfUtf8(generalizedTime);
    ByteString assertValue = ByteString.valueOfUtf8(assertionValue);
    FakeByteStringIndex fakeIndex = new FakeByteStringIndex(EXT_PARTIAL_DATE_TIME_NAME);
    fakeIndex.add(attrValue);
    Set<ByteString> attrValues = fakeIndex.evaluateAssertionValue(assertValue, FilterType.EXTENSIBLE_MATCH);
    assertThat(attrValues).containsOnly(attrValue);
  }
  /**
   * Tests the assertion syntax of the relative time matching rules.
   */
  /** Tests the assertion syntax of the relative time matching rules. */
  @Test(dataProvider= "relativeTimeValues")
  public void testRelativeTimeMatchingRuleAssertionSyntax(String assertion,boolean isValid)
  {
@@ -281,9 +278,7 @@
  /**
   * Tests the assertion syntax of the partial date and time matching rules.
   */
  /** Tests the assertion syntax of the partial date and time matching rules. */
  @Test(dataProvider= "partialDateTimeSyntaxes")
  public void testPartialDateTimeMatchingRuleAssertionSyntax(String assertion,boolean isValid)
  {
@@ -303,9 +298,7 @@
  /**
   * Generates data for testing relative time matching rule assertion syntax.
   */
  /** Generates data for testing relative time matching rule assertion syntax. */
  @DataProvider(name="relativeTimeValues")
  private Object[][] createRelativeTimeValues()
  {
@@ -322,43 +315,42 @@
      {"12w-2d",false},
      {"1s2s",false},
      {"1d4s5d",false}
    };
  }
  /**
   * Generates the data for testing partial time date and time values.
   */
  @DataProvider(name="partialDateTimeValues")
  private Object[][] createPartialDateTimeValues()
  /** Generates the data for testing partial time date and time values. */
  @DataProvider
  private Object[][] partialDateTimeValues()
  {
    SimpleDateFormat sdf = new SimpleDateFormat("YYYYMMddHHmmssZ");
    GregorianCalendar c = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
    c.setLenient(false);
    c.clear();
    sdf.setCalendar(c);
    c.set(Calendar.HOUR_OF_DAY,23);
    c.set(Calendar.MINUTE,0);
    c.set(Calendar.SECOND,0);
    long time1 = c.getTimeInMillis();
    String format1 = sdf.format(c.getTime());
    c.set(Calendar.HOUR_OF_DAY,00);
    c.set(Calendar.MINUTE,59);
    c.set(Calendar.SECOND,59);
    long time2 = c.getTimeInMillis();
    String format2 = sdf.format(c.getTime());
    return new Object[][] {
      {time1,"0s"},
      {time1,"0m"},
      {time1,"23h"},
      {time2,"59m59s"},
      {time2,"0h59m59s"}
      { time1, format1, "0s" },
      { time1, format1, "0m" },
      { time1, format1, "23h" },
      { time2, format2, "59m59s" },
      { time2, format2, "0h59m59s" }
    };
  }
  /**
   * Generates data for testing partial date and time assertion syntax.
   */
  /** Generates data for testing partial date and time assertion syntax. */
  @DataProvider(name="partialDateTimeSyntaxes")
  private Object[][] createPartialDateTimeSyntaxes()
  {
@@ -407,37 +399,20 @@
    };
  }
  /** Validate if the args are found in the entries list. */
  private boolean dnFoundInEntryList(List<SearchResultEntry> entries, DN... dns)
  {
    for (DN dn : dns)
    {
      assertTrue(find(entries, dn), "Could not find dn " + dn + " in list " + entries);
    }
    return true;
  }
  private boolean find(List<SearchResultEntry> entries, DN dn)
  {
    for (SearchResultEntry entry : entries)
    {
      if (entry.getName().equals(dn))
      {
        return true;
      }
    }
    return false;
  }
  /** Creates the entries. */
  private void populateEntries() throws Exception
  {
    //Get the current time from the TimeThread. Using the current time from new
    TestCaseUtils.clearJEBackend("userRoot", "dc=example,dc=com");
    TestCaseUtils.addEntries(makeEntries());
  }
  private List<Entry> makeEntries() throws Exception
  {
    // Get the current time from the TimeThread. Using the current time from new
    // calendar may fail if the time thread using a stale time.
    long currentTime = TimeThread.getTime();
    TestCaseUtils.clearJEBackend("userRoot", "dc=example,dc=com");
    TestCaseUtils.addEntries(
    return TestCaseUtils.makeEntries(
      "dn: cn=user1,dc=example,dc=com",
      "objectclass: person",
      "objectclass: testoc",
@@ -495,4 +470,4 @@
      DATE_ATTR + ": 20000101000000Z" // Jan 1st 2000
    );
  }
  }
}