From f87a5f98513faa30d38f5106bbcbd3ac8bbf7214 Mon Sep 17 00:00:00 2001
From: Vikas Saurabh <vsaurabh@adobe.com>
Date: Thu, 11 Dec 2014 02:09:37 +0530
Subject: [PATCH 3/4] OAK-2341 Add test case for ContentMirrorStoreStrategy.
 Ignoring path filter optimization for now

---
 .../strategy/ContentMirrorStoreStrategyTest.java   | 120 +++++++++++++++++++++
 1 file changed, 120 insertions(+)

diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategyTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategyTest.java
index d0c759e..53bdb65 100755
--- a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategyTest.java
+++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategyTest.java
@@ -18,17 +18,26 @@ package org.apache.jackrabbit.oak.plugins.index.property.strategy;
 
 import static com.google.common.collect.Sets.newHashSet;
 import static java.util.Arrays.asList;
+import static org.apache.jackrabbit.oak.plugins.index.counter.NodeCounterEditor.DEFAULT_RESOLUTION;
+import static org.apache.jackrabbit.oak.plugins.index.counter.NodeCounterEditor.COUNT_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.ENTRY_COUNT_PROPERTY_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.KEY_COUNT_PROPERTY_NAME;
 import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_CONTENT_NODE_NAME;
 import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.apache.jackrabbit.oak.util.ApproximateCounter.COUNT_PROPERTY_PREFIX;
 
 import java.util.Collections;
 import java.util.Set;
 
 import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.query.index.FilterImpl;
+import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.junit.Assert;
+import org.junit.Ignore;
 import org.junit.Test;
 
 /**
@@ -140,4 +149,115 @@ public class ContentMirrorStoreStrategyTest {
                 store.count(root, indexMeta.getNodeState(), Collections.singleton("key"), 2) > 1);
     }
 
+    @Test
+    public void testIndexCountersUsageWithoutPathRestriction() {
+        final long APPROX_NODE_COUNT = 50;
+        final long APPROX_KEY_COUNT = 25;
+        final long ENTRY_COUNT = 30 * DEFAULT_RESOLUTION;
+        final long KEY_COUNT = 75;
+        final int MAX_TRAVERSALS = 200;
+        final String KEY_VALUE = KEY.iterator().next();
+        final String APPROX_PROP_NAME = COUNT_PROPERTY_PREFIX + "gen_uuid";
+
+        IndexStoreStrategy store = new ContentMirrorStoreStrategy();
+        NodeState root = EMPTY_NODE;
+        NodeBuilder indexMeta = root.builder();
+        NodeBuilder index = indexMeta.child(INDEX_CONTENT_NODE_NAME);
+        NodeBuilder key = index.child(KEY_VALUE);
+
+        //is-not-null query without entryCount
+        index.setProperty(APPROX_PROP_NAME, APPROX_NODE_COUNT, Type.LONG);
+        Assert.assertEquals("Approximate count not used for is-not-null query", APPROX_NODE_COUNT,
+                store.count(root, indexMeta.getNodeState(), null, MAX_TRAVERSALS));
+
+        //prop=value query without entryCount
+        key.setProperty(APPROX_PROP_NAME, APPROX_KEY_COUNT, Type.LONG);
+        Assert.assertEquals("Approximate count not used for key=value query", APPROX_KEY_COUNT,
+                store.count(root, indexMeta.getNodeState(), KEY, MAX_TRAVERSALS));
+
+        //is-not-null query with entryCount
+        indexMeta.setProperty(ENTRY_COUNT_PROPERTY_NAME, ENTRY_COUNT, Type.LONG);
+        Assert.assertEquals("Entry count not used even when present for is-not-null query", ENTRY_COUNT,
+                store.count(root, indexMeta.getNodeState(), null, MAX_TRAVERSALS));
+
+        //prop=value query with entryCount but without keyCount
+        Assert.assertTrue("Rough key count not considered for key=value query",
+                ENTRY_COUNT > store.count(root, indexMeta.getNodeState(), KEY, MAX_TRAVERSALS));
+
+        //prop=value query with entryCount and keyCount
+        indexMeta.setProperty(KEY_COUNT_PROPERTY_NAME, KEY_COUNT, Type.LONG);
+        Assert.assertTrue("Key count not considered for key=value query",
+                ENTRY_COUNT > store.count(root, indexMeta.getNodeState(), KEY, MAX_TRAVERSALS));
+
+        //is-not-null query with entryCount=-1 (this should lead to traversal and hence should result in '0'
+        indexMeta.setProperty(ENTRY_COUNT_PROPERTY_NAME, (long)-1, Type.LONG);
+        Assert.assertEquals("Entry count not used even when present for is-not-null query", 0,
+                store.count(root, indexMeta.getNodeState(), null, MAX_TRAVERSALS));
+    }
+
+    @Ignore("OAK-2341")
+    @Test
+    public void testIndexCountersUsageWithPathRestriction() {
+        final String SUB_PATH_NAME = "sub-path";
+        final int FILTERED_NODE_FACTOR = 2;
+        final long REPO_TREE_APPROX_NODE_COUNT = 50000;
+        final long REPO_SUB_PATH_APPROX_NODE_COUNT = REPO_TREE_APPROX_NODE_COUNT / FILTERED_NODE_FACTOR;
+        final FilterImpl FILTER = new FilterImpl();
+        FILTER.restrictPath("/" + SUB_PATH_NAME, Filter.PathRestriction.ALL_CHILDREN);
+
+        final long APPROX_NODE_COUNT = 100;
+        final long APPROX_KEY_COUNT = 50;
+        final long ENTRY_COUNT = 60 * DEFAULT_RESOLUTION;
+        final long KEY_COUNT = 150;
+        final int MAX_TRAVERSALS = 200;
+        final String KEY_VALUE = KEY.iterator().next();
+        final String APPROX_PROP_NAME = COUNT_PROPERTY_PREFIX + "gen_uuid";
+
+        IndexStoreStrategy store = new ContentMirrorStoreStrategy();
+        NodeBuilder rootBuilder = EMPTY_NODE.builder();
+
+        //setup tree for NodeCounter to work
+        {
+            rootBuilder.setProperty(COUNT_PROPERTY_NAME, REPO_TREE_APPROX_NODE_COUNT, Type.LONG);
+            NodeBuilder subPath = rootBuilder.child(SUB_PATH_NAME);
+            subPath.setProperty(COUNT_PROPERTY_NAME, REPO_SUB_PATH_APPROX_NODE_COUNT, Type.LONG);
+        }
+        NodeState root = rootBuilder.getNodeState();
+
+        NodeBuilder indexMeta = rootBuilder.child("propIndex");
+        NodeBuilder index = indexMeta.child(INDEX_CONTENT_NODE_NAME);
+        NodeBuilder key = index.child(KEY_VALUE);
+
+        //is-not-null query without entryCount
+        index.setProperty(APPROX_PROP_NAME, APPROX_NODE_COUNT, Type.LONG);
+        assertInRange("Approximate count not used for is-not-null query", APPROX_NODE_COUNT,
+                FILTERED_NODE_FACTOR * store.count(FILTER, root, indexMeta.getNodeState(), null, MAX_TRAVERSALS));
+
+        //prop=value query without entryCount
+        key.setProperty(APPROX_PROP_NAME, APPROX_KEY_COUNT, Type.LONG);
+        assertInRange("Approximate count not used for key=value query", APPROX_KEY_COUNT,
+                FILTERED_NODE_FACTOR * store.count(FILTER, root, indexMeta.getNodeState(), KEY, MAX_TRAVERSALS));
+
+        //is-not-null query with entryCount
+        indexMeta.setProperty(ENTRY_COUNT_PROPERTY_NAME, ENTRY_COUNT, Type.LONG);
+        assertInRange("Entry count not used even when present for is-not-null query", ENTRY_COUNT,
+                FILTERED_NODE_FACTOR * store.count(FILTER, root, indexMeta.getNodeState(), null, MAX_TRAVERSALS));
+
+        //prop=value query with entryCount but without keyCount
+        Assert.assertTrue("Rough key count not considered for key=value query",
+                ENTRY_COUNT > FILTERED_NODE_FACTOR * store.count(FILTER, root, indexMeta.getNodeState(), KEY, MAX_TRAVERSALS));
+
+        //prop=value query with entryCount and keyCount
+        indexMeta.setProperty(KEY_COUNT_PROPERTY_NAME, KEY_COUNT, Type.LONG);
+        Assert.assertTrue("Key count not considered for key=value query",
+                ENTRY_COUNT > FILTERED_NODE_FACTOR * store.count(FILTER, root, indexMeta.getNodeState(), KEY, MAX_TRAVERSALS));
+    }
+
+    private void assertInRange(String msg, double expected, double actual)
+    {
+        final double ALLOWED_ERROR = 0.1;
+
+        double diff = Math.abs(expected - actual);
+        Assert.assertTrue(msg, diff < expected * ALLOWED_ERROR);
+    }
 }
-- 
2.1.1

