Fix latest dep tests after the recent Spring release (#9947)

This commit is contained in:
Mateusz Rzeszutek 2023-11-24 22:07:48 +01:00 committed by GitHub
parent 7c3a412b0b
commit 63468157fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 156 additions and 61 deletions

View File

@ -15,6 +15,10 @@ dependencies {
} }
tasks { tasks {
withType<Test>().configureEach {
systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean)
}
val testStableSemconv by registering(Test::class) { val testStableSemconv by registering(Test::class) {
jvmArgs("-Dotel.semconv-stability.opt-in=http") jvmArgs("-Dotel.semconv-stability.opt-in=http")
} }

View File

@ -202,6 +202,11 @@ public class ApacheHttpClientTest {
super.configure(optionsBuilder); super.configure(optionsBuilder);
// apparently apache http client does not report the 302 status code? // apparently apache http client does not report the 302 status code?
optionsBuilder.setResponseCodeOnRedirectError(null); optionsBuilder.setResponseCodeOnRedirectError(null);
if (Boolean.getBoolean("testLatestDeps")) {
optionsBuilder.disableTestHttps();
optionsBuilder.disableTestRemoteConnection();
}
} }
} }

View File

@ -21,6 +21,9 @@ dependencies {
testImplementation(project(":instrumentation:spring:spring-cloud-gateway:spring-cloud-gateway-common:testing")) testImplementation(project(":instrumentation:spring:spring-cloud-gateway:spring-cloud-gateway-common:testing"))
testLibrary("org.springframework.boot:spring-boot-starter-test:2.0.0.RELEASE") testLibrary("org.springframework.boot:spring-boot-starter-test:2.0.0.RELEASE")
latestDepTestLibrary("org.springframework.cloud:spring-cloud-starter-gateway:2.1.+")
latestDepTestLibrary("org.springframework.boot:spring-boot-starter-test:2.1.+")
} }
tasks.withType<Test>().configureEach { tasks.withType<Test>().configureEach {
@ -33,19 +36,9 @@ tasks.withType<Test>().configureEach {
systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean) systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean)
} }
val latestDepTest = findProperty("testLatestDeps") as Boolean configurations.testRuntimeClasspath {
resolutionStrategy {
if (latestDepTest) { force("ch.qos.logback:logback-classic:1.2.11")
// spring 6 requires java 17 force("org.slf4j:slf4j-api:1.7.36")
otelJava {
minJavaVersionSupported.set(JavaVersion.VERSION_17)
}
} else {
// spring 5 requires old logback (and therefore also old slf4j)
configurations.testRuntimeClasspath {
resolutionStrategy {
force("ch.qos.logback:logback-classic:1.2.11")
force("org.slf4j:slf4j-api:1.7.36")
}
} }
} }

View File

@ -13,6 +13,10 @@ dependencies {
testLibrary("org.springframework.cloud:spring-cloud-starter-gateway:2.2.0.RELEASE") testLibrary("org.springframework.cloud:spring-cloud-starter-gateway:2.2.0.RELEASE")
testLibrary("org.springframework.boot:spring-boot-starter-test:2.2.0.RELEASE") testLibrary("org.springframework.boot:spring-boot-starter-test:2.2.0.RELEASE")
// spring-cloud-gateway hasn't yet updated to spring 6.2/boot 3.2
latestDepTestLibrary("org.springframework.boot:spring-boot-starter-webflux:3.1.+")
latestDepTestLibrary("org.springframework.boot:spring-boot-starter-test:3.1.+")
} }
tasks.withType<Test>().configureEach { tasks.withType<Test>().configureEach {

View File

@ -36,6 +36,7 @@ import static org.junit.jupiter.api.Named.named;
import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension;
import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension;
import io.opentelemetry.sdk.testing.assertj.EventDataAssert;
import io.opentelemetry.sdk.testing.assertj.TraceAssert; import io.opentelemetry.sdk.testing.assertj.TraceAssert;
import io.opentelemetry.sdk.trace.data.StatusData; import io.opentelemetry.sdk.trace.data.StatusData;
import io.opentelemetry.testing.internal.armeria.client.WebClient; import io.opentelemetry.testing.internal.armeria.client.WebClient;
@ -484,28 +485,33 @@ public class SpringWebfluxTest {
.hasKind(SpanKind.INTERNAL) .hasKind(SpanKind.INTERNAL)
.hasParent(trace.getSpan(0)) .hasParent(trace.getSpan(0))
.hasStatus(StatusData.error()) .hasStatus(StatusData.error())
.hasEventsSatisfyingExactly( .hasEventsSatisfyingExactly(SpringWebfluxTest::resource404Exception)
event ->
event
.hasName(EXCEPTION_EVENT_NAME)
.hasAttributesSatisfyingExactly(
equalTo(
EXCEPTION_TYPE,
"org.springframework.web.server.ResponseStatusException"),
satisfies(
EXCEPTION_MESSAGE,
val ->
val.containsAnyOf(
"Response status 404", "404 NOT_FOUND")),
satisfies(
EXCEPTION_STACKTRACE,
val -> val.isInstanceOf(String.class))))
.hasAttributesSatisfyingExactly( .hasAttributesSatisfyingExactly(
equalTo( equalTo(
stringKey("spring-webflux.handler.type"), stringKey("spring-webflux.handler.type"),
"org.springframework.web.reactive.resource.ResourceWebHandler")))); "org.springframework.web.reactive.resource.ResourceWebHandler"))));
} }
private static void resource404Exception(EventDataAssert event) {
if (Boolean.getBoolean("testLatestDeps")) {
event
.hasName(EXCEPTION_EVENT_NAME)
.hasAttributesSatisfyingExactly(
equalTo(
EXCEPTION_TYPE,
"org.springframework.web.reactive.resource.NoResourceFoundException"),
satisfies(EXCEPTION_MESSAGE, val -> val.isInstanceOf(String.class)),
satisfies(EXCEPTION_STACKTRACE, val -> val.isInstanceOf(String.class)));
} else {
event
.hasName(EXCEPTION_EVENT_NAME)
.hasAttributesSatisfyingExactly(
equalTo(EXCEPTION_TYPE, "org.springframework.web.server.ResponseStatusException"),
equalTo(EXCEPTION_MESSAGE, "Response status 404"),
satisfies(EXCEPTION_STACKTRACE, val -> val.isInstanceOf(String.class)));
}
}
@Test @Test
void basicPostTest() { void basicPostTest() {
String echoString = "TEST"; String echoString = "TEST";

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package server.base; package io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.server.base;
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION; import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION;
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.NOT_FOUND; import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.NOT_FOUND;
@ -52,8 +52,9 @@ public abstract class ControllerSpringWebFluxServerTest extends SpringWebFluxSer
.hasAttributesSatisfyingExactly( .hasAttributesSatisfyingExactly(
equalTo( equalTo(
EXCEPTION_TYPE, EXCEPTION_TYPE,
"org.springframework.web.server.ResponseStatusException"), "org.springframework.web.reactive.resource.NoResourceFoundException"),
equalTo(EXCEPTION_MESSAGE, "404 NOT_FOUND"), equalTo(
EXCEPTION_MESSAGE, "404 NOT_FOUND \"No static resource notFound.\""),
satisfies(EXCEPTION_STACKTRACE, val -> val.isInstanceOf(String.class)))); satisfies(EXCEPTION_STACKTRACE, val -> val.isInstanceOf(String.class))));
} else { } else {
span.hasEventsSatisfyingExactly( span.hasEventsSatisfyingExactly(

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package server.base; package io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.server.base;
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint; import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint;
import java.time.Duration; import java.time.Duration;

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package server.base; package io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.server.base;
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint; import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint;
import java.time.Duration; import java.time.Duration;

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package server.base; package io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.server.base;
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION; import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION;
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.NOT_FOUND; import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.NOT_FOUND;
@ -50,8 +50,9 @@ public abstract class HandlerSpringWebFluxServerTest extends SpringWebFluxServer
.hasAttributesSatisfyingExactly( .hasAttributesSatisfyingExactly(
equalTo( equalTo(
EXCEPTION_TYPE, EXCEPTION_TYPE,
"org.springframework.web.server.ResponseStatusException"), "org.springframework.web.reactive.resource.NoResourceFoundException"),
equalTo(EXCEPTION_MESSAGE, "404 NOT_FOUND"), equalTo(
EXCEPTION_MESSAGE, "404 NOT_FOUND \"No static resource notFound.\""),
satisfies(EXCEPTION_STACKTRACE, val -> val.isInstanceOf(String.class)))); satisfies(EXCEPTION_STACKTRACE, val -> val.isInstanceOf(String.class))));
} else { } else {
span.hasEventsSatisfyingExactly( span.hasEventsSatisfyingExactly(

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package server.base; package io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.server.base;
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint; import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint;
import java.util.function.Supplier; import java.util.function.Supplier;

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package server.base; package io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.server.base;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assumptions.assumeTrue; import static org.junit.jupiter.api.Assumptions.assumeTrue;

View File

@ -3,9 +3,9 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package server.base; package io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.server.base;
import static server.base.SpringWebFluxServerTest.NESTED_PATH; import static io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.server.base.SpringWebFluxServerTest.NESTED_PATH;
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint; import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint;
import java.net.URI; import java.net.URI;

View File

@ -3,13 +3,13 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package server.base; package io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.server.base;
import static io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.server.base.SpringWebFluxServerTest.NESTED_PATH;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET; import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RequestPredicates.path; import static org.springframework.web.reactive.function.server.RequestPredicates.path;
import static org.springframework.web.reactive.function.server.RouterFunctions.nest; import static org.springframework.web.reactive.function.server.RouterFunctions.nest;
import static org.springframework.web.reactive.function.server.RouterFunctions.route; import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static server.base.SpringWebFluxServerTest.NESTED_PATH;
import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Span;
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint; import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint;

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package server.base; package io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.server.base;
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION; import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.EXCEPTION;
import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.NOT_FOUND; import static io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint.NOT_FOUND;

View File

@ -2,4 +2,4 @@
* The classes in this package are specific to tests that extend {@link * The classes in this package are specific to tests that extend {@link
* io.opentelemetry.instrumentation.test.base.HttpServerTest}. * io.opentelemetry.instrumentation.test.base.HttpServerTest}.
*/ */
package server.base; package io.opentelemetry.javaagent.instrumentation.spring.webflux.v5_0.server.base;

View File

@ -17,7 +17,6 @@ import java.util.concurrent.TimeUnit;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.BodyInserters;
@ -27,9 +26,7 @@ import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
@SpringBootApplication @SpringBootApplication
@ComponentScan( @ComponentScan(basePackages = {"server"})
basePackages = {"server"},
excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "server.base.*"))
public class SpringWebFluxTestApplication { public class SpringWebFluxTestApplication {
private static final Tracer tracer = GlobalOpenTelemetry.getTracer("test"); private static final Tracer tracer = GlobalOpenTelemetry.getTracer("test");

View File

@ -71,8 +71,8 @@ class TestWebfluxSpringBootApp {
@RequestMapping("/query") @RequestMapping("/query")
@ResponseBody @ResponseBody
String query_param(@RequestParam("some") String param) { Mono<String> query_param(@RequestParam("some") String param) {
return controller(QUERY_PARAM, () -> "some=" + param); return Mono.just(controller(QUERY_PARAM, () -> "some=" + param));
} }
@RequestMapping("/redirect") @RequestMapping("/redirect")
@ -102,20 +102,21 @@ class TestWebfluxSpringBootApp {
} }
@RequestMapping("/captureHeaders") @RequestMapping("/captureHeaders")
ResponseEntity<String> capture_headers( Mono<ResponseEntity<String>> capture_headers(
@RequestHeader("X-Test-Request") String testRequestHeader) { @RequestHeader("X-Test-Request") String testRequestHeader) {
return controller( return Mono.just(
CAPTURE_HEADERS, controller(
() -> CAPTURE_HEADERS,
ResponseEntity.ok() () ->
.header("X-Test-Response", testRequestHeader) ResponseEntity.ok()
.body(CAPTURE_HEADERS.getBody())); .header("X-Test-Response", testRequestHeader)
.body(CAPTURE_HEADERS.getBody())));
} }
@RequestMapping("/path/{id}/param") @RequestMapping("/path/{id}/param")
@ResponseBody @ResponseBody
String path_param(@PathVariable("id") int id) { Mono<String> path_param(@PathVariable("id") int id) {
return controller(PATH_PARAM, () -> String.valueOf(id)); return Mono.just(controller(PATH_PARAM, () -> String.valueOf(id)));
} }
@RequestMapping("/child") @RequestMapping("/child")

View File

@ -50,4 +50,6 @@ tasks.withType<Test>().configureEach {
// required on jdk17 // required on jdk17
jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED") jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED")
jvmArgs("-XX:+IgnoreUnrecognizedVMOptions") jvmArgs("-XX:+IgnoreUnrecognizedVMOptions")
systemProperty("testLatestDeps", findProperty("testLatestDeps") as Boolean)
} }

View File

@ -4,6 +4,13 @@
*/ */
import filter.AbstractServletFilterTest import filter.AbstractServletFilterTest
import io.opentelemetry.api.trace.SpanKind
import io.opentelemetry.api.trace.StatusCode
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
import io.opentelemetry.sdk.trace.data.SpanData
import static io.opentelemetry.api.trace.SpanKind.INTERNAL
class ServletFilterTest extends AbstractServletFilterTest { class ServletFilterTest extends AbstractServletFilterTest {
@ -14,4 +21,32 @@ class ServletFilterTest extends AbstractServletFilterTest {
Class<?> filterConfigClass() { Class<?> filterConfigClass() {
ServletFilterConfig ServletFilterConfig
} }
@Override
void handlerSpan(TraceAssert trace, int index, Object parent, String method = "GET", ServerEndpoint endpoint) {
if (Boolean.getBoolean("testLatestDeps") && endpoint == ServerEndpoint.NOT_FOUND) {
trace.span(index) {
name "ResourceHttpRequestHandler.handleRequest"
kind INTERNAL
childOf((SpanData) parent)
status StatusCode.ERROR
errorEventWithAnyMessage Class.forName("org.springframework.web.servlet.resource.NoResourceFoundException")
}
} else {
super.handlerSpan(trace, index, parent, method, endpoint)
}
}
@Override
void responseSpan(TraceAssert trace, int index, Object parent, String method, ServerEndpoint endpoint) {
if (Boolean.getBoolean("testLatestDeps") && endpoint == ServerEndpoint.NOT_FOUND) {
trace.span(index) {
name ~/\.sendError$/
kind SpanKind.INTERNAL
// not verifying the parent span, in the latest version the responseSpan is the child of the SERVER span, not the handler span
}
} else {
super.responseSpan(trace, index, parent, method, endpoint)
}
}
} }

View File

@ -4,10 +4,31 @@
*/ */
import boot.AbstractSpringBootBasedTest import boot.AbstractSpringBootBasedTest
import io.opentelemetry.api.trace.StatusCode
import io.opentelemetry.instrumentation.test.asserts.TraceAssert
import io.opentelemetry.instrumentation.testing.junit.http.ServerEndpoint
import io.opentelemetry.sdk.trace.data.SpanData
import static io.opentelemetry.api.trace.SpanKind.INTERNAL
class SpringBootBasedTest extends AbstractSpringBootBasedTest { class SpringBootBasedTest extends AbstractSpringBootBasedTest {
Class<?> securityConfigClass() { Class<?> securityConfigClass() {
SecurityConfig SecurityConfig
} }
@Override
void handlerSpan(TraceAssert trace, int index, Object parent, String method = "GET", ServerEndpoint endpoint) {
if (Boolean.getBoolean("testLatestDeps") && endpoint == ServerEndpoint.NOT_FOUND) {
trace.span(index) {
name "ResourceHttpRequestHandler.handleRequest"
kind INTERNAL
childOf((SpanData) parent)
status StatusCode.ERROR
errorEventWithAnyMessage Class.forName("org.springframework.web.servlet.resource.NoResourceFoundException")
}
} else {
super.handlerSpan(trace, index, parent, method, endpoint)
}
}
} }

View File

@ -0,0 +1,25 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.javaagent.tooling.ignore;
import com.google.auto.service.AutoService;
import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesBuilder;
import io.opentelemetry.javaagent.extension.ignore.IgnoredTypesConfigurer;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
/**
* Unlike the {@link AdditionalLibraryIgnoredTypesConfigurer}, this one is applied to all tests. It
* should only contain classes that are included in the most commonly used libraries in test (e.g.
* Spring Boot).
*/
@AutoService(IgnoredTypesConfigurer.class)
public class CommonLibraryIgnoredTypesConfigurer implements IgnoredTypesConfigurer {
@Override
public void configure(IgnoredTypesBuilder builder, ConfigProperties config) {
builder.ignoreClass("org.springframework.boot.autoconfigure.ssl.FileWatcher$WatcherThread");
}
}