From 05d69c6f9c226c38e40ca7a105b8ea9791ff4b50 Mon Sep 17 00:00:00 2001
From: Jean-Noël Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Thu, 05 Nov 2015 12:25:29 +0000
Subject: [PATCH] TimeBasedMatchingRuleTest.java: Added tests for indexing Removed code duplication

---
 opendj-server-legacy/src/test/java/org/opends/server/schema/FakeByteStringIndex.java       |  154 ++++++++++++
 opendj-server-legacy/src/test/java/org/opends/server/schema/FakeIndexQueryFactory.java     |  126 ++++++++++
 opendj-server-legacy/src/test/java/org/opends/server/schema/FakeEntryIndex.java            |  180 +++++++++++++++
 opendj-server-legacy/src/test/java/org/opends/server/schema/TimeBasedMatchingRuleTest.java |  243 +++++++++-----------
 4 files changed, 569 insertions(+), 134 deletions(-)

diff --git a/opendj-server-legacy/src/test/java/org/opends/server/schema/FakeByteStringIndex.java b/opendj-server-legacy/src/test/java/org/opends/server/schema/FakeByteStringIndex.java
new file mode 100644
index 0000000..bd96d0d
--- /dev/null
+++ b/opendj-server-legacy/src/test/java/org/opends/server/schema/FakeByteStringIndex.java
@@ -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();
+  }
+}
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/schema/FakeEntryIndex.java b/opendj-server-legacy/src/test/java/org/opends/server/schema/FakeEntryIndex.java
new file mode 100644
index 0000000..f4e8d0a
--- /dev/null
+++ b/opendj-server-legacy/src/test/java/org/opends/server/schema/FakeEntryIndex.java
@@ -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();
+  }
+}
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/schema/FakeIndexQueryFactory.java b/opendj-server-legacy/src/test/java/org/opends/server/schema/FakeIndexQueryFactory.java
new file mode 100644
index 0000000..1c86fd5
--- /dev/null
+++ b/opendj-server-legacy/src/test/java/org/opends/server/schema/FakeIndexQueryFactory.java
@@ -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;
+  }
+}
\ No newline at end of file
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/schema/TimeBasedMatchingRuleTest.java b/opendj-server-legacy/src/test/java/org/opends/server/schema/TimeBasedMatchingRuleTest.java
index 71a2830..a18c815 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/schema/TimeBasedMatchingRuleTest.java
+++ b/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
     );
   }
-  }
+}

--
Gitblit v1.10.0