diff --git a/instrument-starters/opentracing-spring-cloud-mongo-starter/src/main/java/io/opentracing/contrib/spring/cloud/mongo/MongoTracingAutoConfiguration.java b/instrument-starters/opentracing-spring-cloud-mongo-starter/src/main/java/io/opentracing/contrib/spring/cloud/mongo/MongoTracingAutoConfiguration.java index 0e9141f0..7fe89ac8 100644 --- a/instrument-starters/opentracing-spring-cloud-mongo-starter/src/main/java/io/opentracing/contrib/spring/cloud/mongo/MongoTracingAutoConfiguration.java +++ b/instrument-starters/opentracing-spring-cloud-mongo-starter/src/main/java/io/opentracing/contrib/spring/cloud/mongo/MongoTracingAutoConfiguration.java @@ -14,49 +14,32 @@ package io.opentracing.contrib.spring.cloud.mongo; import com.mongodb.MongoClient; -import com.mongodb.MongoClientOptions; import io.opentracing.Tracer; -import io.opentracing.contrib.mongo.TracingMongoClient; -import io.opentracing.contrib.mongo.common.TracingCommandListener; -import io.opentracing.contrib.mongo.common.TracingCommandListener.Builder; -import io.opentracing.contrib.mongo.common.providers.PrefixSpanNameProvider; import io.opentracing.contrib.spring.tracer.configuration.TracerAutoConfiguration; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; -import org.springframework.boot.autoconfigure.mongo.MongoProperties; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; /** * @author Vivien Maleze */ @Configuration -@AutoConfigureBefore(MongoAutoConfiguration.class) -@ConditionalOnClass(MongoClient.class) -@ConditionalOnBean(Tracer.class) -@AutoConfigureAfter(TracerAutoConfiguration.class) +@AutoConfigureAfter({ TracerAutoConfiguration.class, MongoAutoConfiguration.class }) +@ConditionalOnBean({ Tracer.class, MongoClient.class }) @ConditionalOnProperty(name = "opentracing.spring.cloud.mongo.enabled", havingValue = "true", matchIfMissing = true) -public class MongoTracingAutoConfiguration extends MongoAutoConfiguration { +public class MongoTracingAutoConfiguration { - private Tracer tracer; + private final Tracer tracer; - public MongoTracingAutoConfiguration(@Autowired(required = false) MongoProperties properties, - ObjectProvider options, Environment environment, Tracer tracer) { - super(properties, options, environment); + public MongoTracingAutoConfiguration(final Tracer tracer) { this.tracer = tracer; } - @Override - public MongoClient mongo() { - MongoClient mongo = super.mongo(); - TracingCommandListener commandListener = new Builder(tracer) - .build(); - return new TracingMongoClient(commandListener, mongo.getAllAddress(), mongo.getCredentialsList(), mongo.getMongoClientOptions()); + @Bean + TracingMongoClientPostProcessor tracingMongoClientPostProcessor() { + return new TracingMongoClientPostProcessor(tracer); } } diff --git a/instrument-starters/opentracing-spring-cloud-mongo-starter/src/main/java/io/opentracing/contrib/spring/cloud/mongo/TracingMongoClientPostProcessor.java b/instrument-starters/opentracing-spring-cloud-mongo-starter/src/main/java/io/opentracing/contrib/spring/cloud/mongo/TracingMongoClientPostProcessor.java new file mode 100644 index 00000000..b1d9c36f --- /dev/null +++ b/instrument-starters/opentracing-spring-cloud-mongo-starter/src/main/java/io/opentracing/contrib/spring/cloud/mongo/TracingMongoClientPostProcessor.java @@ -0,0 +1,45 @@ +/** + * Copyright 2017-2019 The OpenTracing 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 io.opentracing.contrib.spring.cloud.mongo; + +import com.mongodb.MongoClient; +import io.opentracing.Tracer; +import io.opentracing.contrib.mongo.TracingMongoClient; +import io.opentracing.contrib.mongo.common.TracingCommandListener; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; + +class TracingMongoClientPostProcessor implements BeanPostProcessor { + + private final Tracer tracer; + + TracingMongoClientPostProcessor(Tracer tracer) { + this.tracer = tracer; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + + if (bean instanceof MongoClient && !(bean instanceof TracingMongoClient)) { + final MongoClient client = (MongoClient) bean; + + final TracingCommandListener commandListener = new TracingCommandListener.Builder(tracer) + .build(); + + return new TracingMongoClient(commandListener, client.getAllAddress(), client.getCredentialsList(), client.getMongoClientOptions()); + } + + return bean; + } +} diff --git a/instrument-starters/opentracing-spring-cloud-mongo-starter/src/test/java/io/opentracing/contrib/spring/cloud/mongo/MongoTracingAutoConfigurationTest.java b/instrument-starters/opentracing-spring-cloud-mongo-starter/src/test/java/io/opentracing/contrib/spring/cloud/mongo/MongoTracingAutoConfigurationTest.java index cec74db3..1d9beb7b 100644 --- a/instrument-starters/opentracing-spring-cloud-mongo-starter/src/test/java/io/opentracing/contrib/spring/cloud/mongo/MongoTracingAutoConfigurationTest.java +++ b/instrument-starters/opentracing-spring-cloud-mongo-starter/src/test/java/io/opentracing/contrib/spring/cloud/mongo/MongoTracingAutoConfigurationTest.java @@ -1,5 +1,5 @@ /** - * Copyright 2017-2018 The OpenTracing Authors + * Copyright 2017-2019 The OpenTracing 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 @@ -13,16 +13,18 @@ */ package io.opentracing.contrib.spring.cloud.mongo; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import com.mongodb.MongoClient; +import com.mongodb.MongoClientURI; import io.opentracing.Tracer; +import io.opentracing.contrib.spring.tracer.configuration.TracerAutoConfiguration; +import org.assertj.core.api.Assertions; import org.junit.Test; -import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; +import org.springframework.boot.context.annotation.UserConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -32,22 +34,52 @@ public class MongoTracingAutoConfigurationTest { @Test - public void loadMongoTracingByDefault() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.register(TracerConfig.class, MongoTracingAutoConfiguration.class); - context.refresh(); - MongoClient mongoClient = context.getBean(MongoClient.class); - assertNotNull(mongoClient); + public void createsTracingPostProcessor() { + final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(UserConfigurations.of(TracerConfig.class, MongoConfig.class)) + .withConfiguration(AutoConfigurations.of(MongoTracingAutoConfiguration.class)); + + contextRunner.run(context -> Assertions.assertThat(context).hasSingleBean(TracingMongoClientPostProcessor.class)); + } + + @Test + public void doesNotCreateTracingPostProcessorWhenNoTracer() { + final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(UserConfigurations.of(MongoConfig.class)) + .withConfiguration(AutoConfigurations.of(MongoTracingAutoConfiguration.class)); + + contextRunner.run(context -> Assertions.assertThat(context).doesNotHaveBean(TracingMongoClientPostProcessor.class)); + } + + @Test + public void doesNotCreateTracingPostProcessorWhenNoMongoClient() { + final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(UserConfigurations.of(TracerConfig.class)) + .withConfiguration(AutoConfigurations.of(MongoTracingAutoConfiguration.class)); + + contextRunner.run(context -> Assertions.assertThat(context).doesNotHaveBean(TracingMongoClientPostProcessor.class)); + } + + @Test + public void doesNotCreateTracingPostProcessorWhenDisabled() { + final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues("opentracing.spring.cloud.mongo.enabled=false") + .withConfiguration(UserConfigurations.of(TracerConfig.class, MongoConfig.class)) + .withConfiguration(AutoConfigurations.of(MongoTracingAutoConfiguration.class)); + + contextRunner.run(context -> Assertions.assertThat(context).doesNotHaveBean(TracingMongoClientPostProcessor.class)); } @Test - public void disableMongoTracing() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.register(TracerConfig.class, MongoTracingAutoConfiguration.class); - TestPropertyValues.of("opentracing.spring.cloud.mongo.enabled:false").applyTo(context); - context.refresh(); - String[] tracingMongoClientBeans = context.getBeanNamesForType(MongoClient.class); - assertThat(tracingMongoClientBeans.length, is(0)); + public void createsTracingPostProcessorWhenAutoConfigured() { + final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + MongoTracingAutoConfiguration.class, + TracerAutoConfiguration.class, + MongoAutoConfiguration.class + )); + + contextRunner.run(context -> Assertions.assertThat(context).hasSingleBean(TracingMongoClientPostProcessor.class)); } @Configuration @@ -58,4 +90,13 @@ public Tracer tracer() { return mock(Tracer.class); } } -} \ No newline at end of file + + @Configuration + static class MongoConfig { + + @Bean + public MongoClient client() { + return new MongoClient(new MongoClientURI("mongodb://localhost/test")); + } + } +} diff --git a/instrument-starters/opentracing-spring-cloud-mongo-starter/src/test/java/io/opentracing/contrib/spring/cloud/mongo/TracingMongoClientPostProcessorTest.java b/instrument-starters/opentracing-spring-cloud-mongo-starter/src/test/java/io/opentracing/contrib/spring/cloud/mongo/TracingMongoClientPostProcessorTest.java new file mode 100644 index 00000000..5979ab86 --- /dev/null +++ b/instrument-starters/opentracing-spring-cloud-mongo-starter/src/test/java/io/opentracing/contrib/spring/cloud/mongo/TracingMongoClientPostProcessorTest.java @@ -0,0 +1,69 @@ +/** + * Copyright 2017-2019 The OpenTracing 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 io.opentracing.contrib.spring.cloud.mongo; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.mongodb.MongoClient; +import com.mongodb.MongoClientOptions; +import com.mongodb.MongoClientURI; +import io.opentracing.Tracer; +import io.opentracing.contrib.mongo.TracingMongoClient; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; + +public class TracingMongoClientPostProcessorTest { + + @Mock + private Tracer tracer; + + @Mock + private TracingMongoClient tracingClient; + + private TracingMongoClientPostProcessor processor; + + @Before + public void setup() { + processor = new TracingMongoClientPostProcessor(tracer); + } + + @Test + public void testNonMongoClientBeansAreReturnedUnaltered() { + + final Object expected = new Object(); + + final Object actual = processor.postProcessAfterInitialization(expected, "any-bean-name"); + + assertThat(actual).isSameAs(expected); + } + + @Test + public void testMongoClientBeansReplacedWithTracingClient() { + + final MongoClient client = new MongoClient(new MongoClientURI("mongodb://localhost/test", MongoClientOptions.builder())); + + final Object actual = processor.postProcessAfterInitialization(client, "any-bean-name"); + + assertThat(actual).isInstanceOf(TracingMongoClient.class); + } + + @Test + public void testTracingMongoClientBeanNotWrapped() { + + final Object actual = processor.postProcessAfterInitialization(tracingClient, "any-bean-name"); + + assertThat(actual).isSameAs(tracingClient); + } +}