/* * 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.distributed; import org.apache.geode.SystemConnectException; import org.apache.geode.cache.client.internal.locator.ClientConnectionRequest; import org.apache.geode.cache.client.internal.locator.ClientConnectionResponse; import org.apache.geode.cache.client.internal.locator.QueueConnectionRequest; import org.apache.geode.cache.client.internal.locator.QueueConnectionResponse; import org.apache.geode.distributed.internal.DistributionConfig; import org.apache.geode.distributed.internal.InternalDistributedSystem; import org.apache.geode.distributed.internal.InternalLocator; import org.apache.geode.distributed.internal.ServerLocation; import org.apache.geode.distributed.internal.membership.gms.messenger.JGroupsMessenger; import org.apache.geode.distributed.internal.tcpserver.TcpClient; import org.apache.geode.internal.AvailablePortHelper; import org.apache.geode.internal.OSProcess; import org.apache.geode.internal.cache.GemFireCacheImpl; import org.apache.geode.internal.cache.tier.sockets.ClientProxyMembershipID; import org.apache.geode.management.internal.JmxManagerAdvisor.JmxManagerProfile; import org.apache.geode.management.internal.configuration.messages.ConfigurationRequest; import org.apache.geode.management.internal.configuration.messages.SharedConfigurationStatusRequest; import org.apache.geode.test.junit.categories.IntegrationTest; import org.apache.geode.test.junit.categories.MembershipTest; import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactory; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.IntSupplier; import static org.apache.geode.distributed.ConfigurationProperties.*; import static org.apache.geode.internal.AvailablePort.SOCKET; import static org.apache.geode.internal.AvailablePort.getRandomAvailablePort; import static org.junit.Assert.*; import com.jayway.awaitility.Awaitility; @Category({IntegrationTest.class, MembershipTest.class}) @RunWith(Parameterized.class) @Parameterized.UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class) public class LocatorJUnitTest { private static final int REQUEST_TIMEOUT = 5 * 1000; private Locator locator; private File tmpFile; private int port; @Parameterized.Parameters public static Collection<Object> data() { return Arrays.asList(new Object[] {(IntSupplier) () -> 0, (IntSupplier) () -> AvailablePortHelper.getRandomAvailableTCPPort()}); } @Parameterized.Parameter public IntSupplier portSupplier; @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @Before public void setUp() throws IOException { tmpFile = File.createTempFile("locator", ".log"); this.port = portSupplier.getAsInt(); File locatorFile = new File("locator" + this.port + ".dat"); if (locatorFile.exists()) { locatorFile.delete(); } } @After public void tearDown() { if (locator != null) { locator.stop(); } assertEquals(false, Locator.hasLocator()); } /** * TRAC #45804: if jmx-manager-start is true in a locator then gfsh connect will fail */ @Test public void testGfshConnectShouldSucceedIfJmxManagerStartIsTrueInLocator() throws Exception { Properties dsprops = new Properties(); int jmxPort = getRandomAvailablePort(SOCKET); dsprops.setProperty(MCAST_PORT, "0"); dsprops.setProperty(JMX_MANAGER_PORT, "" + jmxPort); dsprops.setProperty(JMX_MANAGER_START, "true"); dsprops.setProperty(JMX_MANAGER_HTTP_PORT, "0"); dsprops.setProperty(ENABLE_CLUSTER_CONFIGURATION, "false"); dsprops.setProperty(LOG_FILE, ""); System.setProperty(DistributionConfig.GEMFIRE_PREFIX + "disableManagement", "false"); // not // needed try { locator = Locator.startLocatorAndDS(port, null, dsprops); List<JmxManagerProfile> alreadyManaging = GemFireCacheImpl.getInstance().getJmxManagerAdvisor().adviseAlreadyManaging(); assertEquals(1, alreadyManaging.size()); assertEquals(GemFireCacheImpl.getInstance().getMyId(), alreadyManaging.get(0).getDistributedMember()); } finally { System.clearProperty(DistributionConfig.GEMFIRE_PREFIX + "enabledManagement"); } } /** * GEODE-2253 - a locator should handle a SharedConfigurationStatusRequest regardless of whether * it has the service or not */ @Test public void testHandlersAreWaitedOn() throws Exception { Properties dsprops = new Properties(); int jmxPort = getRandomAvailablePort(SOCKET); dsprops.setProperty(MCAST_PORT, "0"); dsprops.setProperty(ENABLE_CLUSTER_CONFIGURATION, "false"); dsprops.setProperty(LOCATOR_WAIT_TIME, "1"); // seconds dsprops.setProperty(LOG_FILE, ""); locator = Locator.startLocatorAndDS(port, null, dsprops); InternalLocator internalLocator = (InternalLocator) locator; // the locator should always install a SharedConfigurationStatusRequest handler assertTrue(internalLocator.hasHandlerForClass(SharedConfigurationStatusRequest.class)); // the locator should wait if a handler isn't installed assertFalse(internalLocator.hasHandlerForClass(ConfigurationRequest.class)); ConfigurationRequest request = new ConfigurationRequest(); Object result = internalLocator.getPrimaryHandler().processRequest(request); assertNull(result); assertTrue(internalLocator.getPrimaryHandler().hasWaitedForHandlerInitialization()); } @Test public void testBasicInfo() throws Exception { locator = Locator.startLocator(port, tmpFile); int boundPort = (port == 0) ? locator.getPort() : port; TcpClient client = new TcpClient(); String[] info = client.getInfo(InetAddress.getLocalHost(), boundPort); assertNotNull(info); assertTrue(info.length > 1); } @Test public void testNoThreadLeftBehind() throws Exception { Properties dsprops = new Properties(); dsprops.setProperty(MCAST_PORT, "0"); dsprops.setProperty(JMX_MANAGER_START, "false"); dsprops.setProperty(ENABLE_CLUSTER_CONFIGURATION, "false"); JGroupsMessenger.THROW_EXCEPTION_ON_START_HOOK = true; int threadCount = Thread.activeCount(); try { locator = Locator.startLocatorAndDS(port, new File(""), dsprops); locator.stop(); fail("expected an exception"); } catch (SystemConnectException expected) { for (int i = 0; i < 10; i++) { if (threadCount < Thread.activeCount()) { Thread.sleep(1000); } } if (threadCount < Thread.activeCount()) { OSProcess.printStacks(0); fail("expected " + threadCount + " threads or fewer but found " + Thread.activeCount() + ". Check log file for a thread dump."); } } finally { JGroupsMessenger.THROW_EXCEPTION_ON_START_HOOK = false; } } /** * Make sure two ServerLocation objects on different hosts but with the same port are not equal * <p/> * TRAC #42040: LoadBalancing directs all traffic to a single cache server if all servers are * started on the same port */ @Test public void testServerLocationOnDifferentHostsShouldNotTestEqual() { ServerLocation sl1 = new ServerLocation("host1", 777); ServerLocation sl2 = new ServerLocation("host2", 777); if (sl1.equals(sl2)) { fail("ServerLocation instances on different hosts should not test equal"); } } }