com.xpn.xwiki.plugin.lucene.IndexUpdaterTest.java Source code

Java tutorial

Introduction

Here is the source code for com.xpn.xwiki.plugin.lucene.IndexUpdaterTest.java

Source

/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package com.xpn.xwiki.plugin.lucene;

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Date;
import java.util.concurrent.Semaphore;

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
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.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.util.Version;
import org.jmock.Mock;
import org.jmock.core.Invocation;
import org.jmock.core.stub.CustomStub;
import org.xwiki.model.reference.DocumentReference;

import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.store.XWikiStoreInterface;
import com.xpn.xwiki.test.AbstractBridgedXWikiComponentTestCase;

/**
 * Unit tests for {@link IndexUpdater}.
 * 
 * @version $Id: a301bc67accca1e113041f9677de09314ec310bc $
 */
public class IndexUpdaterTest extends AbstractBridgedXWikiComponentTestCase {
    private final static String INDEXDIR = "target/lucenetest";

    private final Semaphore rebuildDone = new Semaphore(0);

    private final Semaphore writeBlockerWait = new Semaphore(0);

    private final Semaphore writeBlockerAcquiresLock = new Semaphore(0);

    private Mock mockXWiki;

    private Mock mockXWikiStoreInterface;

    private XWikiDocument loremIpsum;

    private class TestIndexRebuilder extends IndexRebuilder {
        TestIndexRebuilder(IndexUpdater indexUpdater, XWikiContext context) {
            super(indexUpdater, context);
        }

        @Override
        protected void runInternal() {
            super.runInternal();

            IndexUpdaterTest.this.rebuildDone.release();
        }
    }

    private class TestIndexUpdater extends IndexUpdater {
        TestIndexUpdater(Directory directory, int indexingInterval, int maxQueueSize, LucenePlugin plugin,
                XWikiContext context) {
            super(directory, indexingInterval, maxQueueSize, plugin, context);
        }

        @Override
        protected void runInternal() {
            if (Thread.currentThread().getName().equals("writerBlocker")) {
                try {
                    IndexWriter writer = openWriter(true);
                    Thread.sleep(5000);
                    writer.close();
                } catch (Exception e) {
                }
            } else if (Thread.currentThread().getName().equals("permanentBlocker")) {
                try {
                    IndexWriter writer = openWriter(false);
                    IndexUpdaterTest.this.writeBlockerAcquiresLock.release();
                    IndexUpdaterTest.this.writeBlockerWait.acquireUninterruptibly();
                    writer.close();
                } catch (Exception e) {
                }
            } else {
                super.runInternal();
            }
        }
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();

        this.loremIpsum = new TestXWikiDocument(new DocumentReference("wiki", "Lorem", "Ipsum"));
        this.loremIpsum.setAuthor("User");
        this.loremIpsum.setCreator("User");
        this.loremIpsum.setDate(new Date(0));
        this.loremIpsum.setCreationDate(new Date(0));
        this.loremIpsum.setTitle("Lorem Ipsum");
        this.loremIpsum.setContent(
                "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
                        + " Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
                        + " Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur."
                        + " Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");

        this.mockXWikiStoreInterface = mock(XWikiStoreInterface.class);
        this.mockXWikiStoreInterface.stubs().method("cleanUp");

        this.mockXWiki = mock(XWiki.class);
        this.mockXWiki.stubs().method("getDocument").with(eq(this.loremIpsum.getDocumentReference()), ANYTHING)
                .will(returnValue(this.loremIpsum));
        this.mockXWiki.stubs().method("Param").with(ANYTHING, ANYTHING)
                .will(new CustomStub("Implements XWiki.Param") {
                    public Object invoke(Invocation invocation) throws Throwable {
                        return invocation.parameterValues.get(1);
                    }
                });
        this.mockXWiki.stubs().method("Param").with(eq(LucenePlugin.PROP_INDEX_DIR))
                .will(returnValue(IndexUpdaterTest.INDEXDIR));
        this.mockXWiki.stubs().method("checkAccess").will(returnValue(true));
        this.mockXWiki.stubs().method("isVirtualMode").will(returnValue(false));
        this.mockXWiki.stubs().method("getStore").will(returnValue(this.mockXWikiStoreInterface.proxy()));
        this.mockXWiki.stubs().method("search").will(returnValue(Collections.EMPTY_LIST));

        getContext().setWiki((XWiki) this.mockXWiki.proxy());
        getContext().setDatabase("wiki");
    }

    public void testCreateIndex() throws IOException {
        File f = new File(INDEXDIR);

        if (!f.exists()) {
            f.mkdirs();
        }

        Directory directory = FSDirectory.open(f);

        LucenePlugin plugin = new LucenePlugin("Monkey", "Monkey", getContext());
        IndexUpdater indexUpdater = new TestIndexUpdater(directory, 100, 1000, plugin, getContext());
        IndexRebuilder indexRebuilder = new TestIndexRebuilder(indexUpdater, getContext());
        indexRebuilder.startRebuildIndex(getContext());

        this.rebuildDone.acquireUninterruptibly();

        assertTrue(IndexReader.indexExists(directory));
    }

    public void testIndexUpdater() throws Exception {
        File f = new File(INDEXDIR);
        Directory directory;
        if (!f.exists()) {
            f.mkdirs();
        }
        directory = FSDirectory.open(f);

        int indexingInterval;
        indexingInterval = 100;
        int maxQueueSize;
        maxQueueSize = 1000;

        LucenePlugin plugin = new LucenePlugin("Monkey", "Monkey", getContext());
        IndexUpdater indexUpdater = new TestIndexUpdater(directory, indexingInterval, maxQueueSize, plugin,
                getContext());
        IndexRebuilder indexRebuilder = new TestIndexRebuilder(indexUpdater, getContext());
        Thread writerBlocker = new Thread(indexUpdater, "writerBlocker");
        writerBlocker.start();
        plugin.init(indexUpdater, indexRebuilder, getContext());

        indexUpdater.cleanIndex();

        Thread indexUpdaterThread = new Thread(indexUpdater, "Lucene Index Updater");
        indexUpdaterThread.start();

        indexUpdater.queueDocument(this.loremIpsum.clone(), getContext(), false);
        indexUpdater.queueDocument(this.loremIpsum.clone(), getContext(), false);

        try {
            Thread.sleep(1000);
            indexUpdater.doExit();
        } catch (InterruptedException e) {
        }
        while (true) {
            try {
                indexUpdaterThread.join();
                break;
            } catch (InterruptedException e) {
            }
        }

        Query q = new TermQuery(new Term(IndexFields.DOCUMENT_ID, "wiki:Lorem.Ipsum.default"));
        IndexSearcher searcher = new IndexSearcher(directory, true);
        TopDocs t = searcher.search(q, null, 10);

        assertEquals(1, t.totalHits);

        SearchResults results = plugin.getSearchResultsFromIndexes("Ipsum", "target/lucenetest", null,
                getContext());

        assertEquals(1, results.getTotalHitcount());
    }

    public void testLock() throws IOException {
        Directory directory;
        File f = new File(INDEXDIR);
        int indexingInterval;
        indexingInterval = 100;
        int maxQueueSize;
        maxQueueSize = 1000;

        if (!f.exists()) {
            f.mkdirs();
        }
        directory = FSDirectory.open(f);

        LucenePlugin plugin = new LucenePlugin("Monkey", "Monkey", getContext());

        final IndexUpdater indexUpdater = new TestIndexUpdater(directory, indexingInterval, maxQueueSize, plugin,
                getContext());

        plugin.init(indexUpdater, getContext());

        Thread permanentBlocker = new Thread(indexUpdater, "permanentBlocker");
        permanentBlocker.start();
        this.writeBlockerAcquiresLock.acquireUninterruptibly();

        assertTrue(IndexWriter.isLocked(indexUpdater.getDirectory()));

        final boolean[] doneCleaningIndex = { false };

        Thread indexCleaner = new Thread(new Runnable() {
            public void run() {
                indexUpdater.cleanIndex();

                doneCleaningIndex[0] = true;
            }
        }, "indexCleaner");

        indexCleaner.start();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
        }

        assertFalse(doneCleaningIndex[0]);

        boolean wasActuallyLocked = false;

        try {
            if (!IndexWriter.isLocked(indexUpdater.getDirectory())) {
                new IndexWriter(indexUpdater.getDirectory(), new StandardAnalyzer(Version.LUCENE_29),
                        MaxFieldLength.LIMITED);
            } else {
                wasActuallyLocked = true;
            }
            // assert(IndexWriter.isLocked(indexUpdater.getDirectory()));
        } catch (LockObtainFailedException e) {
            /*
             * Strange, the isLocked method appears to be unreliable.
             */
            wasActuallyLocked = true;
        }

        assertTrue(wasActuallyLocked);

        this.writeBlockerWait.release();

        while (true) {
            try {
                indexCleaner.join();
                break;
            } catch (InterruptedException e) {
            }
        }

        assertTrue(doneCleaningIndex[0]);

        assertFalse(IndexWriter.isLocked(indexUpdater.getDirectory()));

        IndexWriter w = new IndexWriter(indexUpdater.getDirectory(), new StandardAnalyzer(Version.LUCENE_29),
                MaxFieldLength.LIMITED);
        w.close();
    }
}