Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
6497aa1
Add Tomcat support in the system test runner and tests to the spring-…
alexander-alderman-webb Aug 13, 2025
90ab6da
Create webapps directory and revert library changes only needed for t…
alexander-alderman-webb Aug 13, 2025
b6fe8bc
Adapt test instead of endpoint in spring-jakarta sample
alexander-alderman-webb Aug 13, 2025
dcc9cc8
Format code
getsentry-bot Aug 13, 2025
e1edcf2
Add task dependency from run on war in spring-jakarta sample
alexander-alderman-webb Aug 13, 2025
506baad
Merge branch 'webb/e2e_tests_with_tomcat' of github.com:getsentry/sen…
alexander-alderman-webb Aug 13, 2025
a90c5af
Format code
getsentry-bot Aug 13, 2025
9a62123
Add missing argument in interactive mode and build before launching i…
alexander-alderman-webb Aug 13, 2025
7897b39
Merge branch 'webb/e2e_tests_with_tomcat' of github.com:getsentry/sen…
alexander-alderman-webb Aug 13, 2025
65fea05
Add spring-jakarta sample to CI system tests config file
alexander-alderman-webb Aug 13, 2025
7713458
Stop tomcat server on signal in system-test-runner
alexander-alderman-webb Aug 13, 2025
b027648
merge main
alexander-alderman-webb Aug 13, 2025
aa79e43
Stop Tomcat process in all cases
alexander-alderman-webb Aug 13, 2025
c8d4c97
Merge branch 'main' into webb/e2e_tests_with_tomcat
alexander-alderman-webb Aug 13, 2025
7c23dbc
Merge branch 'main' into webb/e2e_tests_with_tomcat
alexander-alderman-webb Aug 13, 2025
337c221
Merge branch 'main' into webb/e2e_tests_with_tomcat
alexander-alderman-webb Aug 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/system-tests-backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ jobs:
- sample: "sentry-samples-jul"
agent: "false"
agent-auto-init: "true"
- sample: "sentry-samples-spring-jakarta"
agent: "false"
agent-auto-init: "true"
steps:
- uses: actions/checkout@v4
with:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ distributions/
sentry-spring-boot-starter-jakarta/src/main/resources/META-INF/spring.factories
sentry-samples/sentry-samples-spring-boot-jakarta/spy.log
sentry-mock-server.txt
tomcat-server.txt
spring-server.txt
*.pid
spy.log
.kotlin
**/tomcat.8080/webapps/
6 changes: 5 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit
retrofit-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" }
sentry-native-ndk = { module = "io.sentry:sentry-native-ndk", version = "0.10.0" }
servlet-api = { module = "javax.servlet:javax.servlet-api", version = "3.1.0" }
servlet-jakarta-api = { module = "jakarta.servlet:jakarta.servlet-api", version = "5.0.0" }
servlet-jakarta-api = { module = "jakarta.servlet:jakarta.servlet-api", version = "6.1.0" }
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
slf4j-jdk14 = { module = "org.slf4j:slf4j-jdk14", version.ref = "slf4j" }
slf4j2-api = { module = "org.slf4j:slf4j-api", version = "2.0.5" }
Expand Down Expand Up @@ -152,6 +152,10 @@ springboot3-starter-jdbc = { module = "org.springframework.boot:spring-boot-star
springboot3-starter-actuator = { module = "org.springframework.boot:spring-boot-starter-actuator", version.ref = "springboot3" }
timber = { module = "com.jakewharton.timber:timber", version = "4.7.1" }

# tomcat libraries
tomcat-catalina-jakarta = { module = "org.apache.tomcat:tomcat-catalina", version = "11.0.10" }
tomcat-embed-jasper-jakarta = { module = "org.apache.tomcat.embed:tomcat-embed-jasper", version = "11.0.10" }

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Java Version Mismatch with Tomcat 11

New Tomcat 11.0.10 (Servlet 6.1.0) dependencies require Java 21, but the project and CI currently use Java 17. This causes an UnsupportedClassVersionError when running the spring-jakarta sample, breaking new system tests in CI and local development environments. To resolve, either upgrade the CI/runtime JDK to 21 (aligning toolchains) or use Tomcat 10.1.x (Servlet 6.0) which is compatible with Java 17.

Fix in Cursor Fix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# test libraries
androidx-compose-ui-test-junit4 = { module = "androidx.compose.ui:ui-test-junit4", version = "1.6.8" }
androidx-test-core = { module = "androidx.test:core", version.ref = "androidxTestCore" }
Expand Down
37 changes: 35 additions & 2 deletions sentry-samples/sentry-samples-spring-jakarta/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.springframework.boot.gradle.plugin.SpringBootPlugin

plugins {
application
alias(libs.plugins.springboot3) apply false
alias(libs.plugins.spring.dependency.management)
kotlin("jvm")
Expand All @@ -11,6 +12,11 @@ plugins {
alias(libs.plugins.gretty)
}

application { mainClass.set("io.sentry.samples.spring.jakarta.Main") }

// Ensure WAR is up to date before run task
tasks.named("run") { dependsOn(tasks.named("war")) }

group = "io.sentry.sample.spring-jakarta"

version = "0.0.1-SNAPSHOT"
Expand All @@ -37,16 +43,43 @@ dependencies {
implementation(libs.logback.classic)
implementation(libs.servlet.jakarta.api)
implementation(libs.slf4j2.api)

implementation(libs.tomcat.catalina.jakarta)
implementation(libs.tomcat.embed.jasper.jakarta)

testImplementation(projects.sentrySystemTestSupport)
testImplementation(libs.kotlin.test.junit)
testImplementation(libs.springboot.starter.test) {
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
}
}

tasks.withType<Test>().configureEach { useJUnitPlatform() }

tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = JavaVersion.VERSION_17.toString()
}
}

configure<SourceSetContainer> { test { java.srcDir("src/test/java") } }

tasks.register<Test>("systemTest").configure {
group = "verification"
description = "Runs the System tests"

outputs.upToDateWhen { false }

maxParallelForks = 1

// Cap JVM args per test
minHeapSize = "128m"
maxHeapSize = "1g"

filter { includeTestsMatching("io.sentry.systemtest*") }
}

tasks.named("test").configure {
require(this is Test)

filter { excludeTestsMatching("io.sentry.systemtest.*") }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.sentry.samples.spring.jakarta;

import java.io.File;
import java.io.IOException;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;

public class Main {

public static void main(String[] args) throws LifecycleException, IOException {
File webappsDirectory = new File("./tomcat.8080/webapps");
if (!webappsDirectory.exists()) {
boolean didCreateDirectories = webappsDirectory.mkdirs();
if (!didCreateDirectories) {
throw new RuntimeException(
"Failed to create directory required by Tomcat: " + webappsDirectory.getAbsolutePath());
}
}

String pathToWar = "./build/libs";
String warName = "sentry-samples-spring-jakarta-0.0.1-SNAPSHOT";
File war = new File(pathToWar + "/" + warName + ".war");

Tomcat tomcat = new Tomcat();
tomcat.setPort(8080);
tomcat.getConnector();

tomcat.addWebapp("/" + warName, war.getCanonicalPath());
tomcat.start();
tomcat.getServer().await();
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package io.sentry.samples.spring.jakarta.web;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public class Person {
private final String firstName;
private final String lastName;

public Person(String firstName, String lastName) {
@JsonCreator
public Person(
@JsonProperty("firstName") String firstName, @JsonProperty("lastName") String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public PersonController(PersonService personService) {
}

@GetMapping("{id}")
Person person(@PathVariable Long id) {
Person person(@PathVariable("id") Long id) {
Sentry.logger().warn("warn Sentry logging");
Sentry.logger().error("error Sentry logging");
Sentry.logger().info("hello %s %s", "there", "world!");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.sentry

import kotlin.test.Test
import kotlin.test.assertTrue

class DummyTest {
@Test
fun `the only test`() {
// only needed to have more than 0 tests and not fail the build
assertTrue(true)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package io.sentry.systemtest

import io.sentry.systemtest.util.TestHelper
import kotlin.test.Test
import kotlin.test.assertEquals
import org.junit.Before

class PersonSystemTest {
lateinit var testHelper: TestHelper

@Before
fun setup() {
testHelper = TestHelper("http://localhost:8080/sentry-samples-spring-jakarta-0.0.1-SNAPSHOT")
testHelper.reset()
}

@Test
fun `get person fails`() {
val restClient = testHelper.restClient
restClient.getPerson(11L)
assertEquals(500, restClient.lastKnownStatusCode)

testHelper.ensureTransactionReceived { transaction, envelopeHeader ->
testHelper.doesTransactionHaveOp(transaction, "http.server")
}

Thread.sleep(10000)

testHelper.ensureLogsReceived { logs, envelopeHeader ->
testHelper.doesContainLogWithBody(logs, "warn Sentry logging") &&
testHelper.doesContainLogWithBody(logs, "error Sentry logging") &&
testHelper.doesContainLogWithBody(logs, "hello there world!")
}
}

@Test
fun `create person works`() {
val restClient = testHelper.restClient
val person = Person("firstA", "lastB")
val returnedPerson = restClient.createPerson(person)
assertEquals(200, restClient.lastKnownStatusCode)

assertEquals(person.firstName, returnedPerson!!.firstName)
assertEquals(person.lastName, returnedPerson!!.lastName)
}
}
Loading
Loading