/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch 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.elasticsearch.transport; import org.apache.lucene.util.IOUtils; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.Version; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.transport.MockTransportService; import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.ThreadPool; import org.junit.Before; import java.io.IOException; import java.util.concurrent.CountDownLatch; public class TransportActionProxyTests extends ESTestCase { protected ThreadPool threadPool; // we use always a non-alpha or beta version here otherwise minimumCompatibilityVersion will be different for the two used versions private static final Version CURRENT_VERSION = Version.fromString(String.valueOf(Version.CURRENT.major) + ".0.0"); protected static final Version version0 = CURRENT_VERSION.minimumCompatibilityVersion(); protected DiscoveryNode nodeA; protected MockTransportService serviceA; protected static final Version version1 = Version.fromId(CURRENT_VERSION.id + 1); protected DiscoveryNode nodeB; protected MockTransportService serviceB; protected DiscoveryNode nodeC; protected MockTransportService serviceC; @Override @Before public void setUp() throws Exception { super.setUp(); threadPool = new TestThreadPool(getClass().getName()); serviceA = buildService(version0); // this one supports dynamic tracer updates nodeA = serviceA.getLocalDiscoNode(); serviceB = buildService(version1); // this one doesn't support dynamic tracer updates nodeB = serviceB.getLocalDiscoNode(); serviceC = buildService(version1); // this one doesn't support dynamic tracer updates nodeC = serviceC.getLocalDiscoNode(); } @Override public void tearDown() throws Exception { super.tearDown(); IOUtils.close(serviceA, serviceB, serviceC, () -> { try { terminate(threadPool); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); } private MockTransportService buildService(final Version version) { MockTransportService service = MockTransportService.createNewService(Settings.EMPTY, version, threadPool, null); service.start(); service.acceptIncomingRequests(); return service; } public void testSendMessage() throws InterruptedException { serviceA.registerRequestHandler("/test", SimpleTestRequest::new, ThreadPool.Names.SAME, (request, channel) -> { assertEquals(request.sourceNode, "TS_A"); SimpleTestResponse response = new SimpleTestResponse(); response.targetNode = "TS_A"; channel.sendResponse(response); }); TransportActionProxy.registerProxyAction(serviceA, "/test", SimpleTestResponse::new); serviceA.connectToNode(nodeB); serviceB.registerRequestHandler("/test", SimpleTestRequest::new, ThreadPool.Names.SAME, (request, channel) -> { assertEquals(request.sourceNode, "TS_A"); SimpleTestResponse response = new SimpleTestResponse(); response.targetNode = "TS_B"; channel.sendResponse(response); }); TransportActionProxy.registerProxyAction(serviceB, "/test", SimpleTestResponse::new); serviceB.connectToNode(nodeC); serviceC.registerRequestHandler("/test", SimpleTestRequest::new, ThreadPool.Names.SAME, (request, channel) -> { assertEquals(request.sourceNode, "TS_A"); SimpleTestResponse response = new SimpleTestResponse(); response.targetNode = "TS_C"; channel.sendResponse(response); }); TransportActionProxy.registerProxyAction(serviceC, "/test", SimpleTestResponse::new); CountDownLatch latch = new CountDownLatch(1); serviceA.sendRequest(nodeB, TransportActionProxy.getProxyAction("/test"), TransportActionProxy.wrapRequest(nodeC, new SimpleTestRequest("TS_A")), new TransportResponseHandler<SimpleTestResponse>() { @Override public SimpleTestResponse newInstance() { return new SimpleTestResponse(); } @Override public void handleResponse(SimpleTestResponse response) { try { assertEquals("TS_C", response.targetNode); } finally { latch.countDown(); } } @Override public void handleException(TransportException exp) { try { throw new AssertionError(exp); } finally { latch.countDown(); } } @Override public String executor() { return ThreadPool.Names.SAME; } }); latch.await(); } public void testException() throws InterruptedException { serviceA.registerRequestHandler("/test", SimpleTestRequest::new, ThreadPool.Names.SAME, (request, channel) -> { assertEquals(request.sourceNode, "TS_A"); SimpleTestResponse response = new SimpleTestResponse(); response.targetNode = "TS_A"; channel.sendResponse(response); }); TransportActionProxy.registerProxyAction(serviceA, "/test", SimpleTestResponse::new); serviceA.connectToNode(nodeB); serviceB.registerRequestHandler("/test", SimpleTestRequest::new, ThreadPool.Names.SAME, (request, channel) -> { assertEquals(request.sourceNode, "TS_A"); SimpleTestResponse response = new SimpleTestResponse(); response.targetNode = "TS_B"; channel.sendResponse(response); }); TransportActionProxy.registerProxyAction(serviceB, "/test", SimpleTestResponse::new); serviceB.connectToNode(nodeC); serviceC.registerRequestHandler("/test", SimpleTestRequest::new, ThreadPool.Names.SAME, (request, channel) -> { throw new ElasticsearchException("greetings from TS_C"); }); TransportActionProxy.registerProxyAction(serviceC, "/test", SimpleTestResponse::new); CountDownLatch latch = new CountDownLatch(1); serviceA.sendRequest(nodeB, TransportActionProxy.getProxyAction("/test"), TransportActionProxy.wrapRequest(nodeC, new SimpleTestRequest("TS_A")), new TransportResponseHandler<SimpleTestResponse>() { @Override public SimpleTestResponse newInstance() { return new SimpleTestResponse(); } @Override public void handleResponse(SimpleTestResponse response) { try { fail("expected exception"); } finally { latch.countDown(); } } @Override public void handleException(TransportException exp) { try { Throwable cause = ExceptionsHelper.unwrapCause(exp); assertEquals("greetings from TS_C", cause.getMessage()); } finally { latch.countDown(); } } @Override public String executor() { return ThreadPool.Names.SAME; } }); latch.await(); } public static class SimpleTestRequest extends TransportRequest { String sourceNode; public SimpleTestRequest(String sourceNode) { this.sourceNode = sourceNode; } public SimpleTestRequest() {} @Override public void readFrom(StreamInput in) throws IOException { super.readFrom(in); sourceNode = in.readString(); } @Override public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); out.writeString(sourceNode); } } public static class SimpleTestResponse extends TransportResponse { String targetNode; @Override public void readFrom(StreamInput in) throws IOException { super.readFrom(in); targetNode = in.readString(); } @Override public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); out.writeString(targetNode); } } public void testGetAction() { String action = "foo/bar"; String proxyAction = TransportActionProxy.getProxyAction(action); assertTrue(proxyAction.endsWith(action)); assertEquals("internal:transport/proxy/foo/bar", proxyAction); } public void testUnwrap() { TransportRequest transportRequest = TransportActionProxy.wrapRequest(nodeA, TransportService.HandshakeRequest.INSTANCE); assertTrue(transportRequest instanceof TransportActionProxy.ProxyRequest); assertSame(TransportService.HandshakeRequest.INSTANCE, TransportActionProxy.unwrapRequest(transportRequest)); } }