/* * 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.geode.management.internal.cli.commands; import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION; import static org.apache.geode.distributed.ConfigurationProperties.GROUPS; import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT; import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER; import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_BIND_ADDRESS; import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT; import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START; import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL; import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT; import static org.apache.geode.distributed.ConfigurationProperties.NAME; import static org.apache.geode.distributed.ConfigurationProperties.USE_CLUSTER_CONFIGURATION; import static org.apache.geode.test.dunit.Assert.assertEquals; import static org.apache.geode.test.dunit.Assert.assertFalse; import static org.apache.geode.test.dunit.Assert.assertNotNull; import static org.apache.geode.test.dunit.Assert.assertTrue; import static org.apache.geode.test.dunit.Assert.fail; import static org.apache.geode.test.dunit.LogWriterUtils.getLogWriter; import static org.apache.geode.test.dunit.Wait.waitForCriterion; import org.apache.geode.cache.Cache; import org.apache.geode.cache.asyncqueue.AsyncEventQueue; import org.apache.geode.distributed.Locator; import org.apache.geode.distributed.internal.InternalLocator; import org.apache.geode.distributed.internal.ClusterConfigurationService; import org.apache.geode.internal.AvailablePort; import org.apache.geode.internal.AvailablePortHelper; import org.apache.geode.internal.ClassBuilder; import org.apache.geode.internal.FileUtil; import org.apache.geode.management.cli.Result; import org.apache.geode.management.internal.cli.i18n.CliStrings; import org.apache.geode.management.internal.cli.result.CommandResult; import org.apache.geode.management.internal.cli.util.CommandStringBuilder; import org.apache.geode.test.dunit.Host; import org.apache.geode.test.dunit.SerializableRunnable; import org.apache.geode.test.dunit.VM; import org.apache.geode.test.dunit.WaitCriterion; import org.apache.geode.test.junit.categories.DistributedTest; import org.apache.geode.test.junit.categories.FlakyTest; import org.junit.Test; import org.junit.experimental.categories.Category; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.List; import java.util.Properties; import java.util.concurrent.CopyOnWriteArrayList; /** * A distributed test suite of test cases for testing the queue commands that are part of Gfsh. * * @since GemFire 8.0 */ @Category(DistributedTest.class) public class QueueCommandsDUnitTest extends CliCommandTestBase { private static final long serialVersionUID = 1L; final List<String> filesToBeDeleted = new CopyOnWriteArrayList<String>(); @Override public final void preSetUp() throws Exception { disconnectAllFromDS(); } @Category(FlakyTest.class) // GEODE-1429 @Test public void testAsyncEventQueue() throws IOException { final String queue1Name = "testAsyncEventQueue1"; final String queue2Name = "testAsyncEventQueue2"; final String diskStoreName = "testAsyncEventQueueDiskStore"; Properties localProps = new Properties(); localProps.setProperty(GROUPS, "Group0"); setUpJmxManagerOnVm0ThenConnect(localProps); CommandResult cmdResult = executeCommand(CliStrings.LIST_ASYNC_EVENT_QUEUES); assertEquals(Result.Status.OK, cmdResult.getStatus()); assertTrue(commandResultToString(cmdResult).contains("No Async Event Queues Found")); final VM vm1 = Host.getHost(0).getVM(1); final String vm1Name = "VM" + vm1.getPid(); final File diskStoreDir = new File(new File(".").getAbsolutePath(), diskStoreName); this.filesToBeDeleted.add(diskStoreDir.getAbsolutePath()); vm1.invoke(new SerializableRunnable() { public void run() { diskStoreDir.mkdirs(); Properties localProps = new Properties(); localProps.setProperty(NAME, vm1Name); localProps.setProperty(GROUPS, "Group1"); getSystem(localProps); getCache(); } }); final VM vm2 = Host.getHost(0).getVM(2); final String vm2Name = "VM" + vm2.getPid(); vm2.invoke(new SerializableRunnable() { public void run() { Properties localProps = new Properties(); localProps.setProperty(NAME, vm2Name); localProps.setProperty(GROUPS, "Group2"); getSystem(localProps); getCache(); } }); // Deploy a JAR file with an // AsyncEventListener/GatewayEventFilter/GatewayEventSubstitutionFilter // that can be instantiated on each server final File jarFile = new File(new File(".").getAbsolutePath(), "QueueCommandsDUnit.jar"); QueueCommandsDUnitTest.this.filesToBeDeleted.add(jarFile.getAbsolutePath()); ClassBuilder classBuilder = new ClassBuilder(); byte[] jarBytes = classBuilder.createJarFromClassContent("com/qcdunit/QueueCommandsDUnitTestHelper", "package com.qcdunit;" + "import java.util.List; import java.util.Properties;" + "import org.apache.geode.internal.cache.xmlcache.Declarable2; import org.apache.geode.cache.asyncqueue.AsyncEvent;" + "import org.apache.geode.cache.wan.GatewayEventFilter; import org.apache.geode.cache.wan.GatewayEventSubstitutionFilter;" + "import org.apache.geode.cache.asyncqueue.AsyncEventListener; import org.apache.geode.cache.wan.GatewayQueueEvent;" + "import org.apache.geode.cache.EntryEvent;" + "public class QueueCommandsDUnitTestHelper implements Declarable2, GatewayEventFilter, GatewayEventSubstitutionFilter, AsyncEventListener {" + "Properties props;" + "public boolean processEvents(List<AsyncEvent> events) { return true; }" + "public void afterAcknowledgement(GatewayQueueEvent event) {}" + "public boolean beforeEnqueue(GatewayQueueEvent event) { return true; }" + "public boolean beforeTransmit(GatewayQueueEvent event) { return true; }" + "public Object getSubstituteValue(EntryEvent event) { return null; }" + "public void close() {}" + "public void init(final Properties props) {this.props = props;}" + "public Properties getConfig() {return this.props;}}"); writeJarBytesToFile(jarFile, jarBytes); cmdResult = executeCommand("deploy --jar=QueueCommandsDUnit.jar"); assertEquals(Result.Status.OK, cmdResult.getStatus()); CommandStringBuilder commandStringBuilder = new CommandStringBuilder(CliStrings.CREATE_DISK_STORE); commandStringBuilder.addOption(CliStrings.CREATE_DISK_STORE__NAME, diskStoreName); commandStringBuilder.addOption(CliStrings.CREATE_DISK_STORE__GROUP, "Group1"); commandStringBuilder.addOption(CliStrings.CREATE_DISK_STORE__DIRECTORY_AND_SIZE, diskStoreDir.getAbsolutePath()); cmdResult = executeCommand(commandStringBuilder.toString()); assertEquals(Result.Status.OK, cmdResult.getStatus()); String stringResult = commandResultToString(cmdResult); assertEquals(3, countLinesInString(stringResult, false)); assertEquals(false, stringResult.contains("ERROR")); assertTrue(stringContainsLine(stringResult, vm1Name + ".*Success")); commandStringBuilder = new CommandStringBuilder(CliStrings.CREATE_ASYNC_EVENT_QUEUE); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__ID, queue1Name); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__GROUP, "Group1"); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__BATCH_SIZE, "514"); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__PERSISTENT, "true"); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__DISK_STORE, diskStoreName); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__MAXIMUM_QUEUE_MEMORY, "213"); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__BATCHTIMEINTERVAL, "946"); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__PARALLEL, "true"); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__ENABLEBATCHCONFLATION, "true"); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__DISPATCHERTHREADS, "2"); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__ORDERPOLICY, "PARTITION"); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__GATEWAYEVENTFILTER, "com.qcdunit.QueueCommandsDUnitTestHelper"); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__SUBSTITUTION_FILTER, "com.qcdunit.QueueCommandsDUnitTestHelper"); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__DISKSYNCHRONOUS, "false"); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__FORWARD_EXPIRATION_DESTROY, "true"); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__LISTENER, "com.qcdunit.QueueCommandsDUnitTestHelper"); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__LISTENER_PARAM_AND_VALUE, "param1"); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__LISTENER_PARAM_AND_VALUE, "param2#value2"); cmdResult = executeCommand(commandStringBuilder.toString()); assertEquals(Result.Status.OK, cmdResult.getStatus()); stringResult = commandResultToString(cmdResult); assertEquals(3, countLinesInString(stringResult, false)); assertEquals(false, stringResult.contains("ERROR")); assertTrue(stringContainsLine(stringResult, vm1Name + ".*Success")); // Verify that the queue was created on the correct member cmdResult = executeCommand(CliStrings.LIST_ASYNC_EVENT_QUEUES); assertEquals(Result.Status.OK, cmdResult.getStatus()); stringResult = commandResultToString(cmdResult); assertEquals(3, countLinesInString(stringResult, false)); assertTrue(stringContainsLine(stringResult, vm1Name + " .*" + queue1Name + " .*514 .*true .*" + diskStoreName + " .*213 .*" + " .*com.qcdunit.QueueCommandsDUnitTestHelper" + ".*")); assertTrue(stringContainsLine(stringResult, vm1Name + ".*param2=value2.*")); assertTrue(stringContainsLine(stringResult, vm1Name + ".*param1=[^\\w].*")); assertFalse(stringContainsLine(stringResult, vm2Name + ".*" + queue1Name + ".*")); vm1.invoke(new SerializableRunnable() { public void run() { Cache cache = getCache(); AsyncEventQueue queue = cache.getAsyncEventQueue(queue1Name); assertEquals(queue.getBatchSize(), 514); assertEquals(queue.isPersistent(), true); assertEquals(queue.getDiskStoreName(), diskStoreName); assertEquals(queue.getMaximumQueueMemory(), 213); assertEquals(queue.getBatchTimeInterval(), 946); assertEquals(queue.isParallel(), true); assertEquals(queue.isBatchConflationEnabled(), true); assertEquals(queue.getDispatcherThreads(), 2); assertEquals(queue.getOrderPolicy().toString(), "PARTITION"); assertEquals(queue.getGatewayEventFilters().size(), 1); assertEquals(queue.getGatewayEventFilters().get(0).getClass().getName(), "com.qcdunit.QueueCommandsDUnitTestHelper"); assertEquals(queue.getGatewayEventSubstitutionFilter().getClass().getName(), "com.qcdunit.QueueCommandsDUnitTestHelper"); assertEquals(queue.isDiskSynchronous(), false); assertEquals(queue.isForwardExpirationDestroy(), true); assertEquals(queue.getAsyncEventListener().getClass().getName(), "com.qcdunit.QueueCommandsDUnitTestHelper"); } }); commandStringBuilder = new CommandStringBuilder(CliStrings.CREATE_ASYNC_EVENT_QUEUE); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__ID, queue2Name); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__LISTENER, "com.qcdunit.QueueCommandsDUnitTestHelper"); cmdResult = executeCommand(commandStringBuilder.toString()); assertEquals(Result.Status.OK, cmdResult.getStatus()); stringResult = commandResultToString(cmdResult); assertEquals(5, countLinesInString(stringResult, false)); assertTrue(stringContainsLine(stringResult, "Manager.*Success")); assertTrue(stringContainsLine(stringResult, vm2Name + ".*Success")); assertTrue(stringContainsLine(stringResult, vm1Name + ".*Success")); // Verify that the queue was created on the correct members cmdResult = executeCommand(CliStrings.LIST_ASYNC_EVENT_QUEUES); assertEquals(Result.Status.OK, cmdResult.getStatus()); stringResult = commandResultToString(cmdResult); assertEquals(6, countLinesInString(stringResult, false)); assertTrue(stringContainsLine(stringResult, "Manager .*" + queue2Name + " .*100 .*false .*null .*100 .*" + " .*com.qcdunit.QueueCommandsDUnitTestHelper")); assertTrue(stringContainsLine(stringResult, vm1Name + " .*" + queue1Name + " .*514 .*true .*" + diskStoreName + " .*213 .*" + " .*com.qcdunit.QueueCommandsDUnitTestHelper" + ".*")); assertTrue(stringContainsLine(stringResult, vm1Name + " .*" + queue2Name + " .*100 .*false .*null .*100 .*" + " .*com.qcdunit.QueueCommandsDUnitTestHelper")); assertTrue(stringContainsLine(stringResult, vm2Name + " .*" + queue2Name + " .*100 .*false .*null .*100 .*" + " .*com.qcdunit.QueueCommandsDUnitTestHelper")); } /** * Asserts that creating async event queues correctly updates the shared configuration. */ @Category(FlakyTest.class) // GEODE-1976 @Test public void testCreateUpdatesSharedConfig() throws IOException { disconnectAllFromDS(); final int[] ports = AvailablePortHelper.getRandomAvailableTCPPorts(2); jmxPort = ports[0]; httpPort = ports[1]; try { jmxHost = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException ignore) { jmxHost = "localhost"; } final String queueName = "testAsyncEventQueueQueue"; final String groupName = "testAsyncEventQueueSharedConfigGroup"; final Properties locatorProps = new Properties(); locatorProps.setProperty(NAME, "Locator"); locatorProps.setProperty(MCAST_PORT, "0"); locatorProps.setProperty(LOG_LEVEL, "fine"); 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)); // Start the Locator and wait for shared configuration to be available final int locatorPort = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET); Host.getHost(0).getVM(0).invoke(new SerializableRunnable() { @Override public void run() { final File locatorLogFile = new File("locator-" + locatorPort + ".log"); try { final InternalLocator locator = (InternalLocator) Locator.startLocatorAndDS(locatorPort, locatorLogFile, null, locatorProps); WaitCriterion wc = new WaitCriterion() { @Override public boolean done() { return locator.isSharedConfigurationRunning(); } @Override public String description() { return "Waiting for shared configuration to be started"; } }; waitForCriterion(wc, 5000, 500, true); } catch (IOException ioex) { fail("Unable to create a locator with a shared configuration"); } } }); connect(jmxHost, jmxPort, httpPort, getDefaultShell()); // Create a cache in VM 1 VM vm = Host.getHost(0).getVM(1); vm.invoke(new SerializableRunnable() { @Override public void run() { Properties localProps = new Properties(); localProps.setProperty(MCAST_PORT, "0"); localProps.setProperty(LOCATORS, "localhost[" + locatorPort + "]"); localProps.setProperty(GROUPS, groupName); getSystem(localProps); assertNotNull(getCache()); } }); // Deploy a JAR file with an AsyncEventListener that can be instantiated on each server final File jarFile = new File(new File(".").getAbsolutePath(), "QueueCommandsDUnit.jar"); QueueCommandsDUnitTest.this.filesToBeDeleted.add(jarFile.getAbsolutePath()); ClassBuilder classBuilder = new ClassBuilder(); byte[] jarBytes = classBuilder.createJarFromClassContent("com/qcdunit/QueueCommandsDUnitTestListener", "package com.qcdunit;" + "import java.util.List; import java.util.Properties;" + "import org.apache.geode.internal.cache.xmlcache.Declarable2; import org.apache.geode.cache.asyncqueue.AsyncEvent;" + "import org.apache.geode.cache.asyncqueue.AsyncEventListener;" + "public class QueueCommandsDUnitTestListener implements Declarable2, AsyncEventListener {" + "Properties props;" + "public boolean processEvents(List<AsyncEvent> events) { return true; }" + "public void close() {}" + "public void init(final Properties props) {this.props = props;}" + "public Properties getConfig() {return this.props;}}"); writeJarBytesToFile(jarFile, jarBytes); CommandResult cmdResult = executeCommand("deploy --jar=QueueCommandsDUnit.jar"); assertEquals(Result.Status.OK, cmdResult.getStatus()); // Test creating the queue CommandStringBuilder commandStringBuilder = new CommandStringBuilder(CliStrings.CREATE_ASYNC_EVENT_QUEUE); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__ID, queueName); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__GROUP, groupName); commandStringBuilder.addOption(CliStrings.CREATE_ASYNC_EVENT_QUEUE__LISTENER, "com.qcdunit.QueueCommandsDUnitTestListener"); cmdResult = executeCommand(commandStringBuilder.toString()); assertEquals(Result.Status.OK, cmdResult.getStatus()); // Make sure the queue exists in the shared config Host.getHost(0).getVM(0).invoke(new SerializableRunnable() { @Override public void run() { ClusterConfigurationService sharedConfig = ((InternalLocator) Locator.getLocator()).getSharedConfiguration(); String xmlFromConfig; try { xmlFromConfig = sharedConfig.getConfiguration(groupName).getCacheXmlContent(); assertTrue(xmlFromConfig.contains(queueName)); } catch (Exception e) { fail("Error occurred in cluster configuration service", e); } } }); // Close cache in the vm1 and restart it to get the shared configuration vm = Host.getHost(0).getVM(1); vm.invoke(new SerializableRunnable() { @Override public void run() { Cache cache = getCache(); assertNotNull(cache); cache.close(); assertTrue(cache.isClosed()); Properties localProps = new Properties(); localProps.setProperty(MCAST_PORT, "0"); localProps.setProperty(LOCATORS, "localhost[" + locatorPort + "]"); localProps.setProperty(GROUPS, groupName); localProps.setProperty(USE_CLUSTER_CONFIGURATION, "true"); getSystem(localProps); cache = getCache(); assertNotNull(cache); AsyncEventQueue aeq = cache.getAsyncEventQueue(queueName); assertNotNull(aeq); } }); } @Override protected final void preTearDownCliCommandTestBase() throws Exception { for (String path : this.filesToBeDeleted) { try { final File fileToDelete = new File(path); FileUtil.delete(fileToDelete); if (path.endsWith(".jar")) { executeCommand("undeploy --jar=" + fileToDelete.getName()); } } catch (IOException e) { getLogWriter().error("Unable to delete file", e); } } this.filesToBeDeleted.clear(); } private void writeJarBytesToFile(File jarFile, byte[] jarBytes) throws IOException { final OutputStream outStream = new FileOutputStream(jarFile); outStream.write(jarBytes); outStream.close(); } }