Skip to content

Commit

Permalink
Test earliest spring boot version (#11474)
Browse files Browse the repository at this point in the history
  • Loading branch information
zeitlinger committed Jun 12, 2024
1 parent e07ef6f commit 40cea5e
Show file tree
Hide file tree
Showing 24 changed files with 246 additions and 58 deletions.
4 changes: 3 additions & 1 deletion .github/renovate.json5
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@
},
{
// intentionally using Spring Boot 2 in this smoke tests
// new versions of Spring Boot 3 are tested with
// https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/dc4330e0a3060bd7d8c4090ad0b8fc4727e68113/settings.gradle.kts#L43-L45
"matchFileNames": [
"smoke-tests/images/spring-boot/build.gradle.kts",
"smoke-tests-otel-starter/spring-boot-2/build.gradle.kts",
Expand All @@ -116,7 +118,7 @@
"org.slf4j:slf4j-api",
"org.springframework.boot",
"org.springframework.boot:spring-boot-dependencies"],
"matchUpdateTypes": ["major"],
"matchUpdateTypes": ["major", "minor"],
"enabled": false,
},
{
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/native-tests-daily.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ on:
jobs:
graalvm-native-tests:
uses: ./.github/workflows/reusable-native-tests.yml
with:
test-latest-deps: true

workflow-notification:
needs:
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/reusable-native-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
skip-native-tests:
type: boolean
required: false
test-latest-deps:
type: boolean
required: false

jobs:
graalvm-native-tests:
Expand All @@ -32,5 +35,5 @@ jobs:
# therefore we're starting a Kafka container manually for the tests
docker compose -f .github/graal-native-docker-compose.yaml up -d
# don't wait for startup - gradle compile takes long enough
./gradlew nativeTest
./gradlew ${{ inputs.test-latest-deps && '-PtestLatestDeps=true' || '' }} nativeTest
docker compose -f .github/graal-native-docker-compose.yaml down # is this needed?
2 changes: 0 additions & 2 deletions dependencyManagement/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,6 @@ val DEPENDENCIES = listOf(
"org.codehaus.mojo:animal-sniffer-annotations:1.23",
"org.junit-pioneer:junit-pioneer:1.9.1",
"org.objenesis:objenesis:3.4",
// Note that this is only referenced as "org.springframework.boot" in build files, not the artifact name.
"org.springframework.boot:spring-boot-dependencies:2.7.18",
"javax.validation:validation-api:2.0.1.Final",
"org.snakeyaml:snakeyaml-engine:2.7"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ plugins {
base.archivesName.set("opentelemetry-spring-boot")
group = "io.opentelemetry.instrumentation"

val versions: Map<String, String> by project
val springBootVersion = versions["org.springframework.boot"]
val springBootVersion = "2.7.18" // AutoConfiguration is added in 2.7.0, but can be used with older versions

// r2dbc-proxy is shadowed to prevent org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration
// from being loaded by Spring Boot (by the presence of META-INF/services/io.r2dbc.spi.ConnectionFactoryProvider) - even if the user doesn't want to use R2DBC.
Expand All @@ -22,7 +21,7 @@ sourceSets {
}

dependencies {
implementation("org.springframework.boot:spring-boot-autoconfigure:$springBootVersion")
compileOnly("org.springframework.boot:spring-boot-autoconfigure:$springBootVersion")
annotationProcessor("org.springframework.boot:spring-boot-autoconfigure-processor:$springBootVersion")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor:$springBootVersion")
implementation("javax.validation:validation-api")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ plugins {
id("otel.library-instrumentation")
}

val versions: Map<String, String> by project
val springBootVersion = versions["org.springframework.boot"]
val springBootVersion = "2.6.15"

dependencies {
compileOnly("org.springframework:spring-webmvc:5.3.0")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ plugins {

group = "io.opentelemetry.instrumentation"

val versions: Map<String, String> by project
val springBootVersion = versions["org.springframework.boot"]
val springBootVersion = "2.6.15"

dependencies {
api("org.springframework.boot:spring-boot-starter:$springBootVersion")
api("org.springframework.boot:spring-boot-starter-aop:$springBootVersion")
compileOnly("org.springframework.boot:spring-boot-starter:$springBootVersion")
compileOnly("org.springframework.boot:spring-boot-starter-aop:$springBootVersion")
api(project(":instrumentation:spring:spring-boot-autoconfigure"))
api(project(":instrumentation:spring:spring-boot-autoconfigure-3"))
api(project(":instrumentation-annotations"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ plugins {

group = "io.opentelemetry.instrumentation"

val versions: Map<String, String> by project
val springBootVersion = versions["org.springframework.boot"]
val springBootVersion = "2.6.15"

dependencies {
api("org.springframework.boot:spring-boot-starter:$springBootVersion")
Expand Down
18 changes: 18 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,23 @@ dependencyResolutionManagement {
mavenCentral()
mavenLocal()
}

versionCatalogs {
fun addSpringBootCatalog(name: String, minVersion: String, maxVersion: String) {
val latestDepTest = gradle.startParameter.projectProperties["testLatestDeps"] == "true"
create(name) {
val version =
gradle.startParameter.projectProperties["${name}Version"]
?: (if (latestDepTest) maxVersion else minVersion)
plugin("versions", "org.springframework.boot").version(version)
}
}
// r2dbc is not compatible with earlier versions
addSpringBootCatalog("springBoot2", "2.6.15", "2.+")
// spring boot 3.0 is not compatible with graalvm native image
addSpringBootCatalog("springBoot31", "3.1.0", "3.+")
addSpringBootCatalog("springBoot32", "3.2.0", "3.+")
}
}

val gradleEnterpriseServer = "https://ge.opentelemetry.io"
Expand Down Expand Up @@ -141,6 +158,7 @@ include(":smoke-tests:images:spring-boot")
include(":smoke-tests-otel-starter:spring-smoke-testing")
include(":smoke-tests-otel-starter:spring-boot-2")
include(":smoke-tests-otel-starter:spring-boot-3")
include(":smoke-tests-otel-starter:spring-boot-3.2")
include(":smoke-tests-otel-starter:spring-boot-common")
include(":smoke-tests-otel-starter:spring-boot-reactive-2")
include(":smoke-tests-otel-starter:spring-boot-reactive-3")
Expand Down
2 changes: 1 addition & 1 deletion smoke-tests-otel-starter/spring-boot-2/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
id("otel.java-conventions")
id("org.springframework.boot") version "2.7.18"
alias(springBoot2.plugins.versions)
}

description = "smoke-tests-otel-starter-spring-boot-2"
Expand Down
76 changes: 76 additions & 0 deletions smoke-tests-otel-starter/spring-boot-3.2/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
plugins {
id("otel.java-conventions")
alias(springBoot32.plugins.versions)
id("org.graalvm.buildtools.native")
}

description = "smoke-tests-otel-starter-spring-boot-3.2"

otelJava {
minJavaVersionSupported.set(JavaVersion.VERSION_17)
}

dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-jdbc")
runtimeOnly("com.h2database:h2")
implementation("org.apache.commons:commons-dbcp2")
implementation("org.springframework.kafka:spring-kafka")
implementation("org.springframework.boot:spring-boot-starter-data-mongodb")
implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES))

implementation(project(":smoke-tests-otel-starter:spring-boot-common"))
testImplementation("org.springframework.boot:spring-boot-starter-test")
}

springBoot {
mainClass = "io.opentelemetry.spring.smoketest.OtelSpringStarterSmokeTestApplication"
}

tasks {
compileAotJava {
with(options) {
compilerArgs.add("-Xlint:-deprecation,-unchecked,none")
// To disable warnings/failure coming from the Java compiler during the Spring AOT processing
// -deprecation,-unchecked and none are required (none is not enough)
}
}
compileAotTestJava {
with(options) {
compilerArgs.add("-Xlint:-deprecation,-unchecked,none")
// To disable warnings/failure coming from the Java compiler during the Spring AOT processing
// -deprecation,-unchecked and none are required (none is not enough)
}
}
checkstyleAot {
isEnabled = false
}
checkstyleAotTest {
isEnabled = false
}
}

// To be able to execute the tests as GraalVM native executables
configurations.configureEach {
exclude("org.apache.groovy", "groovy")
exclude("org.apache.groovy", "groovy-json")
exclude("org.spockframework", "spock-core")
}

graalvmNative {
binaries.all {
// Workaround for https://github.com/junit-team/junit5/issues/3405
buildArgs.add("--initialize-at-build-time=org.junit.platform.launcher.core.LauncherConfig")
buildArgs.add("--initialize-at-build-time=org.junit.jupiter.engine.config.InstantiatingConfigurationParameterConverter")
}

// See https://github.com/graalvm/native-build-tools/issues/572
metadataRepository {
enabled.set(false)
}

tasks.test {
useJUnitPlatform()
setForkEvery(1)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.spring.smoketest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportRuntimeHints;

@SpringBootApplication
@ImportRuntimeHints(RuntimeHints.class)
public class OtelSpringStarterSmokeTestApplication {

public OtelSpringStarterSmokeTestApplication() {}

public static void main(String[] args) {
SpringApplication.run(OtelSpringStarterSmokeTestApplication.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.spring.smoketest;

import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;

// Necessary for GraalVM native test
public class RuntimeHints implements RuntimeHintsRegistrar {

@Override
public void registerHints(
org.springframework.aot.hint.RuntimeHints hints, ClassLoader classLoader) {
hints.resources().registerResourceBundle("org.apache.commons.dbcp2.LocalStrings");

// To avoid Spring native issue with MongoDB: java.lang.ClassNotFoundException:
// org.springframework.data.mongodb.core.aggregation.AggregationOperation
hints
.reflection()
.registerType(
TypeReference.of(
"org.springframework.data.mongodb.core.aggregation.AggregationOperation"),
hint -> {
hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.spring.smoketest;

import static org.assertj.core.api.Assertions.assertThat;

import io.opentelemetry.api.trace.SpanKind;
import io.opentelemetry.sdk.testing.assertj.TraceAssert;
import io.opentelemetry.semconv.HttpAttributes;
import io.opentelemetry.semconv.UrlAttributes;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.web.client.RestClient;

@SpringBootTest(
classes = {
OtelSpringStarterSmokeTestApplication.class,
AbstractOtelSpringStarterSmokeTest.TestConfiguration.class,
SpringSmokeOtelConfiguration.class
},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class OtelSpringStarterSmokeTest extends AbstractSpringStarterSmokeTest {

@Autowired RestClient.Builder restClientBuilder;
@LocalServerPort private int port;

@Test
void restClient() {
testing.clearAllExportedData();

RestClient client = restClientBuilder.baseUrl("http:https://localhost:" + port).build();
assertThat(
client
.get()
.uri(OtelSpringStarterSmokeTestController.PING)
.retrieve()
.body(String.class))
.isEqualTo("pong");

if (System.getProperty("org.graalvm.nativeimage.imagecode") != null) {
// ignore the trace for creating the db table
testing.waitAndAssertTraces(trace -> {}, OtelSpringStarterSmokeTest::assertClient);
} else {
testing.waitAndAssertTraces(OtelSpringStarterSmokeTest::assertClient);
}
}

private static void assertClient(TraceAssert traceAssert) {
traceAssert.hasSpansSatisfyingExactly(
nestedClientSpan ->
nestedClientSpan
.hasKind(SpanKind.CLIENT)
.hasAttributesSatisfying(
a -> assertThat(a.get(UrlAttributes.URL_FULL)).endsWith("/ping")),
nestedServerSpan ->
nestedServerSpan
.hasKind(SpanKind.SERVER)
.hasAttribute(HttpAttributes.HTTP_ROUTE, "/ping"));
}
}
2 changes: 1 addition & 1 deletion smoke-tests-otel-starter/spring-boot-3/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
id("otel.java-conventions")
id("org.springframework.boot") version "3.3.0"
alias(springBoot31.plugins.versions)
id("org.graalvm.buildtools.native")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,7 @@

package io.opentelemetry.spring.smoketest;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.web.client.RestClient;

@SpringBootTest(
classes = {
Expand All @@ -24,23 +18,4 @@
// The headers are simply set here to make sure that headers can be parsed
"otel.exporter.otlp.headers.c=3"
})
class OtelSpringStarterSmokeTest extends AbstractOtelSpringStarterSmokeTest {

@Autowired RestClient.Builder restClientBuilder;
@LocalServerPort private int port;

@Test
void restClient() {
testing.clearAllExportedData();

RestClient client = restClientBuilder.baseUrl("http:https://localhost:" + port).build();
assertThat(
client
.get()
.uri(OtelSpringStarterSmokeTestController.PING)
.retrieve()
.body(String.class))
.isEqualTo("pong");
assertClient();
}
}
class OtelSpringStarterSmokeTest extends AbstractOtelSpringStarterSmokeTest {}
Loading

0 comments on commit 40cea5e

Please sign in to comment.