Bump to 3.1.x
This commit is contained in:
@@ -1,195 +1,235 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2020 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
|
||||
~
|
||||
~ https://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.
|
||||
~
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-cloud-sleuth-tests-common</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Sleuth Tests Common</name>
|
||||
<description>Spring Cloud Sleuth Tests Common</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-tests</artifactId>
|
||||
<version>3.0.2-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-instrumentation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>mockwebserver</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-quartz</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-okhttp</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-autoconfigure</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-brave</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.brave</groupId>
|
||||
<artifactId>brave-tests</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.zipkin2</groupId>
|
||||
<artifactId>zipkin</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-reporter</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-reporter-brave</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-sender-kafka</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<!-- assigned with spring-kafka -->
|
||||
<exclusion>
|
||||
<groupId>org.apache.kafka</groupId>
|
||||
<artifactId>kafka-clients</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-sender-activemq-client</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>activemq-client</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>activemq-client</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-sender-amqp-client</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<!-- assigned with spring-rabbit -->
|
||||
<exclusion>
|
||||
<groupId>com.rabbitmq</groupId>
|
||||
<artifactId>amqp-client</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2013-2021 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
|
||||
~
|
||||
~ https://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.
|
||||
~
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-cloud-sleuth-tests-common</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Sleuth Tests Common</name>
|
||||
<description>Spring Cloud Sleuth Tests Common</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-tests</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-instrumentation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>mockwebserver</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-task</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-quartz</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-okhttp</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-config-server</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-autoconfigure</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-brave</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.brave</groupId>
|
||||
<artifactId>brave-tests</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor.kafka</groupId>
|
||||
<artifactId>reactor-kafka</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>kafka</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-rsocket</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.zipkin2</groupId>
|
||||
<artifactId>zipkin</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-reporter</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-reporter-brave</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-sender-kafka</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<!-- assigned with spring-kafka -->
|
||||
<exclusion>
|
||||
<groupId>org.apache.kafka</groupId>
|
||||
<artifactId>kafka-clients</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-sender-activemq-client</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>activemq-client</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>activemq-client</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.reporter2</groupId>
|
||||
<artifactId>zipkin-sender-amqp-client</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<!-- assigned with spring-rabbit -->
|
||||
<exclusion>
|
||||
<groupId>com.rabbitmq</groupId>
|
||||
<artifactId>amqp-client</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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
|
||||
*
|
||||
* https://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.cloud.sleuth.autoconfig.instrument.reactor;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class Issue866Configuration {
|
||||
|
||||
private static final Log log = LogFactory.getLog(Issue866Configuration.class);
|
||||
|
||||
/**
|
||||
* We don't want to force direct dependencies between components because Spring might
|
||||
* just properly setup the context we want to ensure that the HRBDRPP is always
|
||||
* executed before any other object is started.
|
||||
*/
|
||||
public static TestHook hook;
|
||||
|
||||
@Bean
|
||||
HookRegisteringBeanDefinitionRegistryPostProcessor overridingProcessorForTests(
|
||||
ConfigurableApplicationContext context) {
|
||||
log.info("Registering a HookRegisteringBeanDefinitionRegistryPostProcessor for context [" + context + "]");
|
||||
TestHook hook = new TestHook(context);
|
||||
Issue866Configuration.hook = hook;
|
||||
return hook;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Hook.
|
||||
*/
|
||||
public static class TestHook extends HookRegisteringBeanDefinitionRegistryPostProcessor {
|
||||
|
||||
/**
|
||||
* Whether the hook was called.
|
||||
*/
|
||||
public boolean executed = false;
|
||||
|
||||
public TestHook(ConfigurableApplicationContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
super.postProcessBeanFactory(beanFactory);
|
||||
this.executed = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
@@ -52,7 +52,7 @@ import static org.assertj.core.api.BDDAssertions.then;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
@ContextConfiguration(classes = MultipleHopsIntegrationTests.TestConfig.class)
|
||||
@TestPropertySource(properties = { "spring.sleuth.baggage.remote-fields=x-vcap-request-id,country-code",
|
||||
@TestPropertySource(properties = { "spring.sleuth.baggage.remote-fields=x-vcap-request-id,country-code,Foo-Id",
|
||||
"spring.sleuth.baggage.local-fields=bp", "spring.sleuth.integration.enabled=true" })
|
||||
public abstract class MultipleHopsIntegrationTests {
|
||||
|
||||
@@ -62,6 +62,10 @@ public abstract class MultipleHopsIntegrationTests {
|
||||
|
||||
protected static final String COUNTRY_CODE = "country-code";
|
||||
|
||||
protected static final String CASE_INSENSITIVE_ID = "Foo-Id";
|
||||
|
||||
protected static final String NOT_PROPAGATED_HEADER = "baz-id";
|
||||
|
||||
@Autowired
|
||||
Tracer tracer;
|
||||
|
||||
@@ -117,6 +121,8 @@ public abstract class MultipleHopsIntegrationTests {
|
||||
// set request ID in a header not with the api explicitly
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.put(REQUEST_ID, Collections.singletonList("f4308d05-2228-4468-80f6-92a8377ba193"));
|
||||
headers.put(CASE_INSENSITIVE_ID, Collections.singletonList("123"));
|
||||
headers.put(NOT_PROPAGATED_HEADER, Collections.singletonList("456"));
|
||||
RequestEntity requestEntity = new RequestEntity(headers, HttpMethod.GET,
|
||||
URI.create("http://localhost:" + this.testConfig.port + "/greeting"));
|
||||
this.restTemplate.exchange(requestEntity, String.class);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
@@ -25,6 +25,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
@@ -84,9 +85,11 @@ public abstract class SleuthSpanCreatorAspectFluxTests {
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
@AfterEach
|
||||
public void setup() {
|
||||
this.spans.clear();
|
||||
this.testBean.reset();
|
||||
this.tracer.withSpan(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
@@ -69,6 +69,7 @@ public abstract class SleuthSpanCreatorAspectMonoTests {
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.spans.clear();
|
||||
this.tracer.withSpan(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
@@ -50,6 +50,7 @@ public abstract class SleuthSpanCreatorAspectTests {
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.spans.clear();
|
||||
this.tracer.withSpan(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
@@ -343,7 +343,7 @@ public abstract class LazyTraceThreadPoolTaskSchedulerTests implements TestTraci
|
||||
};
|
||||
this.executor.newThread(runnable);
|
||||
|
||||
BDDMockito.then(this.delegate).should().newThread(runnable);
|
||||
BDDMockito.then(this.delegate).should().newThread(BDDMockito.isA(TraceRunnable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -409,7 +409,7 @@ public abstract class LazyTraceThreadPoolTaskSchedulerTests implements TestTraci
|
||||
};
|
||||
this.executor.createThread(r);
|
||||
|
||||
BDDMockito.then(this.delegate).should().createThread(r);
|
||||
BDDMockito.then(this.delegate).should().createThread(BDDMockito.isA(TraceRunnable.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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
|
||||
*
|
||||
* https://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.cloud.sleuth.instrument.async;
|
||||
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
public abstract class TraceScheduledThreadPoolExecutorAnotherConstructorTests
|
||||
extends TraceScheduledThreadPoolExecutorTests {
|
||||
|
||||
@Override
|
||||
protected LazyTraceScheduledThreadPoolExecutor executor() {
|
||||
return new LazyTraceScheduledThreadPoolExecutor(1, new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
return new Thread(r);
|
||||
}
|
||||
}, new RejectedExecutionHandler() {
|
||||
@Override
|
||||
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
|
||||
|
||||
}
|
||||
}, beanFactory, delegate, "foo");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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
|
||||
*
|
||||
* https://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.cloud.sleuth.instrument.async;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Delayed;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.RunnableScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.BDDMockito;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.SpanNamer;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.internal.DefaultSpanNamer;
|
||||
import org.springframework.cloud.sleuth.internal.SleuthContextListenerAccessor;
|
||||
import org.springframework.cloud.sleuth.test.TestTracingAwareSupplier;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
public abstract class TraceScheduledThreadPoolExecutorTests implements TestTracingAwareSupplier {
|
||||
|
||||
ScheduledThreadPoolExecutor delegate = new ScheduledThreadPoolExecutor(1);
|
||||
|
||||
BeanFactory beanFactory = beanFactory();
|
||||
|
||||
LazyTraceScheduledThreadPoolExecutor traceThreadPoolTaskExecutor = executor();
|
||||
|
||||
protected LazyTraceScheduledThreadPoolExecutor executor() {
|
||||
return new LazyTraceScheduledThreadPoolExecutor(1, this.beanFactory, this.delegate, "foo");
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
SleuthContextListenerAccessor.set(this.beanFactory, true);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void clear() {
|
||||
this.delegate.shutdown();
|
||||
}
|
||||
|
||||
private BeanFactory beanFactory() {
|
||||
BeanFactory beanFactory = BDDMockito.mock(BeanFactory.class);
|
||||
BDDMockito.given(beanFactory.getBean(Tracer.class)).willReturn(tracerTest().tracing().tracer());
|
||||
BDDMockito.given(beanFactory.getBean(SpanNamer.class)).willReturn(new DefaultSpanNamer());
|
||||
return beanFactory;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.schedule(aRunnable(executed, span), 1, TimeUnit.MILLISECONDS).get(1,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
then(executed.get()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_decorate_task_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
Runnable runnable = aRunnable(executed, span);
|
||||
this.traceThreadPoolTaskExecutor.decorateTask(runnable, runnableScheduledFuture(runnable)).run();
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_decorate_task_trace_callable() throws Exception {
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
RunnableScheduledFuture<Span> fromCallable;
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
Callable<Span> callable = aCallable(span);
|
||||
fromCallable = this.traceThreadPoolTaskExecutor.decorateTask(callable, runnableScheduledFuture(callable));
|
||||
fromCallable.run();
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(fromCallable.get(10, TimeUnit.MILLISECONDS)).isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
private RunnableScheduledFuture<Span> runnableScheduledFuture(Callable<Span> run) {
|
||||
return new RunnableScheduledFuture<Span>() {
|
||||
|
||||
private Span result;
|
||||
|
||||
@Override
|
||||
public boolean isPeriodic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDelay(TimeUnit unit) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Delayed o) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
this.result = run.call();
|
||||
}
|
||||
catch (Exception exception) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span get() throws InterruptedException, ExecutionException {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span get(long timeout, TimeUnit unit)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
return this.result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private RunnableScheduledFuture<Object> runnableScheduledFuture(Runnable run) {
|
||||
return new RunnableScheduledFuture<Object>() {
|
||||
|
||||
@Override
|
||||
public boolean isPeriodic() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDelay(TimeUnit unit) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Delayed o) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
run.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get() throws InterruptedException, ExecutionException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(long timeout, TimeUnit unit)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_trace_callable() throws Exception {
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
Span spanFromCallable;
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
spanFromCallable = this.traceThreadPoolTaskExecutor.schedule(aCallable(span), 1, TimeUnit.MILLISECONDS)
|
||||
.get(1, TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
then(spanFromCallable).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_at_fixed_rate_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.scheduleAtFixedRate(aRunnable(executed, span), 1L, 1L,
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_with_fixed_delay_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.scheduleWithFixedDelay(aRunnable(executed, span), 1L, 1L,
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_execute_a_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.execute(aRunnable(executed, span));
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_trace_callable() throws Exception {
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
Span spanFromListenable;
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
spanFromListenable = this.traceThreadPoolTaskExecutor.submit(aCallable(span)).get(1, TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
then(spanFromListenable).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.submit(aRunnable(executed, span)).get(1, TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
Runnable aRunnable(AtomicBoolean executed, Span currentSpan) {
|
||||
return () -> {
|
||||
Span span = tracerTest().tracing().tracer().currentSpan();
|
||||
then(span).isNotNull();
|
||||
then(span.context().traceId()).isEqualTo(currentSpan.context().traceId());
|
||||
executed.set(true);
|
||||
};
|
||||
}
|
||||
|
||||
Callable<Span> aCallable(Span currentSpan) {
|
||||
return () -> {
|
||||
Span span = tracerTest().tracing().tracer().currentSpan();
|
||||
then(span.context().traceId()).isEqualTo(currentSpan.context().traceId());
|
||||
return span;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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
|
||||
*
|
||||
* https://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.cloud.sleuth.instrument.async;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.BDDMockito;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.SpanNamer;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.internal.DefaultSpanNamer;
|
||||
import org.springframework.cloud.sleuth.internal.SleuthContextListenerAccessor;
|
||||
import org.springframework.cloud.sleuth.test.TestTracingAwareSupplier;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
public abstract class TraceThreadPoolTaskExecutorTests implements TestTracingAwareSupplier {
|
||||
|
||||
ThreadPoolTaskExecutor delegate = new ThreadPoolTaskExecutor();
|
||||
|
||||
BeanFactory beanFactory = beanFactory();
|
||||
|
||||
LazyTraceThreadPoolTaskExecutor traceThreadPoolTaskExecutor = new LazyTraceThreadPoolTaskExecutor(this.beanFactory,
|
||||
this.delegate);
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
this.delegate.initialize();
|
||||
SleuthContextListenerAccessor.set(this.beanFactory, true);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void clear() {
|
||||
this.delegate.shutdown();
|
||||
}
|
||||
|
||||
private BeanFactory beanFactory() {
|
||||
BeanFactory beanFactory = BDDMockito.mock(BeanFactory.class);
|
||||
BDDMockito.given(beanFactory.getBean(Tracer.class)).willReturn(tracerTest().tracing().tracer());
|
||||
BDDMockito.given(beanFactory.getBean(SpanNamer.class)).willReturn(new DefaultSpanNamer());
|
||||
return beanFactory;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_create_thread_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.createThread(aRunnable(executed, span)).start();
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
BDDAssertions.then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_listenable_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.submitListenable(aRunnable(executed, span)).get();
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
BDDAssertions.then(executed.get()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_listenable_trace_callable() throws Exception {
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
Span spanFromListenable;
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
spanFromListenable = this.traceThreadPoolTaskExecutor.submitListenable(aCallable(span)).get(1,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
BDDAssertions.then(spanFromListenable).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_execute_a_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.execute(aRunnable(executed, span));
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
BDDAssertions.then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_execute_with_timeout_a_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.execute(aRunnable(executed, span), 1L);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
BDDAssertions.then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_trace_callable() throws Exception {
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
Span spanFromListenable;
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
spanFromListenable = this.traceThreadPoolTaskExecutor.submit(aCallable(span)).get(1, TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
BDDAssertions.then(spanFromListenable).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.submit(aRunnable(executed, span)).get(1, TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
BDDAssertions.then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_trace_runnable_via_new_thread() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.newThread(aRunnable(executed, span)).start();
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
BDDAssertions.then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_trace_runnable_via_create_thread() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.createThread(aRunnable(executed, span)).start();
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
BDDAssertions.then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
Runnable aRunnable(AtomicBoolean executed, Span currentSpan) {
|
||||
return () -> {
|
||||
Span span = tracerTest().tracing().tracer().currentSpan();
|
||||
BDDAssertions.then(span).isNotNull();
|
||||
BDDAssertions.then(span.context().traceId()).isEqualTo(currentSpan.context().traceId());
|
||||
executed.set(true);
|
||||
};
|
||||
}
|
||||
|
||||
Callable<Span> aCallable(Span currentSpan) {
|
||||
return () -> {
|
||||
Span span = tracerTest().tracing().tracer().currentSpan();
|
||||
BDDAssertions.then(span.context().traceId()).isEqualTo(currentSpan.context().traceId());
|
||||
return span;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,527 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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
|
||||
*
|
||||
* https://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.cloud.sleuth.instrument.async;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.BDDMockito;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.SpanNamer;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.internal.DefaultSpanNamer;
|
||||
import org.springframework.cloud.sleuth.internal.SleuthContextListenerAccessor;
|
||||
import org.springframework.cloud.sleuth.test.TestTracingAwareSupplier;
|
||||
import org.springframework.scheduling.Trigger;
|
||||
import org.springframework.scheduling.TriggerContext;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
public abstract class TraceThreadPoolTaskSchedulerTests implements TestTracingAwareSupplier {
|
||||
|
||||
ThreadPoolTaskScheduler delegate = new ThreadPoolTaskScheduler();
|
||||
|
||||
BeanFactory beanFactory = beanFactory();
|
||||
|
||||
LazyTraceThreadPoolTaskScheduler traceThreadPoolTaskExecutor = new LazyTraceThreadPoolTaskScheduler(
|
||||
this.beanFactory, this.delegate, "foo");
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
this.delegate.initialize();
|
||||
SleuthContextListenerAccessor.set(this.beanFactory, true);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void clear() {
|
||||
this.delegate.shutdown();
|
||||
}
|
||||
|
||||
private BeanFactory beanFactory() {
|
||||
BeanFactory beanFactory = BDDMockito.mock(BeanFactory.class);
|
||||
BDDMockito.given(beanFactory.getBean(Tracer.class)).willReturn(tracerTest().tracing().tracer());
|
||||
BDDMockito.given(beanFactory.getBean(SpanNamer.class)).willReturn(new DefaultSpanNamer());
|
||||
return beanFactory;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_initialize_wrapped_executor() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.initializeExecutor(new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
return new Thread(r);
|
||||
}
|
||||
}, new RejectedExecutionHandler() {
|
||||
@Override
|
||||
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
|
||||
|
||||
}
|
||||
}).submit(aRunnable(executed, span)).get(1, TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_create_wrapped_executor() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.createExecutor(1, new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
return new Thread(r);
|
||||
}
|
||||
}, new RejectedExecutionHandler() {
|
||||
@Override
|
||||
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
|
||||
|
||||
}
|
||||
}).submit(aRunnable(executed, span)).get(1, TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_get_scheduled_wrapped_executor() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.getScheduledExecutor().submit(aRunnable(executed, span)).get(1,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_get_scheduled_thread_pool_wrapped_executor() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.getScheduledThreadPoolExecutor().submit(aRunnable(executed, span)).get(1,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_create_thread_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.createThread(aRunnable(executed, span)).start();
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.schedule(aRunnable(executed, span), Instant.now()).get(1,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
then(executed.get()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_trace_runnable_with_start_time() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.schedule(aRunnable(executed, span), Date.from(Instant.now())).get(1,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
then(executed.get()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_trace_runnable_with_trigger() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.schedule(aRunnable(executed, span), new Trigger() {
|
||||
@Override
|
||||
public java.util.Date nextExecutionTime(TriggerContext triggerContext) {
|
||||
return java.util.Date.from(Instant.now());
|
||||
}
|
||||
}).get(1, TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
then(executed.get()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_at_fixed_rate_trace_runnable_with_date() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.scheduleAtFixedRate(aRunnable(executed, span), Date.from(Instant.now()),
|
||||
1L);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_at_fixed_rate_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.scheduleAtFixedRate(aRunnable(executed, span), 1L);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_at_fixed_rate_trace_runnable_with_instant() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.scheduleAtFixedRate(aRunnable(executed, span), Instant.now(),
|
||||
Duration.ofMillis(10));
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_at_fixed_rate_trace_runnable_with_duration() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.scheduleAtFixedRate(aRunnable(executed, span), Duration.ofMillis(10));
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_with_fixed_delay_trace_runnable_with_date() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.scheduleWithFixedDelay(aRunnable(executed, span), Date.from(Instant.now()),
|
||||
1L);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_with_fixed_delay_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.scheduleWithFixedDelay(aRunnable(executed, span), 1L);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_with_fixed_delay_trace_runnable_with_instant() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.scheduleWithFixedDelay(aRunnable(executed, span), Instant.now(),
|
||||
Duration.ofMillis(10));
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_with_fixed_delay_trace_runnable_with_duration() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.scheduleWithFixedDelay(aRunnable(executed, span), Duration.ofMillis(10));
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_listenable_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.submitListenable(aRunnable(executed, span)).get(1, TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_listenable_trace_callable() throws Exception {
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
Span spanFromListenable;
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
spanFromListenable = this.traceThreadPoolTaskExecutor.submitListenable(aCallable(span)).get(1,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
then(spanFromListenable).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_execute_a_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.execute(aRunnable(executed, span));
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_execute_with_timeout_a_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.execute(aRunnable(executed, span), 1L);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_trace_callable() throws Exception {
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
Span spanFromListenable;
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
spanFromListenable = this.traceThreadPoolTaskExecutor.submit(aCallable(span)).get(1, TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
then(spanFromListenable).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_trace_runnable() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.submit(aRunnable(executed, span)).get(1, TimeUnit.SECONDS);
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_trace_runnable_via_new_thread() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.newThread(aRunnable(executed, span)).start();
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_trace_runnable_via_create_thread() throws Exception {
|
||||
AtomicBoolean executed = new AtomicBoolean();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan().name("foo");
|
||||
|
||||
try (Tracer.SpanInScope ws = tracerTest().tracing().tracer().withSpan(span.start())) {
|
||||
this.traceThreadPoolTaskExecutor.createThread(aRunnable(executed, span)).start();
|
||||
}
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(executed.get()).isTrue();
|
||||
});
|
||||
}
|
||||
|
||||
Runnable aRunnable(AtomicBoolean executed, Span currentSpan) {
|
||||
return () -> {
|
||||
Span span = tracerTest().tracing().tracer().currentSpan();
|
||||
then(span).isNotNull();
|
||||
then(span.context().traceId()).isEqualTo(currentSpan.context().traceId());
|
||||
executed.set(true);
|
||||
};
|
||||
}
|
||||
|
||||
Callable<Span> aCallable(Span currentSpan) {
|
||||
return () -> {
|
||||
Span span = tracerTest().tracing().tracer().currentSpan();
|
||||
then(span.context().traceId()).isEqualTo(currentSpan.context().traceId());
|
||||
return span;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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
|
||||
*
|
||||
* https://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.cloud.sleuth.instrument.circuitbreaker;
|
||||
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JCircuitBreakerFactory;
|
||||
import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
|
||||
import org.springframework.cloud.sleuth.ScopedSpan;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.exporter.FinishedSpan;
|
||||
import org.springframework.cloud.sleuth.test.TestSpanHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
@ContextConfiguration(classes = ReactiveCircuitBreakerIntegrationTests.TestConfig.class)
|
||||
public abstract class ReactiveCircuitBreakerIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
TestSpanHandler spans;
|
||||
|
||||
@Autowired
|
||||
Tracer tracer;
|
||||
|
||||
@Autowired
|
||||
ReactiveCircuitBreakerFactory factory;
|
||||
|
||||
@Autowired
|
||||
CircuitService circuitService;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.spans.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_pass_tracing_information_when_using_circuit_breaker() {
|
||||
// given
|
||||
Tracer tracer = this.tracer;
|
||||
ScopedSpan scopedSpan = null;
|
||||
try {
|
||||
scopedSpan = tracer.startScopedSpan("start");
|
||||
// when
|
||||
Span span = this.factory.create("name").run(Mono.defer(() -> Mono.just(tracer.currentSpan()))).block();
|
||||
|
||||
BDDAssertions.then(span).isNotNull();
|
||||
BDDAssertions.then(scopedSpan.context().traceId()).isEqualTo(span.context().traceId());
|
||||
}
|
||||
finally {
|
||||
scopedSpan.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_pass_tracing_information_when_using_circuit_breaker_with_fallback() {
|
||||
// when
|
||||
BDDAssertions.then(this.circuitService.call().block()).isEqualTo("fallback");
|
||||
|
||||
BDDAssertions.then(this.spans).hasSize(2);
|
||||
String traceId = this.circuitService.firstSpan.context().traceId();
|
||||
BDDAssertions.then(this.circuitService.secondSpan.context().traceId()).isEqualTo(traceId);
|
||||
|
||||
FinishedSpan finishedSpan = this.spans.get(0);
|
||||
BDDAssertions.then(finishedSpan.getName()).contains("CircuitBreakerIntegrationTests");
|
||||
|
||||
finishedSpan = this.spans.get(1);
|
||||
BDDAssertions.then(finishedSpan.getName()).contains("function");
|
||||
}
|
||||
|
||||
public void assertException(FinishedSpan finishedSpan) {
|
||||
throw new UnsupportedOperationException("Implement this assertion");
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAutoConfiguration
|
||||
public static class TestConfig {
|
||||
|
||||
@Bean
|
||||
ReactiveResilience4JCircuitBreakerFactory reactiveResilience4JCircuitBreakerFactory() {
|
||||
return new ReactiveResilience4JCircuitBreakerFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
CircuitService circuitService(ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory, Tracer tracer) {
|
||||
return new CircuitService(reactiveCircuitBreakerFactory, tracer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class CircuitService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CircuitService.class);
|
||||
|
||||
private final ReactiveCircuitBreakerFactory factory;
|
||||
|
||||
private final Tracer tracer;
|
||||
|
||||
Span firstSpan;
|
||||
|
||||
Span secondSpan;
|
||||
|
||||
CircuitService(ReactiveCircuitBreakerFactory factory, Tracer tracer) {
|
||||
this.factory = factory;
|
||||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
Mono<String> call() {
|
||||
return this.factory.create("circuit").run(Mono.defer(() -> {
|
||||
this.firstSpan = this.tracer.currentSpan();
|
||||
log.info("<ACCEPTANCE_TEST> <TRACE:{}> Hello from consumer",
|
||||
this.tracer.currentSpan().context().traceId());
|
||||
return Mono.error(new IllegalStateException("boom"));
|
||||
}), throwable -> {
|
||||
this.secondSpan = this.tracer.currentSpan();
|
||||
log.info("<ACCEPTANCE_TEST> <TRACE:{}> Hello from producer",
|
||||
this.tracer.currentSpan().context().traceId());
|
||||
return Mono.just("fallback");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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
|
||||
*
|
||||
* https://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.cloud.sleuth.instrument.circuitbreaker;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JCircuitBreakerFactory;
|
||||
import org.springframework.cloud.sleuth.ScopedSpan;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.exporter.FinishedSpan;
|
||||
import org.springframework.cloud.sleuth.test.TestTracingAwareSupplier;
|
||||
|
||||
public abstract class ReactiveCircuitBreakerTests implements TestTracingAwareSupplier {
|
||||
|
||||
@Test
|
||||
public void should_pass_tracing_information_when_using_circuit_breaker() {
|
||||
// given
|
||||
Tracer tracer = tracerTest().tracing().tracer();
|
||||
ScopedSpan scopedSpan = null;
|
||||
try {
|
||||
scopedSpan = tracer.startScopedSpan("start");
|
||||
// when
|
||||
Span span = new TraceReactiveCircuitBreaker(new ReactiveResilience4JCircuitBreakerFactory().create("name"),
|
||||
tracer, tracerTest().tracing().currentTraceContext())
|
||||
.run(Mono.defer(() -> Mono.just(tracer.currentSpan()))).block();
|
||||
|
||||
BDDAssertions.then(span).isNotNull();
|
||||
BDDAssertions.then(scopedSpan.context().traceId()).isEqualTo(span.context().traceId());
|
||||
}
|
||||
finally {
|
||||
scopedSpan.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_pass_tracing_information_when_using_circuit_breaker_with_fallback() {
|
||||
// given
|
||||
Tracer tracer = tracerTest().tracing().tracer();
|
||||
AtomicReference<Span> first = new AtomicReference<>();
|
||||
AtomicReference<Span> second = new AtomicReference<>();
|
||||
ScopedSpan scopedSpan = null;
|
||||
try {
|
||||
scopedSpan = tracer.startScopedSpan("start");
|
||||
// when
|
||||
BDDAssertions.thenThrownBy(() -> new TraceReactiveCircuitBreaker(
|
||||
new ReactiveResilience4JCircuitBreakerFactory().create("name"), tracer,
|
||||
tracerTest().tracing().currentTraceContext()).run(Mono.defer(() -> {
|
||||
first.set(tracer.currentSpan());
|
||||
throw new IllegalStateException("boom");
|
||||
}), throwable -> {
|
||||
second.set(tracer.currentSpan());
|
||||
throw new IllegalStateException("boom2");
|
||||
}).block()).isInstanceOf(IllegalStateException.class).hasMessageContaining("boom2");
|
||||
|
||||
BDDAssertions.then(tracerTest().handler().reportedSpans()).hasSize(2);
|
||||
BDDAssertions.then(first.get()).isNotNull();
|
||||
BDDAssertions.then(second.get()).isNotNull();
|
||||
BDDAssertions.then(scopedSpan.context().traceId()).isEqualTo(first.get().context().traceId());
|
||||
BDDAssertions.then(scopedSpan.context().traceId()).isEqualTo(second.get().context().traceId());
|
||||
BDDAssertions.then(first.get().context().spanId()).isNotEqualTo(second.get().context().spanId());
|
||||
|
||||
FinishedSpan finishedSpan = tracerTest().handler().reportedSpans().get(1);
|
||||
BDDAssertions.then(finishedSpan.getName()).contains("function");
|
||||
additionalAssertions(finishedSpan);
|
||||
}
|
||||
finally {
|
||||
scopedSpan.end();
|
||||
}
|
||||
}
|
||||
|
||||
public void additionalAssertions(FinishedSpan finishedSpan) {
|
||||
throw new UnsupportedOperationException("Assert errors");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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
|
||||
*
|
||||
* https://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.cloud.sleuth.instrument.config;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.config.server.EnableConfigServer;
|
||||
import org.springframework.cloud.sleuth.exporter.FinishedSpan;
|
||||
import org.springframework.cloud.sleuth.test.TestSpanHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
@ContextConfiguration(classes = ConfigServerIntegrationTests.TestConfig.class)
|
||||
@TestPropertySource(properties = { "server.port=0",
|
||||
"spring.cloud.config.server.git.uri=https://github.com/spring-cloud-samples/config-repo" })
|
||||
public abstract class ConfigServerIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
TestSpanHandler spans;
|
||||
|
||||
@Autowired
|
||||
WebClientService webClientService;
|
||||
|
||||
@LocalServerPort
|
||||
int port;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.spans.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_instrument_config_server() {
|
||||
this.webClientService.call(port);
|
||||
|
||||
await().atMost(30, TimeUnit.SECONDS).untilAsserted(() -> {
|
||||
then(this.spans.reportedSpans()).as("1 for mvc, 1 for composite env repo and 1 for git env repo")
|
||||
.hasSize(3);
|
||||
then(this.spans.reportedSpans().stream().map(FinishedSpan::getTraceId).collect(Collectors.toSet()))
|
||||
.as("There must be 1 trace id").hasSize(1);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAutoConfiguration
|
||||
@EnableConfigServer
|
||||
public static class TestConfig {
|
||||
|
||||
@Bean
|
||||
WebClientService webClientService() {
|
||||
return new WebClientService();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class WebClientService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(WebClientService.class);
|
||||
|
||||
void call(int port) {
|
||||
log.info("Sending request");
|
||||
String result = new RestTemplate().getForObject("http://localhost:" + port + "/foo/default/main",
|
||||
String.class);
|
||||
log.info("Got [\n" + result + "\n]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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
|
||||
*
|
||||
* https://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.cloud.sleuth.instrument.kafka;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.apache.kafka.clients.producer.Callback;
|
||||
import org.apache.kafka.clients.producer.KafkaProducer;
|
||||
import org.apache.kafka.clients.producer.ProducerConfig;
|
||||
import org.apache.kafka.clients.producer.ProducerRecord;
|
||||
import org.apache.kafka.common.serialization.StringSerializer;
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.KafkaContainer;
|
||||
import org.testcontainers.containers.wait.strategy.Wait;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.propagation.Propagator;
|
||||
import org.springframework.cloud.sleuth.test.TestSpanHandler;
|
||||
import org.springframework.cloud.sleuth.test.TestTracingAwareSupplier;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
@Testcontainers
|
||||
public abstract class KafkaProducerTest implements TestTracingAwareSupplier {
|
||||
|
||||
protected Tracer tracer = tracerTest().tracing().tracer();
|
||||
|
||||
protected Propagator propagator = tracerTest().tracing().propagator();
|
||||
|
||||
protected TestSpanHandler spans = tracerTest().handler();
|
||||
|
||||
protected TracingKafkaProducer<String, String> kafkaProducer;
|
||||
|
||||
@Container
|
||||
protected final KafkaContainer kafkaContainer = new KafkaContainer(
|
||||
DockerImageName.parse("confluentinc/cp-kafka:5.2.1")).withExposedPorts(9093)
|
||||
.waitingFor(Wait.forListeningPort());
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
kafkaContainer.start();
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaContainer.getBootstrapServers());
|
||||
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
|
||||
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
|
||||
kafkaProducer = new TracingKafkaProducer<>(new KafkaProducer<>(properties), tracer, propagator,
|
||||
new TracingKafkaPropagatorSetter());
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void destroy() {
|
||||
kafkaContainer.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_create_and_finish_producer_span() {
|
||||
AtomicBoolean acknowledged = new AtomicBoolean(false);
|
||||
Callback callback = (metadata, ex) -> acknowledged.set(true);
|
||||
ProducerRecord<String, String> producerRecord = new ProducerRecord<>("spring-cloud-sleuth-otel-topic", "test",
|
||||
"test");
|
||||
this.kafkaProducer.send(producerRecord, callback);
|
||||
await().atMost(Duration.ofSeconds(5)).until(acknowledged::get);
|
||||
|
||||
BDDAssertions.then(this.tracer.currentSpan()).isNull();
|
||||
BDDAssertions.then(this.spans).isNotEmpty();
|
||||
BDDAssertions.then(this.spans.get(0).getKind()).isEqualTo(Span.Kind.PRODUCER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanUpTracing() {
|
||||
this.spans.clear();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
@@ -45,8 +45,10 @@ import org.springframework.messaging.support.ErrorMessage;
|
||||
import org.springframework.messaging.support.ExecutorChannelInterceptor;
|
||||
import org.springframework.messaging.support.ExecutorSubscribableChannel;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.messaging.support.NativeMessageHeaderAccessor.NATIVE_HEADERS;
|
||||
|
||||
@@ -348,6 +350,45 @@ public abstract class TracingChannelInterceptorTest implements TestTracingAwareS
|
||||
assertThat(this.spans).extracting(FinishedSpan::getRemoteServiceName).containsOnly("broker", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_propagate_headers_case_insensitive() {
|
||||
channel.addInterceptor(this.interceptor);
|
||||
Map<String, Object> headers = new HashMap<>();
|
||||
headers.put("Foo-Id", "123");
|
||||
headers.put("baz-id", "456");
|
||||
|
||||
channel.send(MessageBuilder.createMessage("foo", new MessageHeaders(headers)));
|
||||
|
||||
Message<?> actualMessage = channel.receive();
|
||||
|
||||
assertThat(actualMessage.getHeaders()).isNotEmpty();
|
||||
assertThat(actualMessage.getHeaders().get("not-propagated-header")).isNull();
|
||||
assertThat(actualMessage.getHeaders().get("Foo-Id")).isEqualTo("123");
|
||||
assertThat(actualMessage.getHeaders().get("baz-id")).isEqualTo("456");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_propagate_native_headers_case_insensitive() {
|
||||
channel.addInterceptor(this.interceptor);
|
||||
LinkedMultiValueMap<String, String> nativeHeaders = new LinkedMultiValueMap<>();
|
||||
nativeHeaders.put("Foo-Id", singletonList("123"));
|
||||
nativeHeaders.put("baz-id", singletonList("456"));
|
||||
Map<String, Object> headers = new HashMap<>();
|
||||
headers.put(NATIVE_HEADERS, nativeHeaders);
|
||||
|
||||
channel.send(MessageBuilder.createMessage("foo", new MessageHeaders(headers)));
|
||||
|
||||
Message<?> actualMessage = channel.receive();
|
||||
|
||||
assertThat(actualMessage.getHeaders()).isNotEmpty();
|
||||
LinkedMultiValueMap<String, String> actualNativeHeaders = (LinkedMultiValueMap) actualMessage.getHeaders()
|
||||
.get(NATIVE_HEADERS);
|
||||
assertThat(actualNativeHeaders).isNotEmpty();
|
||||
assertThat(actualNativeHeaders.get("not-propagated-header")).isNull();
|
||||
assertThat(actualNativeHeaders.get("Foo-Id")).isEqualTo(singletonList("123"));
|
||||
assertThat(actualNativeHeaders.get("baz-id")).isEqualTo(singletonList("456"));
|
||||
}
|
||||
|
||||
public ChannelInterceptor producerSideOnly(ChannelInterceptor delegate) {
|
||||
return new ChannelInterceptorAdapter() {
|
||||
@Override
|
||||
@@ -424,26 +465,26 @@ class B3Context {
|
||||
|
||||
}
|
||||
|
||||
// @formatter:off
|
||||
// tag::message_span_customizer[]
|
||||
class MyMessageSpanCustomizer extends DefaultMessageSpanCustomizer {
|
||||
@Override
|
||||
public Span customizeHandle(Span spanCustomizer,
|
||||
Message<?> message, MessageChannel messageChannel) {
|
||||
return super.customizeHandle(spanCustomizer, message, messageChannel)
|
||||
.name("changedHandle")
|
||||
.tag("handleKey", "handleValue")
|
||||
.tag("channelName", channelName(messageChannel));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span.Builder customizeSend(Span.Builder builder,
|
||||
Message<?> message, MessageChannel messageChannel) {
|
||||
return super.customizeSend(builder, message, messageChannel)
|
||||
.name("changedSend")
|
||||
.tag("sendKey", "sendValue")
|
||||
.tag("channelName", channelName(messageChannel));
|
||||
}
|
||||
}
|
||||
// end::message_span_customizer[]
|
||||
// @formatter:off
|
||||
// tag::message_span_customizer[]
|
||||
class MyMessageSpanCustomizer extends DefaultMessageSpanCustomizer {
|
||||
@Override
|
||||
public Span customizeHandle(Span spanCustomizer,
|
||||
Message<?> message, MessageChannel messageChannel) {
|
||||
return super.customizeHandle(spanCustomizer, message, messageChannel)
|
||||
.name("changedHandle")
|
||||
.tag("handleKey", "handleValue")
|
||||
.tag("channelName", channelName(messageChannel));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span.Builder customizeSend(Span.Builder builder,
|
||||
Message<?> message, MessageChannel messageChannel) {
|
||||
return super.customizeSend(builder, message, messageChannel)
|
||||
.name("changedSend")
|
||||
.tag("sendKey", "sendValue")
|
||||
.tag("channelName", channelName(messageChannel));
|
||||
}
|
||||
}
|
||||
// end::message_span_customizer[]
|
||||
// @formatter:on
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
@@ -22,6 +22,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
@@ -165,6 +166,7 @@ public abstract class ScopePassingSpanSubscriberSpringBootTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled("Will work only for on each - by accident")
|
||||
public void should_pass_tracing_info_when_using_reactor_async_processor() {
|
||||
final AtomicReference<TraceContext> spanInOperation = new AtomicReference<>();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
@@ -77,13 +77,14 @@ public abstract class FlatMapTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_work_with_flat_maps(CapturedOutput capture) {
|
||||
public void should_work_with_flat_maps_with_on_queues_instrumentation(CapturedOutput capture) {
|
||||
// given
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder(FlatMapTests.TestConfiguration.class,
|
||||
testConfiguration(), Issue866Configuration.class)
|
||||
.web(WebApplicationType.REACTIVE)
|
||||
.properties("server.port=0", "spring.jmx.enabled=false",
|
||||
"spring.application.name=TraceWebFluxTests", "security.basic.enabled=false",
|
||||
"spring.sleuth.reactor.instrumentation-type=DECORATE_QUEUES",
|
||||
"spring.application.name=TraceWebFluxOnQueuesTests", "security.basic.enabled=false",
|
||||
"management.security.enabled=false")
|
||||
.run();
|
||||
assertReactorTracing(context, capture, () -> context.getBean(TestConfiguration.class).spanInFoo);
|
||||
@@ -98,8 +99,22 @@ public abstract class FlatMapTests {
|
||||
testConfiguration(), Issue866Configuration.class)
|
||||
.web(WebApplicationType.REACTIVE)
|
||||
.properties("server.port=0", "spring.jmx.enabled=false",
|
||||
"spring.sleuth.reactor.decorate-on-each=false",
|
||||
"spring.application.name=TraceWebFlux2Tests", "security.basic.enabled=false",
|
||||
"spring.sleuth.reactor.instrumentation-type=DECORATE_ON_LAST",
|
||||
"spring.application.name=TraceWebFluxOnLastTests", "security.basic.enabled=false",
|
||||
"management.security.enabled=false")
|
||||
.run();
|
||||
assertReactorTracing(context, capture, () -> context.getBean(TestConfiguration.class).spanInFoo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_work_with_flat_maps_with_on_each_operator_instrumentation(CapturedOutput capture) {
|
||||
// given
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder(FlatMapTests.TestConfiguration.class,
|
||||
testConfiguration(), Issue866Configuration.class)
|
||||
.web(WebApplicationType.REACTIVE)
|
||||
.properties("server.port=0", "spring.jmx.enabled=false",
|
||||
"spring.sleuth.reactor.instrumentation-type=DECORATE_ON_EACH",
|
||||
"spring.application.name=TraceWebFluxOnEachTests", "security.basic.enabled=false",
|
||||
"management.security.enabled=false")
|
||||
.run();
|
||||
assertReactorTracing(context, capture, () -> context.getBean(TestConfiguration.class).spanInFoo);
|
||||
@@ -113,7 +128,7 @@ public abstract class FlatMapTests {
|
||||
.web(WebApplicationType.REACTIVE)
|
||||
.properties("server.port=0", "spring.jmx.enabled=false",
|
||||
"spring.sleuth.reactor.instrumentation-type=MANUAL",
|
||||
"spring.application.name=TraceWebFlux3Tests", "security.basic.enabled=false",
|
||||
"spring.application.name=TraceWebFluxOnManualTests", "security.basic.enabled=false",
|
||||
"management.security.enabled=false")
|
||||
.run();
|
||||
assertReactorTracing(context, capture, () -> context.getBean(TestManualConfiguration.class).spanInFoo);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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
|
||||
*
|
||||
* https://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.cloud.sleuth.instrument.rsocket;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
|
||||
import io.rsocket.frame.FrameType;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.context.ContextView;
|
||||
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.TraceContext;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.exporter.FinishedSpan;
|
||||
import org.springframework.cloud.sleuth.test.TestSpanHandler;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||
import org.springframework.messaging.handler.annotation.Payload;
|
||||
import org.springframework.messaging.rsocket.RSocketRequester;
|
||||
import org.springframework.messaging.rsocket.RSocketRequester.Builder;
|
||||
import org.springframework.messaging.rsocket.RSocketStrategies;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.util.MimeType;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
public abstract class TraceRSocketTests {
|
||||
|
||||
public static final String EXPECTED_TRACE_ID = "b919095138aa4c6e";
|
||||
|
||||
@Test
|
||||
public void should_instrument_responder() throws Exception {
|
||||
// setup
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder(MyConfig.class, testConfiguration())
|
||||
.web(WebApplicationType.REACTIVE)
|
||||
.properties("server.port=0", "spring.rsocket.server.transport=websocket",
|
||||
"spring.rsocket.server.mapping-path=/rsocket", "spring.jmx.enabled=false",
|
||||
"spring.application.name=TraceRSocketTests", "security.basic.enabled=false",
|
||||
"management.security.enabled=false")
|
||||
.run();
|
||||
final TestSpanHandler spans = context.getBean(TestSpanHandler.class);
|
||||
final int port = context.getBean(Environment.class).getProperty("local.server.port", Integer.class);
|
||||
final TestController controller2 = context.getBean(TestController.class);
|
||||
final RSocketStrategies strategies = context.getBean(RSocketStrategies.class);
|
||||
|
||||
final Builder rsocketRequesterBuilder = RSocketRequester.builder().rsocketStrategies(strategies);
|
||||
|
||||
final RSocketRequester rSocketRequester = rsocketRequesterBuilder
|
||||
.websocket(URI.create("ws://localhost:" + port + "/rsocket"));
|
||||
|
||||
// REQUEST FNF
|
||||
whenRequestFnFIsSent(rSocketRequester, "api.c2.fnf").block();
|
||||
|
||||
FrameType receivedFrame = controller2.getReceivedFrames().take();
|
||||
thenSpanWasReportedWithTags(spans, "api.c2.fnf", receivedFrame);
|
||||
spans.clear();
|
||||
controller2.reset();
|
||||
|
||||
// REQUEST RESPONSE
|
||||
whenRequestResponseIsSent(rSocketRequester, "api.c2.rr").block();
|
||||
|
||||
receivedFrame = controller2.getReceivedFrames().take();
|
||||
thenSpanWasReportedWithTags(spans, "api.c2.rr", receivedFrame);
|
||||
spans.clear();
|
||||
controller2.reset();
|
||||
|
||||
// REQUEST STREAM
|
||||
whenRequestStreamIsSent(rSocketRequester, "api.c2.rs").blockLast();
|
||||
|
||||
receivedFrame = controller2.getReceivedFrames().take();
|
||||
thenSpanWasReportedWithTags(spans, "api.c2.rs", receivedFrame);
|
||||
spans.clear();
|
||||
controller2.reset();
|
||||
|
||||
// REQUEST CHANNEL
|
||||
whenRequestChannelIsSent(rSocketRequester, "api.c2.rc").blockLast();
|
||||
|
||||
receivedFrame = controller2.getReceivedFrames().take();
|
||||
thenSpanWasReportedWithTags(spans, "api.c2.rc", receivedFrame);
|
||||
spans.clear();
|
||||
controller2.reset();
|
||||
|
||||
// REQUEST FNF
|
||||
whenNonSampledRequestFnfIsSent(rSocketRequester);
|
||||
controller2.getReceivedFrames().take();
|
||||
// then
|
||||
thenNoSpanWasReported(spans, controller2, EXPECTED_TRACE_ID);
|
||||
spans.clear();
|
||||
controller2.reset();
|
||||
|
||||
// REQUEST RESPONSE
|
||||
whenNonSampledRequestResponseIsSent(rSocketRequester);
|
||||
controller2.getReceivedFrames().take();
|
||||
// then
|
||||
thenNoSpanWasReported(spans, controller2, EXPECTED_TRACE_ID);
|
||||
spans.clear();
|
||||
controller2.reset();
|
||||
|
||||
// REQUEST STREAM
|
||||
whenNonSampledRequestStreamIsSent(rSocketRequester);
|
||||
controller2.getReceivedFrames().take();
|
||||
// then
|
||||
thenNoSpanWasReported(spans, controller2, EXPECTED_TRACE_ID);
|
||||
spans.clear();
|
||||
controller2.reset();
|
||||
|
||||
// REQUEST CHANNEL
|
||||
whenNonSampledRequestChannelIsSent(rSocketRequester);
|
||||
controller2.getReceivedFrames().take();
|
||||
// then
|
||||
thenNoSpanWasReported(spans, controller2, EXPECTED_TRACE_ID);
|
||||
spans.clear();
|
||||
controller2.reset();
|
||||
|
||||
// cleanup
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_instrument_requester_and_responder() throws Exception {
|
||||
// setup
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder(MyConfig.class, testConfiguration())
|
||||
.web(WebApplicationType.REACTIVE)
|
||||
.properties("server.port=0", "spring.rsocket.server.transport=websocket",
|
||||
"spring.rsocket.server.mapping-path=/rsocket", "spring.jmx.enabled=false",
|
||||
"spring.application.name=TraceRSocketTests", "security.basic.enabled=false",
|
||||
"management.security.enabled=false")
|
||||
.run();
|
||||
|
||||
final org.springframework.cloud.sleuth.Tracer tracer = context
|
||||
.getBean(org.springframework.cloud.sleuth.Tracer.class);
|
||||
final TestSpanHandler spans = context.getBean(TestSpanHandler.class);
|
||||
final int port = context.getBean(Environment.class).getProperty("local.server.port", Integer.class);
|
||||
final TestController controller2 = context.getBean(TestController.class);
|
||||
|
||||
final Builder rsocketRequesterBuilder = context.getBean(Builder.class);
|
||||
|
||||
final RSocketRequester rSocketRequester = rsocketRequesterBuilder
|
||||
.websocket(URI.create("ws://localhost:" + port + "/rsocket"));
|
||||
|
||||
// REQUEST FNF
|
||||
final org.springframework.cloud.sleuth.Span nextSpanFnf = tracer.nextSpan().start();
|
||||
whenRequestFnFIsSent(rSocketRequester, "api.c2.fnf")
|
||||
.contextWrite(ctx -> ctx.put(TraceContext.class, nextSpanFnf.context()))
|
||||
.doFinally(signalType -> nextSpanFnf.end()).block();
|
||||
controller2.getReceivedFrames().take();
|
||||
thenNoSpanWasReported(spans, controller2, nextSpanFnf.context().traceId());
|
||||
spans.clear();
|
||||
controller2.reset();
|
||||
|
||||
// REQUEST RESPONSE
|
||||
final org.springframework.cloud.sleuth.Span nextSpanRR = tracer.nextSpan().start();
|
||||
whenRequestResponseIsSent(rSocketRequester, "api.c2.rr")
|
||||
.contextWrite(ctx -> ctx.put(TraceContext.class, nextSpanRR.context()))
|
||||
.doFinally(signalType -> nextSpanRR.end()).block();
|
||||
|
||||
controller2.getReceivedFrames().take();
|
||||
thenNoSpanWasReported(spans, controller2, nextSpanRR.context().traceId());
|
||||
spans.clear();
|
||||
controller2.reset();
|
||||
|
||||
// REQUEST STREAM
|
||||
final org.springframework.cloud.sleuth.Span nextSpanRS = tracer.nextSpan().start();
|
||||
whenRequestStreamIsSent(rSocketRequester, "api.c2.rs")
|
||||
.contextWrite(ctx -> ctx.put(TraceContext.class, nextSpanRS.context()))
|
||||
.doFinally(signalType -> nextSpanRS.end()).blockLast();
|
||||
|
||||
controller2.getReceivedFrames().take();
|
||||
thenNoSpanWasReported(spans, controller2, nextSpanRS.context().traceId());
|
||||
spans.clear();
|
||||
controller2.reset();
|
||||
|
||||
// REQUEST CHANNEL
|
||||
final org.springframework.cloud.sleuth.Span nextSpanRC = tracer.nextSpan().start();
|
||||
whenRequestChannelIsSent(rSocketRequester, "api.c2.rc")
|
||||
.contextWrite(ctx -> ctx.put(TraceContext.class, nextSpanRC.context()))
|
||||
.doFinally(signalType -> nextSpanRC.end()).blockLast();
|
||||
|
||||
controller2.getReceivedFrames().take();
|
||||
thenNoSpanWasReported(spans, controller2, nextSpanRC.context().traceId());
|
||||
spans.clear();
|
||||
controller2.reset();
|
||||
|
||||
// cleanup
|
||||
context.close();
|
||||
}
|
||||
|
||||
protected abstract Class testConfiguration();
|
||||
|
||||
private void thenSpanWasReportedWithTags(TestSpanHandler spans, String path, FrameType frameType) {
|
||||
then(spans).hasSize(1);
|
||||
// TODO: Preferred option would be : [api.c2.{name}]
|
||||
FinishedSpan span = spans.get(0);
|
||||
then(span.getName()).isEqualTo(frameType.name() + " " + path);
|
||||
then(span.getTags()).containsEntry("messaging.controller.class",
|
||||
"org.springframework.cloud.sleuth.instrument.rsocket.TraceRSocketTests$TestController");
|
||||
then(span.getTags()).containsKey("messaging.controller.method");
|
||||
}
|
||||
|
||||
private Mono<Void> whenRequestFnFIsSent(RSocketRequester requester, String path) {
|
||||
return requester.route(path).send();
|
||||
}
|
||||
|
||||
private Mono<String> whenRequestResponseIsSent(RSocketRequester requester, String path) {
|
||||
return requester.route(path).retrieveMono(String.class);
|
||||
}
|
||||
|
||||
private Flux<String> whenRequestStreamIsSent(RSocketRequester requester, String path) {
|
||||
return requester.route(path).retrieveFlux(String.class);
|
||||
}
|
||||
|
||||
private Flux<String> whenRequestChannelIsSent(RSocketRequester requester, String path) {
|
||||
return requester.route(path).data(Flux.fromArray(new String[] { "test1", "test2" })).retrieveFlux(String.class);
|
||||
}
|
||||
|
||||
private void whenNonSampledRequestFnfIsSent(RSocketRequester requester) {
|
||||
requester.route("api.c2.fnf").metadata(EXPECTED_TRACE_ID + "-" + EXPECTED_TRACE_ID + "-0", new MimeType("b3") {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "b3";
|
||||
}
|
||||
}).send().block();
|
||||
}
|
||||
|
||||
private void whenNonSampledRequestResponseIsSent(RSocketRequester requester) {
|
||||
requester.route("api.c2.rr").metadata(EXPECTED_TRACE_ID + "-" + EXPECTED_TRACE_ID + "-0", new MimeType("b3") {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "b3";
|
||||
}
|
||||
}).retrieveMono(String.class).block();
|
||||
}
|
||||
|
||||
private void whenNonSampledRequestStreamIsSent(RSocketRequester requester) {
|
||||
requester.route("api.c2.rs").metadata(EXPECTED_TRACE_ID + "-" + EXPECTED_TRACE_ID + "-0", new MimeType("b3") {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "b3";
|
||||
}
|
||||
}).retrieveFlux(String.class).blockLast();
|
||||
}
|
||||
|
||||
private void whenNonSampledRequestChannelIsSent(RSocketRequester requester) {
|
||||
requester.route("api.c2.rc").metadata(EXPECTED_TRACE_ID + "-" + EXPECTED_TRACE_ID + "-0", new MimeType("b3") {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "b3";
|
||||
}
|
||||
}).data(Flux.fromArray(new String[] { "test1", "test2" })).retrieveFlux(String.class).blockLast();
|
||||
}
|
||||
|
||||
private void thenNoSpanWasReported(TestSpanHandler spans, TestController controller2, String expectedTraceId) {
|
||||
// then(spans).isEmpty(); // FIXME: does not work for request case
|
||||
then(controller2.getSpan()).isNotNull();
|
||||
then(controller2.getSpan().context().traceId()).isEqualTo(expectedTraceId);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAutoConfiguration
|
||||
static class MyConfig {
|
||||
|
||||
@Bean
|
||||
TestController controller(Tracer tracer) {
|
||||
return new TestController(tracer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Controller
|
||||
@MessageMapping("api.c2")
|
||||
static class TestController {
|
||||
|
||||
final Tracer tracer;
|
||||
|
||||
Span span;
|
||||
|
||||
ContextView interceptedContext;
|
||||
|
||||
BlockingQueue<FrameType> receivedFrames = new LinkedBlockingDeque<>();
|
||||
|
||||
TestController(Tracer tracer) {
|
||||
this.tracer = tracer;
|
||||
}
|
||||
|
||||
BlockingQueue<FrameType> getReceivedFrames() {
|
||||
return this.receivedFrames;
|
||||
}
|
||||
|
||||
Span getSpan() {
|
||||
return this.span;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
this.span = null;
|
||||
}
|
||||
|
||||
@MessageMapping("fnf")
|
||||
Mono<Void> testFnf() {
|
||||
|
||||
this.span = this.tracer.currentSpan();
|
||||
|
||||
return Mono.deferContextual(c -> {
|
||||
interceptedContext = c;
|
||||
receivedFrames.offer(FrameType.REQUEST_FNF);
|
||||
return Mono.empty();
|
||||
});
|
||||
}
|
||||
|
||||
@MessageMapping("rr")
|
||||
Mono<String> testRR() {
|
||||
this.span = this.tracer.currentSpan();
|
||||
|
||||
return Mono.deferContextual(c -> {
|
||||
interceptedContext = c;
|
||||
receivedFrames.offer(FrameType.REQUEST_RESPONSE);
|
||||
return Mono.just("response");
|
||||
});
|
||||
}
|
||||
|
||||
@MessageMapping("rs")
|
||||
Flux<String> testRS() {
|
||||
this.span = this.tracer.currentSpan();
|
||||
|
||||
return Flux.deferContextual(c -> {
|
||||
interceptedContext = c;
|
||||
receivedFrames.offer(FrameType.REQUEST_STREAM);
|
||||
return Flux.just("stream");
|
||||
});
|
||||
}
|
||||
|
||||
@MessageMapping("rc")
|
||||
Flux<String> testRC(@Payload Flux<String> inbound) {
|
||||
this.span = this.tracer.currentSpan();
|
||||
|
||||
return Flux.deferContextual(c -> {
|
||||
interceptedContext = c;
|
||||
receivedFrames.offer(FrameType.REQUEST_CHANNEL);
|
||||
return inbound;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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
|
||||
*
|
||||
* https://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.cloud.sleuth.instrument.task;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.exporter.FinishedSpan;
|
||||
import org.springframework.cloud.sleuth.test.TestSpanHandler;
|
||||
import org.springframework.cloud.task.configuration.EnableTask;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
@ContextConfiguration(classes = SpringCloudTaskIntegrationTests.TestConfig.class)
|
||||
@TestPropertySource(properties = "spring.application.name=MyApplication")
|
||||
public abstract class SpringCloudTaskIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
TestSpanHandler spans;
|
||||
|
||||
@Test
|
||||
public void should_pass_tracing_information_when_using_spring_cloud_task() {
|
||||
Set<String> traceIds = this.spans.reportedSpans().stream().map(FinishedSpan::getTraceId)
|
||||
.collect(Collectors.toSet());
|
||||
then(traceIds).as("There's one traceid").hasSize(1);
|
||||
Set<String> spanIds = this.spans.reportedSpans().stream().map(FinishedSpan::getSpanId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
then(spanIds).as("There are 3 spans").hasSize(3);
|
||||
Iterator<FinishedSpan> spanIterator = this.spans.reportedSpans().iterator();
|
||||
|
||||
FinishedSpan first = spanIterator.next();
|
||||
FinishedSpan second = spanIterator.next();
|
||||
FinishedSpan third = spanIterator.next();
|
||||
then(first.getName()).isEqualTo("myApplicationRunner");
|
||||
then(second.getName()).isEqualTo("myCommandLineRunner");
|
||||
then(third.getName()).isEqualTo("MyApplication");
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAutoConfiguration
|
||||
@EnableTask
|
||||
public static class TestConfig {
|
||||
|
||||
@Bean
|
||||
MyCommandLineRunner myCommandLineRunner() {
|
||||
return new MyCommandLineRunner();
|
||||
}
|
||||
|
||||
@Bean
|
||||
MyApplicationRunner myApplicationRunner() {
|
||||
return new MyApplicationRunner();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class MyCommandLineRunner implements CommandLineRunner {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MyCommandLineRunner.class);
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
log.info("Ran MyCommandLineRunner");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class MyApplicationRunner implements ApplicationRunner {
|
||||
|
||||
private static final Log log = LogFactory.getLog(MyApplicationRunner.class);
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
log.info("Ran MyApplicationRunner");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
@@ -53,6 +53,7 @@ public abstract class IgnoreAutoConfiguredSkipPatternsIntegrationTests {
|
||||
@AfterEach
|
||||
public void clearSpans() {
|
||||
this.spans.clear();
|
||||
this.tracer.withSpan(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
@@ -24,6 +24,7 @@ import org.assertj.core.api.BDDAssertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.cloud.gateway.filter.headers.HttpHeadersFilter;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.test.TestTracingAwareSupplier;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
@@ -44,7 +45,11 @@ public abstract class TraceRequestHttpHeadersFilterTests implements TestTracingA
|
||||
MockServerWebExchange exchange = MockServerWebExchange.builder(request).build();
|
||||
|
||||
HttpHeaders filteredHeaders = filter.filter(requestHeaders(httpHeaders), exchange);
|
||||
thenTraceContinuedWithNewSpan(httpHeaders, filteredHeaders);
|
||||
BDDAssertions.then((Object) exchange.getAttribute(TraceRequestHttpHeadersFilter.SPAN_ATTRIBUTE)).isNotNull();
|
||||
}
|
||||
|
||||
private void thenTraceContinuedWithNewSpan(HttpHeaders httpHeaders, HttpHeaders filteredHeaders) {
|
||||
// we want to continue the trace
|
||||
BDDAssertions.then(high(filteredHeaders.get("X-B3-TraceId"))).isEqualTo(high(httpHeaders.get("X-B3-TraceId")));
|
||||
// but we want to have a new span id
|
||||
@@ -53,6 +58,25 @@ public abstract class TraceRequestHttpHeadersFilterTests implements TestTracingA
|
||||
BDDAssertions.then(filteredHeaders.get("X-Hello-Request"))
|
||||
.isEqualTo(Collections.singletonList("Request World"));
|
||||
BDDAssertions.then(filteredHeaders.get("X-Auth-User")).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_continue_span_tracing_when_span_already_in_exchange_attributes() {
|
||||
HttpHeadersFilter filter = new TraceRequestHttpHeadersFilter(tracerTest().tracing().tracer(),
|
||||
tracerTest().tracing().httpClientHandler(), tracerTest().tracing().propagator());
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
Span span = tracerTest().tracing().tracer().nextSpan();
|
||||
httpHeaders.set("X-Hello", "World");
|
||||
httpHeaders.set("X-B3-TraceId", span.context().traceId());
|
||||
httpHeaders.set("X-B3-SpanId", span.context().spanId());
|
||||
MockServerHttpRequest request = MockServerHttpRequest.post("foo/bar").headers(httpHeaders).build();
|
||||
MockServerWebExchange exchange = MockServerWebExchange.builder(request).build();
|
||||
exchange.getAttributes().put(TraceRequestHttpHeadersFilter.TRACE_REQUEST_ATTR_FROM_TRACE_WEB_FILTER, span);
|
||||
|
||||
HttpHeaders filteredHeaders = filter.filter(requestHeaders(httpHeaders), exchange);
|
||||
|
||||
// we want to continue the trace
|
||||
thenTraceContinuedWithNewSpan(httpHeaders, filteredHeaders);
|
||||
BDDAssertions.then((Object) exchange.getAttribute(TraceRequestHttpHeadersFilter.SPAN_ATTRIBUTE)).isNotNull();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
@@ -130,6 +130,11 @@ public abstract class WebClientTests {
|
||||
this.fooController.clear();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
log.info("Starting test");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("parametersForShouldCreateANewSpanWithClientSideTagsWhenNoPreviousTracingWasPresent")
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -141,15 +146,23 @@ public abstract class WebClientTests {
|
||||
then(this.spans).isNotEmpty();
|
||||
Optional<FinishedSpan> noTraceSpan = this.spans.reportedSpans().stream()
|
||||
.filter(span -> span.getName().contains("GET") && !span.getTags().isEmpty()
|
||||
&& span.getTags().containsKey("http.path"))
|
||||
&& span.getTags().containsKey(pathKey()))
|
||||
.findFirst();
|
||||
then(noTraceSpan.isPresent()).isTrue();
|
||||
then(noTraceSpan.get().getTags()).containsEntry("http.path", "/notrace").containsEntry("http.method",
|
||||
"GET");
|
||||
then(noTraceSpan.get().getTags()).containsEntry(pathKey(), "/notrace").containsEntry("http.method", "GET");
|
||||
// TODO: matches cause there is an issue with Feign not providing the full URL
|
||||
// at the interceptor level
|
||||
then(noTraceSpan.get().getTags().get("http.path")).matches(".*/notrace");
|
||||
then(noTraceSpan.get().getTags().get(pathKey())).matches(".*/notrace");
|
||||
});
|
||||
thenThereIsNoCurrentSpan();
|
||||
}
|
||||
|
||||
protected String pathKey() {
|
||||
return "http.path";
|
||||
}
|
||||
|
||||
private void thenThereIsNoCurrentSpan() {
|
||||
log.info("Current span [" + this.tracer.currentSpan() + "]");
|
||||
then(this.tracer.currentSpan()).isNull();
|
||||
}
|
||||
|
||||
@@ -197,7 +210,7 @@ public abstract class WebClientTests {
|
||||
span.end();
|
||||
}
|
||||
|
||||
then(this.tracer.currentSpan()).isNull();
|
||||
thenThereIsNoCurrentSpan();
|
||||
then(this.spans).isNotEmpty();
|
||||
}
|
||||
|
||||
@@ -213,7 +226,7 @@ public abstract class WebClientTests {
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
then(this.tracer.currentSpan()).isNull();
|
||||
thenThereIsNoCurrentSpan();
|
||||
then(this.spans.reportedSpans().stream().filter(r -> r.getKind() != null).map(r -> r.getKind().name())
|
||||
.collect(Collectors.toList())).isNotEmpty().contains("CLIENT");
|
||||
}
|
||||
@@ -234,7 +247,7 @@ public abstract class WebClientTests {
|
||||
span.end();
|
||||
}
|
||||
|
||||
then(this.tracer.currentSpan()).isNull();
|
||||
thenThereIsNoCurrentSpan();
|
||||
then(this.spans.reportedSpans().stream().filter(r -> r.getKind() != null).map(r -> r.getKind().name())
|
||||
.collect(Collectors.toList())).isNotEmpty().contains("CLIENT");
|
||||
}
|
||||
@@ -286,7 +299,7 @@ public abstract class WebClientTests {
|
||||
span.end();
|
||||
}
|
||||
|
||||
then(this.tracer.currentSpan()).isNull();
|
||||
thenThereIsNoCurrentSpan();
|
||||
then(this.spans).isNotEmpty();
|
||||
}
|
||||
|
||||
@@ -305,7 +318,7 @@ public abstract class WebClientTests {
|
||||
catch (HttpClientErrorException e) {
|
||||
}
|
||||
|
||||
then(this.tracer.currentSpan()).isNull();
|
||||
thenThereIsNoCurrentSpan();
|
||||
Optional<FinishedSpan> storedSpan = this.spans.reportedSpans().stream()
|
||||
.filter(span -> "404".equals(span.getTags().get("http.status_code"))).findFirst();
|
||||
then(storedSpan.isPresent()).isTrue();
|
||||
@@ -325,7 +338,7 @@ public abstract class WebClientTests {
|
||||
public void shouldNotExecuteErrorControllerWhenUrlIsFound() {
|
||||
this.template.getForEntity("http://fooservice/notrace", String.class);
|
||||
|
||||
then(this.tracer.currentSpan()).isNull();
|
||||
thenThereIsNoCurrentSpan();
|
||||
then(this.testErrorController.getSpan()).isNull();
|
||||
}
|
||||
|
||||
@@ -341,9 +354,10 @@ public abstract class WebClientTests {
|
||||
finally {
|
||||
span.end();
|
||||
}
|
||||
then(this.tracer.currentSpan()).isNull();
|
||||
thenThereIsNoCurrentSpan();
|
||||
then(this.customizer.isExecuted()).isTrue();
|
||||
then(this.spans).extracting("kind.name").contains("CLIENT");
|
||||
then(this.spans.reportedSpans().stream().filter(s -> s.getKind() != null).map(s -> s.getKind().name())
|
||||
.collect(Collectors.toList())).contains("CLIENT");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
* Copyright 2013-2021 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.
|
||||
|
||||
Reference in New Issue
Block a user