Commit 2b453bbb authored by Andy Wilkinson's avatar Andy Wilkinson

Minimise dependencies on Log4j2

Closes gh-15441
parent e1651127
...@@ -234,11 +234,6 @@ ...@@ -234,11 +234,6 @@
<artifactId>kafka-clients</artifactId> <artifactId>kafka-clients</artifactId>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>org.apache.tomcat.embed</groupId> <groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId> <artifactId>tomcat-embed-core</artifactId>
...@@ -488,7 +483,7 @@ ...@@ -488,7 +483,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId> <artifactId>log4j-to-slf4j</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
......
...@@ -16,12 +16,10 @@ ...@@ -16,12 +16,10 @@
package org.springframework.boot.actuate.autoconfigure.metrics; package org.springframework.boot.actuate.autoconfigure.metrics;
import java.util.Collections;
import io.micrometer.core.instrument.MeterRegistry; import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.logging.Log4j2Metrics; import io.micrometer.core.instrument.binder.logging.Log4j2Metrics;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext; import org.apache.logging.log4j.spi.LoggerContext;
import org.springframework.boot.actuate.autoconfigure.metrics.Log4J2MetricsAutoConfiguration.Log4JCoreLoggerContextCondition; import org.springframework.boot.actuate.autoconfigure.metrics.Log4J2MetricsAutoConfiguration.Log4JCoreLoggerContextCondition;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
...@@ -44,7 +42,8 @@ import org.springframework.core.type.AnnotatedTypeMetadata; ...@@ -44,7 +42,8 @@ import org.springframework.core.type.AnnotatedTypeMetadata;
*/ */
@Configuration @Configuration
@AutoConfigureAfter(MetricsAutoConfiguration.class) @AutoConfigureAfter(MetricsAutoConfiguration.class)
@ConditionalOnClass({ Log4j2Metrics.class, LoggerContext.class, LogManager.class }) @ConditionalOnClass(value = { Log4j2Metrics.class,
LogManager.class }, name = "org.apache.logging.log4j.core.LoggerContext")
@ConditionalOnBean(MeterRegistry.class) @ConditionalOnBean(MeterRegistry.class)
@Conditional(Log4JCoreLoggerContextCondition.class) @Conditional(Log4JCoreLoggerContextCondition.class)
public class Log4J2MetricsAutoConfiguration { public class Log4J2MetricsAutoConfiguration {
...@@ -52,8 +51,7 @@ public class Log4J2MetricsAutoConfiguration { ...@@ -52,8 +51,7 @@ public class Log4J2MetricsAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public Log4j2Metrics log4j2Metrics() { public Log4j2Metrics log4j2Metrics() {
return new Log4j2Metrics(Collections.emptyList(), return new Log4j2Metrics();
(LoggerContext) LogManager.getContext(false));
} }
static class Log4JCoreLoggerContextCondition extends SpringBootCondition { static class Log4JCoreLoggerContextCondition extends SpringBootCondition {
...@@ -61,14 +59,19 @@ public class Log4J2MetricsAutoConfiguration { ...@@ -61,14 +59,19 @@ public class Log4J2MetricsAutoConfiguration {
@Override @Override
public ConditionOutcome getMatchOutcome(ConditionContext context, public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) { AnnotatedTypeMetadata metadata) {
org.apache.logging.log4j.spi.LoggerContext loggerContext = LogManager LoggerContext loggerContext = LogManager.getContext(false);
.getContext(false); try {
if (loggerContext instanceof LoggerContext) { if (Class.forName("org.apache.logging.log4j.core.LoggerContext")
return ConditionOutcome.match( .isInstance(loggerContext)) {
"LoggerContext was an instance of org.apache.logging.log4j.spi.LoggerContext"); return ConditionOutcome.match(
"LoggerContext was an instance of org.apache.logging.log4j.core.LoggerContext");
}
}
catch (Throwable ex) {
// Continue with no match
} }
return ConditionOutcome.noMatch( return ConditionOutcome.noMatch(
"Logger context was not an instance of org.apache.logging.log4j.spi.LoggerContext"); "Logger context was not an instance of org.apache.logging.log4j.core.LoggerContext");
} }
} }
......
...@@ -17,11 +17,15 @@ ...@@ -17,11 +17,15 @@
package org.springframework.boot.actuate.autoconfigure.metrics; package org.springframework.boot.actuate.autoconfigure.metrics;
import io.micrometer.core.instrument.binder.logging.Log4j2Metrics; import io.micrometer.core.instrument.binder.logging.Log4j2Metrics;
import org.junit.jupiter.api.Test; import org.apache.logging.log4j.LogManager;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.testsupport.runner.classpath.ClassPathOverrides;
import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -32,7 +36,9 @@ import static org.assertj.core.api.Assertions.assertThat; ...@@ -32,7 +36,9 @@ import static org.assertj.core.api.Assertions.assertThat;
* *
* @author Andy Wilkinson * @author Andy Wilkinson
*/ */
public class Log4J2MetricsAutoConfigurationTests { @RunWith(ModifiedClassPathRunner.class)
@ClassPathOverrides("org.apache.logging.log4j:log4j-core:2.11.1")
public class Log4J2MetricsWithLog4jLoggerContextAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.with(MetricsRun.simple()).withConfiguration( .with(MetricsRun.simple()).withConfiguration(
...@@ -40,12 +46,16 @@ public class Log4J2MetricsAutoConfigurationTests { ...@@ -40,12 +46,16 @@ public class Log4J2MetricsAutoConfigurationTests {
@Test @Test
public void autoConfiguresLog4J2Metrics() { public void autoConfiguresLog4J2Metrics() {
assertThat(LogManager.getContext().getClass().getName())
.isEqualTo("org.apache.logging.log4j.core.LoggerContext");
this.contextRunner this.contextRunner
.run((context) -> assertThat(context).hasSingleBean(Log4j2Metrics.class)); .run((context) -> assertThat(context).hasSingleBean(Log4j2Metrics.class));
} }
@Test @Test
public void allowsCustomLog4J2MetricsToBeUsed() { public void allowsCustomLog4J2MetricsToBeUsed() {
assertThat(LogManager.getContext().getClass().getName())
.isEqualTo("org.apache.logging.log4j.core.LoggerContext");
this.contextRunner.withUserConfiguration(CustomLog4J2MetricsConfiguration.class) this.contextRunner.withUserConfiguration(CustomLog4J2MetricsConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(Log4j2Metrics.class) .run((context) -> assertThat(context).hasSingleBean(Log4j2Metrics.class)
.hasBean("customLog4J2Metrics")); .hasBean("customLog4J2Metrics"));
......
...@@ -17,15 +17,13 @@ ...@@ -17,15 +17,13 @@
package org.springframework.boot.actuate.autoconfigure.metrics; package org.springframework.boot.actuate.autoconfigure.metrics;
import io.micrometer.core.instrument.binder.logging.Log4j2Metrics; import io.micrometer.core.instrument.binder.logging.Log4j2Metrics;
import org.junit.Test; import org.apache.logging.log4j.LogManager;
import org.junit.runner.RunWith; import org.apache.logging.slf4j.SLF4JLoggerContext;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun; import org.springframework.boot.actuate.autoconfigure.metrics.test.MetricsRun;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.testsupport.runner.classpath.ClassPathExclusions;
import org.springframework.boot.testsupport.runner.classpath.ClassPathOverrides;
import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
...@@ -34,10 +32,6 @@ import static org.assertj.core.api.Assertions.assertThat; ...@@ -34,10 +32,6 @@ import static org.assertj.core.api.Assertions.assertThat;
* *
* @author Andy Wilkinson * @author Andy Wilkinson
*/ */
@RunWith(ModifiedClassPathRunner.class)
@ClassPathOverrides({ "org.apache.logging.log4j:log4j-to-slf4j:2.11.1",
"org.apache.logging.log4j:log4j-core:2.11.1" })
@ClassPathExclusions("log4j-slf4j-impl-*.jar")
public class Log4J2MetricsWithSlf4jLoggerContextAutoConfigurationTests { public class Log4J2MetricsWithSlf4jLoggerContextAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
...@@ -46,6 +40,7 @@ public class Log4J2MetricsWithSlf4jLoggerContextAutoConfigurationTests { ...@@ -46,6 +40,7 @@ public class Log4J2MetricsWithSlf4jLoggerContextAutoConfigurationTests {
@Test @Test
public void backsOffWhenLoggerContextIsBackedBySlf4j() { public void backsOffWhenLoggerContextIsBackedBySlf4j() {
assertThat(LogManager.getContext()).isInstanceOf(SLF4JLoggerContext.class);
this.contextRunner.run( this.contextRunner.run(
(context) -> assertThat(context).doesNotHaveBean(Log4j2Metrics.class)); (context) -> assertThat(context).doesNotHaveBean(Log4j2Metrics.class));
} }
......
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="test" packages="">
<Properties>
<Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property>
<Property name="LOG_LEVEL_PATTERN">%5p</Property>
</Properties>
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT" follow="true">
<PatternLayout pattern="%clr{%d{yyyy-MM-dd HH:mm:ss.SSS}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD}"/>
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
...@@ -294,23 +294,18 @@ ...@@ -294,23 +294,18 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.xml.bind</groupId> <groupId>ch.qos.logback</groupId>
<artifactId>jaxb-api</artifactId> <artifactId>logback-classic</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>javax.xml.bind</groupId>
<artifactId>log4j-slf4j-impl</artifactId> <artifactId>jaxb-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId> <artifactId>log4j-to-slf4j</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
......
...@@ -767,7 +767,7 @@ ...@@ -767,7 +767,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId> <artifactId>log4j-to-slf4j</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
...@@ -790,11 +790,6 @@ ...@@ -790,11 +790,6 @@
<artifactId>neo4j-ogm-embedded-driver</artifactId> <artifactId>neo4j-ogm-embedded-driver</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId> <artifactId>spring-test</artifactId>
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.autoconfigure.data.elasticsearch; package org.springframework.boot.autoconfigure.data.elasticsearch;
import java.util.List; import java.util.List;
...@@ -22,10 +21,12 @@ import org.elasticsearch.client.Client; ...@@ -22,10 +21,12 @@ import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNode;
import org.junit.After; import org.junit.After;
import org.junit.jupiter.api.Test; import org.junit.ClassRule;
import org.junit.Test;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.testsupport.testcontainers.ElasticsearchContainer;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -41,6 +42,9 @@ import static org.mockito.Mockito.mock; ...@@ -41,6 +42,9 @@ import static org.mockito.Mockito.mock;
*/ */
public class ElasticsearchAutoConfigurationTests { public class ElasticsearchAutoConfigurationTests {
@ClassRule
public static ElasticsearchContainer elasticsearch = new ElasticsearchContainer();
private AnnotationConfigApplicationContext context; private AnnotationConfigApplicationContext context;
@After @After
...@@ -65,19 +69,17 @@ public class ElasticsearchAutoConfigurationTests { ...@@ -65,19 +69,17 @@ public class ElasticsearchAutoConfigurationTests {
@Test @Test
public void createTransportClient() { public void createTransportClient() {
this.context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
new ElasticsearchNodeTemplate().doWithNode((node) -> { TestPropertyValues
TestPropertyValues.of( .of("spring.data.elasticsearch.cluster-nodes:localhost:"
"spring.data.elasticsearch.cluster-nodes:localhost:" + elasticsearch.getMappedTransportPort(),
+ node.getTcpPort(), "spring.data.elasticsearch.cluster-name:docker-cluster")
"spring.data.elasticsearch.properties.path.home:target/es/client") .applyTo(this.context);
.applyTo(this.context); this.context.register(PropertyPlaceholderAutoConfiguration.class,
this.context.register(PropertyPlaceholderAutoConfiguration.class, ElasticsearchAutoConfiguration.class);
ElasticsearchAutoConfiguration.class); this.context.refresh();
this.context.refresh(); List<DiscoveryNode> connectedNodes = this.context.getBean(TransportClient.class)
List<DiscoveryNode> connectedNodes = this.context .connectedNodes();
.getBean(TransportClient.class).connectedNodes(); assertThat(connectedNodes).hasSize(1);
assertThat(connectedNodes).hasSize(1);
});
} }
@Configuration @Configuration
......
...@@ -17,10 +17,12 @@ ...@@ -17,10 +17,12 @@
package org.springframework.boot.autoconfigure.data.elasticsearch; package org.springframework.boot.autoconfigure.data.elasticsearch;
import org.junit.After; import org.junit.After;
import org.junit.jupiter.api.Test; import org.junit.ClassRule;
import org.junit.Test;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.testsupport.testcontainers.ElasticsearchContainer;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
...@@ -36,6 +38,9 @@ import static org.assertj.core.api.Assertions.assertThat; ...@@ -36,6 +38,9 @@ import static org.assertj.core.api.Assertions.assertThat;
*/ */
public class ElasticsearchDataAutoConfigurationTests { public class ElasticsearchDataAutoConfigurationTests {
@ClassRule
public static ElasticsearchContainer elasticsearch = new ElasticsearchContainer();
private AnnotationConfigApplicationContext context; private AnnotationConfigApplicationContext context;
@After @After
...@@ -55,55 +60,46 @@ public class ElasticsearchDataAutoConfigurationTests { ...@@ -55,55 +60,46 @@ public class ElasticsearchDataAutoConfigurationTests {
@Test @Test
public void templateExists() { public void templateExists() {
this.context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
new ElasticsearchNodeTemplate().doWithNode((node) -> { TestPropertyValues
TestPropertyValues .of("spring.data.elasticsearch.cluster-nodes:localhost:"
.of("spring.data.elasticsearch.properties.path.data:target/data", + elasticsearch.getMappedTransportPort(),
"spring.data.elasticsearch.properties.path.logs:target/logs", "spring.data.elasticsearch.cluster-name:docker-cluster")
"spring.data.elasticsearch.cluster-nodes:localhost:" .applyTo(this.context);
+ node.getTcpPort()) this.context.register(PropertyPlaceholderAutoConfiguration.class,
.applyTo(this.context); ElasticsearchAutoConfiguration.class,
this.context.register(PropertyPlaceholderAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class);
ElasticsearchAutoConfiguration.class, this.context.refresh();
ElasticsearchDataAutoConfiguration.class); assertHasSingleBean(ElasticsearchTemplate.class);
this.context.refresh();
assertHasSingleBean(ElasticsearchTemplate.class);
});
} }
@Test @Test
public void mappingContextExists() { public void mappingContextExists() {
this.context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
new ElasticsearchNodeTemplate().doWithNode((node) -> { TestPropertyValues
TestPropertyValues .of("spring.data.elasticsearch.cluster-nodes:localhost:"
.of("spring.data.elasticsearch.properties.path.data:target/data", + elasticsearch.getMappedTransportPort(),
"spring.data.elasticsearch.properties.path.logs:target/logs", "spring.data.elasticsearch.cluster-name:docker-cluster")
"spring.data.elasticsearch.cluster-nodes:localhost:" .applyTo(this.context);
+ node.getTcpPort()) this.context.register(PropertyPlaceholderAutoConfiguration.class,
.applyTo(this.context); ElasticsearchAutoConfiguration.class,
this.context.register(PropertyPlaceholderAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class);
ElasticsearchAutoConfiguration.class, this.context.refresh();
ElasticsearchDataAutoConfiguration.class); assertHasSingleBean(SimpleElasticsearchMappingContext.class);
this.context.refresh();
assertHasSingleBean(SimpleElasticsearchMappingContext.class);
});
} }
@Test @Test
public void converterExists() { public void converterExists() {
this.context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
new ElasticsearchNodeTemplate().doWithNode((node) -> { TestPropertyValues
TestPropertyValues .of("spring.data.elasticsearch.cluster-nodes:localhost:"
.of("spring.data.elasticsearch.properties.path.data:target/data", + elasticsearch.getMappedTransportPort(),
"spring.data.elasticsearch.properties.path.logs:target/logs", "spring.data.elasticsearch.cluster-name:docker-cluster")
"spring.data.elasticsearch.cluster-nodes:localhost:" .applyTo(this.context);
+ node.getTcpPort()) this.context.register(PropertyPlaceholderAutoConfiguration.class,
.applyTo(this.context); ElasticsearchAutoConfiguration.class,
this.context.register(PropertyPlaceholderAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class);
ElasticsearchAutoConfiguration.class, this.context.refresh();
ElasticsearchDataAutoConfiguration.class); assertHasSingleBean(ElasticsearchConverter.class);
this.context.refresh();
assertHasSingleBean(ElasticsearchConverter.class);
});
} }
private void assertHasSingleBean(Class<?> type) { private void assertHasSingleBean(Class<?> type) {
......
/*
* Copyright 2012-2018 the original author or authors.
*
* 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 org.springframework.boot.autoconfigure.data.elasticsearch;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.function.Consumer;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.node.InternalSettingsPreparer;
import org.elasticsearch.node.Node;
import org.elasticsearch.node.NodeValidationException;
import org.elasticsearch.transport.Netty4Plugin;
import org.elasticsearch.transport.Transport;
/**
* Helper class for managing an Elasticsearch {@link Node}.
*
* @author Andy Wilkinson
*/
public class ElasticsearchNodeTemplate {
public void doWithNode(Consumer<ElasticsearchNode> consumer) {
System.setProperty("es.set.netty.runtime.available.processors", "false");
Node node = null;
try {
node = startNode();
consumer.accept(new ElasticsearchNode(node));
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
finally {
if (node != null) {
try {
node.close();
}
catch (Exception ex) {
// Continue
}
}
System.clearProperty("es.set.netty.runtime.available.processors");
}
}
private Node startNode() throws NodeValidationException {
Node node = new NettyTransportNode();
node.start();
return node;
}
private static final class NettyTransportNode extends Node {
private NettyTransportNode() {
super(InternalSettingsPreparer.prepareEnvironment(Settings.builder()
.put("path.home", "target/es/node").put("transport.type", "netty4")
.put("http.enabled", true).put("node.portsfile", true)
.put("http.port", 0).put("transport.tcp.port", 0).build(), null),
Arrays.asList(Netty4Plugin.class));
new File("target/es/node/logs").mkdirs();
}
}
public final class ElasticsearchNode {
private final Node node;
private ElasticsearchNode(Node node) {
this.node = node;
}
public int getTcpPort() {
return this.node.injector().getInstance(Transport.class).boundAddress()
.publishAddress().getPort();
}
public int getHttpPort() {
try {
for (String line : Files
.readAllLines(Paths.get("target/es/node/logs/http.ports"))) {
if (line.startsWith("127.0.0.1")) {
return Integer.parseInt(line.substring(line.indexOf(":") + 1));
}
}
throw new IllegalStateException("HTTP port not found");
}
catch (IOException ex) {
throw new IllegalStateException("Failed to read HTTP port", ex);
}
}
}
}
...@@ -18,19 +18,17 @@ package org.springframework.boot.autoconfigure.data.elasticsearch; ...@@ -18,19 +18,17 @@ package org.springframework.boot.autoconfigure.data.elasticsearch;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.junit.After; import org.junit.After;
import org.junit.ClassRule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.data.alt.elasticsearch.CityElasticsearchDbRepository; import org.springframework.boot.autoconfigure.data.alt.elasticsearch.CityElasticsearchDbRepository;
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchNodeTemplate.ElasticsearchNode;
import org.springframework.boot.autoconfigure.data.elasticsearch.city.City; import org.springframework.boot.autoconfigure.data.elasticsearch.city.City;
import org.springframework.boot.autoconfigure.data.elasticsearch.city.CityRepository; import org.springframework.boot.autoconfigure.data.elasticsearch.city.CityRepository;
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage; import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.testsupport.runner.classpath.ClassPathOverrides; import org.springframework.boot.testsupport.testcontainers.ElasticsearchContainer;
import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories; import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
...@@ -43,10 +41,11 @@ import static org.assertj.core.api.Assertions.assertThat; ...@@ -43,10 +41,11 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Phillip Webb * @author Phillip Webb
* @author Andy Wilkinson * @author Andy Wilkinson
*/ */
@RunWith(ModifiedClassPathRunner.class)
@ClassPathOverrides("org.apache.logging.log4j:log4j-core:2.10.0")
public class ElasticsearchRepositoriesAutoConfigurationTests { public class ElasticsearchRepositoriesAutoConfigurationTests {
@ClassRule
public static ElasticsearchContainer elasticsearch = new ElasticsearchContainer();
private AnnotationConfigApplicationContext context; private AnnotationConfigApplicationContext context;
@After @After
...@@ -56,34 +55,27 @@ public class ElasticsearchRepositoriesAutoConfigurationTests { ...@@ -56,34 +55,27 @@ public class ElasticsearchRepositoriesAutoConfigurationTests {
@Test @Test
public void testDefaultRepositoryConfiguration() { public void testDefaultRepositoryConfiguration() {
new ElasticsearchNodeTemplate().doWithNode((node) -> { load(TestConfiguration.class);
load(TestConfiguration.class, node); assertThat(this.context.getBean(CityRepository.class)).isNotNull();
assertThat(this.context.getBean(CityRepository.class)).isNotNull(); assertThat(this.context.getBean(Client.class)).isNotNull();
assertThat(this.context.getBean(Client.class)).isNotNull();
});
} }
@Test @Test
public void testNoRepositoryConfiguration() { public void testNoRepositoryConfiguration() {
new ElasticsearchNodeTemplate().doWithNode((node) -> { load(EmptyConfiguration.class);
load(EmptyConfiguration.class, node); assertThat(this.context.getBean(Client.class)).isNotNull();
assertThat(this.context.getBean(Client.class)).isNotNull();
});
} }
@Test @Test
public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() { public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() {
new ElasticsearchNodeTemplate().doWithNode((node) -> { load(CustomizedConfiguration.class);
load(CustomizedConfiguration.class, node); assertThat(this.context.getBean(CityElasticsearchDbRepository.class)).isNotNull();
assertThat(this.context.getBean(CityElasticsearchDbRepository.class))
.isNotNull();
});
} }
private void load(Class<?> config, ElasticsearchNode node) { private void load(Class<?> config) {
this.context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
addElasticsearchProperties(this.context, node); addElasticsearchProperties(this.context);
this.context.register(config, ElasticsearchAutoConfiguration.class, this.context.register(config, ElasticsearchAutoConfiguration.class,
ElasticsearchRepositoriesAutoConfiguration.class, ElasticsearchRepositoriesAutoConfiguration.class,
ElasticsearchDataAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class,
...@@ -91,11 +83,11 @@ public class ElasticsearchRepositoriesAutoConfigurationTests { ...@@ -91,11 +83,11 @@ public class ElasticsearchRepositoriesAutoConfigurationTests {
this.context.refresh(); this.context.refresh();
} }
private void addElasticsearchProperties(AnnotationConfigApplicationContext context, private void addElasticsearchProperties(AnnotationConfigApplicationContext context) {
ElasticsearchNode node) { TestPropertyValues.of(
TestPropertyValues.of("spring.data.elasticsearch.properties.path.home:target", "spring.data.elasticsearch.cluster-nodes:localhost:"
"spring.data.elasticsearch.cluster-nodes:localhost:" + node.getTcpPort()) + elasticsearch.getMappedTransportPort(),
.applyTo(context); "spring.data.elasticsearch.cluster-name:docker-cluster").applyTo(context);
} }
@Configuration @Configuration
......
...@@ -27,18 +27,14 @@ import io.searchbox.client.JestResult; ...@@ -27,18 +27,14 @@ import io.searchbox.client.JestResult;
import io.searchbox.client.http.JestHttpClient; import io.searchbox.client.http.JestHttpClient;
import io.searchbox.core.Get; import io.searchbox.core.Get;
import io.searchbox.core.Index; import io.searchbox.core.Index;
import org.junit.After; import org.junit.ClassRule;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchNodeTemplate;
import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration; import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.testsupport.runner.classpath.ClassPathOverrides; import org.springframework.boot.testsupport.testcontainers.ElasticsearchContainer;
import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
...@@ -52,24 +48,15 @@ import static org.mockito.Mockito.mock; ...@@ -52,24 +48,15 @@ import static org.mockito.Mockito.mock;
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Andy Wilkinson * @author Andy Wilkinson
*/ */
@RunWith(ModifiedClassPathRunner.class)
@ClassPathOverrides("org.apache.logging.log4j:log4j-core:2.10.0")
public class JestAutoConfigurationTests { public class JestAutoConfigurationTests {
@ClassRule
public static ElasticsearchContainer elasticsearch = new ElasticsearchContainer();
private ApplicationContextRunner contextRunner = new ApplicationContextRunner() private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(GsonAutoConfiguration.class, .withConfiguration(AutoConfigurations.of(GsonAutoConfiguration.class,
JestAutoConfiguration.class)); JestAutoConfiguration.class));
@Before
public void preventElasticsearchFromConfiguringNetty() {
System.setProperty("es.set.netty.runtime.available.processors", "false");
}
@After
public void close() {
System.clearProperty("es.set.netty.runtime.available.processors");
}
@Test @Test
public void jestClientOnLocalhostByDefault() { public void jestClientOnLocalhostByDefault() {
this.contextRunner this.contextRunner
...@@ -122,9 +109,9 @@ public class JestAutoConfigurationTests { ...@@ -122,9 +109,9 @@ public class JestAutoConfigurationTests {
@Test @Test
public void jestCanCommunicateWithElasticsearchInstance() { public void jestCanCommunicateWithElasticsearchInstance() {
new ElasticsearchNodeTemplate().doWithNode((node) -> this.contextRunner this.contextRunner
.withPropertyValues("spring.elasticsearch.jest.uris=http://localhost:" .withPropertyValues("spring.elasticsearch.jest.uris=http://localhost:"
+ node.getHttpPort()) + elasticsearch.getMappedPort())
.run((context) -> { .run((context) -> {
JestClient client = context.getBean(JestClient.class); JestClient client = context.getBean(JestClient.class);
Map<String, String> source = new HashMap<>(); Map<String, String> source = new HashMap<>();
...@@ -136,7 +123,7 @@ public class JestAutoConfigurationTests { ...@@ -136,7 +123,7 @@ public class JestAutoConfigurationTests {
Get getRequest = new Get.Builder("foo", "1").build(); Get getRequest = new Get.Builder("foo", "1").build();
assertThat(execute(client, getRequest).getResponseCode()) assertThat(execute(client, getRequest).getResponseCode())
.isEqualTo(200); .isEqualTo(200);
})); });
} }
private JestResult execute(JestClient client, Action<? extends JestResult> action) { private JestResult execute(JestClient client, Action<? extends JestResult> action) {
......
...@@ -25,11 +25,12 @@ import org.elasticsearch.action.index.IndexRequest; ...@@ -25,11 +25,12 @@ import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.RestHighLevelClient;
import org.junit.jupiter.api.Test; import org.junit.ClassRule;
import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchNodeTemplate;
import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.testsupport.testcontainers.ElasticsearchContainer;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
...@@ -44,6 +45,9 @@ import static org.mockito.Mockito.mock; ...@@ -44,6 +45,9 @@ import static org.mockito.Mockito.mock;
*/ */
public class RestClientAutoConfigurationTests { public class RestClientAutoConfigurationTests {
@ClassRule
public static ElasticsearchContainer elasticsearch = new ElasticsearchContainer();
private ApplicationContextRunner contextRunner = new ApplicationContextRunner() private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(RestClientAutoConfiguration.class)); .withConfiguration(AutoConfigurations.of(RestClientAutoConfiguration.class));
...@@ -77,9 +81,9 @@ public class RestClientAutoConfigurationTests { ...@@ -77,9 +81,9 @@ public class RestClientAutoConfigurationTests {
@Test @Test
public void restClientCanQueryElasticsearchNode() { public void restClientCanQueryElasticsearchNode() {
new ElasticsearchNodeTemplate().doWithNode((node) -> this.contextRunner this.contextRunner
.withPropertyValues("spring.elasticsearch.rest.uris=http://localhost:" .withPropertyValues("spring.elasticsearch.rest.uris=http://localhost:"
+ node.getHttpPort()) + RestClientAutoConfigurationTests.elasticsearch.getMappedPort())
.run((context) -> { .run((context) -> {
RestHighLevelClient client = context RestHighLevelClient client = context
.getBean(RestHighLevelClient.class); .getBean(RestHighLevelClient.class);
...@@ -92,7 +96,7 @@ public class RestClientAutoConfigurationTests { ...@@ -92,7 +96,7 @@ public class RestClientAutoConfigurationTests {
GetRequest getRequest = new GetRequest("foo", "bar", "1"); GetRequest getRequest = new GetRequest("foo", "bar", "1");
assertThat(client.get(getRequest, RequestOptions.DEFAULT).isExists()) assertThat(client.get(getRequest, RequestOptions.DEFAULT).isExists())
.isTrue(); .isTrue();
})); });
} }
@Configuration @Configuration
......
...@@ -77,6 +77,10 @@ class Container implements TestRule { ...@@ -77,6 +77,10 @@ class Container implements TestRule {
return this.container.getMappedPort(this.port); return this.container.getMappedPort(this.port);
} }
protected GenericContainer<?> getContainer() {
return this.container;
}
private static class SkipStatement extends Statement { private static class SkipStatement extends Statement {
@Override @Override
......
/*
* Copyright 2012-2018 the original author or authors.
*
* 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 org.springframework.boot.testsupport.testcontainers;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
/**
* A {@link Container} for Elasticsearch.
*
* @author Andy Wilkinson
*/
public class ElasticsearchContainer extends Container {
public ElasticsearchContainer() {
super("elasticsearch:6.4.3", 9200, (container) -> container.addExposedPort(9300));
}
public int getMappedTransportPort() {
return getContainer().getMappedPort(9300);
}
@Override
public Statement apply(Statement base, Description description) {
Statement wrapped = super.apply(base, description);
return new Statement() {
@Override
public void evaluate() throws Throwable {
System.setProperty("es.set.netty.runtime.available.processors", "false");
try {
wrapped.evaluate();
}
finally {
System.clearProperty("es.set.netty.runtime.available.processors");
}
}
};
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment