/* * 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.common.network; import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.Table; import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.inject.ModuleTestCase; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.BoundTransportAddress; import org.elasticsearch.common.util.BigArrays; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.http.HttpInfo; import org.elasticsearch.http.HttpServerTransport; import org.elasticsearch.http.HttpStats; import org.elasticsearch.http.NullDispatcher; import org.elasticsearch.indices.breaker.CircuitBreakerService; import org.elasticsearch.plugins.NetworkPlugin; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.action.cat.AbstractCatAction; import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.Transport; import org.elasticsearch.transport.TransportInterceptor; import org.elasticsearch.transport.TransportRequest; import org.elasticsearch.transport.TransportRequestHandler; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; public class NetworkModuleTests extends ModuleTestCase { private ThreadPool threadPool; @Override public void setUp() throws Exception { super.setUp(); threadPool = new TestThreadPool(NetworkModuleTests.class.getName()); } @Override public void tearDown() throws Exception { super.tearDown(); ThreadPool.terminate(threadPool, 10, TimeUnit.SECONDS); } static class FakeHttpTransport extends AbstractLifecycleComponent implements HttpServerTransport { FakeHttpTransport() { super(null); } @Override protected void doStart() {} @Override protected void doStop() {} @Override protected void doClose() {} @Override public BoundTransportAddress boundAddress() { return null; } @Override public HttpInfo info() { return null; } @Override public HttpStats stats() { return null; } } static class FakeRestHandler extends BaseRestHandler { FakeRestHandler() { super(null); } @Override public RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException { return channel -> {}; } } static class FakeCatRestHandler extends AbstractCatAction { FakeCatRestHandler() { super(null); } @Override protected RestChannelConsumer doCatRequest(RestRequest request, NodeClient client) { return channel -> {}; } @Override protected void documentation(StringBuilder sb) {} @Override protected Table getTableWithHeader(RestRequest request) { return null; } } public void testRegisterTransport() { Settings settings = Settings.builder().put(NetworkModule.TRANSPORT_TYPE_KEY, "custom") .put(NetworkModule.HTTP_ENABLED.getKey(), false) .build(); Supplier<Transport> custom = () -> null; // content doesn't matter we check reference equality NetworkPlugin plugin = new NetworkPlugin() { @Override public Map<String, Supplier<Transport>> getTransports(Settings settings, ThreadPool threadPool, BigArrays bigArrays, CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry, NetworkService networkService) { return Collections.singletonMap("custom", custom); } }; NetworkModule module = newNetworkModule(settings, false, plugin); assertFalse(module.isTransportClient()); assertFalse(module.isHttpEnabled()); assertSame(custom, module.getTransportSupplier()); // check it works with transport only as well module = newNetworkModule(settings, true, plugin); assertSame(custom, module.getTransportSupplier()); assertTrue(module.isTransportClient()); assertFalse(module.isHttpEnabled()); } public void testRegisterHttpTransport() { Settings settings = Settings.builder() .put(NetworkModule.HTTP_TYPE_SETTING.getKey(), "custom") .put(NetworkModule.TRANSPORT_TYPE_KEY, "local").build(); Supplier<HttpServerTransport> custom = FakeHttpTransport::new; NetworkModule module = newNetworkModule(settings, false, new NetworkPlugin() { @Override public Map<String, Supplier<HttpServerTransport>> getHttpTransports(Settings settings, ThreadPool threadPool, BigArrays bigArrays, CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry, NamedXContentRegistry xContentRegistry, NetworkService networkService, HttpServerTransport.Dispatcher requestDispatcher) { return Collections.singletonMap("custom", custom); } }); assertSame(custom, module.getHttpServerTransportSupplier()); assertFalse(module.isTransportClient()); assertTrue(module.isHttpEnabled()); settings = Settings.builder().put(NetworkModule.HTTP_ENABLED.getKey(), false) .put(NetworkModule.TRANSPORT_TYPE_KEY, "local").build(); NetworkModule newModule = newNetworkModule(settings, false); assertFalse(newModule.isTransportClient()); assertFalse(newModule.isHttpEnabled()); expectThrows(IllegalStateException.class, () -> newModule.getHttpServerTransportSupplier()); } public void testOverrideDefault() { Settings settings = Settings.builder() .put(NetworkModule.HTTP_TYPE_SETTING.getKey(), "custom") .put(NetworkModule.HTTP_DEFAULT_TYPE_SETTING.getKey(), "default_custom") .put(NetworkModule.TRANSPORT_DEFAULT_TYPE_SETTING.getKey(), "local") .put(NetworkModule.TRANSPORT_TYPE_KEY, "default_custom").build(); Supplier<Transport> customTransport = () -> null; // content doesn't matter we check reference equality Supplier<HttpServerTransport> custom = FakeHttpTransport::new; Supplier<HttpServerTransport> def = FakeHttpTransport::new; NetworkModule module = newNetworkModule(settings, false, new NetworkPlugin() { @Override public Map<String, Supplier<Transport>> getTransports(Settings settings, ThreadPool threadPool, BigArrays bigArrays, CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry, NetworkService networkService) { return Collections.singletonMap("default_custom", customTransport); } @Override public Map<String, Supplier<HttpServerTransport>> getHttpTransports(Settings settings, ThreadPool threadPool, BigArrays bigArrays, CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry, NamedXContentRegistry xContentRegistry, NetworkService networkService, HttpServerTransport.Dispatcher requestDispatcher) { Map<String, Supplier<HttpServerTransport>> supplierMap = new HashMap<>(); supplierMap.put("custom", custom); supplierMap.put("default_custom", def); return supplierMap; } }); assertSame(custom, module.getHttpServerTransportSupplier()); assertSame(customTransport, module.getTransportSupplier()); } public void testDefaultKeys() { Settings settings = Settings.builder() .put(NetworkModule.HTTP_DEFAULT_TYPE_SETTING.getKey(), "default_custom") .put(NetworkModule.TRANSPORT_DEFAULT_TYPE_SETTING.getKey(), "default_custom").build(); Supplier<HttpServerTransport> custom = FakeHttpTransport::new; Supplier<HttpServerTransport> def = FakeHttpTransport::new; Supplier<Transport> customTransport = () -> null; NetworkModule module = newNetworkModule(settings, false, new NetworkPlugin() { @Override public Map<String, Supplier<Transport>> getTransports(Settings settings, ThreadPool threadPool, BigArrays bigArrays, CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry, NetworkService networkService) { return Collections.singletonMap("default_custom", customTransport); } @Override public Map<String, Supplier<HttpServerTransport>> getHttpTransports(Settings settings, ThreadPool threadPool, BigArrays bigArrays, CircuitBreakerService circuitBreakerService, NamedWriteableRegistry namedWriteableRegistry, NamedXContentRegistry xContentRegistry, NetworkService networkService, HttpServerTransport.Dispatcher requestDispatcher) { Map<String, Supplier<HttpServerTransport>> supplierMap = new HashMap<>(); supplierMap.put("custom", custom); supplierMap.put("default_custom", def); return supplierMap; } }); assertSame(def, module.getHttpServerTransportSupplier()); assertSame(customTransport, module.getTransportSupplier()); } public void testRegisterInterceptor() { Settings settings = Settings.builder() .put(NetworkModule.HTTP_ENABLED.getKey(), false) .put(NetworkModule.TRANSPORT_TYPE_KEY, "local").build(); AtomicInteger called = new AtomicInteger(0); TransportInterceptor interceptor = new TransportInterceptor() { @Override public <T extends TransportRequest> TransportRequestHandler<T> interceptHandler(String action, String executor, boolean forceExecution, TransportRequestHandler<T> actualHandler) { called.incrementAndGet(); if ("foo/bar/boom".equals(action)) { assertTrue(forceExecution); } else { assertFalse(forceExecution); } return actualHandler; } }; NetworkModule module = newNetworkModule(settings, false, new NetworkPlugin() { @Override public List<TransportInterceptor> getTransportInterceptors(NamedWriteableRegistry namedWriteableRegistry, ThreadContext threadContext) { assertNotNull(threadContext); return Collections.singletonList(interceptor); } }); TransportInterceptor transportInterceptor = module.getTransportInterceptor(); assertEquals(0, called.get()); transportInterceptor.interceptHandler("foo/bar/boom", null, true, null); assertEquals(1, called.get()); transportInterceptor.interceptHandler("foo/baz/boom", null, false, null); assertEquals(2, called.get()); assertTrue(transportInterceptor instanceof NetworkModule.CompositeTransportInterceptor); assertEquals(((NetworkModule.CompositeTransportInterceptor)transportInterceptor).transportInterceptors.size(), 1); assertSame(((NetworkModule.CompositeTransportInterceptor)transportInterceptor).transportInterceptors.get(0), interceptor); NullPointerException nullPointerException = expectThrows(NullPointerException.class, () -> { newNetworkModule(settings, false, new NetworkPlugin() { @Override public List<TransportInterceptor> getTransportInterceptors(NamedWriteableRegistry namedWriteableRegistry, ThreadContext threadContext) { assertNotNull(threadContext); return Collections.singletonList(null); } }); }); assertEquals("interceptor must not be null", nullPointerException.getMessage()); } private NetworkModule newNetworkModule(Settings settings, boolean transportClient, NetworkPlugin... plugins) { return new NetworkModule(settings, transportClient, Arrays.asList(plugins), threadPool, null, null, null, xContentRegistry(), null, new NullDispatcher()); } }