Added integration tests
This commit is contained in:
18
pom.xml
18
pom.xml
@@ -198,6 +198,24 @@
|
||||
<artifactId>groovy</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jayway.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
<version>1.7.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.tomakehurst</groupId>
|
||||
<artifactId>wiremock</artifactId>
|
||||
<version>2.0.6-beta</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>pl.pragmatists</groupId>
|
||||
<artifactId>JUnitParams</artifactId>
|
||||
<version>1.0.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
||||
@@ -115,6 +115,21 @@
|
||||
<version>2.1.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jayway.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.tomakehurst</groupId>
|
||||
<artifactId>wiremock</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>pl.pragmatists</groupId>
|
||||
<artifactId>JUnitParams</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -19,13 +19,17 @@ package org.springframework.cloud.sleuth.instrument.scheduling;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.cloud.sleuth.IdGenerator;
|
||||
import org.springframework.cloud.sleuth.MilliSpan;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
/**
|
||||
* Aspect that creates a new Span for running threads executing methods annotated with {@link Scheduled} annotation.
|
||||
* For every execution of scheduled method a new trace will be started.
|
||||
* Aspect that creates a new Span for running threads executing methods annotated with
|
||||
* {@link Scheduled} annotation. For every execution of scheduled method a new trace will
|
||||
* be started.
|
||||
*
|
||||
* @author Tomasz Nurkewicz, 4financeIT
|
||||
* @author Michal Chmielarz, 4financeIT
|
||||
@@ -38,17 +42,24 @@ import org.springframework.scheduling.annotation.Scheduled;
|
||||
public class TraceSchedulingAspect {
|
||||
|
||||
private final TraceManager trace;
|
||||
private final IdGenerator idGenerator;
|
||||
|
||||
public TraceSchedulingAspect(TraceManager trace) {
|
||||
public TraceSchedulingAspect(TraceManager trace, IdGenerator idGenerator) {
|
||||
this.trace = trace;
|
||||
this.idGenerator = idGenerator;
|
||||
}
|
||||
|
||||
@Around("execution (@org.springframework.scheduling.annotation.Scheduled * *.*(..))")
|
||||
public Object traceBackgroundThread(final ProceedingJoinPoint pjp) throws Throwable {
|
||||
Trace scope = this.trace.startSpan(pjp.toShortString());
|
||||
final Span span = this.trace.isTracing() ? this.trace.getCurrentSpan()
|
||||
: MilliSpan.builder().begin(System.currentTimeMillis())
|
||||
.traceId(this.idGenerator.create()).spanId(this.idGenerator.create())
|
||||
.build();
|
||||
Trace scope = this.trace.startSpan(pjp.toShortString(), span);
|
||||
try {
|
||||
return pjp.proceed();
|
||||
} finally {
|
||||
}
|
||||
finally {
|
||||
this.trace.close(scope);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.sleuth.IdGenerator;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -48,8 +49,8 @@ public class TraceSchedulingAutoConfiguration {
|
||||
|
||||
@ConditionalOnClass(ProceedingJoinPoint.class)
|
||||
@Bean
|
||||
public TraceSchedulingAspect traceSchedulingAspect(TraceManager trace) {
|
||||
return new TraceSchedulingAspect(trace);
|
||||
public TraceSchedulingAspect traceSchedulingAspect(TraceManager trace, IdGenerator idGenerator) {
|
||||
return new TraceSchedulingAspect(trace, idGenerator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ public class DefaultTraceManager implements TraceManager {
|
||||
+ ". You have " + "probably forgotten to close or detach " + cur);
|
||||
}
|
||||
else {
|
||||
if (span != NullTrace.INSTANCE) {
|
||||
if (span != NullTrace.INSTANCE && span!=null) {
|
||||
span.stop();
|
||||
if (savedTrace != null
|
||||
&& span.getParents().contains(savedTrace.getSpan().getSpanId())) {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.springframework.cloud.sleuth.instrument;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = true)
|
||||
@Configuration
|
||||
@EnableAutoConfiguration(exclude = {LoadBalancerAutoConfiguration.class, JmxAutoConfiguration.class})
|
||||
public class BaseConfigurationForITests {
|
||||
|
||||
@Bean static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
|
||||
return new PropertySourcesPlaceholderConfigurer();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.springframework.cloud.sleuth.instrument;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration;
|
||||
import org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.instrument.integration.TraceSpringIntegrationAutoConfiguration;
|
||||
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@EnableAutoConfiguration(exclude = { TraceSpringIntegrationAutoConfiguration.class,
|
||||
ArchaiusAutoConfiguration.class, LoadBalancerAutoConfiguration.class })
|
||||
public @interface DefaultTestAutoConfiguration {
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.springframework.cloud.sleuth.instrument.scheduling;
|
||||
|
||||
import org.springframework.cloud.sleuth.instrument.BaseConfigurationForITests;
|
||||
import org.springframework.cloud.sleuth.instrument.DefaultTestAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@Configuration
|
||||
@Import(BaseConfigurationForITests.class)
|
||||
@DefaultTestAutoConfiguration
|
||||
class ScheduledTestConfiguration {
|
||||
|
||||
@Bean TestBeanWithScheduledMethod testBeanWithScheduledMethod() {
|
||||
return new TestBeanWithScheduledMethod();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.springframework.cloud.sleuth.instrument.scheduling;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.trace.TraceContextHolder;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
class TestBeanWithScheduledMethod {
|
||||
|
||||
Span span;
|
||||
|
||||
@Scheduled(fixedDelay = 1L)
|
||||
public void scheduledMethod() {
|
||||
this.span = TraceContextHolder.getCurrentSpan();
|
||||
}
|
||||
|
||||
public Span getSpan() {
|
||||
return this.span;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.springframework.cloud.sleuth.instrument.scheduling;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static com.jayway.awaitility.Awaitility.await;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = {ScheduledTestConfiguration.class})
|
||||
public class TracingOnScheduledITest {
|
||||
|
||||
@Autowired TestBeanWithScheduledMethod beanWithScheduledMethod;
|
||||
|
||||
@Test
|
||||
public void should_have_span_set_after_scheduled_method_has_been_executed() {
|
||||
await().until(spanIsSetOnAScheduledMethod());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_have_a_new_span_set_each_time_a_scheduled_method_has_been_executed() {
|
||||
Span firstSpan = beanWithScheduledMethod.getSpan();
|
||||
await().until(differentSpanHasBeenSetThan(firstSpan));
|
||||
}
|
||||
|
||||
private Runnable spanIsSetOnAScheduledMethod() {
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Span storedSpan = beanWithScheduledMethod.getSpan();
|
||||
assertThat(storedSpan).isNotNull();
|
||||
assertThat(storedSpan.getTraceId()).isNotNull();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Runnable differentSpanHasBeenSetThan(final Span spanToCompare) {
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
assertThat(beanWithScheduledMethod.getSpan()).isNotEqualTo(spanToCompare);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.matching;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
import static junitparams.JUnitParamsRunner.$;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.cloud.sleuth.Trace;
|
||||
import org.springframework.cloud.sleuth.instrument.DefaultTestAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.instrument.web.common.HttpMockServer;
|
||||
import org.springframework.cloud.sleuth.instrument.web.common.MvcWiremockITest;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.test.context.junit4.rules.SpringClassRule;
|
||||
import org.springframework.test.context.junit4.rules.SpringMethodRule;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.context.request.async.WebAsyncTask;
|
||||
|
||||
import junitparams.JUnitParamsRunner;
|
||||
import junitparams.Parameters;
|
||||
|
||||
@SpringApplicationConfiguration(classes = {RestTemplateTraceAspectITest.CorrelationIdAspectSpecConfiguration.class})
|
||||
@Ignore("Will fail due to not setting initial values for Trace and Span IDs")
|
||||
@RunWith(JUnitParamsRunner.class)
|
||||
public class RestTemplateTraceAspectITest extends MvcWiremockITest {
|
||||
|
||||
@ClassRule public static final SpringClassRule SCR = new SpringClassRule();
|
||||
@Rule public final SpringMethodRule springMethodRule = new SpringMethodRule();
|
||||
|
||||
@Before public void setupDefaultWireMockStubbing() {
|
||||
stubInteraction(get(urlMatching(".*")), aResponse().withStatus(200));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_set_span_data_on_headers_via_aspect_in_synchronous_call() throws Exception {
|
||||
whenARequestIsSentToASyncEndpoint();
|
||||
|
||||
thenTraceIdHasBeenSetOnARequestHeader();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Parameters
|
||||
public void should_set_span_data_on_headers_via_aspect_in_asynchronous_call(String url) throws Exception {
|
||||
whenARequestIsSentToAnAsyncEndpoint(url);
|
||||
|
||||
thenTraceIdHasBeenSetOnARequestHeader();
|
||||
}
|
||||
|
||||
public Object[] parametersForShould_set_span_data_on_headers_via_aspect_in_asynchronous_call() {
|
||||
return $("/callablePing", "/webAsyncTaskPing");
|
||||
}
|
||||
|
||||
private void whenARequestIsSentToASyncEndpoint() throws Exception {
|
||||
this.mockMvc.perform(MockMvcRequestBuilders.get("/syncPing").accept(MediaType.TEXT_PLAIN)).andReturn();
|
||||
}
|
||||
|
||||
private void thenTraceIdHasBeenSetOnARequestHeader() {
|
||||
this.wireMock.verifyThat(getRequestedFor(urlMatching(".*")).withHeader(Trace.TRACE_ID_NAME, matching("^(?!\\s*$).+/))")));
|
||||
}
|
||||
|
||||
private void whenARequestIsSentToAnAsyncEndpoint(String url) throws Exception {
|
||||
MvcResult mvcResult = this.mockMvc.perform(MockMvcRequestBuilders.get(url).accept(MediaType.TEXT_PLAIN))
|
||||
.andExpect(request().asyncStarted())
|
||||
.andReturn();
|
||||
mvcResult.getAsyncResult(SECONDS.toMillis(2));
|
||||
this.mockMvc.perform(asyncDispatch(mvcResult)).
|
||||
andDo(print()).
|
||||
andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@EnableAsync
|
||||
@DefaultTestAutoConfiguration
|
||||
@Import(AspectTestingController.class)
|
||||
public static class CorrelationIdAspectSpecConfiguration {
|
||||
}
|
||||
|
||||
@RestController
|
||||
public static class AspectTestingController {
|
||||
|
||||
@Autowired HttpMockServer httpMockServer;
|
||||
@Autowired RestTemplate restTemplate;
|
||||
|
||||
@RequestMapping(value = "/syncPing", method = RequestMethod.GET, produces = MediaType.TEXT_PLAIN_VALUE)
|
||||
public String syncPing() {
|
||||
return callWiremockAndReturnOk();
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/callablePing", method = RequestMethod.GET, produces = MediaType.TEXT_PLAIN_VALUE)
|
||||
public Callable<String> asyncPing() {
|
||||
return new Callable<String>() {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
return callWiremockAndReturnOk();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/webAsyncTaskPing", method = RequestMethod.GET, produces = MediaType.TEXT_PLAIN_VALUE)
|
||||
WebAsyncTask<String> webAsyncTaskPing() {
|
||||
return new WebAsyncTask<>(new Callable<String>() {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
return callWiremockAndReturnOk();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
private String callWiremockAndReturnOk() {
|
||||
this.restTemplate.getForObject("http://localhost:"+this.httpMockServer.port(), String.class);
|
||||
return "OK";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.cloud.sleuth.IdGenerator;
|
||||
import org.springframework.cloud.sleuth.MilliSpan;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.instrument.DefaultTestAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.trace.TraceContextHolder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import com.jayway.awaitility.Awaitility;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = {TraceAsyncITest.CorrelationIdAsyncSpecConfiguration.class})
|
||||
public class TraceAsyncITest {
|
||||
|
||||
@Autowired AsyncClass asyncClass;
|
||||
@Autowired AsyncDelegation asyncDelegation;
|
||||
@Autowired IdGenerator idGenerator;
|
||||
@Autowired TraceManager traceManager;
|
||||
|
||||
@Test
|
||||
public void should_set_span_on_an_async_annotated_method() {
|
||||
final Span span = givenASpanInCurrentThread();
|
||||
|
||||
whenAsyncProcessingTakesPlace();
|
||||
|
||||
thenSpanPutInTheAsyncThreadIsSameAs(span);
|
||||
}
|
||||
|
||||
private Span givenASpanInCurrentThread() {
|
||||
Span span = MilliSpan.builder().traceId(this.idGenerator.create()).spanId(this.idGenerator.create()).build();
|
||||
this.traceManager.continueSpan(span);
|
||||
return span;
|
||||
}
|
||||
|
||||
private void whenAsyncProcessingTakesPlace() {
|
||||
this.asyncDelegation.doSthThatDelegatesToAsync();
|
||||
}
|
||||
|
||||
private void thenSpanPutInTheAsyncThreadIsSameAs(final Span span) {
|
||||
Awaitility.await().until(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
assertThat(span.getTraceId()).isNotNull().isEqualTo(TraceAsyncITest.this.asyncClass.getTraceId());
|
||||
assertThat(span.getName()).isNotEqualTo(TraceAsyncITest.this.asyncClass.getSpanName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanTrace() {
|
||||
TraceContextHolder.removeCurrentTrace();
|
||||
}
|
||||
|
||||
@DefaultTestAutoConfiguration
|
||||
@EnableAsync
|
||||
@EnableAspectJAutoProxy(proxyTargetClass = true)
|
||||
@Configuration
|
||||
public static class CorrelationIdAsyncSpecConfiguration {
|
||||
|
||||
@Bean AsyncClass asyncClass() {
|
||||
return new AsyncClass();
|
||||
}
|
||||
|
||||
@Bean AsyncDelegation asyncDelegation() {
|
||||
return new AsyncDelegation(asyncClass());
|
||||
}
|
||||
}
|
||||
|
||||
public static class AsyncDelegation {
|
||||
|
||||
private final AsyncClass asyncClass;
|
||||
|
||||
public AsyncDelegation(AsyncClass asyncClass) {
|
||||
this.asyncClass = asyncClass;
|
||||
}
|
||||
|
||||
public void doSthThatDelegatesToAsync() {
|
||||
this.asyncClass.doSth();
|
||||
}
|
||||
}
|
||||
|
||||
public static class AsyncClass {
|
||||
|
||||
AtomicReference<Span> span;
|
||||
|
||||
@Async
|
||||
public void doSth() {
|
||||
this.span = new AtomicReference<>(TraceContextHolder.getCurrentSpan());
|
||||
}
|
||||
|
||||
public String getTraceId() {
|
||||
if (this.span == null || (this.span.get() != null && this.span.get().getTraceId() == null)) {
|
||||
return null;
|
||||
}
|
||||
return this.span.get().getTraceId();
|
||||
}
|
||||
|
||||
public String getSpanName() {
|
||||
if (this.span == null || (this.span.get() != null && this.span.get().getName() == null)) {
|
||||
return null;
|
||||
}
|
||||
return this.span.get().getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web.common;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.core.Options;
|
||||
|
||||
/**
|
||||
* Custom implementation of {@link WireMockServer} that by default registers itself at port
|
||||
* {@link HttpMockServer#DEFAULT_PORT}.
|
||||
*
|
||||
* @see WireMockServer
|
||||
*
|
||||
* @author 4financeIT
|
||||
*/
|
||||
public class HttpMockServer extends WireMockServer {
|
||||
|
||||
public static final int DEFAULT_PORT = 8030;
|
||||
|
||||
HttpMockServer(int port) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
HttpMockServer() {
|
||||
super(DEFAULT_PORT);
|
||||
}
|
||||
|
||||
HttpMockServer(Options options) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
public void shutdownServer() {
|
||||
if (isRunning()) {
|
||||
stop();
|
||||
}
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web.common;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.SocketUtils;
|
||||
|
||||
@Configuration
|
||||
@Slf4j
|
||||
public class MockServerConfiguration {
|
||||
|
||||
@Bean(destroyMethod = "shutdownServer")
|
||||
HttpMockServer httpMockServer() {
|
||||
return tryToStartMockServer();
|
||||
}
|
||||
|
||||
private HttpMockServer tryToStartMockServer() {
|
||||
HttpMockServer httpMockServer = null;
|
||||
while(httpMockServer == null) {
|
||||
try {
|
||||
httpMockServer = new HttpMockServer(SocketUtils.findAvailableTcpPort());
|
||||
httpMockServer.start();
|
||||
} catch (Exception exception) {
|
||||
log.warn("Exception occurred while trying to set the port for the Wiremock server", exception);
|
||||
httpMockServer = null;
|
||||
}
|
||||
}
|
||||
return httpMockServer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web.common;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.IntegrationTest;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
* Base for specifications that use Spring's {@link MockMvc}. Provides also {@link WebApplicationContext},
|
||||
* {@link ApplicationContext}. The latter you can use to specify what
|
||||
* kind of address should be returned for a given dependency name.
|
||||
*
|
||||
* @see WebApplicationContext
|
||||
* @see ApplicationContext
|
||||
*
|
||||
* @author 4financeIT
|
||||
*/
|
||||
@WebAppConfiguration
|
||||
@IntegrationTest
|
||||
public abstract class MvcITest {
|
||||
|
||||
@Autowired protected WebApplicationContext webApplicationContext;
|
||||
@Autowired protected ApplicationContext applicationContext;
|
||||
protected MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
DefaultMockMvcBuilder mockMvcBuilder = MockMvcBuilders.webAppContextSetup(this.webApplicationContext);
|
||||
configureMockMvcBuilder(mockMvcBuilder);
|
||||
this.mockMvc = mockMvcBuilder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override in a subclass to modify mockMvcBuilder configuration (e.g. add filter).
|
||||
* <p>
|
||||
* The method from super class should be called.
|
||||
*/
|
||||
protected void configureMockMvcBuilder(DefaultMockMvcBuilder mockMvcBuilder) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web.common;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.sleuth.TraceManager;
|
||||
import org.springframework.cloud.sleuth.instrument.web.TraceFilter;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder;
|
||||
|
||||
import com.github.tomakehurst.wiremock.client.MappingBuilder;
|
||||
import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder;
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
|
||||
/**
|
||||
* Base specification for tests that use Wiremock as HTTP server stub.
|
||||
* By extending this specification you gain a bean with {@link HttpMockServer} and a {@link WireMock}
|
||||
*
|
||||
* @author 4financeIT
|
||||
* @see MockServerConfiguration
|
||||
* @see WireMock
|
||||
* @see HttpMockServer
|
||||
*
|
||||
* @author 4financeIT
|
||||
*/
|
||||
@ContextConfiguration(classes = {MockServerConfiguration.class})
|
||||
public abstract class MvcWiremockITest extends MvcITest {
|
||||
|
||||
protected WireMock wireMock;
|
||||
@Autowired protected HttpMockServer httpMockServer;
|
||||
@Autowired protected TraceManager trace;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setup() {
|
||||
super.setup();
|
||||
this.wireMock = new WireMock("localhost", this.httpMockServer.port());
|
||||
this.wireMock.resetToDefaultMappings();
|
||||
}
|
||||
|
||||
protected void stubInteraction(MappingBuilder mapping, ResponseDefinitionBuilder response) {
|
||||
this.wireMock.register(mapping.willReturn(response));
|
||||
}
|
||||
|
||||
public WireMock getWireMock() {
|
||||
return this.wireMock;
|
||||
}
|
||||
|
||||
public void setWireMock(WireMock wireMock) {
|
||||
this.wireMock = wireMock;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureMockMvcBuilder(DefaultMockMvcBuilder mockMvcBuilder) {
|
||||
mockMvcBuilder.addFilters(new TraceFilter(this.trace));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user