You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by to...@apache.org on 2018/09/25 12:24:18 UTC
svn commit: r1841926 [10/14] - in /jackrabbit/oak/trunk:
oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/
oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/benchmark/util/
oak-benchmarks/src/main/java/org/apache/jackrabbit/oak/sca...
Added: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor2Test.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor2Test.java?rev=1841926&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor2Test.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor2Test.java Tue Sep 25 12:24:15 2018
@@ -0,0 +1,353 @@
+/*
+ * 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.jackrabbit.oak.plugins.index.lucene;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.index.IndexCommitCallback;
+import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.IndexUpdateCallback;
+import org.apache.jackrabbit.oak.plugins.index.IndexUpdateProvider;
+import org.apache.jackrabbit.oak.plugins.index.IndexingContext;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexEditor;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexEditorContext;
+import org.apache.jackrabbit.oak.plugins.index.lucene.TestUtil;
+import org.apache.jackrabbit.oak.plugins.index.lucene.util.IndexDefinitionBuilder;
+import org.apache.jackrabbit.oak.plugins.index.lucene.writer.LuceneIndexWriter;
+import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
+import org.apache.jackrabbit.oak.plugins.index.search.PropertyDefinition;
+import org.apache.jackrabbit.oak.plugins.index.search.PropertyUpdateCallback;
+import org.apache.jackrabbit.oak.plugins.index.search.spi.editor.FulltextIndexWriterFactory;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
+import org.apache.jackrabbit.oak.spi.commit.EditorHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.lucene.index.IndexableField;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Test;
+
+import static org.apache.jackrabbit.oak.InitialContentHelper.INITIAL_CONTENT;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.TYPE_LUCENE;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+
+public class LuceneIndexEditor2Test {
+
+ private NodeState root = INITIAL_CONTENT;
+ private NodeState before = root;
+ private IndexUpdateCallback updateCallback = mock(IndexUpdateCallback.class);
+ private ExtractedTextCache extractedTextCache = new ExtractedTextCache(0, 0);
+ private TestIndexingContext indexingContext = new TestIndexingContext();
+ private TestWriterFactory writerFactory = new TestWriterFactory();
+ private TestPropertyUpdateCallback propCallback = new TestPropertyUpdateCallback();
+ private TestWriter writer = new TestWriter();
+ private String indexPath = "/oak:index/fooIndex";
+
+ @Test
+ public void basics() throws Exception{
+ IndexDefinitionBuilder defnb = new IndexDefinitionBuilder();
+ defnb.indexRule("nt:base").property("foo").propertyIndex();
+
+ NodeState defnState = defnb.build();
+ IndexDefinition defn = new IndexDefinition(root, defnState, indexPath);
+ LuceneIndexEditorContext ctx = newContext(defnState.builder(), defn, true);
+ EditorHook hook = createHook(ctx);
+
+ updateBefore(defnb);
+ NodeBuilder builder = before.builder();
+ builder.child("a").setProperty("foo", "bar");
+
+ hook.processCommit(root, builder.getNodeState(), CommitInfo.EMPTY);
+
+ assertThat(writer.docs.keySet(), containsInAnyOrder("/a"));
+ }
+
+ @Test
+ public void simplePropertyUpdateCallback() throws Exception{
+ IndexDefinitionBuilder defnb = new IndexDefinitionBuilder();
+ defnb.indexRule("nt:base").property("foo").propertyIndex();
+
+ NodeState defnState = defnb.build();
+ IndexDefinition defn = new IndexDefinition(root, defnState, indexPath);
+ LuceneIndexEditorContext ctx = newContext(defnState.builder(), defn, true);
+ ctx.setPropertyUpdateCallback(propCallback);
+
+ EditorHook hook = createHook(ctx);
+
+ updateBefore(defnb);
+
+ //Property added
+ NodeBuilder builder = before.builder();
+ builder.child("a").setProperty("foo", "bar");
+ builder.child("a").setProperty("foo2", "bar");
+ builder.child("a").child("b");
+
+ before = hook.processCommit(root, builder.getNodeState(), CommitInfo.EMPTY);
+ propCallback.state.assertState("/a", "foo", UpdateState.ADDED);
+ assertEquals(1, propCallback.invocationCount);
+ assertEquals(1, propCallback.doneInvocationCount);
+ propCallback.reset();
+
+ //Property updated
+ builder = before.builder();
+ builder.child("a").setProperty("foo", "bar2");
+ builder.child("a").setProperty("foo2", "bar2");
+ before = hook.processCommit(before, builder.getNodeState(), CommitInfo.EMPTY);
+
+ propCallback.state.assertState("/a", "foo", UpdateState.UPDATED);
+
+ assertEquals(1, propCallback.invocationCount);
+ propCallback.reset();
+
+ //Property deleted
+ builder = before.builder();
+ builder.child("a").removeProperty("foo");
+ builder.child("a").removeProperty("foo2");
+ before = hook.processCommit(before, builder.getNodeState(), CommitInfo.EMPTY);
+
+ propCallback.state.assertState("/a", "foo", UpdateState.DELETED);
+ assertEquals(1, propCallback.invocationCount);
+ propCallback.reset();
+ }
+
+ @Test
+ public void relativeProperties() throws Exception{
+ IndexDefinitionBuilder defnb = new IndexDefinitionBuilder();
+ defnb.indexRule("nt:base").property("jcr:content/metadata/foo").propertyIndex();
+ defnb.aggregateRule("nt:base").include("*");
+
+ NodeState defnState = defnb.build();
+ IndexDefinition defn = new IndexDefinition(root, defnState, indexPath);
+ LuceneIndexEditorContext ctx = newContext(defnState.builder(), defn, true);
+ ctx.setPropertyUpdateCallback(propCallback);
+
+ EditorHook hook = createHook(ctx);
+
+ updateBefore(defnb);
+
+ //Property added
+ NodeBuilder builder = before.builder();
+ builder.child("a").child("jcr:content").child("metadata").setProperty("foo", "bar");
+ builder.child("a").setProperty("foo2", "bar");
+
+ before = hook.processCommit(root, builder.getNodeState(), CommitInfo.EMPTY);
+ propCallback.state.assertState("/a", "jcr:content/metadata/foo", UpdateState.ADDED);
+ assertEquals(1, propCallback.invocationCount);
+ propCallback.reset();
+
+ //Property updated
+ builder = before.builder();
+ builder.child("a").child("jcr:content").child("metadata").setProperty("foo", "bar2");
+ builder.child("a").setProperty("foo2", "bar2");
+ before = hook.processCommit(before, builder.getNodeState(), CommitInfo.EMPTY);
+
+ propCallback.state.assertState("/a", "jcr:content/metadata/foo", UpdateState.UPDATED);
+
+ assertEquals(1, propCallback.invocationCount);
+ propCallback.reset();
+
+ //Property deleted
+ builder = before.builder();
+ builder.child("a").child("jcr:content").child("metadata").removeProperty("foo");
+ builder.child("a").removeProperty("foo2");
+ before = hook.processCommit(before, builder.getNodeState(), CommitInfo.EMPTY);
+
+ propCallback.state.assertState("/a", "jcr:content/metadata/foo", UpdateState.DELETED);
+ assertEquals(1, propCallback.invocationCount);
+ propCallback.reset();
+ }
+
+ private void updateBefore(IndexDefinitionBuilder defnb) {
+ NodeBuilder builder = before.builder();
+ NodeBuilder cb = TestUtil.child(builder, PathUtils.getParentPath(indexPath));
+ cb.setChildNode(PathUtils.getName(indexPath), defnb.build());
+ before = builder.getNodeState();
+ }
+
+ private EditorHook createHook(LuceneIndexEditorContext context) {
+ IndexEditorProvider provider = new IndexEditorProvider() {
+ @Nullable
+ @Override
+ public Editor getIndexEditor(@NotNull String type, @NotNull NodeBuilder definition,
+ @NotNull NodeState root, @NotNull IndexUpdateCallback callback)
+ throws CommitFailedException {
+ if (TYPE_LUCENE.equals(type)) {
+ return new LuceneIndexEditor(context);
+ }
+ return null;
+ }
+ };
+
+ String async = context.isAsyncIndexing() ? "async" : null;
+ IndexUpdateProvider updateProvider = new IndexUpdateProvider(provider, async, false);
+ return new EditorHook(updateProvider);
+ }
+
+ private LuceneIndexEditorContext newContext(NodeBuilder defnBuilder, IndexDefinition defn, boolean asyncIndex) {
+ return new LuceneIndexEditorContext(root, defnBuilder, defn, updateCallback, writerFactory,
+ extractedTextCache, null, indexingContext, asyncIndex);
+ }
+
+
+ private static class TestPropertyUpdateCallback implements PropertyUpdateCallback {
+ int invocationCount;
+ CallbackState state;
+ int doneInvocationCount;
+
+ @Override
+ public void propertyUpdated(String nodePath, String propertyRelativePath, PropertyDefinition pd,
+ PropertyState before, PropertyState after) {
+ assertNotNull(nodePath);
+ assertNotNull(propertyRelativePath);
+ assertNotNull(pd);
+
+ if (before == null && after == null) {
+ fail("Both states cannot be null at same time");
+ }
+
+ state = new CallbackState(nodePath, propertyRelativePath, pd, before, after);
+ invocationCount++;
+ }
+
+ @Override
+ public void done() throws CommitFailedException {
+ doneInvocationCount++;
+ }
+
+ void reset(){
+ state = null;
+ invocationCount = 0;
+ doneInvocationCount = 0;
+ }
+ }
+
+ enum UpdateState {ADDED, UPDATED, DELETED}
+
+ private static class CallbackState {
+ final String nodePath;
+ final String propertyPath;
+ final PropertyDefinition pd;
+ final PropertyState before;
+ final PropertyState after;
+
+
+ public CallbackState(String nodePath, String propertyPath, PropertyDefinition pd,
+ PropertyState before, PropertyState after) {
+ this.nodePath = nodePath;
+ this.propertyPath = propertyPath;
+ this.pd = pd;
+ this.before = before;
+ this.after = after;
+ }
+
+ public void assertState(String expectedPath, String expectedName, UpdateState us) {
+ assertEquals(expectedPath, nodePath);
+ assertEquals(expectedName, propertyPath);
+
+ switch (us) {
+ case ADDED: assertNotNull(after); assertNull(before); break;
+ case UPDATED: assertNotNull(after); assertNotNull(before); break;
+ case DELETED: assertNull(after); assertNotNull(before); break;
+ }
+ }
+ }
+
+
+ private class TestWriterFactory implements FulltextIndexWriterFactory {
+ @Override
+ public LuceneIndexWriter newInstance(IndexDefinition definition,
+ NodeBuilder definitionBuilder, boolean reindex) {
+ return writer;
+ }
+ }
+
+ private static class TestWriter implements LuceneIndexWriter {
+ Set<String> deletedPaths = new HashSet<>();
+ Map<String, Iterable<? extends IndexableField>> docs = new HashMap<>();
+ boolean closed;
+
+ @Override
+ public void updateDocument(String path, Iterable<? extends IndexableField> doc) throws IOException {
+ docs.put(path, doc);
+ }
+
+ @Override
+ public void deleteDocuments(String path) throws IOException {
+ deletedPaths.add(path);
+ }
+
+ @Override
+ public boolean close(long timestamp) throws IOException {
+ closed = true;
+ return true;
+ }
+ }
+
+ private class TestIndexingContext implements IndexingContext {
+ CommitInfo info = CommitInfo.EMPTY;
+ boolean reindexing;
+ boolean async;
+
+ @Override
+ public String getIndexPath() {
+ return indexPath;
+ }
+
+ @Override
+ public CommitInfo getCommitInfo() {
+ return info;
+ }
+
+ @Override
+ public boolean isReindexing() {
+ return reindexing;
+ }
+
+ @Override
+ public boolean isAsync() {
+ return async;
+ }
+
+ @Override
+ public void indexUpdateFailed(Exception e) {
+
+ }
+
+ @Override
+ public void registerIndexCommitCallback(IndexCommitCallback callback) {
+
+ }
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditor2Test.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProviderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProviderTest.java?rev=1841926&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProviderTest.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProviderTest.java Tue Sep 25 12:24:15 2018
@@ -0,0 +1,194 @@
+/*
+ * 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.jackrabbit.oak.plugins.index.lucene;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.plugins.index.ContextAwareCallback;
+import org.apache.jackrabbit.oak.plugins.index.IndexCommitCallback;
+import org.apache.jackrabbit.oak.plugins.index.IndexUpdateCallback;
+import org.apache.jackrabbit.oak.plugins.index.IndexingContext;
+import org.apache.jackrabbit.oak.plugins.index.lucene.IndexTracker;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexDefinition;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexEditor;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexEditorContext;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.TestUtil;
+import org.apache.jackrabbit.oak.plugins.index.lucene.hybrid.DocumentQueue;
+import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
+import org.apache.jackrabbit.oak.spi.commit.CommitContext;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
+import org.apache.jackrabbit.oak.spi.commit.SimpleCommitContext;
+import org.apache.jackrabbit.oak.spi.mount.Mounts;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.junit.Test;
+
+import static org.apache.jackrabbit.oak.InitialContentHelper.INITIAL_CONTENT;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.TYPE_LUCENE;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexHelper.newLucenePropertyIndexDefinition;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class LuceneIndexEditorProviderTest {
+ private NodeState root = INITIAL_CONTENT;
+ private NodeBuilder builder = root.builder();
+
+ @Test
+ public void readOnlyBuilderUsedForSync() throws Exception {
+ LuceneIndexEditorProvider editorProvider = new LuceneIndexEditorProvider(null,
+ null,
+ null,
+ null,
+ Mounts.defaultMountInfoProvider());
+ editorProvider.setIndexingQueue(mock(DocumentQueue.class));
+
+ IndexUpdateCallback callback = new TestCallback("/oak:index/fooIndex", newCommitInfo(), false, false);
+ NodeBuilder defnBuilder = createIndexDefinition("fooIndex").builder();
+ Editor editor = editorProvider.getIndexEditor(TYPE_LUCENE, defnBuilder, root, callback);
+ LuceneIndexEditor luceneEditor = (LuceneIndexEditor) editor;
+
+ NodeBuilder builderFromContext =
+ (NodeBuilder) FieldUtils.readField(luceneEditor.getContext(), "definitionBuilder", true);
+
+ try {
+ builderFromContext.setProperty("foo", "bar");
+ fail("Should have been read only builder");
+ } catch (UnsupportedOperationException ignore) {
+
+ }
+ }
+
+ @Test
+ public void reuseOldIndexDefinition() throws Exception{
+ IndexTracker tracker = mock(IndexTracker.class);
+ LuceneIndexEditorProvider editorProvider = new LuceneIndexEditorProvider(null,
+ tracker,
+ null,
+ null,
+ Mounts.defaultMountInfoProvider());
+ editorProvider.setIndexingQueue(mock(DocumentQueue.class));
+ //Set up a different IndexDefinition which needs to be returned
+ //from tracker with a marker property
+ NodeBuilder testBuilder = createIndexDefinition("fooIndex").builder();
+ testBuilder.setProperty("foo", "bar");
+ LuceneIndexDefinition defn = new LuceneIndexDefinition(root, testBuilder.getNodeState(), "/foo");
+ when(tracker.getIndexDefinition("/oak:index/fooIndex")).thenReturn(defn);
+
+ IndexUpdateCallback callback = new TestCallback("/oak:index/fooIndex", newCommitInfo(), false, false);
+ NodeBuilder defnBuilder = createIndexDefinition("fooIndex").builder();
+ Editor editor = editorProvider.getIndexEditor(TYPE_LUCENE, defnBuilder, root, callback);
+ LuceneIndexEditor luceneEditor = (LuceneIndexEditor) editor;
+ LuceneIndexEditorContext context = luceneEditor.getContext();
+
+ //Definition should reflect the marker property
+ assertEquals("bar", context.getDefinition().getDefinitionNodeState().getString("foo"));
+ }
+
+ @Test
+ public void editorNullInCaseOfReindex() throws Exception{
+ LuceneIndexEditorProvider editorProvider = new LuceneIndexEditorProvider(null,
+ null,
+ null,
+ null,
+ Mounts.defaultMountInfoProvider());
+ editorProvider.setIndexingQueue(mock(DocumentQueue.class));
+ IndexUpdateCallback callback = new TestCallback("/oak:index/fooIndex", newCommitInfo(), true, false);
+ NodeBuilder defnBuilder = createIndexDefinition("fooIndex").builder();
+ Editor editor = editorProvider.getIndexEditor(TYPE_LUCENE, defnBuilder, root, callback);
+ assertNull(editor);
+ }
+
+ private NodeState createIndexDefinition(String idxName) {
+ NodeBuilder idx = newLucenePropertyIndexDefinition(builder.child("oak:index"),
+ idxName, ImmutableSet.of("foo"), "async");
+ TestUtil.enableIndexingMode(idx, FulltextIndexConstants.IndexingMode.NRT);
+ LuceneIndexEditorContext.configureUniqueId(idx);
+ LuceneIndexDefinition.updateDefinition(idx);
+ return idx.getNodeState();
+ }
+
+ private CommitInfo newCommitInfo() {
+ CommitInfo info = new CommitInfo("admin", "s1",
+ ImmutableMap.<String, Object>of(CommitContext.NAME, new SimpleCommitContext()));
+ return info;
+ }
+
+ private static class TestCallback implements IndexUpdateCallback, IndexingContext, ContextAwareCallback {
+ private final String indexPath;
+ private final CommitInfo commitInfo;
+ private final boolean reindexing;
+ private final boolean async;
+
+ private TestCallback(String indexPath, CommitInfo commitInfo, boolean reindexing, boolean async) {
+ this.indexPath = indexPath;
+ this.commitInfo = commitInfo;
+ this.reindexing = reindexing;
+ this.async = async;
+ }
+
+ @Override
+ public String getIndexPath() {
+ return indexPath;
+ }
+
+ @Override
+ public CommitInfo getCommitInfo() {
+ return commitInfo;
+ }
+
+ @Override
+ public boolean isReindexing() {
+ return reindexing;
+ }
+
+ @Override
+ public boolean isAsync() {
+ return async;
+ }
+
+ @Override
+ public void indexUpdateFailed(Exception e) {
+
+ }
+
+ @Override
+ public void indexUpdate() throws CommitFailedException {
+
+ }
+
+ @Override
+ public IndexingContext getIndexingContext() {
+ return this;
+ }
+
+ @Override
+ public void registerIndexCommitCallback(IndexCommitCallback callback) {
+
+ }
+ }
+
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorProviderTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorTest.java?rev=1841926&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorTest.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorTest.java Tue Sep 25 12:24:15 2018
@@ -0,0 +1,631 @@
+/*
+ * 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.jackrabbit.oak.plugins.index.lucene;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.commons.CIHelper;
+import org.apache.jackrabbit.oak.plugins.blob.datastore.CachingFileDataStore;
+import org.apache.jackrabbit.oak.plugins.blob.datastore.DataStoreBlobStore;
+import org.apache.jackrabbit.oak.plugins.blob.datastore.DataStoreUtils;
+import org.apache.jackrabbit.oak.plugins.index.CompositeIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.IndexEditor;
+import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.IndexUpdateCallback;
+import org.apache.jackrabbit.oak.plugins.index.IndexUpdateProvider;
+import org.apache.jackrabbit.oak.plugins.index.IndexUtils;
+import org.apache.jackrabbit.oak.plugins.index.lucene.FieldFactory;
+import org.apache.jackrabbit.oak.plugins.index.lucene.IndexCopier;
+import org.apache.jackrabbit.oak.plugins.index.lucene.IndexTracker;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexDefinition;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexNode;
+import org.apache.jackrabbit.oak.plugins.index.lucene.directory.OakDirectory;
+import org.apache.jackrabbit.oak.plugins.index.lucene.writer.MultiplexersLucene;
+import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.plugins.index.search.FieldNames;
+import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexFormatVersion;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.DefaultEditor;
+import org.apache.jackrabbit.oak.spi.commit.Editor;
+import org.apache.jackrabbit.oak.spi.commit.EditorHook;
+import org.apache.jackrabbit.oak.spi.mount.Mount;
+import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
+import org.apache.jackrabbit.oak.spi.mount.Mounts;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
+import org.apache.jackrabbit.test.ISO8601;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.queryparser.classic.ParseException;
+import org.apache.lucene.queryparser.classic.QueryParser;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.NumericRangeQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.store.Directory;
+import org.jetbrains.annotations.NotNull;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static com.google.common.collect.ImmutableSet.of;
+import static javax.jcr.PropertyType.TYPENAME_STRING;
+import static org.apache.jackrabbit.oak.InitialContentHelper.INITIAL_CONTENT;
+import static org.apache.jackrabbit.oak.api.Type.STRINGS;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.VERSION;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.TestUtil.newLuceneIndexDefinitionV2;
+import static org.apache.jackrabbit.oak.plugins.index.lucene.util.LuceneIndexHelper.newLuceneIndexDefinition;
+import static org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.INCLUDE_PROPERTY_NAMES;
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+
+@RunWith(Parameterized.class)
+public class LuceneIndexEditorTest {
+ private EditorHook HOOK;
+
+ private NodeState root = INITIAL_CONTENT;
+
+ private NodeBuilder builder = root.builder();
+
+ private IndexTracker tracker = new IndexTracker();
+
+ private LuceneIndexNode indexNode;
+
+ @Rule
+ public final TemporaryFolder temporaryFolder = new TemporaryFolder(new File("target"));
+
+ @Parameterized.Parameter
+ public boolean useBlobStore;
+
+ @Parameterized.Parameters(name = "{index}: useBlobStore ({0})")
+ public static List<Boolean[]> fixtures() {
+ return ImmutableList.of(new Boolean[] {true}, new Boolean[] {false});
+ }
+
+ @Before
+ public void setup() throws Exception {
+ if (useBlobStore) {
+ LuceneIndexEditorProvider provider = new LuceneIndexEditorProvider();
+ CachingFileDataStore ds = DataStoreUtils
+ .createCachingFDS(temporaryFolder.newFolder().getAbsolutePath(),
+ temporaryFolder.newFolder().getAbsolutePath());
+ provider.setBlobStore(new DataStoreBlobStore(ds));
+ HOOK = new EditorHook(new IndexUpdateProvider(provider));
+ } else {
+ HOOK = new EditorHook(new IndexUpdateProvider(new LuceneIndexEditorProvider()));
+ }
+ }
+
+ @Test
+ public void testLuceneWithFullText() throws Exception {
+ NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
+ NodeBuilder idxnb = newLuceneIndexDefinitionV2(index, "lucene",
+ of(TYPENAME_STRING));
+ LuceneIndexDefinition defn = new LuceneIndexDefinition(root, idxnb.getNodeState(), "/foo");
+ NodeState before = builder.getNodeState();
+ builder.child("test").setProperty("foo", "fox is jumping");
+ builder.child("test").setProperty("price", 100);
+ NodeState after = builder.getNodeState();
+
+ NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+ tracker.update(indexed);
+
+ //system fields starts with ':' so need to be escaped
+ assertEquals("/test", query(escape(FieldNames.createAnalyzedFieldName("foo"))+":fox", defn));
+ assertNull("Non string properties not indexed by default",
+ getPath(NumericRangeQuery.newLongRange("price", 100L, 100L, true, true)));
+ }
+
+ @Test
+ public void noChangeIfNonIndexedDelete() throws Exception{
+ NodeState before = builder.getNodeState();
+ NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
+ NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene", of(TYPENAME_STRING));
+ nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
+ nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of("foo"), STRINGS));
+
+
+ builder.child("test").setProperty("foo", "bar");
+ builder.child("test").child("a");
+ NodeState after = builder.getNodeState();
+
+ NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+ tracker.update(indexed);
+ assertEquals("/test", getPath(new TermQuery(new Term("foo", "bar"))));
+
+ NodeState luceneIdxState1 = NodeStateUtils.getNode(indexed, "/oak:index/lucene");
+
+ before = indexed;
+ builder = indexed.builder();
+ builder.getChildNode("test").getChildNode("a").remove();
+ after = builder.getNodeState();
+ indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+
+ NodeState luceneIdxState2 = NodeStateUtils.getNode(indexed, "/oak:index/lucene");
+ assertEquals(luceneIdxState1, luceneIdxState2);
+ }
+
+ private String escape(String name) {
+ return name.replace(":", "\\:");
+ }
+
+ @Test
+ public void testLuceneWithNonFullText() throws Exception {
+ NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
+ NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene",
+ of(TYPENAME_STRING));
+ nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
+ nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of("foo", "price", "weight", "bool", "creationTime"), STRINGS));
+ LuceneIndexDefinition defn = new LuceneIndexDefinition(root, nb.getNodeState(), "/foo");
+ NodeState before = builder.getNodeState();
+ builder.child("test").setProperty("foo", "fox is jumping");
+ builder.child("test").setProperty("bar", "kite is flying");
+ builder.child("test").setProperty("price", 100);
+ builder.child("test").setProperty("weight", 10.0);
+ builder.child("test").setProperty("bool", true);
+ builder.child("test").setProperty("truth", true);
+ builder.child("test").setProperty("creationTime", createCal("05/06/2014"));
+ NodeState after = builder.getNodeState();
+
+ NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+ tracker.update(indexed);
+
+ assertNull("Fulltext search should not work", query("foo:fox",defn));
+ assertEquals("/test", getPath(new TermQuery(new Term("foo", "fox is jumping"))));
+ assertNull("bar must NOT be indexed", getPath(new TermQuery(new Term("bar", "kite is flying"))));
+
+ //Long
+ assertEquals("/test", getPath(NumericRangeQuery.newDoubleRange("weight", 8D, 12D, true, true)));
+
+ //Double
+ assertEquals("/test", getPath(NumericRangeQuery.newLongRange("price", 100L, 100L, true, true)));
+
+ //Boolean
+ assertEquals("/test", getPath(new TermQuery(new Term("bool", "true"))));
+ assertNull("truth must NOT be indexed", getPath(new TermQuery(new Term("truth", "true"))));
+
+ //Date
+ assertEquals("/test", getPath(NumericRangeQuery.newLongRange("creationTime",
+ dateToTime("05/05/2014"), dateToTime("05/07/2014"), true, true)));
+ }
+
+ @Test
+ public void noOfDocsIndexedNonFullText() throws Exception {
+ NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
+ NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene",
+ of(TYPENAME_STRING));
+ nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
+ nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of("foo"), STRINGS));
+
+ NodeState before = builder.getNodeState();
+ builder.child("test").setProperty("foo", "fox is jumping");
+ builder.child("test2").setProperty("bar", "kite is flying");
+ builder.child("test3").setProperty("foo", "wind is blowing");
+ NodeState after = builder.getNodeState();
+
+ NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+ tracker.update(indexed);
+
+ assertEquals(2, getSearcher().getIndexReader().numDocs());
+ }
+
+ @Test
+ public void saveDirectoryListing() throws Exception {
+ NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
+ NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene",
+ of(TYPENAME_STRING));
+ nb.setProperty(LuceneIndexConstants.SAVE_DIR_LISTING, true);
+ nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
+ nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of("foo"), STRINGS));
+
+ NodeState before = builder.getNodeState();
+ builder.child("test").setProperty("foo", "fox is jumping");
+ NodeState after = builder.getNodeState();
+
+ NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+ NodeState dir = indexed.getChildNode("oak:index").getChildNode("lucene").getChildNode(":data");
+ assertTrue(dir.hasProperty(OakDirectory.PROP_DIR_LISTING));
+ }
+
+ /**
+ * 1. Index property foo in /test
+ * 2. Then modify some other property in /test
+ *
+ * This should not cause the index to be updated
+ */
+ @Test
+ public void nonIncludedPropertyChange() throws Exception {
+ NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
+ NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene",
+ of(TYPENAME_STRING));
+ nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
+ nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of("foo"),
+ STRINGS));
+
+ NodeState before = builder.getNodeState();
+ builder.child("test").setProperty("foo", "fox is jumping");
+ builder.child("test2").setProperty("foo", "bird is chirping");
+ NodeState after = builder.getNodeState();
+
+ NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+ tracker.update(indexed);
+
+ assertEquals(2, getSearcher().getIndexReader().numDocs());
+
+ assertEquals("/test", getPath(new TermQuery(new Term("foo", "fox is jumping"))));
+
+ releaseIndexNode();
+ before = indexed;
+ builder = before.builder();
+ builder.child("test").setProperty("bar", "kite is flying");
+ after = builder.getNodeState();
+ indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+ tracker.update(indexed);
+
+ assertEquals(2, getSearcher().getIndexReader().numDocs());
+ assertEquals("change in non included property should not cause " +
+ "index update",0, getSearcher().getIndexReader().numDeletedDocs());
+ }
+
+ @Test
+ public void testLuceneWithRelativeProperty() throws Exception {
+ // OAK-6833
+ assumeFalse(CIHelper.windows());
+
+ NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
+ NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene",
+ of(TYPENAME_STRING));
+ nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
+ nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of("foo", "jcr:content/mime",
+ "jcr:content/metadata/type"), STRINGS));
+
+ NodeState before = builder.getNodeState();
+ builder.child("test").setProperty("foo", "fox is jumping");
+ builder.child("test").child("jcr:content").setProperty("mime", "text");
+ builder.child("test").child("jcr:content").child("metadata").setProperty("type", "image");
+ builder.child("jcr:content").setProperty("count", "text");
+ builder.child("jcr:content").child("boom").child("metadata").setProperty("type", "image");
+ NodeState after = builder.getNodeState();
+
+ NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+ tracker.update(indexed);
+
+ assertEquals(1, getSearcher().getIndexReader().numDocs());
+
+ assertEquals("/test", getPath(new TermQuery(new Term("foo", "fox is jumping"))));
+ assertEquals("/test", getPath(new TermQuery(new Term("jcr:content/mime", "text"))));
+ assertEquals("/test", getPath(new TermQuery(new Term("jcr:content/metadata/type", "image"))));
+ assertNull("bar must NOT be indexed", getPath(new TermQuery(new Term("count", "text"))));
+
+ releaseIndexNode();
+ before = indexed;
+ builder = before.builder();
+ builder.child("test").child("jcr:content").setProperty("mime", "pdf");
+ after = builder.getNodeState();
+ indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+ tracker.update(indexed);
+
+ assertEquals("/test", getPath(new TermQuery(new Term("jcr:content/mime", "pdf"))));
+
+ releaseIndexNode();
+ before = indexed;
+ builder = before.builder();
+ builder.child("test").child("jcr:content").remove();
+ after = builder.getNodeState();
+ indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+ tracker.update(indexed);
+ assertNull("removes must be persisted too, 1st level",
+ getPath(new TermQuery(new Term("jcr:content/mime", "pdf"))));
+ assertNull("removes must be persisted too, 2nd level",
+ getPath(new TermQuery(new Term("jcr:content/metadata/type",
+ "image"))));
+ }
+
+ @Test
+ public void indexVersionSwitchOnReindex() throws Exception{
+ NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
+ NodeBuilder nb = newLuceneIndexDefinition(index, "lucene",
+ of(TYPENAME_STRING));
+
+ //1. Trigger a index so that next index step does not see it as a fresh index
+ NodeState indexed = HOOK.processCommit(EMPTY_NODE, builder.getNodeState(), CommitInfo.EMPTY);
+ builder = indexed.builder();
+
+ //By default logic would use current version. To simulate upgrade we forcefully set
+ //version to V1
+ builder.child(INDEX_DEFINITIONS_NAME).child("lucene").setProperty(IndexDefinition.INDEX_VERSION,
+ IndexFormatVersion.V1.getVersion());
+
+ NodeState before = builder.getNodeState();
+ builder.child("test").setProperty("foo", "fox is jumping");
+ NodeState after = builder.getNodeState();
+
+ indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+ assertEquals(IndexFormatVersion.V1, new IndexDefinition(root,
+ indexed.getChildNode(INDEX_DEFINITIONS_NAME).getChildNode("lucene"), "/foo").getVersion());
+
+ //3. Trigger a reindex and version should switch to current
+ builder = indexed.builder();
+ before = indexed;
+ builder.child(INDEX_DEFINITIONS_NAME).child("lucene").setProperty(IndexConstants.REINDEX_PROPERTY_NAME, true);
+ after = builder.getNodeState();
+ indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+ assertEquals(IndexFormatVersion.getDefault(), new IndexDefinition(root,
+ indexed.getChildNode(INDEX_DEFINITIONS_NAME).getChildNode("lucene"), "/foo").getVersion());
+
+ }
+
+ @Test
+ public void autoFormatUpdate() throws Exception{
+ NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
+ NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene",
+ of(TYPENAME_STRING));
+
+ //1. Trigger a index so that next index step does not see it as a fresh index
+ NodeState indexed = HOOK.processCommit(EMPTY_NODE, builder.getNodeState(), CommitInfo.EMPTY);
+
+ IndexDefinition defn = new IndexDefinition(root, indexed.getChildNode(INDEX_DEFINITIONS_NAME).getChildNode("lucene"), "/foo");
+ assertFalse(defn.isOfOldFormat());
+ }
+
+ @Test
+ public void copyOnWriteAndLocks() throws Exception {
+ assumeFalse(CIHelper.windows());
+
+ ExecutorService executorService = Executors.newFixedThreadPool(2);
+ IndexCopier copier = new IndexCopier(executorService, temporaryFolder.getRoot());
+
+ FailOnDemandEditorProvider failingProvider = new FailOnDemandEditorProvider();
+ EditorHook hook = new EditorHook(
+ new IndexUpdateProvider(
+ new CompositeIndexEditorProvider(
+ failingProvider,
+ new LuceneIndexEditorProvider(copier))));
+
+ NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
+ NodeBuilder nb = newLuceneIndexDefinitionV2(index, "lucene", of(TYPENAME_STRING));
+ IndexUtils.createIndexDefinition(index, "failingIndex", false, false, of("foo"), null);
+
+
+ //1. Get initial set indexed. So that next cycle is normal indexing
+ NodeState indexed = hook.processCommit(EMPTY_NODE, builder.getNodeState(), CommitInfo.EMPTY);
+ builder = indexed.builder();
+
+ NodeState before = indexed;
+ builder.child("test").setProperty("a", "fox is jumping");
+ NodeState after = builder.getNodeState();
+
+ //2. Ensure that Lucene gets triggered but close is not called
+ failingProvider.setShouldFail(true);
+ try {
+ hook.processCommit(before, after, CommitInfo.EMPTY);
+ fail();
+ } catch (CommitFailedException ignore){
+
+ }
+
+ //3. Disable the troubling editor
+ failingProvider.setShouldFail(false);
+
+ //4. Now commit should process fine
+ hook.processCommit(before, after, CommitInfo.EMPTY);
+
+ executorService.shutdown();
+ }
+
+
+ @Test
+ public void multiplexingWriter() throws Exception{
+ newLucenePropertyIndex("lucene", "foo");
+ MountInfoProvider mip = Mounts.newBuilder()
+ .mount("foo", "/libs", "/apps").build();
+ EditorHook hook = new EditorHook(
+ new IndexUpdateProvider(
+ new LuceneIndexEditorProvider(null, new ExtractedTextCache(0, 0), null, mip)));
+
+ NodeState indexed = hook.processCommit(EMPTY_NODE, builder.getNodeState(), CommitInfo.EMPTY);
+ builder = indexed.builder();
+ NodeState before = indexed;
+ builder.child("content").child("en").setProperty("foo", "bar");
+ builder.child("libs").child("install").setProperty("foo", "bar");
+ NodeState after = builder.getNodeState();
+
+ indexed = hook.processCommit(before, after, CommitInfo.EMPTY);
+ builder = indexed.builder();
+
+ assertEquals(1, numDocs(mip.getMountByName("foo")));
+ assertEquals(1, numDocs(mip.getDefaultMount()));
+ }
+
+ private int numDocs(Mount m) throws IOException {
+ String indexDirName = MultiplexersLucene.getIndexDirName(m);
+ NodeBuilder defnBuilder = builder.child(INDEX_DEFINITIONS_NAME).child("lucene");
+ Directory d = new OakDirectory(defnBuilder, indexDirName, new LuceneIndexDefinition(root, defnBuilder.getNodeState(), "/foo"), true);
+ IndexReader r = DirectoryReader.open(d);
+ return r.numDocs();
+ }
+
+
+ //@Test
+ public void checkLuceneIndexFileUpdates() throws Exception{
+ NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
+ NodeBuilder nb = newLuceneIndexDefinition(index, "lucene",
+ of(TYPENAME_STRING));
+ nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
+ nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of("foo" , "bar", "baz"), STRINGS));
+ //nb.removeProperty(REINDEX_PROPERTY_NAME);
+
+ NodeState before = builder.getNodeState();
+ builder.child("test").setProperty("foo", "fox is jumping");
+
+ //InfoStream.setDefault(new PrintStreamInfoStream(System.out));
+ before = commitAndDump(before, builder.getNodeState());
+
+ builder = before.builder();
+ builder.child("test2").setProperty("bar", "ship is sinking");
+ before = commitAndDump(before, builder.getNodeState());
+
+ builder = before.builder();
+ builder.child("test3").setProperty("baz", "horn is blowing");
+ before = commitAndDump(before, builder.getNodeState());
+
+ builder = before.builder();
+ builder.child("test2").remove();
+ before = commitAndDump(before, builder.getNodeState());
+
+ builder = before.builder();
+ builder.child("test2").setProperty("bar", "ship is back again");
+ before = commitAndDump(before, builder.getNodeState());
+ }
+
+ @After
+ public void releaseIndexNode(){
+ if(indexNode != null){
+ indexNode.release();
+ }
+ indexNode = null;
+ }
+
+ private NodeState newLucenePropertyIndex(String indexName, String propName){
+ NodeBuilder index = builder.child(INDEX_DEFINITIONS_NAME);
+ NodeBuilder nb = newLuceneIndexDefinitionV2(index, indexName,
+ of(TYPENAME_STRING));
+ nb.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
+ nb.setProperty(createProperty(INCLUDE_PROPERTY_NAMES, of(propName), STRINGS));
+ return builder.getNodeState();
+ }
+
+ private String query(String query, LuceneIndexDefinition defn) throws IOException, ParseException {
+ QueryParser queryParser = new QueryParser(VERSION, "", defn.getAnalyzer());
+ return getPath(queryParser.parse(query));
+ }
+
+ private String getPath(Query query) throws IOException {
+ TopDocs td = getSearcher().search(query, 100);
+ if (td.totalHits > 0){
+ if(td.totalHits > 1){
+ fail("More than 1 result found for query " + query);
+ }
+ return getSearcher().getIndexReader().document(td.scoreDocs[0].doc).get(FieldNames.PATH);
+ }
+ return null;
+ }
+
+ private IndexSearcher getSearcher(){
+ if(indexNode == null){
+ indexNode = tracker.acquireIndexNode("/oak:index/lucene");
+ }
+ return indexNode.getSearcher();
+ }
+
+ private NodeState commitAndDump(NodeState before, NodeState after) throws CommitFailedException, IOException {
+ NodeState indexed = HOOK.processCommit(before, after, CommitInfo.EMPTY);
+ tracker.update(indexed);
+ dumpIndexDir();
+ return indexed;
+ }
+
+ private void dumpIndexDir() throws IOException {
+ Directory dir = ((DirectoryReader)getSearcher().getIndexReader()).directory();
+
+ System.out.println("================");
+ String[] fileNames = dir.listAll();
+ Arrays.sort(fileNames);
+ for (String file : fileNames){
+ System.out.printf("%s - %d %n", file, dir.fileLength(file));
+ }
+ releaseIndexNode();
+ }
+
+ public static Calendar createCal(String dt) throws java.text.ParseException {
+ SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(sdf.parse(dt));
+ return cal;
+ }
+
+ static long dateToTime(String dt) throws java.text.ParseException {
+ return FieldFactory.dateToLong(ISO8601.format(createCal(dt)));
+ }
+
+ private static class FailOnDemandEditorProvider implements IndexEditorProvider {
+
+ private boolean shouldFail;
+
+ @Override
+ public Editor getIndexEditor(@NotNull String type, @NotNull NodeBuilder definition,
+ @NotNull NodeState root,
+ @NotNull IndexUpdateCallback callback) throws CommitFailedException {
+ if (PropertyIndexEditorProvider.TYPE.equals(type)) {
+ return new FailOnDemandEditor();
+ }
+ return null;
+ }
+
+ public void setShouldFail(boolean shouldFail) {
+ this.shouldFail = shouldFail;
+ }
+
+ private class FailOnDemandEditor extends DefaultEditor implements IndexEditor {
+ @Override
+ public void leave(NodeState before, NodeState after)
+ throws CommitFailedException {
+ throwExceptionIfTold();
+ super.leave(before, after);
+ }
+
+ void throwExceptionIfTold() throws CommitFailedException {
+ if (shouldFail) {
+ throw new CommitFailedException("commit",1 , null);
+ }
+ }
+ }
+ }
+
+}
Propchange: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexEditorTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexExclusionQueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexExclusionQueryTest.java?rev=1841926&r1=1841925&r2=1841926&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexExclusionQueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexExclusionQueryTest.java Tue Sep 25 12:24:15 2018
@@ -24,8 +24,8 @@ import static org.apache.jackrabbit.JcrC
import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED;
import static org.apache.jackrabbit.oak.api.Type.DATE;
import static org.apache.jackrabbit.oak.api.Type.STRINGS;
-import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.EXCLUDE_PROPERTY_NAMES;
-import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.INCLUDE_PROPERTY_TYPES;
+import static org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.EXCLUDE_PROPERTY_NAMES;
+import static org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants.INCLUDE_PROPERTY_TYPES;
import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.TYPE_LUCENE;
import static org.apache.jackrabbit.oak.plugins.index.lucene.TestUtil.useV2;
Modified: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexInfoProviderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexInfoProviderTest.java?rev=1841926&r1=1841925&r2=1841926&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexInfoProviderTest.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexInfoProviderTest.java Tue Sep 25 12:24:15 2018
@@ -21,7 +21,6 @@ package org.apache.jackrabbit.oak.plugin
import java.io.File;
-import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.plugins.index.AsyncIndexInfo;
import org.apache.jackrabbit.oak.plugins.index.AsyncIndexInfoService;
import org.apache.jackrabbit.oak.plugins.index.IndexInfo;
@@ -36,11 +35,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-import static com.google.common.collect.Lists.newArrayList;
-import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
Modified: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexLookupTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexLookupTest.java?rev=1841926&r1=1841925&r2=1841926&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexLookupTest.java (original)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexLookupTest.java Tue Sep 25 12:24:15 2018
@@ -19,6 +19,7 @@
package org.apache.jackrabbit.oak.plugins.index.lucene;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexLookup;
import org.apache.jackrabbit.oak.query.index.FilterImpl;
import org.apache.jackrabbit.oak.spi.query.Filter;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -43,11 +44,11 @@ public class LuceneIndexLookupTest {
newLuceneIndexDefinition(index, "l1", of(TYPENAME_STRING));
newLuceneIndexDefinition(index, "l2", of(TYPENAME_STRING));
- LuceneIndexLookup lookup = new LuceneIndexLookup(builder.getNodeState());
+ IndexLookup lookup = LuceneIndexLookupUtil.getLuceneIndexLookup(builder.getNodeState());
FilterImpl f = FilterImpl.newTestInstance();
f.restrictPath("/", Filter.PathRestriction.EXACT);
assertEquals(of("/oak:index/l1", "/oak:index/l2"),
- lookup.collectIndexNodePaths(f));
+ lookup.collectIndexNodePaths(f));
}
@Test
@@ -61,14 +62,14 @@ public class LuceneIndexLookupTest {
index = builder.child("a").child("b").child(INDEX_DEFINITIONS_NAME);
newLuceneIndexDefinition(index, "l3", of(TYPENAME_STRING));
- LuceneIndexLookup lookup = new LuceneIndexLookup(builder.getNodeState());
+ IndexLookup lookup = LuceneIndexLookupUtil.getLuceneIndexLookup(builder.getNodeState());
FilterImpl f = FilterImpl.newTestInstance();
f.restrictPath("/a", Filter.PathRestriction.EXACT);
assertEquals(of("/oak:index/l1", "/a/oak:index/l2"),
- lookup.collectIndexNodePaths(f));
+ lookup.collectIndexNodePaths(f));
f.restrictPath("/a/b", Filter.PathRestriction.EXACT);
assertEquals(of("/oak:index/l1", "/a/oak:index/l2", "/a/b/oak:index/l3"),
- lookup.collectIndexNodePaths(f));
+ lookup.collectIndexNodePaths(f));
}
}
Added: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderServiceTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderServiceTest.java?rev=1841926&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderServiceTest.java (added)
+++ jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderServiceTest.java Tue Sep 25 12:24:15 2018
@@ -0,0 +1,448 @@
+/*
+ * 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.jackrabbit.oak.plugins.index.lucene;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.jackrabbit.oak.api.jmx.CacheStatsMBean;
+import org.apache.jackrabbit.oak.api.jmx.CheckpointMBean;
+import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard;
+import org.apache.jackrabbit.oak.plugins.blob.datastore.CachingFileDataStore;
+import org.apache.jackrabbit.oak.plugins.blob.datastore.DataStoreBlobStore;
+import org.apache.jackrabbit.oak.plugins.blob.datastore.DataStoreUtils;
+import org.apache.jackrabbit.oak.plugins.document.spi.JournalPropertyService;
+import org.apache.jackrabbit.oak.plugins.index.AsyncIndexInfoService;
+import org.apache.jackrabbit.oak.plugins.index.IndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.IndexPathService;
+import org.apache.jackrabbit.oak.plugins.index.fulltext.PreExtractedTextProvider;
+import org.apache.jackrabbit.oak.plugins.index.importer.IndexImporterProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.CopyOnReadStatsMBean;
+import org.apache.jackrabbit.oak.plugins.index.lucene.IndexAugmentorFactory;
+import org.apache.jackrabbit.oak.plugins.index.lucene.IndexCopier;
+import org.apache.jackrabbit.oak.plugins.index.lucene.IndexTracker;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LoggingInfoStream;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexProvider;
+import org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexProviderService;
+import org.apache.jackrabbit.oak.plugins.index.lucene.directory.BufferedOakDirectory;
+import org.apache.jackrabbit.oak.plugins.index.lucene.property.PropertyIndexCleaner;
+import org.apache.jackrabbit.oak.plugins.index.lucene.reader.DefaultIndexReaderFactory;
+import org.apache.jackrabbit.oak.plugins.index.lucene.score.ScorerProviderFactory;
+import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore;
+import org.apache.jackrabbit.oak.spi.commit.BackgroundObserver;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
+import org.apache.jackrabbit.oak.spi.mount.Mounts;
+import org.apache.jackrabbit.oak.spi.query.QueryIndexProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
+import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils;
+import org.apache.jackrabbit.oak.stats.StatisticsProvider;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.util.InfoStream;
+import org.apache.sling.testing.mock.osgi.MockOsgi;
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.osgi.framework.ServiceReference;
+
+import static org.apache.jackrabbit.oak.plugins.index.lucene.LuceneIndexConstants.TYPE_LUCENE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+public class LuceneIndexProviderServiceTest {
+ /*
+ The test case uses raw config name and not access it via
+ constants in LuceneIndexProviderService to ensure that change
+ in names are detected
+ */
+
+ @Rule
+ public final TemporaryFolder folder = new TemporaryFolder(new File("target"));
+
+ @Rule
+ public final OsgiContext context = new OsgiContext();
+
+ private LuceneIndexProviderService service = new LuceneIndexProviderService();
+
+ private Whiteboard wb;
+
+ private MountInfoProvider mip;
+
+ @Before
+ public void setUp(){
+ mip = Mounts.newBuilder().build();
+ context.registerService(MountInfoProvider.class, mip);
+ context.registerService(StatisticsProvider.class, StatisticsProvider.NOOP);
+ context.registerService(ScorerProviderFactory.class, ScorerProviderFactory.DEFAULT);
+ context.registerService(IndexAugmentorFactory.class, new IndexAugmentorFactory());
+ context.registerService(NodeStore.class, new MemoryNodeStore());
+ context.registerService(IndexPathService.class, mock(IndexPathService.class));
+ context.registerService(AsyncIndexInfoService.class, mock(AsyncIndexInfoService.class));
+ context.registerService(CheckpointMBean.class, mock(CheckpointMBean.class));
+
+ wb = new OsgiWhiteboard(context.bundleContext());
+ MockOsgi.injectServices(service, context.bundleContext());
+ }
+
+ @After
+ public void after(){
+ IndexDefinition.setDisableStoredIndexDefinition(false);
+ }
+
+ @Test
+ public void defaultSetup() throws Exception{
+ MockOsgi.activate(service, context.bundleContext(), getDefaultConfig());
+
+ assertNotNull(context.getService(QueryIndexProvider.class));
+ assertNotNull(context.getService(Observer.class));
+ assertNotNull(context.getService(IndexEditorProvider.class));
+
+ LuceneIndexEditorProvider editorProvider =
+ (LuceneIndexEditorProvider) context.getService(IndexEditorProvider.class);
+ assertNotNull(editorProvider.getIndexCopier());
+ assertNotNull(editorProvider.getIndexingQueue());
+
+ IndexCopier indexCopier = service.getIndexCopier();
+ assertNotNull("IndexCopier should be initialized as CopyOnRead is enabled by default", indexCopier);
+ assertTrue(indexCopier.isPrefetchEnabled());
+ assertFalse(IndexDefinition.isDisableStoredIndexDefinition());
+
+ assertNotNull("CopyOnRead should be enabled by default", context.getService(CopyOnReadStatsMBean.class));
+ assertNotNull(context.getService(CacheStatsMBean.class));
+
+ assertTrue(context.getService(Observer.class) instanceof BackgroundObserver);
+ assertEquals(InfoStream.NO_OUTPUT, InfoStream.getDefault());
+
+ assertEquals(1024, BooleanQuery.getMaxClauseCount());
+
+ assertNotNull(FieldUtils.readDeclaredField(service, "documentQueue", true));
+
+ assertNotNull(context.getService(JournalPropertyService.class));
+ assertNotNull(context.getService(IndexImporterProvider.class));
+
+ assertNotNull(WhiteboardUtils.getServices(wb, Runnable.class, r -> r instanceof PropertyIndexCleaner));
+
+ MockOsgi.deactivate(service, context.bundleContext());
+
+ IndexTracker tracker = (IndexTracker) FieldUtils.readDeclaredField(service, "tracker", true);
+ assertNotNull(tracker.getAsyncIndexInfoService());
+ }
+
+ @Test
+ public void typeProperty() throws Exception{
+ MockOsgi.activate(service, context.bundleContext(), getDefaultConfig());
+ ServiceReference sr = context.bundleContext().getServiceReference(IndexEditorProvider.class.getName());
+ assertEquals(TYPE_LUCENE, sr.getProperty("type"));
+ }
+
+ @Test
+ public void disableOpenIndexAsync() throws Exception{
+ Map<String,Object> config = getDefaultConfig();
+ config.put("enableOpenIndexAsync", false);
+ MockOsgi.activate(service, context.bundleContext(), config);
+
+ assertTrue(context.getService(Observer.class) instanceof LuceneIndexProvider);
+
+ MockOsgi.deactivate(service, context.bundleContext());
+ }
+
+ @Test
+ public void enableCopyOnWrite() throws Exception{
+ Map<String,Object> config = getDefaultConfig();
+ config.put("enableCopyOnWriteSupport", true);
+ MockOsgi.activate(service, context.bundleContext(), config);
+
+ LuceneIndexEditorProvider editorProvider =
+ (LuceneIndexEditorProvider) context.getService(IndexEditorProvider.class);
+
+ assertNotNull(editorProvider);
+ assertNotNull(editorProvider.getIndexCopier());
+
+ MockOsgi.deactivate(service, context.bundleContext());
+ }
+
+ // OAK-7357
+ @Test
+ public void disableCoRCoW() throws Exception {
+ // inject ds as OAK-7357 revealed ABD bean had a bug - which comes into play only with blob stores
+ CachingFileDataStore ds = DataStoreUtils
+ .createCachingFDS(folder.newFolder().getAbsolutePath(),
+ folder.newFolder().getAbsolutePath());
+
+ context.registerService(GarbageCollectableBlobStore.class, new DataStoreBlobStore(ds));
+
+ // re-init service and inject references
+ service = new LuceneIndexProviderService();
+ MockOsgi.injectServices(service, context.bundleContext());
+
+ Map<String,Object> config = getDefaultConfig();
+ config.put("enableCopyOnReadSupport", false);
+ config.put("enableCopyOnWriteSupport", false);
+
+ // activation should work
+ MockOsgi.activate(service, context.bundleContext(), config);
+
+ // get lucene index provider
+ LuceneIndexProvider lip = null;
+ for (QueryIndexProvider qip : context.getServices(QueryIndexProvider.class, null)) {
+ if (qip instanceof LuceneIndexProvider) {
+ lip = (LuceneIndexProvider)qip;
+ break;
+ }
+ }
+ assertNotNull(lip);
+ IndexTracker tracker = lip.getTracker();
+
+ // access reader factory with reflection and implicitly assert that it's DefaultIndexReaderFactory
+ Field readerFactorFld = IndexTracker.class.getDeclaredField("readerFactory");
+ readerFactorFld.setAccessible(true);
+ DefaultIndexReaderFactory readerFactory = (DefaultIndexReaderFactory)readerFactorFld.get(tracker);
+
+ Field mipFld = DefaultIndexReaderFactory.class.getDeclaredField("mountInfoProvider");
+ mipFld.setAccessible(true);
+ // OAK-7408: LIPS was using default tracker ctor and hence reader factor used default mounts
+ assertEquals("Reader factory not using configured MountInfoProvider", mip, mipFld.get(readerFactory));
+
+ // de-activation should work
+ MockOsgi.deactivate(service, context.bundleContext());
+ }
+
+ @Test
+ public void enablePrefetchIndexFiles() throws Exception{
+ Map<String,Object> config = getDefaultConfig();
+ config.put("prefetchIndexFiles", true);
+ MockOsgi.activate(service, context.bundleContext(), config);
+
+ IndexCopier indexCopier = service.getIndexCopier();
+ assertTrue(indexCopier.isPrefetchEnabled());
+
+ MockOsgi.deactivate(service, context.bundleContext());
+ }
+
+ @Test
+ public void debugLogging() throws Exception{
+ Map<String,Object> config = getDefaultConfig();
+ config.put("debug", true);
+ MockOsgi.activate(service, context.bundleContext(), config);
+
+ assertEquals(LoggingInfoStream.INSTANCE, InfoStream.getDefault());
+ MockOsgi.deactivate(service, context.bundleContext());
+ }
+
+ @Test
+ public void enableExtractedTextCaching() throws Exception{
+ Map<String,Object> config = getDefaultConfig();
+ config.put("extractedTextCacheSizeInMB", 11);
+ MockOsgi.activate(service, context.bundleContext(), config);
+
+ ExtractedTextCache textCache = service.getExtractedTextCache();
+ assertNotNull(textCache.getCacheStats());
+ assertNotNull(context.getService(CacheStatsMBean.class));
+
+ assertEquals(11 * FileUtils.ONE_MB, textCache.getCacheStats().getMaxTotalWeight());
+
+ MockOsgi.deactivate(service, context.bundleContext());
+
+ assertNull(context.getService(CacheStatsMBean.class));
+ }
+
+ @Test
+ public void preExtractedTextProvider() throws Exception{
+ MockOsgi.activate(service, context.bundleContext(), getDefaultConfig());
+ LuceneIndexEditorProvider editorProvider =
+ (LuceneIndexEditorProvider) context.getService(IndexEditorProvider.class);
+ assertNull(editorProvider.getExtractedTextCache().getExtractedTextProvider());
+ assertFalse(editorProvider.getExtractedTextCache().isAlwaysUsePreExtractedCache());
+
+ //Mock OSGi does not support components
+ //context.registerService(PreExtractedTextProvider.class, new DummyProvider());
+ service.bindExtractedTextProvider(mock(PreExtractedTextProvider.class));
+
+ assertNotNull(editorProvider.getExtractedTextCache().getExtractedTextProvider());
+ }
+
+ @Test
+ public void preExtractedProviderBindBeforeActivate() throws Exception{
+ service.bindExtractedTextProvider(mock(PreExtractedTextProvider.class));
+ MockOsgi.activate(service, context.bundleContext(), getDefaultConfig());
+ LuceneIndexEditorProvider editorProvider =
+ (LuceneIndexEditorProvider) context.getService(IndexEditorProvider.class);
+ assertNotNull(editorProvider.getExtractedTextCache().getExtractedTextProvider());
+ }
+
+ @Test
+ public void alwaysUsePreExtractedCache() throws Exception{
+ Map<String,Object> config = getDefaultConfig();
+ config.put("alwaysUsePreExtractedCache", "true");
+ MockOsgi.activate(service, context.bundleContext(), config);
+ LuceneIndexEditorProvider editorProvider =
+ (LuceneIndexEditorProvider) context.getService(IndexEditorProvider.class);
+ assertTrue(editorProvider.getExtractedTextCache().isAlwaysUsePreExtractedCache());
+ }
+
+ @Test
+ public void booleanQuerySize() throws Exception{
+ Map<String,Object> config = getDefaultConfig();
+ config.put("booleanClauseLimit", 4000);
+ MockOsgi.activate(service, context.bundleContext(), config);
+
+ assertEquals(4000, BooleanQuery.getMaxClauseCount());
+ }
+
+ @Test
+ public void indexDefnStorafe() throws Exception{
+ Map<String,Object> config = getDefaultConfig();
+ config.put("disableStoredIndexDefinition", true);
+ MockOsgi.activate(service, context.bundleContext(), config);
+
+ assertTrue(IndexDefinition.isDisableStoredIndexDefinition());
+ }
+
+
+ @Test
+ public void blobStoreRegistered() throws Exception{
+ MockOsgi.activate(service, context.bundleContext(), getDefaultConfig());
+ LuceneIndexEditorProvider editorProvider =
+ (LuceneIndexEditorProvider) context.getService(IndexEditorProvider.class);
+ assertNull(editorProvider.getBlobStore());
+
+ /* Register a blob store */
+ CachingFileDataStore ds = DataStoreUtils
+ .createCachingFDS(folder.newFolder().getAbsolutePath(),
+ folder.newFolder().getAbsolutePath());
+
+ context.registerService(GarbageCollectableBlobStore.class, new DataStoreBlobStore(ds));
+ reactivate();
+
+ editorProvider =
+ (LuceneIndexEditorProvider) context.getService(IndexEditorProvider.class);
+ assertNotNull(editorProvider.getBlobStore());
+ }
+
+ @Test
+ public void executorPoolBehaviour() throws Exception{
+ MockOsgi.activate(service, context.bundleContext(), getDefaultConfig());
+ ExecutorService executor = service.getExecutorService();
+
+ final CountDownLatch latch1 = new CountDownLatch(1);
+ final CountDownLatch latch2 = new CountDownLatch(1);
+
+ Callable cb1 = new Callable() {
+ @Override
+ public Object call() throws Exception {
+ latch1.await();
+ return null;
+ }
+ };
+
+ Callable cb2 = new Callable() {
+ @Override
+ public Object call() throws Exception {
+ latch2.countDown();
+ return null;
+ }
+ };
+
+ executor.submit(cb1);
+ executor.submit(cb2);
+
+ //Even if one task gets stuck the other task must get completed
+ assertTrue("Second task not executed", latch2.await(1, TimeUnit.MINUTES));
+ latch1.countDown();
+
+ MockOsgi.deactivate(service, context.bundleContext());
+ }
+
+
+ @Test
+ public void singleBlobPerIndexFileConfig() throws Exception {
+ Map<String, Object> config = getDefaultConfig();
+ config.put("enableSingleBlobIndexFiles", "true");
+ MockOsgi.activate(service, context.bundleContext(), config);
+ assertTrue("Enabling property must reflect in BufferedOakDirectory state",
+ BufferedOakDirectory.isEnableWritingSingleBlobIndexFile());
+ MockOsgi.deactivate(service, context.bundleContext());
+
+ config = getDefaultConfig();
+ config.put("enableSingleBlobIndexFiles", "false");
+ MockOsgi.activate(service, context.bundleContext(), config);
+ assertFalse("Enabling property must reflect in BufferedOakDirectory state",
+ BufferedOakDirectory.isEnableWritingSingleBlobIndexFile());
+ MockOsgi.deactivate(service, context.bundleContext());
+ }
+
+ @Test
+ public void cleanerRegistration() throws Exception{
+ Map<String,Object> config = getDefaultConfig();
+ config.put("propIndexCleanerIntervalInSecs", 142);
+
+ MockOsgi.activate(service, context.bundleContext(), config);
+ ServiceReference[] sr = context.bundleContext().getAllServiceReferences(Runnable.class.getName(),
+ "(scheduler.name="+ PropertyIndexCleaner.class.getName()+")");
+ assertEquals(sr.length, 1);
+
+ assertEquals(142L, sr[0].getProperty("scheduler.period"));
+ }
+
+ @Test
+ public void cleanerRegistrationDisabled() throws Exception{
+ Map<String,Object> config = getDefaultConfig();
+ config.put("propIndexCleanerIntervalInSecs", 0);
+
+ MockOsgi.activate(service, context.bundleContext(), config);
+ ServiceReference[] sr = context.bundleContext().getAllServiceReferences(Runnable.class.getName(),
+ "(scheduler.name="+ PropertyIndexCleaner.class.getName()+")");
+ assertNull(sr);
+ }
+
+ private void reactivate() {
+ MockOsgi.deactivate(service, context.bundleContext());
+ service = new LuceneIndexProviderService();
+
+ MockOsgi.injectServices(service, context.bundleContext());
+ MockOsgi.activate(service, context.bundleContext(), getDefaultConfig());
+ }
+
+ private Map<String,Object> getDefaultConfig(){
+ Map<String,Object> config = new HashMap<String, Object>();
+ config.put("localIndexDir", folder.getRoot().getAbsolutePath());
+ return config;
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneIndexProviderServiceTest.java
------------------------------------------------------------------------------
svn:eol-style = native