Skip to content

Commit 99a5992

Browse files
committed
test(jul): Move the JUL sample's system test into sentry-jul
Adds SentryHandlerIntegrationTest, which configures the Sentry handler through a logging properties file read by LogManager, as the sample does, and checks what reaches MockSentryServer: the warning with its flag, the error with its exception and breadcrumbs, and the logs with their attributes. Its logger is outside io.sentry, whose loggers the handler drops, and the test restores the LogManager configuration the other tests read. The sample has no system tests left, so it comes off the system-test runner and the backend workflow, and drops the Kotlin plugin it only needed for the test. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent f3b9555 commit 99a5992

8 files changed

Lines changed: 77 additions & 135 deletions

File tree

‎.github/workflows/system-tests-backend.yml‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ jobs:
3131
- sample: "sentry-samples-console-otlp"
3232
agent: "false"
3333
agent-auto-init: "true"
34-
- sample: "sentry-samples-jul"
35-
agent: "false"
36-
agent-auto-init: "true"
3734
- sample: "sentry-samples-spring-boot-4-otlp"
3835
agent: "false"
3936
agent-auto-init: "true"

‎sentry-jul/build.gradle.kts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ dependencies {
2828
// tests
2929
testImplementation(projects.sentryTestSupport)
3030
testImplementation(kotlin(Config.kotlinStdLib))
31+
testImplementation(libs.google.truth)
3132
testImplementation(libs.kotlin.test.junit)
3233
testImplementation(libs.logback.classic)
3334
testImplementation(libs.mockito.kotlin)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package io.sentry.jul
2+
3+
import com.google.common.truth.Truth.assertThat
4+
import io.sentry.Sentry
5+
import io.sentry.SentryLevel
6+
import io.sentry.test.MockSentryServer
7+
import io.sentry.test.event
8+
import io.sentry.test.hasFlag
9+
import io.sentry.test.logs
10+
import java.util.logging.Level
11+
import java.util.logging.LogManager
12+
import java.util.logging.Logger
13+
import kotlin.test.AfterTest
14+
import kotlin.test.Test
15+
16+
class SentryHandlerIntegrationTest {
17+
private val server = MockSentryServer()
18+
19+
@AfterTest
20+
fun teardown() {
21+
// Back to the configuration the other tests read, which also closes this test's handler.
22+
LogManager.getLogManager().readConfiguration()
23+
Sentry.close()
24+
server.close()
25+
System.clearProperty("sentry.dsn")
26+
}
27+
28+
@Test
29+
fun `handler configured from logging properties sends events, breadcrumbs and logs`() {
30+
// The handler reads the DSN as external configuration, as an app's sentry.properties would
31+
// set it. The module's test sentry.properties enables logs.
32+
System.setProperty("sentry.dsn", server.dsn)
33+
javaClass.getResourceAsStream("/sentry-handler-integration-test.properties")!!.use {
34+
LogManager.getLogManager().readConfiguration(it)
35+
}
36+
// Outside io.sentry, whose loggers the handler drops so it doesn't capture the SDK's own logs.
37+
val logger = Logger.getLogger("com.example.App")
38+
39+
logger.config("Hello Sentry!")
40+
Sentry.setAttribute("user.type", "admin")
41+
Sentry.setAttribute("feature.version", 2)
42+
Sentry.setAttribute("debug.enabled", true)
43+
Sentry.addFeatureFlag("my-feature-flag", true)
44+
logger.warning("important warning")
45+
logger.log(Level.INFO, "User has made a purchase of product: %d", 445)
46+
logger.log(Level.SEVERE, "Something went wrong", RuntimeException("Invalid productId=445"))
47+
Sentry.flush(5000)
48+
49+
val warning = server.awaitEnvelope { it.event()?.level == SentryLevel.WARNING }.event()!!
50+
assertThat(warning.message!!.message).isEqualTo("important warning")
51+
assertThat(warning.hasFlag("my-feature-flag", true)).isTrue()
52+
53+
val error = server.awaitEnvelope { it.event()?.level == SentryLevel.ERROR }.event()!!
54+
assertThat(error.message!!.message).isEqualTo("Something went wrong")
55+
assertThat(error.exceptions!!.map { it.type to it.value })
56+
.contains("RuntimeException" to "Invalid productId=445")
57+
assertThat(error.breadcrumbs!!.map { it.message to it.level })
58+
.containsAtLeast(
59+
"Hello Sentry!" to SentryLevel.DEBUG,
60+
"User has made a purchase of product: 445" to SentryLevel.INFO,
61+
)
62+
63+
val logs = server.awaitEnvelope { it.logs() != null }.logs()!!
64+
assertThat(logs.items.map { it.body }).contains("User has made a purchase of product: 445")
65+
val failureLog = logs.items.single { it.body == "Something went wrong" }
66+
assertThat(failureLog.attributes!!.mapValues { it.value.value })
67+
.containsAtLeast("user.type", "admin", "feature.version", 2, "debug.enabled", true)
68+
}
69+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
handlers=io.sentry.jul.SentryHandler
2+
.level=FINEST
3+
io.sentry.jul.SentryHandler.level=FINEST
4+
io.sentry.jul.SentryHandler.minimumEventLevel=INFO
5+
io.sentry.jul.SentryHandler.minimumBreadcrumbLevel=CONFIG
6+
io.sentry.jul.SentryHandler.minimumLevel=INFO
7+
io.sentry.jul.SentryHandler.printfStyle=true
Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,15 @@
1-
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2-
31
plugins {
42
java
53
application
6-
alias(libs.plugins.kotlin.jvm)
74
alias(libs.plugins.gradle.versions)
85
alias(libs.plugins.shadow)
9-
id("io.sentry.systemtest")
106
}
117

128
application { mainClass.set("io.sentry.samples.jul.Main") }
139

14-
tasks.withType<KotlinCompile>().configureEach {
15-
kotlin {
16-
compilerOptions.freeCompilerArgs = listOf("-Xjsr305=strict")
17-
}
18-
}
19-
2010
dependencies {
2111
implementation(projects.sentryJul)
2212
implementation(libs.slf4j.jdk14)
23-
24-
testImplementation(kotlin(Config.kotlinStdLib))
25-
testImplementation(projects.sentry)
26-
testImplementation(projects.sentrySystemTestSupport)
27-
testImplementation(libs.kotlin.test.junit)
28-
testImplementation(libs.slf4j.api)
29-
testImplementation(libs.slf4j.jdk14)
3013
}
3114

3215
// Configure the Shadow JAR (executable JAR with all dependencies)
@@ -44,22 +27,3 @@ tasks.jar {
4427

4528
// Fix the startScripts task dependency
4629
tasks.startScripts { dependsOn(tasks.shadowJar) }
47-
48-
tasks.register<Test>("systemTest").configure {
49-
group = "verification"
50-
description = "Runs the System tests"
51-
52-
val test = project.extensions.getByType<SourceSetContainer>()["test"]
53-
testClassesDirs = test.output.classesDirs
54-
classpath = test.runtimeClasspath
55-
56-
maxParallelForks = 1
57-
58-
filter { includeTestsMatching("io.sentry.systemtest*") }
59-
}
60-
61-
tasks.named("test").configure {
62-
require(this is Test)
63-
64-
filter { excludeTestsMatching("io.sentry.systemtest.*") }
65-
}

‎sentry-samples/sentry-samples-jul/src/test/kotlin/io/sentry/DummyTest.kt‎

Lines changed: 0 additions & 12 deletions
This file was deleted.

‎sentry-samples/sentry-samples-jul/src/test/kotlin/io/sentry/systemtest/ConsoleApplicationSystemTest.kt‎

Lines changed: 0 additions & 83 deletions
This file was deleted.

‎test/system-test-runner.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -831,7 +831,6 @@ def get_available_modules(self) -> List[ModuleConfig]:
831831
ModuleConfig("sentry-samples-console", "false", "true", "false"),
832832
ModuleConfig("sentry-samples-console-otlp", "false", "true", "false"),
833833
ModuleConfig("sentry-samples-console-opentelemetry-noagent", "false", "true", "false"),
834-
ModuleConfig("sentry-samples-jul", "false", "true", "false"),
835834
]
836835

837836
def _find_module_number(self, module_name: str, agent: str, auto_init: str) -> int:

0 commit comments

Comments
 (0)