IGNITE-4111 Fixed NPE on client connect before disco impl is initialized - Fixes #5650.
Signed-off-by: Alexey Goncharuk <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/c48f3bc1 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/c48f3bc1 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/c48f3bc1 Branch: refs/heads/ignite-10639 Commit: c48f3bc1046b1c496e0261edf7a693efc728b8f6 Parents: 4ae29fc Author: NSAmelchev <[email protected]> Authored: Tue Dec 18 18:50:38 2018 +0300 Committer: Alexey Goncharuk <[email protected]> Committed: Tue Dec 18 18:55:54 2018 +0300 ---------------------------------------------------------------------- .../spi/discovery/tcp/TcpDiscoverySpi.java | 4 + ...IgniteTcpCommunicationConnectOnInitTest.java | 172 +++++++++++++++++++ .../IgniteSpiCommunicationSelfTestSuite.java | 2 + 3 files changed, 178 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/c48f3bc1/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java index ce3370e..c48fa11 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java @@ -451,6 +451,10 @@ public class TcpDiscoverySpi extends IgniteSpiAdapter implements IgniteDiscovery /** {@inheritDoc} */ @Override public Collection<ClusterNode> getRemoteNodes() { + // Return empty nodes for resolving compatibility until implementation started. + if (impl == null) + return Collections.emptyList(); + return impl.getRemoteNodes(); } http://git-wip-us.apache.org/repos/asf/ignite/blob/c48f3bc1/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteTcpCommunicationConnectOnInitTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteTcpCommunicationConnectOnInitTest.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteTcpCommunicationConnectOnInitTest.java new file mode 100644 index 0000000..0293316 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteTcpCommunicationConnectOnInitTest.java @@ -0,0 +1,172 @@ +/* + * 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.ignite.spi.communication.tcp; + +import java.net.BindException; +import java.net.InetSocketAddress; +import java.nio.channels.SocketChannel; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteInternalFuture; +import org.apache.ignite.internal.util.nio.GridNioServer; +import org.apache.ignite.internal.util.nio.GridNioServerListenerAdapter; +import org.apache.ignite.internal.util.nio.GridNioSession; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.spi.IgniteSpiException; +import org.apache.ignite.spi.communication.tcp.messages.HandshakeWaitMessage; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.jetbrains.annotations.Nullable; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Testing {@link TcpCommunicationSpi} that will send the wait handshake message on received connections until SPI + * context initialized. + */ +@RunWith(JUnit4.class) +public class IgniteTcpCommunicationConnectOnInitTest extends GridCommonAbstractTest { + /** */ + private static final int START_PORT = 55443; + + /** */ + private volatile CountDownLatch commStartLatch; + + /** */ + private volatile int commSpiBoundedPort; + + /** */ + private volatile String commSpiSrvAddr; + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + cfg.setCommunicationSpi(new TestCommunicationSpi()); + + return cfg; + } + + /** + * @throws Exception If failed. + */ + @Test + public void testClientConnectBeforeDiscoveryStarted() throws Exception { + GridNioServer<?> srvr = startServer(); + + try { + commStartLatch = new CountDownLatch(1); + + IgniteInternalFuture<Boolean> fut = GridTestUtils.runAsync(() -> { + startGrid(0); + + return true; + }); + + assertTrue(commStartLatch.await(5_000, TimeUnit.MILLISECONDS)); + + SocketChannel ch = SocketChannel.open(new InetSocketAddress(commSpiSrvAddr, commSpiBoundedPort)); + + GridNioSession ses = srvr.createSession(ch, null, false, null).get(); + + boolean wait = GridTestUtils.waitForCondition( + () -> ses.bytesReceived() == HandshakeWaitMessage.MESSAGE_FULL_SIZE, 1000); + + assertTrue("Handshake not started.", wait); + + fut.get(); + } + finally { + srvr.stop(); + } + } + + /** + * Starts custom server. + * + * @return Started server. + * @throws Exception If failed. + */ + @SuppressWarnings("unchecked") + private GridNioServer<?> startServer() throws Exception { + int srvPort = START_PORT; + + for (int i = 0; i < 10; i++) { + try { + GridNioServerListenerAdapter lsnr = new GridNioServerListenerAdapter() { + @Override public void onConnected(GridNioSession ses) { + // No-op. + } + + @Override public void onDisconnected(GridNioSession ses, @Nullable Exception e) { + // No-op. + } + + @Override public void onMessage(GridNioSession ses, Object msg) { + // No-op. + } + }; + + GridNioServer<?> srvr = GridNioServer.builder() + .address(U.getLocalHost()) + .port(srvPort) + .listener(lsnr) + .logger(log) + .selectorCount(Runtime.getRuntime().availableProcessors()) + .igniteInstanceName("nio-test-grid") + .filters().build(); + + srvr.start(); + + return srvr; + } + catch (IgniteCheckedException e) { + if (i < 9 && e.hasCause(BindException.class)) { + log.error("Failed to start server, will try another port [err=" + e + ", port=" + srvPort + ']'); + + U.sleep(1000); + + srvPort++; + } + else + throw e; + } + } + + fail("Failed to start server."); + + return null; + } + + /** */ + private class TestCommunicationSpi extends TcpCommunicationSpi { + /** {@inheritDoc} */ + @Override public void spiStart(String igniteInstanceName) throws IgniteSpiException { + super.spiStart(igniteInstanceName); + + commSpiBoundedPort = boundPort(); + + commSpiSrvAddr = getLocalAddress(); + + commStartLatch.countDown(); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/c48f3bc1/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiCommunicationSelfTestSuite.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiCommunicationSelfTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiCommunicationSelfTestSuite.java index 6a38c55..5a208e6 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiCommunicationSelfTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteSpiCommunicationSelfTestSuite.java @@ -36,6 +36,7 @@ import org.apache.ignite.spi.communication.tcp.GridTcpCommunicationSpiStartStopS import org.apache.ignite.spi.communication.tcp.GridTcpCommunicationSpiTcpFailureDetectionSelfTest; import org.apache.ignite.spi.communication.tcp.GridTcpCommunicationSpiTcpNoDelayOffSelfTest; import org.apache.ignite.spi.communication.tcp.GridTcpCommunicationSpiTcpSelfTest; +import org.apache.ignite.spi.communication.tcp.IgniteTcpCommunicationConnectOnInitTest; import org.apache.ignite.spi.communication.tcp.IgniteTcpCommunicationHandshakeWaitSslTest; import org.apache.ignite.spi.communication.tcp.IgniteTcpCommunicationHandshakeWaitTest; import org.apache.ignite.spi.communication.tcp.IgniteTcpCommunicationRecoveryAckClosureSelfTest; @@ -92,6 +93,7 @@ public class IgniteSpiCommunicationSelfTestSuite extends TestSuite { suite.addTest(new JUnit4TestAdapter(IgniteTcpCommunicationHandshakeWaitTest.class)); suite.addTest(new JUnit4TestAdapter(IgniteTcpCommunicationHandshakeWaitSslTest.class)); + suite.addTest(new JUnit4TestAdapter(IgniteTcpCommunicationConnectOnInitTest.class)); //suite.addTest(new TestSuite(GridCacheDhtLockBackupSelfTest.class));
