Skip to content

Commit 29f60d6

Browse files
authored
Merge 195937c into 2bfacef
2 parents 2bfacef + 195937c commit 29f60d6

File tree

15 files changed

+1202
-108
lines changed

15 files changed

+1202
-108
lines changed

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

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,39 @@ 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"
28+
agent: "false"
29+
agent-auto-init: "true"
2830
- sample: "sentry-samples-spring-boot-opentelemetry-noagent"
31+
agent: "false"
32+
agent-auto-init: "true"
2933
- sample: "sentry-samples-spring-boot-opentelemetry"
30-
agent: "1"
34+
agent: "true"
3135
agent-auto-init: "true"
3236
- sample: "sentry-samples-spring-boot-opentelemetry"
33-
agent: "1"
37+
agent: "true"
3438
agent-auto-init: "false"
3539
- sample: "sentry-samples-spring-boot-webflux-jakarta"
40+
agent: "false"
41+
agent-auto-init: "true"
3642
- sample: "sentry-samples-spring-boot-webflux"
43+
agent: "false"
44+
agent-auto-init: "true"
3745
- sample: "sentry-samples-spring-boot-jakarta-opentelemetry-noagent"
46+
agent: "false"
47+
agent-auto-init: "true"
3848
- sample: "sentry-samples-spring-boot-jakarta-opentelemetry"
39-
agent: "1"
49+
agent: "true"
4050
agent-auto-init: "true"
4151
- sample: "sentry-samples-spring-boot-jakarta-opentelemetry"
42-
agent: "1"
52+
agent: "true"
4353
agent-auto-init: "false"
54+
- sample: "sentry-samples-console"
55+
agent: "false"
56+
agent-auto-init: "true"
4457
steps:
4558
- uses: actions/checkout@v4
4659
with:
@@ -50,6 +63,11 @@ jobs:
5063
with:
5164
python-version: '3.10.5'
5265

66+
- name: Install Python dependencies
67+
run: |
68+
python3 -m pip install --upgrade pip
69+
python3 -m pip install requests
70+
5371
- name: Set up Java
5472
uses: actions/setup-java@v4
5573
with:
@@ -90,17 +108,9 @@ jobs:
90108
-e '/.*"sentry-samples-android",/d' \
91109
build.gradle.kts
92110
93-
- name: Build server jar
94-
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
111+
- name: Build and run system tests
102112
run: |
103-
test/system-test-run.sh "${{ matrix.sample }}" "${{ matrix.agent }}" "${{ matrix.agent-auto-init }}" "0"
113+
python3 test/system-test-runner.py test --module "${{ matrix.sample }}" --agent "${{ matrix.agent }}" --auto-init "${{ matrix.agent-auto-init }}" --build "true"
104114
105115
- name: Upload test results
106116
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
Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,83 @@
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 { attributes["Main-Class"] = "io.sentry.samples.console.Main" }
49+
archiveClassifier.set("") // Remove the classifier so it replaces the regular JAR
50+
mergeServiceFiles()
1251
}
1352

14-
dependencies { implementation(projects.sentry) }
53+
// Make the regular jar task depend on shadowJar
54+
tasks.jar {
55+
enabled = false
56+
dependsOn(tasks.shadowJar)
57+
}
58+
59+
// Fix the startScripts task dependency
60+
tasks.startScripts { dependsOn(tasks.shadowJar) }
61+
62+
configure<SourceSetContainer> { test { java.srcDir("src/test/java") } }
63+
64+
tasks.register<Test>("systemTest").configure {
65+
group = "verification"
66+
description = "Runs the System tests"
67+
68+
outputs.upToDateWhen { false }
69+
70+
maxParallelForks = 1
71+
72+
// Cap JVM args per test
73+
minHeapSize = "128m"
74+
maxHeapSize = "1g"
75+
76+
filter { includeTestsMatching("io.sentry.systemtest*") }
77+
}
78+
79+
tasks.named("test").configure {
80+
require(this is Test)
81+
82+
filter { excludeTestsMatching("io.sentry.systemtest.*") }
83+
}

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

Lines changed: 13 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://[email protected]/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,16 @@ 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+
// {
90+
// return 0.1;
91+
// } else {
92+
// return 0.5;
93+
// }
94+
// });
9595
});
9696

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

sentry-system-test-support/api/sentry-system-test-support.api

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,8 @@ public final class io/sentry/systemtest/util/TestHelper {
558558
public final fun doesTransactionHaveOp (Lio/sentry/protocol/SentryTransaction;Ljava/lang/String;)Z
559559
public final fun doesTransactionHaveTraceId (Lio/sentry/protocol/SentryTransaction;Ljava/lang/String;)Z
560560
public final fun ensureEnvelopeCountIncreased ()V
561-
public final fun ensureEnvelopeReceived (Lkotlin/jvm/functions/Function1;)V
561+
public final fun ensureEnvelopeReceived (ILkotlin/jvm/functions/Function1;)V
562+
public static synthetic fun ensureEnvelopeReceived$default (Lio/sentry/systemtest/util/TestHelper;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
562563
public final fun ensureErrorCount (Lcom/apollographql/apollo3/api/ApolloResponse;I)V
563564
public final fun ensureErrorReceived (Lkotlin/jvm/functions/Function1;)V
564565
public final fun ensureLogsReceived (Lkotlin/jvm/functions/Function2;)V
@@ -567,11 +568,15 @@ public final class io/sentry/systemtest/util/TestHelper {
567568
public final fun ensureNoTransactionReceived (Lkotlin/jvm/functions/Function2;)V
568569
public final fun ensureTransactionReceived (Lkotlin/jvm/functions/Function2;)V
569570
public final fun ensureTransactionWithSpanReceived (Lkotlin/jvm/functions/Function1;)V
571+
public final fun findJar (Ljava/lang/String;Ljava/lang/String;)Ljava/io/File;
572+
public static synthetic fun findJar$default (Lio/sentry/systemtest/util/TestHelper;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Ljava/io/File;
573+
public final fun getDsn ()Ljava/lang/String;
570574
public final fun getEnvelopeCounts ()Lio/sentry/systemtest/util/EnvelopeCounts;
571575
public final fun getGraphqlClient ()Lio/sentry/systemtest/graphql/GraphqlTestClient;
572576
public final fun getJsonSerializer ()Lio/sentry/JsonSerializer;
573577
public final fun getRestClient ()Lio/sentry/systemtest/util/RestTestClient;
574578
public final fun getSentryClient ()Lio/sentry/systemtest/util/SentryMockServerClient;
579+
public final fun launch (Ljava/io/File;Ljava/util/Map;)Ljava/lang/Process;
575580
public final fun logObject (Ljava/lang/Object;)V
576581
public final fun reset ()V
577582
public final fun setEnvelopeCounts (Lio/sentry/systemtest/util/EnvelopeCounts;)V

0 commit comments

Comments
 (0)