/* * Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved. * * Licensed 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.hazelcast.client; import com.hazelcast.client.config.ClientConfig; import com.hazelcast.client.connection.ClientConnectionManager; import com.hazelcast.client.impl.ClientTestUtil; import com.hazelcast.client.impl.HazelcastClientInstanceImpl; import com.hazelcast.client.spi.properties.ClientProperty; import com.hazelcast.client.test.TestHazelcastFactory; import com.hazelcast.core.Client; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.core.IExecutorService; import com.hazelcast.core.LifecycleEvent; import com.hazelcast.core.LifecycleListener; import com.hazelcast.core.Member; import com.hazelcast.nio.Address; import com.hazelcast.nio.Connection; import com.hazelcast.nio.ConnectionListener; import com.hazelcast.security.UsernamePasswordCredentials; import com.hazelcast.test.AssertTask; import com.hazelcast.test.HazelcastParallelClassRunner; import com.hazelcast.test.HazelcastTestSupport; import com.hazelcast.test.annotation.ParallelTest; import com.hazelcast.test.annotation.QuickTest; import com.hazelcast.util.EmptyStatement; import org.junit.After; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import java.net.InetSocketAddress; import java.util.Collection; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @RunWith(HazelcastParallelClassRunner.class) @Category({QuickTest.class, ParallelTest.class}) public class ClientConnectionTest extends HazelcastTestSupport { private final TestHazelcastFactory hazelcastFactory = new TestHazelcastFactory(); @After public void cleanup() { hazelcastFactory.terminateAll(); } @Test(expected = IllegalStateException.class) public void testWithIllegalAddress() { String illegalAddress = randomString(); hazelcastFactory.newHazelcastInstance(); ClientConfig config = new ClientConfig(); config.getNetworkConfig().setConnectionAttemptPeriod(1); config.getNetworkConfig().addAddress(illegalAddress); hazelcastFactory.newHazelcastClient(config); } @Test public void testWithLegalAndIllegalAddressTogether() { String illegalAddress = randomString(); HazelcastInstance server = hazelcastFactory.newHazelcastInstance(); ClientConfig config = new ClientConfig(); config.setProperty(ClientProperty.SHUFFLE_MEMBER_LIST.getName(), "false"); config.getNetworkConfig().addAddress(illegalAddress).addAddress("localhost"); HazelcastInstance client = hazelcastFactory.newHazelcastClient(config); Collection<Client> connectedClients = server.getClientService().getConnectedClients(); assertEquals(connectedClients.size(), 1); Client serverSideClientInfo = connectedClients.iterator().next(); assertEquals(serverSideClientInfo.getUuid(), client.getLocalEndpoint().getUuid()); } @Test public void testMemberConnectionOrder() { HazelcastInstance server1 = hazelcastFactory.newHazelcastInstance(); HazelcastInstance server2 = hazelcastFactory.newHazelcastInstance(); ClientConfig config = new ClientConfig(); config.setProperty(ClientProperty.SHUFFLE_MEMBER_LIST.getName(), "false"); config.getNetworkConfig().setSmartRouting(false); InetSocketAddress socketAddress1 = server1.getCluster().getLocalMember().getSocketAddress(); InetSocketAddress socketAddress2 = server2.getCluster().getLocalMember().getSocketAddress(); config.getNetworkConfig(). addAddress(socketAddress1.getHostName() + ":" + socketAddress1.getPort()). addAddress(socketAddress2.getHostName() + ":" + socketAddress2.getPort()); hazelcastFactory.newHazelcastClient(config); Collection<Client> connectedClients1 = server1.getClientService().getConnectedClients(); assertEquals(connectedClients1.size(), 1); Collection<Client> connectedClients2 = server2.getClientService().getConnectedClients(); assertEquals(connectedClients2.size(), 0); } @Test public void destroyConnection_whenDestroyedMultipleTimes_thenListenerRemoveCalledOnce() { HazelcastInstance server = hazelcastFactory.newHazelcastInstance(); HazelcastInstance client = hazelcastFactory.newHazelcastClient(); HazelcastClientInstanceImpl clientImpl = ClientTestUtil.getHazelcastClientInstanceImpl(client); ClientConnectionManager connectionManager = clientImpl.getConnectionManager(); final CountingConnectionRemoveListener listener = new CountingConnectionRemoveListener(); connectionManager.addConnectionListener(listener); final Address serverAddress = new Address(server.getCluster().getLocalMember().getSocketAddress()); final Connection connectionToServer = connectionManager.getConnection(serverAddress); final CountDownLatch isConnected = new CountDownLatch(1); clientImpl.getLifecycleService().addLifecycleListener(new LifecycleListener() { @Override public void stateChanged(LifecycleEvent event) { if (LifecycleEvent.LifecycleState.CLIENT_CONNECTED == event.getState()) { isConnected.countDown(); } } }); connectionToServer.close(null, null); assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { assertTrue(isConnected.await(5, TimeUnit.SECONDS)); } }); connectionToServer.close(null, null); assertEquals("connection removed should be called only once", 1, listener.count.get()); } private class CountingConnectionRemoveListener implements ConnectionListener { final AtomicInteger count = new AtomicInteger(); @Override public void connectionAdded(Connection connection) { } @Override public void connectionRemoved(Connection connection) { count.incrementAndGet(); } } @Test public void testAsyncConnectionCreationInAsyncMethods() throws ExecutionException, InterruptedException { hazelcastFactory.newHazelcastInstance(); CountDownLatch countDownLatch = new CountDownLatch(1); ClientConfig config = new ClientConfig(); WaitingCredentials credentials = new WaitingCredentials("dev", "dev-pass", countDownLatch); config.setCredentials(credentials); HazelcastInstance client = hazelcastFactory.newHazelcastClient(config); final IExecutorService executorService = client.getExecutorService(randomString()); credentials.waitFlag.set(true); final HazelcastInstance secondInstance = hazelcastFactory.newHazelcastInstance(); final AtomicReference<Future> atomicReference = new AtomicReference<Future>(); Thread thread = new Thread(new Runnable() { @Override public void run() { Member secondMember = secondInstance.getCluster().getLocalMember(); Future future = executorService.submitToMember(new DummySerializableCallable(), secondMember); atomicReference.set(future); } }); thread.start(); try { assertTrueEventually(new AssertTask() { @Override public void run() throws Exception { assertNotNull(atomicReference.get()); } }, 30); } finally { thread.interrupt(); thread.join(); countDownLatch.countDown(); } } static class WaitingCredentials extends UsernamePasswordCredentials { private final CountDownLatch countDownLatch; AtomicBoolean waitFlag = new AtomicBoolean(); WaitingCredentials(String username, String password, CountDownLatch countDownLatch) { super(username, password); this.countDownLatch = countDownLatch; } @Override public String getUsername() { return super.getUsername(); } @Override public String getPassword() { if (waitFlag.get()) { try { countDownLatch.await(); } catch (InterruptedException e) { EmptyStatement.ignore(e); } } return super.getPassword(); } } }