Skip to content

Commit 97a4817

Browse files
authored
Merge 16dcaee into 0ceb6bf
2 parents 0ceb6bf + 16dcaee commit 97a4817

File tree

10 files changed

+1187
-39
lines changed

10 files changed

+1187
-39
lines changed

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

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,27 @@ jobs:
2121
fail-fast: false
2222
matrix:
2323
sample: [ "sentry-samples-spring-boot-jakarta" ]
24-
agent: [ "0" ]
24+
agent: [ "false" ]
2525
agent-auto-init: [ "true" ]
2626
include:
2727
- sample: "sentry-samples-spring-boot"
2828
- sample: "sentry-samples-spring-boot-opentelemetry-noagent"
2929
- sample: "sentry-samples-spring-boot-opentelemetry"
30-
agent: "1"
30+
agent: "true"
3131
agent-auto-init: "true"
3232
- sample: "sentry-samples-spring-boot-opentelemetry"
33-
agent: "1"
33+
agent: "true"
3434
agent-auto-init: "false"
3535
- sample: "sentry-samples-spring-boot-webflux-jakarta"
3636
- sample: "sentry-samples-spring-boot-webflux"
3737
- sample: "sentry-samples-spring-boot-jakarta-opentelemetry-noagent"
3838
- sample: "sentry-samples-spring-boot-jakarta-opentelemetry"
39-
agent: "1"
39+
agent: "true"
4040
agent-auto-init: "true"
4141
- sample: "sentry-samples-spring-boot-jakarta-opentelemetry"
42-
agent: "1"
42+
agent: "true"
4343
agent-auto-init: "false"
44+
- sample: "sentry-samples-console"
4445
steps:
4546
- uses: actions/checkout@v4
4647
with:
@@ -90,17 +91,9 @@ jobs:
9091
-e '/.*"sentry-samples-android",/d' \
9192
build.gradle.kts
9293
93-
- name: Build server jar
94+
- name: Build and run system tests
9495
run: |
95-
./gradlew :sentry-samples:${{ matrix.sample }}:bootJar
96-
97-
- name: Build agent jar
98-
run: |
99-
./gradlew :sentry-opentelemetry:sentry-opentelemetry-agent:assemble
100-
101-
- name: Start server and run integration test for sentry-cli commands
102-
run: |
103-
test/system-test-run.sh "${{ matrix.sample }}" "${{ matrix.agent }}" "${{ matrix.agent-auto-init }}" "0"
96+
python3 test/system-test-runner.py test --module "${{ matrix.sample }}" --agent "${{ matrix.agent }}" --auto-init "${{ matrix.agent-auto-init }}" --build "true"
10497
10598
- name: Upload test results
10699
if: always()

Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: all clean compile javadocs dryRelease update checkFormat api assembleBenchmarkTestRelease assembleUiTestRelease assembleUiTestCriticalRelease createCoverageReports runUiTestCritical check preMerge publish
1+
.PHONY: all clean compile javadocs dryRelease update checkFormat api assembleBenchmarkTestRelease assembleUiTestRelease assembleUiTestCriticalRelease createCoverageReports runUiTestCritical check preMerge publish systemtest systemtest-interactive
22

33
all: stop clean javadocs compile createCoverageReports
44
assembleBenchmarks: assembleBenchmarkTestRelease
@@ -59,6 +59,14 @@ createCoverageReports:
5959
./gradlew jacocoTestReport
6060
./gradlew koverXmlReportRelease
6161

62+
# Run system tests for sample applications
63+
systemtest:
64+
python3 test/system-test-runner.py test --all
65+
66+
# Run system tests with interactive module selection
67+
systemtest-interactive:
68+
python3 test/system-test-runner.py test --interactive
69+
6270
# Run tests and lint
6371
check:
6472
./gradlew check

sentry-samples/sentry-samples-console/build.gradle.kts

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,88 @@
1+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2+
13
plugins {
24
java
35
application
6+
kotlin("jvm")
47
alias(libs.plugins.gradle.versions)
8+
id("com.github.johnrengelman.shadow") version "8.1.1"
59
}
610

711
application { mainClass.set("io.sentry.samples.console.Main") }
812

13+
java.sourceCompatibility = JavaVersion.VERSION_17
14+
15+
java.targetCompatibility = JavaVersion.VERSION_17
16+
17+
repositories { mavenCentral() }
18+
919
configure<JavaPluginExtension> {
10-
sourceCompatibility = JavaVersion.VERSION_1_8
11-
targetCompatibility = JavaVersion.VERSION_1_8
20+
sourceCompatibility = JavaVersion.VERSION_17
21+
targetCompatibility = JavaVersion.VERSION_17
22+
}
23+
24+
tasks.withType<KotlinCompile>().configureEach {
25+
kotlinOptions.jvmTarget = JavaVersion.VERSION_17.toString()
26+
}
27+
28+
tasks.withType<KotlinCompile>().configureEach {
29+
kotlinOptions {
30+
freeCompilerArgs = listOf("-Xjsr305=strict")
31+
jvmTarget = JavaVersion.VERSION_17.toString()
32+
}
33+
}
34+
35+
dependencies {
36+
implementation(projects.sentry)
37+
38+
testImplementation(kotlin(Config.kotlinStdLib))
39+
testImplementation(projects.sentry)
40+
testImplementation(projects.sentrySystemTestSupport)
41+
testImplementation(libs.kotlin.test.junit)
42+
testImplementation(libs.slf4j.api)
43+
testImplementation(libs.slf4j.jdk14)
44+
}
45+
46+
// Configure the Shadow JAR (executable JAR with all dependencies)
47+
tasks.shadowJar {
48+
manifest {
49+
attributes["Main-Class"] = "io.sentry.samples.console.Main"
50+
}
51+
archiveClassifier.set("") // Remove the classifier so it replaces the regular JAR
52+
mergeServiceFiles()
53+
}
54+
55+
// Make the regular jar task depend on shadowJar
56+
tasks.jar {
57+
enabled = false
58+
dependsOn(tasks.shadowJar)
59+
}
60+
61+
// Fix the startScripts task dependency
62+
tasks.startScripts {
63+
dependsOn(tasks.shadowJar)
64+
}
65+
66+
configure<SourceSetContainer> { test { java.srcDir("src/test/java") } }
67+
68+
tasks.register<Test>("systemTest").configure {
69+
group = "verification"
70+
description = "Runs the System tests"
71+
72+
outputs.upToDateWhen { false }
73+
74+
maxParallelForks = 1
75+
76+
// Cap JVM args per test
77+
minHeapSize = "128m"
78+
maxHeapSize = "1g"
79+
80+
filter { includeTestsMatching("io.sentry.systemtest*") }
81+
}
82+
83+
tasks.named("test").configure {
84+
require(this is Test)
85+
86+
filter { excludeTestsMatching("io.sentry.systemtest.*") }
1287
}
1388

14-
dependencies { implementation(projects.sentry) }

sentry-samples/sentry-samples-console/src/main/java/io/sentry/samples/console/Main.java

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public static void main(String[] args) throws InterruptedException {
2020
options -> {
2121
// NOTE: Replace the test DSN below with YOUR OWN DSN to see the events from this app in
2222
// your Sentry project/dashboard
23+
options.setEnableExternalConfiguration(true);
2324
options.setDsn(
2425
"https://502f25099c204a2fbf4cb16edc5975d1@o447951.ingest.sentry.io/5428563");
2526

@@ -66,10 +67,8 @@ public static void main(String[] args) throws InterruptedException {
6667
options.setDebug(true);
6768
// To change the verbosity, use:
6869
// By default it's DEBUG.
69-
options.setDiagnosticLevel(
70-
SentryLevel
71-
.ERROR); // A good option to have SDK debug log in prod is to use only level
72-
// ERROR here.
70+
// options.setDiagnosticLevel(SentryLevel.ERROR);
71+
// A good option to have SDK debug log in prod is to use only level ERROR here.
7372

7473
// Exclude frames from some packages from being "inApp" so are hidden by default in Sentry
7574
// UI:
@@ -83,15 +82,15 @@ public static void main(String[] args) throws InterruptedException {
8382
options.setTracesSampleRate(1.0); // set 0.5 to send 50% of traces
8483

8584
// Determine traces sample rate based on the sampling context
86-
options.setTracesSampler(
87-
context -> {
88-
// only 10% of transactions with "/product" prefix will be collected
89-
if (!context.getTransactionContext().getName().startsWith("/products")) {
90-
return 0.1;
91-
} else {
92-
return 0.5;
93-
}
94-
});
85+
// options.setTracesSampler(
86+
// context -> {
87+
// // only 10% of transactions with "/product" prefix will be collected
88+
// if (!context.getTransactionContext().getName().startsWith("/products")) {
89+
// return 0.1;
90+
// } else {
91+
// return 0.5;
92+
// }
93+
// });
9594
});
9695

9796
Sentry.addBreadcrumb(
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package io.sentry
2+
3+
import kotlin.test.Test
4+
import kotlin.test.assertTrue
5+
6+
class DummyTest {
7+
@Test
8+
fun `the only test`() {
9+
// only needed to have more than 0 tests and not fail the build
10+
assertTrue(true)
11+
}
12+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package io.sentry.systemtest
2+
3+
import io.sentry.systemtest.util.TestHelper
4+
import java.io.File
5+
import java.util.concurrent.TimeUnit
6+
import org.junit.Test
7+
import org.junit.Before
8+
import org.junit.Assert.assertEquals
9+
import org.junit.Assert.assertTrue
10+
11+
class ConsoleApplicationSystemTest {
12+
lateinit var testHelper: TestHelper
13+
14+
@Before
15+
fun setup() {
16+
testHelper = TestHelper("http://localhost:8000")
17+
testHelper.reset()
18+
}
19+
20+
@Test
21+
fun `console application sends expected events when run as JAR`() {
22+
val jarFile = testHelper.findJar("sentry-samples-console")
23+
val process = testHelper.launch(
24+
jarFile,
25+
mapOf(
26+
"SENTRY_DSN" to testHelper.dsn,
27+
"SENTRY_TRACES_SAMPLE_RATE" to "1.0",
28+
"SENTRY_ENABLE_PRETTY_SERIALIZATION_OUTPUT" to "false",
29+
"SENTRY_DEBUG" to "true",
30+
))
31+
32+
process.waitFor(30, TimeUnit.SECONDS);
33+
assertEquals(0, process.exitValue())
34+
35+
// Verify that we received the expected events
36+
verifyExpectedEvents()
37+
}
38+
39+
private fun verifyExpectedEvents() {
40+
// Verify we received a "Fatal message!" event
41+
testHelper.ensureErrorReceived { event ->
42+
event.message?.formatted == "Fatal message!" && event.level?.name == "FATAL"
43+
}
44+
45+
// Verify we received a "Some warning!" event
46+
testHelper.ensureErrorReceived { event ->
47+
event.message?.formatted == "Some warning!" && event.level?.name == "WARNING"
48+
}
49+
50+
// Verify we received the RuntimeException
51+
testHelper.ensureErrorReceived { event ->
52+
event.exceptions?.any { ex -> ex.type == "RuntimeException" && ex.value == "Some error!" } ==
53+
true
54+
}
55+
56+
// Verify we received the detailed event with fingerprint
57+
testHelper.ensureErrorReceived { event ->
58+
event.message?.message == "Detailed event" &&
59+
event.fingerprints?.contains("NewClientDebug") == true &&
60+
event.level?.name == "DEBUG"
61+
}
62+
63+
// Verify we received transaction events
64+
testHelper.ensureTransactionReceived { transaction, _ ->
65+
transaction.transaction == "transaction name" &&
66+
transaction.spans?.any { span -> span.op == "child" } == true
67+
}
68+
69+
// Verify we received the loop messages (should be 10 of them)
70+
var loopMessageCount = 0
71+
try {
72+
for (i in 0..9) {
73+
testHelper.ensureErrorReceived { event ->
74+
val matches = event.message?.message?.contains("items we'll wait to flush to Sentry!") == true
75+
if (matches) loopMessageCount++
76+
matches
77+
}
78+
}
79+
} catch (e: Exception) {
80+
// Some loop messages might be missing, but we should have at least some
81+
}
82+
83+
assertTrue("Should receive at least 5 loop messages, got $loopMessageCount", loopMessageCount >= 5)
84+
85+
// Verify we have breadcrumbs
86+
testHelper.ensureErrorReceived { event ->
87+
event.breadcrumbs?.any { breadcrumb ->
88+
breadcrumb.message?.contains("Processed by") == true
89+
} == true
90+
}
91+
}
92+
}

sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/TestHelper.kt

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import io.sentry.SentryOptions
1111
import io.sentry.protocol.SentrySpan
1212
import io.sentry.protocol.SentryTransaction
1313
import io.sentry.systemtest.graphql.GraphqlTestClient
14+
import java.io.File
1415
import java.io.PrintWriter
16+
import java.util.concurrent.TimeUnit
1517
import kotlin.test.assertEquals
1618
import kotlin.test.assertFalse
1719
import kotlin.test.assertNotNull
@@ -22,6 +24,7 @@ class TestHelper(backendUrl: String) {
2224
val graphqlClient: GraphqlTestClient
2325
val sentryClient: SentryMockServerClient
2426
val jsonSerializer: JsonSerializer
27+
val dsn = "http://502f25099c204a2fbf4cb16edc5975d1@localhost:8000/0"
2528

2629
var envelopeCounts: EnvelopeCounts? = null
2730

@@ -42,8 +45,7 @@ class TestHelper(backendUrl: String) {
4245
assertTrue(envelopeCountsAfter!!.envelopes!! > envelopeCounts!!.envelopes!!)
4346
}
4447

45-
fun ensureEnvelopeReceived(callback: ((String) -> Boolean)) {
46-
Thread.sleep(10000)
48+
fun ensureEnvelopeReceived(retryCount: Int = 1, callback: ((String) -> Boolean)) {
4749
val envelopes = sentryClient.getEnvelopes()
4850
assertNotNull(envelopes.envelopes)
4951
envelopes.envelopes.forEach { envelopeString ->
@@ -52,7 +54,12 @@ class TestHelper(backendUrl: String) {
5254
return
5355
}
5456
}
55-
throw RuntimeException("Unable to find matching envelope received by relay")
57+
if (retryCount <= 0) {
58+
throw RuntimeException("Unable to find matching envelope received by relay")
59+
} else {
60+
Thread.sleep(10000)
61+
ensureEnvelopeReceived(retryCount - 1, callback)
62+
}
5663
}
5764

5865
fun ensureNoEnvelopeReceived(callback: ((String) -> Boolean)) {
@@ -268,4 +275,27 @@ class TestHelper(backendUrl: String) {
268275

269276
return true
270277
}
278+
279+
fun findJar(prefix: String, inDir: String = "build/libs"): File {
280+
val buildDir = File(inDir)
281+
val jarFiles =
282+
buildDir
283+
.listFiles { _, name -> name.startsWith(prefix) && name.endsWith(".jar") }
284+
?.toList() ?: emptyList()
285+
286+
if (jarFiles.isEmpty()) {
287+
throw AssertionError("No JAR found in ${buildDir.absolutePath}")
288+
}
289+
290+
return jarFiles.maxOf { it }
291+
}
292+
293+
fun launch(jar: File, env: Map<String, String>): Process {
294+
val processBuilder = ProcessBuilder("java", "-jar", jar.absolutePath)
295+
.inheritIO() // forward i/o to current process
296+
297+
processBuilder.environment().putAll(env)
298+
299+
return processBuilder.start()
300+
}
271301
}

test/system-test-run-all.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
./test/system-test-run.sh "sentry-samples-spring-boot-jakarta-opentelemetry-noagent" "0" "true" "0"
1111
./test/system-test-run.sh "sentry-samples-spring-boot-jakarta-opentelemetry" "1" "true" "0"
1212
./test/system-test-run.sh "sentry-samples-spring-boot-jakarta-opentelemetry" "1" "false" "0"
13+
./test/system-test-run.sh "sentry-samples-console" "0" "true" "0"

0 commit comments

Comments
 (0)