GEODE-11: Added test for lucene index cluster configuration support. As part of this added new test rule "LocatorServerConfigurationRule" that will help to setup locators and servers/peers to configure using test properties.
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/79620807 Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/79620807 Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/79620807 Branch: refs/heads/feature/GEODE-420 Commit: 79620807bfded3e6f178a1062cd925ec38959981 Parents: da29fb3 Author: Anil <[email protected]> Authored: Thu Aug 18 18:00:11 2016 -0700 Committer: Anil <[email protected]> Committed: Thu Aug 18 18:00:32 2016 -0700 ---------------------------------------------------------------------- .../rules/LocatorServerConfigurationRule.java | 149 ++++++++ .../LuceneClusterConfigurationDUnitTest.java | 361 +++++++++++++++++++ 2 files changed, 510 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/79620807/geode-core/src/test/java/com/gemstone/gemfire/test/dunit/rules/LocatorServerConfigurationRule.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/com/gemstone/gemfire/test/dunit/rules/LocatorServerConfigurationRule.java b/geode-core/src/test/java/com/gemstone/gemfire/test/dunit/rules/LocatorServerConfigurationRule.java new file mode 100644 index 0000000..3855412 --- /dev/null +++ b/geode-core/src/test/java/com/gemstone/gemfire/test/dunit/rules/LocatorServerConfigurationRule.java @@ -0,0 +1,149 @@ +/* + * 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 com.gemstone.gemfire.test.dunit.rules; + +import static com.gemstone.gemfire.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION; +import static com.gemstone.gemfire.distributed.ConfigurationProperties.LOCATORS; +import static com.gemstone.gemfire.distributed.ConfigurationProperties.MCAST_PORT; +import static com.gemstone.gemfire.internal.AvailablePortHelper.getRandomAvailableTCPPorts; +import static com.gemstone.gemfire.test.dunit.Host.getHost; +import static com.gemstone.gemfire.test.dunit.internal.JUnit4DistributedTestCase.disconnectAllFromDS; +import static com.gemstone.gemfire.test.dunit.internal.JUnit4DistributedTestCase.disconnectFromDS; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.io.Serializable; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +import org.junit.rules.ExternalResource; + +import com.gemstone.gemfire.distributed.Locator; +import com.gemstone.gemfire.distributed.internal.InternalLocator; +import com.gemstone.gemfire.test.dunit.Host; +import com.gemstone.gemfire.test.dunit.VM; +import com.gemstone.gemfire.test.dunit.cache.internal.JUnit4CacheTestCase; +import com.jayway.awaitility.Awaitility; + + +public class LocatorServerConfigurationRule extends ExternalResource implements + Serializable { + + private int locatorPort = 0; + + private boolean locatorInitialized = false; + + private JUnit4CacheTestCase testCase; + + public LocatorServerConfigurationRule(JUnit4CacheTestCase testCase) { + this.testCase = testCase; + } + + Host host = getHost(0); + VM locator = host.getVM(0); + + @Override + protected void before() { + // Add initialization requirement if any. + disconnectAllFromDS(); + } + + @Override + protected void after() { + disconnectAllFromDS(); + } + + + /** + * Returns getHost(0).getVM(0) as a locator instance with the given + * configuration properties. + * + * @param locatorProperties + * @return VM locator vm + * @throws IOException + */ + public VM getLocatorVM(Properties locatorProperties) throws IOException { + initLocator(locatorProperties); + this.locatorInitialized = true; + return locator; + } + + /** + * Returns a node VM with given configuration properties. + * + * @param index + * valid 1 to 3 (returns getHist(0).getVM(index) + * @param nodeProperties + * @return VM node vm + */ + public VM getNodeVM(int index, Properties nodeProperties) { + assertTrue("Locator not initialized. Initialize locator by calling getLocatorVM()", this.locatorInitialized); + assertTrue("VM with index 0 is used for locator service.", (index != 0)); + VM nodeVM = host.getVM(index); + initNode(nodeVM, nodeProperties); + return nodeVM; + } + + private void initLocator(Properties locatorProperties) throws IOException { + final int[] ports = getRandomAvailableTCPPorts(1); + locatorPort = ports[0]; + + if (!locatorProperties.containsKey(MCAST_PORT)) { + locatorProperties.setProperty(MCAST_PORT, "0"); + } + + locatorPort = locator.invoke(() -> { + InternalLocator locator = (InternalLocator)Locator.startLocatorAndDS(0, + null, locatorProperties); + locatorPort = locator.getPort(); + locator.resetInternalLocatorFileNamesWithCorrectPortNumber(locatorPort); + + if (locatorProperties.containsKey(ENABLE_CLUSTER_CONFIGURATION)) { + Awaitility.await().atMost(65, TimeUnit.SECONDS) + .until(() -> assertTrue(locator.isSharedConfigurationRunning())); + } + return locatorPort; + }); + } + + private void initNode(VM nodeVM, Properties props) { + if (!props.containsKey(MCAST_PORT)) { + props.setProperty(MCAST_PORT, "0"); + } + + props.setProperty(LOCATORS, getHostName() + ":" + locatorPort); + + nodeVM.invoke(() -> { + testCase.getSystem(props); + assertNotNull(testCase.getCache()); + }); + } + + private String getHostName() { + try { + return InetAddress.getLocalHost().getHostName(); + } + catch (UnknownHostException ignore) { + return "localhost"; + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/79620807/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/configuration/LuceneClusterConfigurationDUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/configuration/LuceneClusterConfigurationDUnitTest.java b/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/configuration/LuceneClusterConfigurationDUnitTest.java new file mode 100755 index 0000000..27e1587 --- /dev/null +++ b/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/configuration/LuceneClusterConfigurationDUnitTest.java @@ -0,0 +1,361 @@ +/* + * 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 com.gemstone.gemfire.cache.lucene.internal.configuration; + +import static com.gemstone.gemfire.cache.lucene.test.LuceneTestUtilities.INDEX_NAME; +import static com.gemstone.gemfire.cache.lucene.test.LuceneTestUtilities.REGION_NAME; +import static com.gemstone.gemfire.distributed.ConfigurationProperties.CLUSTER_CONFIGURATION_DIR; +import static com.gemstone.gemfire.distributed.ConfigurationProperties.DEPLOY_WORKING_DIR; +import static com.gemstone.gemfire.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION; +import static com.gemstone.gemfire.distributed.ConfigurationProperties.GROUPS; +import static com.gemstone.gemfire.distributed.ConfigurationProperties.HTTP_SERVICE_PORT; +import static com.gemstone.gemfire.distributed.ConfigurationProperties.JMX_MANAGER; +import static com.gemstone.gemfire.distributed.ConfigurationProperties.JMX_MANAGER_BIND_ADDRESS; +import static com.gemstone.gemfire.distributed.ConfigurationProperties.JMX_MANAGER_PORT; +import static com.gemstone.gemfire.distributed.ConfigurationProperties.JMX_MANAGER_START; +import static com.gemstone.gemfire.distributed.ConfigurationProperties.USE_CLUSTER_CONFIGURATION; +import static com.gemstone.gemfire.internal.AvailablePortHelper.getRandomAvailableTCPPorts; +import static org.junit.Assert.assertArrayEquals; +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 java.io.File; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.Map; +import java.util.Properties; + +import org.apache.lucene.analysis.Analyzer; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import com.gemstone.gemfire.cache.RegionShortcut; +import com.gemstone.gemfire.cache.lucene.LuceneIndex; +import com.gemstone.gemfire.cache.lucene.LuceneService; +import com.gemstone.gemfire.cache.lucene.LuceneServiceProvider; +import com.gemstone.gemfire.cache.lucene.internal.cli.LuceneCliStrings; +import com.gemstone.gemfire.cache.lucene.internal.cli.LuceneIndexCommands; +import com.gemstone.gemfire.management.cli.Result.Status; +import com.gemstone.gemfire.management.internal.cli.CommandManager; +import com.gemstone.gemfire.management.internal.cli.HeadlessGfsh; +import com.gemstone.gemfire.management.internal.cli.commands.CliCommandTestBase; +import com.gemstone.gemfire.management.internal.cli.i18n.CliStrings; +import com.gemstone.gemfire.management.internal.cli.result.CommandResult; +import com.gemstone.gemfire.management.internal.cli.util.CommandStringBuilder; +import com.gemstone.gemfire.test.dunit.VM; +import com.gemstone.gemfire.test.dunit.rules.LocatorServerConfigurationRule; +import com.gemstone.gemfire.test.junit.categories.DistributedTest; + + +@Category(DistributedTest.class) +public class LuceneClusterConfigurationDUnitTest extends CliCommandTestBase { + + private String groupName = "Lucene"; + + @Rule + public LocatorServerConfigurationRule ls = new LocatorServerConfigurationRule( + this); + + @Test + public void indexGetsCreatedUsingClusterConfiguration() + throws Exception { + VM locator = startLocatorWithClusterConfigurationEnabled(); + VM vm1 = startNodeUsingClusterConfiguration(1, false); + + // Connect Gfsh to locator. + createAndConnectGfshToLocator(); + + // Create lucene index. + createLuceneIndexUsingGfsh(false); + + createRegionUsingGfsh(REGION_NAME, RegionShortcut.PARTITION, null); + + // Start vm2. This should have lucene index created using cluster + // configuration. + VM vm2 = startNodeUsingClusterConfiguration(2, false); + vm2.invoke(() -> { + LuceneService luceneService = LuceneServiceProvider.get(getCache()); + final LuceneIndex index = luceneService.getIndex(INDEX_NAME, REGION_NAME); + assertNotNull(index); + validateIndexFields(new String[] { "field1", "field2", "field3" }, index); + }); + } + + @Test + public void indexWithAnalyzerGetsCreatedUsingClusterConfiguration() + throws Exception { + VM locator = startLocatorWithClusterConfigurationEnabled(); + VM vm1 = startNodeUsingClusterConfiguration(1, false); + + // Connect Gfsh to locator. + createAndConnectGfshToLocator(); + + // Create lucene index. + // createLuceneIndexUsingGfsh(false); + createLuceneIndexWithAnalyzerUsingGfsh(false); + + createRegionUsingGfsh(REGION_NAME, RegionShortcut.PARTITION, null); + + // Start vm2. This should have lucene index created using cluster + // configuration. + VM vm2 = startNodeUsingClusterConfiguration(2, false); + vm2.invoke(() -> { + LuceneService luceneService = LuceneServiceProvider.get(getCache()); + final LuceneIndex index = luceneService.getIndex(INDEX_NAME, REGION_NAME); + assertNotNull(index); + String[] fields = new String[] { "field1", "field2", "field3" }; + validateIndexFields(fields, index); + // Add this check back when we complete xml generation for analyzer. + this.validateIndexFieldAnalyzer(fields, new String[] { + "org.apache.lucene.analysis.standard.StandardAnalyzer", + "org.apache.lucene.analysis.standard.StandardAnalyzer", + "org.apache.lucene.analysis.standard.StandardAnalyzer" }, index); + }); + } + + @Test + public void indexGetsCreatedOnGroupOfNodes() throws Exception { + VM locator = startLocatorWithClusterConfigurationEnabled(); + + // Start vm1, vm2 in group + VM vm1 = startNodeUsingClusterConfiguration(1, true); + VM vm2 = startNodeUsingClusterConfiguration(2, true); + + // Start vm3 outside the group. The Lucene index should not be present here. + VM vm3 = startNodeUsingClusterConfiguration(3, true); + + // Connect Gfsh to locator. + createAndConnectGfshToLocator(); + + // Create lucene index on group. + createLuceneIndexUsingGfsh(true); + + // Create region. + createRegionUsingGfsh(REGION_NAME, RegionShortcut.PARTITION, groupName); + + // VM2 should have lucene index created using gfsh execution. + vm2.invoke(() -> { + LuceneService luceneService = LuceneServiceProvider.get(getCache()); + final LuceneIndex index = luceneService.getIndex(INDEX_NAME, REGION_NAME); + assertNotNull(index); + validateIndexFields(new String[] { "field1", "field2", "field3" }, index); + }); + + // The Lucene index is present in vm3. + vm3.invoke(() -> { + LuceneService luceneService = LuceneServiceProvider.get(getCache()); + final LuceneIndex index = luceneService.getIndex(INDEX_NAME, REGION_NAME); + assertNotNull(index); + }); + } + + @Test + public void indexNotCreatedOnNodeOutSideTheGroup() + throws Exception { + VM locator = startLocatorWithClusterConfigurationEnabled(); + + // Start vm1, vm2 in group + VM vm1 = startNodeUsingClusterConfiguration(1, true); + VM vm2 = startNodeUsingClusterConfiguration(2, true); + + // Start vm3 outside the group. The Lucene index should not be present here. + VM vm3 = startNodeUsingClusterConfiguration(3, false); + + // Connect Gfsh to locator. + createAndConnectGfshToLocator(); + + // Create lucene index on group. + createLuceneIndexUsingGfsh(true); + + // Create region. + createRegionUsingGfsh(REGION_NAME, RegionShortcut.PARTITION, groupName); + + // VM2 should have lucene index created using gfsh execution + vm2.invoke(() -> { + LuceneService luceneService = LuceneServiceProvider.get(getCache()); + final LuceneIndex index = luceneService.getIndex(INDEX_NAME, REGION_NAME); + assertNotNull(index); + validateIndexFields(new String[] { "field1", "field2", "field3" }, index); + }); + + // The Lucene index should not be present in vm3. + vm3.invoke(() -> { + LuceneService luceneService = LuceneServiceProvider.get(getCache()); + final LuceneIndex index = luceneService.getIndex(INDEX_NAME, REGION_NAME); + assertNull(index); + }); + } + + @Test + public void indexAreCreatedInValidGroupOfNodesJoiningLater() + throws Exception { + VM locator = startLocatorWithClusterConfigurationEnabled(); + + // Start vm1 in group + VM vm1 = startNodeUsingClusterConfiguration(1, true); + // Connect Gfsh to locator. + createAndConnectGfshToLocator(); + + // Create lucene index on group. + createLuceneIndexUsingGfsh(true); + + createRegionUsingGfsh(REGION_NAME, RegionShortcut.PARTITION, groupName); + + // Start vm2 in group + VM vm2 = startNodeUsingClusterConfiguration(2, true); + + // Start vm3 outside the group. The Lucene index should not be present here. + VM vm3 = startNodeUsingClusterConfiguration(3, false); + + // VM2 should have lucene index created using gfsh execution + vm2.invoke(() -> { + LuceneService luceneService = LuceneServiceProvider.get(getCache()); + final LuceneIndex index = luceneService.getIndex(INDEX_NAME, REGION_NAME); + assertNotNull(index); + validateIndexFields(new String[] { "field1", "field2", "field3" }, index); + }); + + // The Lucene index should not be present in vm3. + vm3.invoke(() -> { + LuceneService luceneService = LuceneServiceProvider.get(getCache()); + final LuceneIndex index = luceneService.getIndex(INDEX_NAME, REGION_NAME); + assertNull(index); + }); + } + + private void createAndConnectGfshToLocator() { + HeadlessGfsh gfsh = getDefaultShell(); + connect(jmxHost, jmxPort, httpPort, gfsh); + } + + private VM startNodeUsingClusterConfiguration(int vmIndex, boolean addGroup) + throws Exception { + File dir = this.temporaryFolder.newFolder(); + Properties nodeProperties = new Properties(); + nodeProperties.setProperty(USE_CLUSTER_CONFIGURATION, "true"); + nodeProperties.setProperty(DEPLOY_WORKING_DIR, + dir.getCanonicalPath()); + if (addGroup) { + nodeProperties.setProperty(GROUPS, groupName); + } + return ls.getNodeVM(vmIndex, nodeProperties); + } + + private VM startLocatorWithClusterConfigurationEnabled() throws Exception { + try { + jmxHost = InetAddress.getLocalHost().getHostName(); + } + catch (UnknownHostException ignore) { + jmxHost = "localhost"; + } + + File dir = this.temporaryFolder.newFolder(); + + final int[] ports = getRandomAvailableTCPPorts(2); + jmxPort = ports[0]; + httpPort = ports[1]; + + Properties locatorProps = new Properties(); + locatorProps.setProperty(ENABLE_CLUSTER_CONFIGURATION, "true"); + locatorProps.setProperty(JMX_MANAGER, "true"); + locatorProps.setProperty(JMX_MANAGER_START, "true"); + locatorProps.setProperty(JMX_MANAGER_BIND_ADDRESS, String.valueOf(jmxHost)); + locatorProps.setProperty(JMX_MANAGER_PORT, String.valueOf(jmxPort)); + locatorProps.setProperty(HTTP_SERVICE_PORT, String.valueOf(httpPort)); + locatorProps.setProperty(CLUSTER_CONFIGURATION_DIR, + dir.getCanonicalPath()); + return ls.getLocatorVM(locatorProps); + } + + private void createLuceneIndexUsingGfsh(boolean addGroup) throws Exception { + // Execute Gfsh command to create lucene index. + CommandManager.getInstance().add(LuceneIndexCommands.class.newInstance()); + CommandStringBuilder csb = new CommandStringBuilder( + LuceneCliStrings.LUCENE_CREATE_INDEX); + csb.addOption(LuceneCliStrings.LUCENE__INDEX_NAME, INDEX_NAME); + csb.addOption(LuceneCliStrings.LUCENE__REGION_PATH, REGION_NAME); + if (addGroup) { + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__GROUP, groupName); + } + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__FIELD, + "field1,field2,field3"); + executeCommand(csb.toString()); + } + + private void createLuceneIndexWithAnalyzerUsingGfsh(boolean addGroup) + throws Exception { + // Gfsh command to create lucene index. + CommandManager.getInstance().add(LuceneIndexCommands.class.newInstance()); + CommandStringBuilder csb = new CommandStringBuilder( + LuceneCliStrings.LUCENE_CREATE_INDEX); + csb.addOption(LuceneCliStrings.LUCENE__INDEX_NAME, INDEX_NAME); + csb.addOption(LuceneCliStrings.LUCENE__REGION_PATH, REGION_NAME); + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__FIELD, + "field1,field2,field3"); + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__ANALYZER, + "org.apache.lucene.analysis.standard.StandardAnalyzer," + + "org.apache.lucene.analysis.standard.StandardAnalyzer," + + "org.apache.lucene.analysis.standard.StandardAnalyzer"); + + if (addGroup) { + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__GROUP, groupName); + } + // Execute Gfsh command. + executeCommand(csb.toString()); + } + + private void createRegionUsingGfsh(String regionName, + RegionShortcut regionShortCut, String group) { + CommandStringBuilder csb = new CommandStringBuilder( + CliStrings.CREATE_REGION); + csb.addOption(CliStrings.CREATE_REGION__REGION, regionName); + csb.addOption(CliStrings.CREATE_REGION__REGIONSHORTCUT, + regionShortCut.name()); + csb.addOptionWithValueCheck(CliStrings.CREATE_REGION__GROUP, group); + executeAndVerifyCommand(csb.toString()); + } + + private void executeAndVerifyCommand(String commandString) { + CommandResult cmdResult = executeCommand(commandString); + com.gemstone.gemfire.test.dunit.LogWriterUtils.getLogWriter().info( + "Command : " + commandString); + com.gemstone.gemfire.test.dunit.LogWriterUtils.getLogWriter().info( + "Command Result : " + commandResultToString(cmdResult)); + assertEquals(Status.OK, cmdResult.getStatus()); + } + + private void validateIndexFields(String[] indexFields, LuceneIndex index) { + String[] indexFieldNames = index.getFieldNames(); + Arrays.sort(indexFieldNames); + assertArrayEquals(indexFields, indexFieldNames); + } + + private void validateIndexFieldAnalyzer(String[] fields, String[] analyzers, + LuceneIndex index) { + Map<String, Analyzer> indexfieldAnalyzers = index.getFieldAnalyzers(); + for (int i = 0; i < fields.length; i++) { + Analyzer a = indexfieldAnalyzers.get(fields[i]); + System.out.println("#### Analyzer name :" + a.getClass().getName()); + assertEquals(analyzers[i], a.getClass().getName()); + } + } + +}
