You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by sy...@apache.org on 2014/12/31 20:12:17 UTC

[11/14] lucenenet git commit: Moving Lucene.Net.Facet tests to their appropriate place

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/68aa9728/src/Lucene.Net.Tests.Facet/Taxonomy/TestCachedOrdinalsReader.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Facet/Taxonomy/TestCachedOrdinalsReader.cs b/src/Lucene.Net.Tests.Facet/Taxonomy/TestCachedOrdinalsReader.cs
new file mode 100644
index 0000000..d528276
--- /dev/null
+++ b/src/Lucene.Net.Tests.Facet/Taxonomy/TestCachedOrdinalsReader.cs
@@ -0,0 +1,116 @@
+using System;
+using System.IO;
+using System.Threading;
+using Lucene.Net.Support;
+using NUnit.Framework;
+
+namespace Lucene.Net.Facet.Taxonomy
+{
+
+    /*
+     * 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.
+     */
+
+    using MockAnalyzer = Lucene.Net.Analysis.MockAnalyzer;
+    using Document = Lucene.Net.Documents.Document;
+    using DirectoryTaxonomyWriter = Lucene.Net.Facet.Taxonomy.Directory.DirectoryTaxonomyWriter;
+    using AtomicReaderContext = Lucene.Net.Index.AtomicReaderContext;
+    using DirectoryReader = Lucene.Net.Index.DirectoryReader;
+    using IndexWriter = Lucene.Net.Index.IndexWriter;
+    using IndexWriterConfig = Lucene.Net.Index.IndexWriterConfig;
+    using Directory = Lucene.Net.Store.Directory;
+    using IOUtils = Lucene.Net.Util.IOUtils;
+    [TestFixture]
+    public class TestCachedOrdinalsReader : FacetTestCase
+    {
+
+        [Test]
+        public virtual void TestWithThreads()
+        {
+            // LUCENE-5303: OrdinalsCache used the ThreadLocal BinaryDV instead of reader.getCoreCacheKey().
+            Store.Directory indexDir = NewDirectory();
+            Store.Directory taxoDir = NewDirectory();
+            IndexWriterConfig conf = NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random()));
+            IndexWriter writer = new IndexWriter(indexDir, conf);
+            var taxoWriter = new DirectoryTaxonomyWriter(taxoDir);
+            FacetsConfig config = new FacetsConfig();
+
+            Document doc = new Document();
+            doc.Add(new FacetField("A", "1"));
+            writer.AddDocument(config.Build(taxoWriter, doc));
+            doc = new Document();
+            doc.Add(new FacetField("A", "2"));
+            writer.AddDocument(config.Build(taxoWriter, doc));
+
+            var reader = DirectoryReader.Open(writer, true);
+            CachedOrdinalsReader ordsReader = new CachedOrdinalsReader(new DocValuesOrdinalsReader(FacetsConfig.DEFAULT_INDEX_FIELD_NAME));
+            ThreadClass[] threads = new ThreadClass[3];
+            for (int i = 0; i < threads.Length; i++)
+            {
+                threads[i] = new ThreadAnonymousInnerClassHelper(this, "CachedOrdsThread-" + i, reader, ordsReader);
+            }
+
+            long ramBytesUsed = 0;
+            foreach (ThreadClass t in threads)
+            {
+                t.Start();
+                t.Join();
+                if (ramBytesUsed == 0)
+                {
+                    ramBytesUsed = ordsReader.RamBytesUsed();
+                }
+                else
+                {
+                    Assert.AreEqual(ramBytesUsed, ordsReader.RamBytesUsed());
+                }
+            }
+
+            IOUtils.Close(writer, taxoWriter, reader, indexDir, taxoDir);
+        }
+
+        private class ThreadAnonymousInnerClassHelper : ThreadClass
+        {
+            private readonly TestCachedOrdinalsReader outerInstance;
+
+            private DirectoryReader reader;
+            private Lucene.Net.Facet.Taxonomy.CachedOrdinalsReader ordsReader;
+
+            public ThreadAnonymousInnerClassHelper(TestCachedOrdinalsReader outerInstance, string CachedOrdsThread, DirectoryReader reader, Lucene.Net.Facet.Taxonomy.CachedOrdinalsReader ordsReader)
+                : base("CachedOrdsThread-")
+            {
+                this.outerInstance = outerInstance;
+                this.reader = reader;
+                this.ordsReader = ordsReader;
+            }
+
+            public override void Run()
+            {
+                foreach (var context in reader.Leaves)
+                {
+                    try
+                    {
+                        ordsReader.GetReader(context);
+                    }
+                    catch (IOException e)
+                    {
+                        throw new Exception(e.Message, e);
+                    }
+                }
+            }
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/68aa9728/src/Lucene.Net.Tests.Facet/Taxonomy/TestFacetLabel.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Facet/Taxonomy/TestFacetLabel.cs b/src/Lucene.Net.Tests.Facet/Taxonomy/TestFacetLabel.cs
new file mode 100644
index 0000000..0226137
--- /dev/null
+++ b/src/Lucene.Net.Tests.Facet/Taxonomy/TestFacetLabel.cs
@@ -0,0 +1,360 @@
+using System;
+using Lucene.Net.Support;
+using NUnit.Framework;
+
+namespace Lucene.Net.Facet.Taxonomy
+{
+
+    using SortedSetDocValuesFacetField = Lucene.Net.Facet.SortedSet.SortedSetDocValuesFacetField;
+    using BytesRef = Lucene.Net.Util.BytesRef;
+    using TestUtil = Lucene.Net.Util.TestUtil;
+
+    /*
+     * 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.
+     */
+    [TestFixture]
+    public class TestFacetLabel : FacetTestCase
+    {
+
+        [Test]
+        public virtual void TestBasic()
+        {
+            Assert.AreEqual(0, (new FacetLabel()).Length);
+            Assert.AreEqual(1, (new FacetLabel("hello")).Length);
+            Assert.AreEqual(2, (new FacetLabel("hello", "world")).Length);
+        }
+
+        [Test]
+        public virtual void TestToString()
+        {
+            // When the category is empty, we expect an empty string
+            Assert.AreEqual("FacetLabel: []", (new FacetLabel()).ToString());
+            // one category
+            Assert.AreEqual("FacetLabel: [hello]", (new FacetLabel("hello")).ToString());
+            // more than one category
+            Assert.AreEqual("FacetLabel: [hello, world]", (new FacetLabel("hello", "world")).ToString());
+        }
+
+        [Test]
+        public virtual void TestGetComponent()
+        {
+            string[] components = new string[AtLeast(10)];
+            for (int i = 0; i < components.Length; i++)
+            {
+                components[i] = Convert.ToString(i);
+            }
+            FacetLabel cp = new FacetLabel(components);
+            for (int i = 0; i < components.Length; i++)
+            {
+                Assert.AreEqual(i, Convert.ToInt32(cp.Components[i]));
+            }
+        }
+
+        [Test]
+        public virtual void TestDefaultConstructor()
+        {
+            // test that the default constructor (no parameters) currently
+            // defaults to creating an object with a 0 initial capacity.
+            // If we change this default later, we also need to change this
+            // test.
+            FacetLabel p = new FacetLabel();
+            Assert.AreEqual(0, p.Length);
+            Assert.AreEqual("FacetLabel: []", p.ToString());
+        }
+
+        [Test]
+        public virtual void TestSubPath()
+        {
+            FacetLabel p = new FacetLabel("hi", "there", "man");
+            Assert.AreEqual(p.Length, 3);
+
+            FacetLabel p1 = p.Subpath(2);
+            Assert.AreEqual(2, p1.Length);
+            Assert.AreEqual("FacetLabel: [hi, there]", p1.ToString());
+
+            p1 = p.Subpath(1);
+            Assert.AreEqual(1, p1.Length);
+            Assert.AreEqual("FacetLabel: [hi]", p1.ToString());
+
+            p1 = p.Subpath(0);
+            Assert.AreEqual(0, p1.Length);
+            Assert.AreEqual("FacetLabel: []", p1.ToString());
+
+            // with all the following lengths, the prefix should be the whole path 
+            int[] lengths = new int[] { 3, -1, 4 };
+            for (int i = 0; i < lengths.Length; i++)
+            {
+                p1 = p.Subpath(lengths[i]);
+                Assert.AreEqual(3, p1.Length);
+                Assert.AreEqual("FacetLabel: [hi, there, man]", p1.ToString());
+                Assert.AreEqual(p, p1);
+            }
+        }
+
+        [Test]
+        public virtual void TestEquals()
+        {
+            Assert.AreEqual(new FacetLabel(), new FacetLabel());
+            Assert.False((new FacetLabel()).Equals(new FacetLabel("hi")));
+            Assert.False((new FacetLabel()).Equals(Convert.ToInt32(3)));
+            Assert.AreEqual(new FacetLabel("hello", "world"), new FacetLabel("hello", "world"));
+        }
+
+        [Test]
+        public virtual void TestHashCode()
+        {
+            Assert.AreEqual((new FacetLabel()).GetHashCode(), (new FacetLabel()).GetHashCode());
+            Assert.False((new FacetLabel()).GetHashCode() == (new FacetLabel("hi")).GetHashCode());
+            Assert.AreEqual((new FacetLabel("hello", "world")).GetHashCode(), (new FacetLabel("hello", "world")).GetHashCode());
+        }
+
+        [Test]
+        public virtual void TestLongHashCode()
+        {
+            Assert.AreEqual((new FacetLabel()).LongHashCode(), (new FacetLabel()).LongHashCode());
+            Assert.False((new FacetLabel()).LongHashCode() == (new FacetLabel("hi")).LongHashCode());
+            Assert.AreEqual((new FacetLabel("hello", "world")).LongHashCode(), (new FacetLabel("hello", "world")).LongHashCode());
+        }
+
+        [Test]
+        public virtual void TestArrayConstructor()
+        {
+            FacetLabel p = new FacetLabel("hello", "world", "yo");
+            Assert.AreEqual(3, p.Length);
+            Assert.AreEqual("FacetLabel: [hello, world, yo]", p.ToString());
+        }
+
+        [Test]
+        public virtual void TestCompareTo()
+        {
+            FacetLabel p = new FacetLabel("a", "b", "c", "d");
+            FacetLabel pother = new FacetLabel("a", "b", "c", "d");
+            Assert.AreEqual(0, pother.CompareTo(p));
+            Assert.AreEqual(0, p.CompareTo(pother));
+            pother = new FacetLabel();
+            Assert.True(pother.CompareTo(p) < 0);
+            Assert.True(p.CompareTo(pother) > 0);
+            pother = new FacetLabel("a", "b_", "c", "d");
+            Assert.True(pother.CompareTo(p) > 0);
+            Assert.True(p.CompareTo(pother) < 0);
+            pother = new FacetLabel("a", "b", "c");
+            Assert.True(pother.CompareTo(p) < 0);
+            Assert.True(p.CompareTo(pother) > 0);
+            pother = new FacetLabel("a", "b", "c", "e");
+            Assert.True(pother.CompareTo(p) > 0);
+            Assert.True(p.CompareTo(pother) < 0);
+        }
+
+        [Test]
+        public virtual void TestEmptyNullComponents()
+        {
+            // LUCENE-4724: CategoryPath should not allow empty or null components
+            string[][] components_tests = new string[][]
+		{
+			new string[] {"", "test"},
+			new string[] {"test", ""},
+			new string[] {"test", "", "foo"},
+			new string[] {null, "test"},
+			new string[] {"test", null},
+			new string[] {"test", null, "foo"}
+		};
+
+            foreach (string[] components in components_tests)
+            {
+                try
+                {
+                    Assert.NotNull(new FacetLabel(components));
+                    Fail("empty or null components should not be allowed: " + Arrays.ToString(components));
+                }
+                catch (System.ArgumentException)
+                {
+                    // expected
+                }
+                try
+                {
+                    new FacetField("dim", components);
+                    Fail("empty or null components should not be allowed: " + Arrays.ToString(components));
+                }
+                catch (System.ArgumentException)
+                {
+                    // expected
+                }
+                try
+                {
+                    new AssociationFacetField(new BytesRef(), "dim", components);
+                    Fail("empty or null components should not be allowed: " + Arrays.ToString(components));
+                }
+                catch (System.ArgumentException)
+                {
+                    // expected
+                }
+                try
+                {
+                    new IntAssociationFacetField(17, "dim", components);
+                    Fail("empty or null components should not be allowed: " + Arrays.ToString(components));
+                }
+                catch (System.ArgumentException)
+                {
+                    // expected
+                }
+                try
+                {
+                    new FloatAssociationFacetField(17.0f, "dim", components);
+                    Fail("empty or null components should not be allowed: " + Arrays.ToString(components));
+                }
+                catch (System.ArgumentException)
+                {
+                    // expected
+                }
+            }
+            try
+            {
+                new FacetField(null, new string[] { "abc" });
+                Fail("empty or null components should not be allowed");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+            try
+            {
+                new FacetField("", new string[] { "abc" });
+                Fail("empty or null components should not be allowed");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+            try
+            {
+                new IntAssociationFacetField(17, null, new string[] { "abc" });
+                Fail("empty or null components should not be allowed");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+            try
+            {
+                new IntAssociationFacetField(17, "", new string[] { "abc" });
+                Fail("empty or null components should not be allowed");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+            try
+            {
+                new FloatAssociationFacetField(17.0f, null, new string[] { "abc" });
+                Fail("empty or null components should not be allowed");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+            try
+            {
+                new FloatAssociationFacetField(17.0f, "", new string[] { "abc" });
+                Fail("empty or null components should not be allowed");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+            try
+            {
+                new AssociationFacetField(new BytesRef(), null, new string[] { "abc" });
+                Fail("empty or null components should not be allowed");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+            try
+            {
+                new AssociationFacetField(new BytesRef(), "", new string[] { "abc" });
+                Fail("empty or null components should not be allowed");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+            try
+            {
+                new SortedSetDocValuesFacetField(null, "abc");
+                Fail("empty or null components should not be allowed");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+            try
+            {
+                new SortedSetDocValuesFacetField("", "abc");
+                Fail("empty or null components should not be allowed");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+            try
+            {
+                new SortedSetDocValuesFacetField("dim", null);
+                Fail("empty or null components should not be allowed");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+            try
+            {
+                new SortedSetDocValuesFacetField("dim", "");
+                Fail("empty or null components should not be allowed");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+        }
+
+        [Test]
+        public virtual void TestLongPath()
+        {
+            string bigComp = null;
+            while (true)
+            {
+                int len = FacetLabel.MAX_CATEGORY_PATH_LENGTH;
+                bigComp = TestUtil.RandomSimpleString(Random(), len, len);
+                if (bigComp.IndexOf('\u001f') != -1)
+                {
+                    continue;
+                }
+                break;
+            }
+
+            try
+            {
+                Assert.NotNull(new FacetLabel("dim", bigComp));
+                Fail("long paths should not be allowed; len=" + bigComp.Length);
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/68aa9728/src/Lucene.Net.Tests.Facet/Taxonomy/TestLRUHashMap.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Facet/Taxonomy/TestLRUHashMap.cs b/src/Lucene.Net.Tests.Facet/Taxonomy/TestLRUHashMap.cs
new file mode 100644
index 0000000..71b62c5
--- /dev/null
+++ b/src/Lucene.Net.Tests.Facet/Taxonomy/TestLRUHashMap.cs
@@ -0,0 +1,65 @@
+using NUnit.Framework;
+
+namespace Lucene.Net.Facet.Taxonomy
+{
+
+    /*
+     * 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.
+     */
+
+    using Lucene.Net.Facet.Taxonomy;
+    [TestFixture]
+    public class TestLRUHashMap : FacetTestCase
+    {
+        // testLRU() tests that the specified size limit is indeed honored, and
+        // the remaining objects in the map are indeed those that have been most
+        // recently used
+        [Test]
+        public virtual void TestLru()
+        {
+            LRUHashMap<string, string> lru = new LRUHashMap<string, string>(3,1);
+            Assert.AreEqual(0, lru.Size());
+            lru.Put("one", "Hello world");
+            Assert.AreEqual(1, lru.Size());
+            lru.Put("two", "Hi man");
+            Assert.AreEqual(2, lru.Size());
+            lru.Put("three", "Bonjour");
+            Assert.AreEqual(3, lru.Size());
+            lru.Put("four", "Shalom");
+            Assert.AreEqual(3, lru.Size());
+            Assert.NotNull(lru.Get("three"));
+            Assert.NotNull(lru.Get("two"));
+            Assert.NotNull(lru.Get("four"));
+            Assert.Null(lru.Get("one"));
+            lru.Put("five", "Yo!");
+            Assert.AreEqual(3, lru.Size());
+            Assert.Null(lru.Get("three")); // three was last used, so it got removed
+            Assert.NotNull(lru.Get("five"));
+            lru.Get("four");
+            lru.Put("six", "hi");
+            lru.Put("seven", "hey dude");
+            Assert.AreEqual(3, lru.Size());
+            Assert.Null(lru.Get("one"));
+            Assert.Null(lru.Get("two"));
+            Assert.Null(lru.Get("three"));
+            Assert.NotNull(lru.Get("four"));
+            Assert.Null(lru.Get("five"));
+            Assert.NotNull(lru.Get("six"));
+            Assert.NotNull(lru.Get("seven"));
+        }
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/68aa9728/src/Lucene.Net.Tests.Facet/Taxonomy/TestSearcherTaxonomyManager.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Facet/Taxonomy/TestSearcherTaxonomyManager.cs b/src/Lucene.Net.Tests.Facet/Taxonomy/TestSearcherTaxonomyManager.cs
new file mode 100644
index 0000000..dd93d18
--- /dev/null
+++ b/src/Lucene.Net.Tests.Facet/Taxonomy/TestSearcherTaxonomyManager.cs
@@ -0,0 +1,398 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using Apache.NMS;
+using Lucene.Net.Support;
+using NUnit.Framework;
+
+namespace Lucene.Net.Facet.Taxonomy
+{
+
+    /*
+     * 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.
+     */
+
+
+    using MockAnalyzer = Lucene.Net.Analysis.MockAnalyzer;
+    using Document = Lucene.Net.Documents.Document;
+    using SearcherAndTaxonomy = Lucene.Net.Facet.Taxonomy.SearcherTaxonomyManager.SearcherAndTaxonomy;
+    using DirectoryTaxonomyWriter = Lucene.Net.Facet.Taxonomy.Directory.DirectoryTaxonomyWriter;
+    using IndexWriter = Lucene.Net.Index.IndexWriter;
+    using IndexWriterConfig = Lucene.Net.Index.IndexWriterConfig;
+    using TieredMergePolicy = Lucene.Net.Index.TieredMergePolicy;
+    using MatchAllDocsQuery = Lucene.Net.Search.MatchAllDocsQuery;
+    using Lucene.Net.Search;
+    using Directory = Lucene.Net.Store.Directory;
+    using IOUtils = Lucene.Net.Util.IOUtils;
+    using TestUtil = Lucene.Net.Util.TestUtil;
+    [TestFixture]
+    public class TestSearcherTaxonomyManager : FacetTestCase
+    {
+
+        private class IndexerThread : ThreadClass
+        {
+
+            internal IndexWriter w;
+            internal FacetsConfig config;
+            internal TaxonomyWriter tw;
+            internal ReferenceManager<SearcherAndTaxonomy> mgr;
+            internal int ordLimit;
+            internal AtomicBoolean stop;
+
+            public IndexerThread(IndexWriter w, FacetsConfig config, TaxonomyWriter tw, ReferenceManager<SearcherAndTaxonomy> mgr, int ordLimit, AtomicBoolean stop)
+            {
+                this.w = w;
+                this.config = config;
+                this.tw = tw;
+                this.mgr = mgr;
+                this.ordLimit = ordLimit;
+                this.stop = stop;
+            }
+
+            public override void Run()
+            {
+                try
+                {
+                    var seen = new HashSet<string>();
+                    IList<string> paths = new List<string>();
+                    while (true)
+                    {
+                        Document doc = new Document();
+                        int numPaths = TestUtil.NextInt(Random(), 1, 5);
+                        for (int i = 0; i < numPaths; i++)
+                        {
+                            string path;
+                            if (paths.Count > 0 && Random().Next(5) != 4)
+                            {
+                                // Use previous path
+                                path = paths[Random().Next(paths.Count)];
+                            }
+                            else
+                            {
+                                // Create new path
+                                path = null;
+                                while (true)
+                                {
+                                    path = TestUtil.RandomRealisticUnicodeString(Random());
+                                    if (path.Length != 0 && !seen.Contains(path))
+                                    {
+                                        seen.Add(path);
+                                        paths.Add(path);
+                                        break;
+                                    }
+                                }
+                            }
+                            doc.Add(new FacetField("field", path));
+                        }
+                        try
+                        {
+                            w.AddDocument(config.Build(tw, doc));
+                            if (mgr != null && Random().NextDouble() < 0.02)
+                            {
+                                w.Commit();
+                                tw.Commit();
+                                mgr.MaybeRefresh();
+                            }
+                        }
+                        catch (IOException ioe)
+                        {
+                            throw new Exception(ioe.Message, ioe);
+                        }
+
+                        if (VERBOSE)
+                        {
+                            Console.WriteLine("TW size=" + tw.Size + " vs " + ordLimit);
+                        }
+
+                        if (tw.Size >= ordLimit)
+                        {
+                            break;
+                        }
+                    }
+                }
+                finally
+                {
+                    stop.Set(true);
+                }
+            }
+
+        }
+
+        [Test]
+        public virtual void TestNrt()
+        {
+            Store.Directory dir = NewDirectory();
+            Store.Directory taxoDir = NewDirectory();
+            IndexWriterConfig iwc = NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random()));
+            // Don't allow tiny maxBufferedDocs; it can make this
+            // test too slow:
+            iwc.SetMaxBufferedDocs(Math.Max(500, iwc.MaxBufferedDocs));
+
+            // MockRandom/AlcololicMergePolicy are too slow:
+            TieredMergePolicy tmp = new TieredMergePolicy();
+            tmp.FloorSegmentMB = .001;
+            iwc.SetMergePolicy(tmp);
+            IndexWriter w = new IndexWriter(dir, iwc);
+            var tw = new DirectoryTaxonomyWriter(taxoDir);
+            FacetsConfig config = new FacetsConfig();
+            config.SetMultiValued("field", true);
+            AtomicBoolean stop = new AtomicBoolean();
+
+            // How many unique facets to index before stopping:
+            int ordLimit = TEST_NIGHTLY ? 100000 : 6000;
+
+            var indexer = new IndexerThread(w, config, tw, null, ordLimit, stop);
+
+            var mgr = new SearcherTaxonomyManager(w, true, null, tw);
+
+            var reopener = new ThreadAnonymousInnerClassHelper(this, stop, mgr);
+
+            reopener.Name = "reopener";
+            reopener.Start();
+
+            indexer.Name = "indexer";
+            indexer.Start();
+
+            try
+            {
+                while (!stop.Get())
+                {
+                    SearcherAndTaxonomy pair = mgr.Acquire();
+                    try
+                    {
+                        //System.out.println("search maxOrd=" + pair.taxonomyReader.getSize());
+                        FacetsCollector sfc = new FacetsCollector();
+                        pair.searcher.Search(new MatchAllDocsQuery(), sfc);
+                        Facets facets = GetTaxonomyFacetCounts(pair.taxonomyReader, config, sfc);
+                        FacetResult result = facets.GetTopChildren(10, "field");
+                        if (pair.searcher.IndexReader.NumDocs > 0)
+                        {
+                            //System.out.println(pair.taxonomyReader.getSize());
+                            Assert.True(result.ChildCount > 0);
+                            Assert.True(result.LabelValues.Length > 0);
+                        }
+
+                        //if (VERBOSE) {
+                        //System.out.println("TEST: facets=" + FacetTestUtils.toString(results.get(0)));
+                        //}
+                    }
+                    finally
+                    {
+                        mgr.Release(pair);
+                    }
+                }
+            }
+            finally
+            {
+                indexer.Join();
+                reopener.Join();
+            }
+
+            if (VERBOSE)
+            {
+                Console.WriteLine("TEST: now stop");
+            }
+
+            IOUtils.Close(mgr, tw, w, taxoDir, dir);
+        }
+
+        private class ThreadAnonymousInnerClassHelper : ThreadClass
+        {
+            private readonly TestSearcherTaxonomyManager outerInstance;
+
+            private AtomicBoolean stop;
+            private Lucene.Net.Facet.Taxonomy.SearcherTaxonomyManager mgr;
+
+            public ThreadAnonymousInnerClassHelper(TestSearcherTaxonomyManager outerInstance, AtomicBoolean stop, Lucene.Net.Facet.Taxonomy.SearcherTaxonomyManager mgr)
+            {
+                this.outerInstance = outerInstance;
+                this.stop = stop;
+                this.mgr = mgr;
+            }
+
+            public override void Run()
+            {
+                while (!stop.Get())
+                {
+                    try
+                    {
+                        // Sleep for up to 20 msec:
+                        Thread.Sleep(Random().Next(20));
+
+                        if (VERBOSE)
+                        {
+                            Console.WriteLine("TEST: reopen");
+                        }
+
+                        mgr.MaybeRefresh();
+
+                        if (VERBOSE)
+                        {
+                            Console.WriteLine("TEST: reopen done");
+                        }
+                    }
+                    catch (Exception ioe)
+                    {
+                        throw new Exception(ioe.Message, ioe);
+                    }
+                }
+            }
+        }
+
+        
+        [Test]
+        public virtual void TestDirectory()
+        {
+            Store.Directory indexDir = NewDirectory();
+            Store.Directory taxoDir = NewDirectory();
+            IndexWriter w = new IndexWriter(indexDir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random())));
+            var tw = new DirectoryTaxonomyWriter(taxoDir);
+            // first empty commit
+            w.Commit();
+            tw.Commit();
+            var mgr = new SearcherTaxonomyManager(indexDir, taxoDir, null);
+            FacetsConfig config = new FacetsConfig();
+            config.SetMultiValued("field", true);
+            AtomicBoolean stop = new AtomicBoolean();
+
+            // How many unique facets to index before stopping:
+            int ordLimit = TEST_NIGHTLY ? 100000 : 6000;
+
+            var indexer = new IndexerThread(w, config, tw, mgr, ordLimit, stop);
+            indexer.Start();
+
+            try
+            {
+                while (!stop.Get())
+                {
+                    SearcherAndTaxonomy pair = mgr.Acquire();
+                    try
+                    {
+                        //System.out.println("search maxOrd=" + pair.taxonomyReader.getSize());
+                        FacetsCollector sfc = new FacetsCollector();
+                        pair.searcher.Search(new MatchAllDocsQuery(), sfc);
+                        Facets facets = GetTaxonomyFacetCounts(pair.taxonomyReader, config, sfc);
+                        FacetResult result = facets.GetTopChildren(10, "field");
+                        if (pair.searcher.IndexReader.NumDocs > 0)
+                        {
+                            //System.out.println(pair.taxonomyReader.getSize());
+                            Assert.True(result.ChildCount > 0);
+                            Assert.True(result.LabelValues.Length > 0);
+                        }
+
+                        //if (VERBOSE) {
+                        //System.out.println("TEST: facets=" + FacetTestUtils.toString(results.get(0)));
+                        //}
+                    }
+                    finally
+                    {
+                        mgr.Release(pair);
+                    }
+                }
+            }
+            finally
+            {
+                indexer.Join();
+            }
+
+            if (VERBOSE)
+            {
+                Console.WriteLine("TEST: now stop");
+            }
+
+            IOUtils.Close(mgr, tw, w, taxoDir, indexDir);
+        }
+
+        [Test]
+        public virtual void TestReplaceTaxonomyNrt()
+        {
+            Store.Directory dir = NewDirectory();
+            Store.Directory taxoDir = NewDirectory();
+            IndexWriter w = new IndexWriter(dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random())));
+            var tw = new DirectoryTaxonomyWriter(taxoDir);
+
+            Store.Directory taxoDir2 = NewDirectory();
+            var tw2 = new DirectoryTaxonomyWriter(taxoDir2);
+            tw2.Dispose();
+
+            var mgr = new SearcherTaxonomyManager(w, true, null, tw);
+            w.AddDocument(new Document());
+            tw.ReplaceTaxonomy(taxoDir2);
+            taxoDir2.Dispose();
+
+            try
+            {
+                mgr.MaybeRefresh();
+                Fail("should have hit exception");
+            }
+            catch (IllegalStateException)
+            {
+                // expected
+            }
+
+            IOUtils.Close(mgr, tw, w, taxoDir, dir);
+        }
+
+        [Test]
+        public virtual void TestReplaceTaxonomyDirectory()
+        {
+            Store.Directory indexDir = NewDirectory();
+            Store.Directory taxoDir = NewDirectory();
+            IndexWriter w = new IndexWriter(indexDir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random())));
+            var tw = new DirectoryTaxonomyWriter(taxoDir);
+            w.Commit();
+            tw.Commit();
+
+            Store.Directory taxoDir2 = NewDirectory();
+            var tw2 = new DirectoryTaxonomyWriter(taxoDir2);
+            tw2.AddCategory(new FacetLabel("a", "b"));
+            tw2.Dispose();
+
+            var mgr = new SearcherTaxonomyManager(indexDir, taxoDir, null);
+            SearcherAndTaxonomy pair = mgr.Acquire();
+            try
+            {
+                Assert.AreEqual(1, pair.taxonomyReader.Size);
+            }
+            finally
+            {
+                mgr.Release(pair);
+            }
+
+            w.AddDocument(new Document());
+            tw.ReplaceTaxonomy(taxoDir2);
+            taxoDir2.Dispose();
+            w.Commit();
+            tw.Commit();
+
+            mgr.MaybeRefresh();
+            pair = mgr.Acquire();
+            try
+            {
+                Assert.AreEqual(3, pair.taxonomyReader.Size);
+            }
+            finally
+            {
+                mgr.Release(pair);
+            }
+
+            IOUtils.Close(mgr, tw, w, taxoDir, indexDir);
+        }
+
+    }
+
+}
\ No newline at end of file