From d577084a1bafb9dd70f45df4f0c77b8344504623 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Tue, 20 Oct 2026 20:21:13 +0200 Subject: [PATCH] test: Remove the io.sentry.systemtest plugin and sentry-system-test-support With the runner gone, nothing applies the io.sentry.systemtest convention plugin or depends on sentry-system-test-support, which held the HTTP and GraphQL clients and the TestHelper the system tests used. The envelope matchers it delegated to stay in sentry-test-support. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../kotlin/io.sentry.systemtest.gradle.kts | 38 --- .../io/sentry/gradle/SystemTestExtension.kt | 17 - build.gradle.kts | 5 +- sentry-system-test-support/build.gradle.kts | 50 --- .../src/main/graphql/greeting.graphql | 3 - .../src/main/graphql/project.graphql | 11 - .../src/main/graphql/schema.graphqls | 70 ---- .../src/main/graphql/task.graphql | 16 - .../io/sentry/systemtest/ResponseTypes.kt | 7 - .../systemtest/graphql/GraphqlTestClient.kt | 38 --- .../util/LoggingInsecureRestClient.kt | 83 ----- .../sentry/systemtest/util/RestTestClient.kt | 115 ------- .../systemtest/util/SentryMockServerClient.kt | 35 -- .../io/sentry/systemtest/util/TestHelper.kt | 298 ------------------ settings.gradle.kts | 1 - 15 files changed, 2 insertions(+), 785 deletions(-) delete mode 100644 build-logic/src/main/kotlin/io.sentry.systemtest.gradle.kts delete mode 100644 build-logic/src/main/kotlin/io/sentry/gradle/SystemTestExtension.kt delete mode 100644 sentry-system-test-support/build.gradle.kts delete mode 100644 sentry-system-test-support/src/main/graphql/greeting.graphql delete mode 100644 sentry-system-test-support/src/main/graphql/project.graphql delete mode 100644 sentry-system-test-support/src/main/graphql/schema.graphqls delete mode 100644 sentry-system-test-support/src/main/graphql/task.graphql delete mode 100644 sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/ResponseTypes.kt delete mode 100644 sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt delete mode 100644 sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt delete mode 100644 sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/RestTestClient.kt delete mode 100644 sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt delete mode 100644 sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/TestHelper.kt diff --git a/build-logic/src/main/kotlin/io.sentry.systemtest.gradle.kts b/build-logic/src/main/kotlin/io.sentry.systemtest.gradle.kts deleted file mode 100644 index a21079e1336..00000000000 --- a/build-logic/src/main/kotlin/io.sentry.systemtest.gradle.kts +++ /dev/null @@ -1,38 +0,0 @@ -import io.sentry.gradle.SystemTestExtension -import org.gradle.api.tasks.ClasspathNormalizer - -val systemTest = extensions.create("sentrySystemTest") - -// The sample system tests launch the packaged app (war/shadowJar/bootJar) from build/libs as a -// separate process, so the archive is a real input even though it is not on the test classpath. -// Agent-based samples are additionally launched with -javaagent:, another runtime -// input not on the classpath. See test/system-test-runner.py. -tasks.matching { it.name == "systemTest" }.configureEach { - val archiveTask = - listOf("war", "shadowJar", "bootJar").firstOrNull { it in tasks.names } - ?: throw GradleException( - "io.sentry.systemtest is applied to $path but none of war/shadowJar/bootJar " + - "exist to provide the launched app archive for the systemTest task" - ) - // Declaring the archive as an input also wires the dependency on its producing task. - inputs - .files(tasks.named(archiveTask)) - .withPropertyName("appArchive") - .withNormalizer(ClasspathNormalizer::class.java) - - if (systemTest.usesOpenTelemetryAgent.get()) { - // The runner builds the agent and launches the app with -javaagent before invoking this task, - // so the agent jar is tracked for content only (by path, no cross-project task dependency): a - // change to it makes systemTest out of date even though it runs outside the test JVM. - val version = providers.gradleProperty("versionName").get() - inputs - .files( - rootProject.layout.projectDirectory.file( - "sentry-opentelemetry/sentry-opentelemetry-agent/build/libs/" + - "sentry-opentelemetry-agent-$version.jar" - ) - ) - .withPropertyName("openTelemetryAgent") - .withNormalizer(ClasspathNormalizer::class.java) - } -} diff --git a/build-logic/src/main/kotlin/io/sentry/gradle/SystemTestExtension.kt b/build-logic/src/main/kotlin/io/sentry/gradle/SystemTestExtension.kt deleted file mode 100644 index 9111ce17b1f..00000000000 --- a/build-logic/src/main/kotlin/io/sentry/gradle/SystemTestExtension.kt +++ /dev/null @@ -1,17 +0,0 @@ -package io.sentry.gradle - -import org.gradle.api.provider.Property - -/** Configuration for the `io.sentry.systemtest` convention plugin. */ -abstract class SystemTestExtension { - /** - * Set to `true` for samples that the system-test runner launches with the Sentry OpenTelemetry - * Java agent (`-javaagent`). The agent jar is then tracked as a `systemTest` input so the task - * re-runs when the agent changes, even though it is started outside the test JVM. - */ - abstract val usesOpenTelemetryAgent: Property - - init { - usesOpenTelemetryAgent.convention(false) - } -} diff --git a/build.gradle.kts b/build.gradle.kts index 3cd052ce08c..031456cdae4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -83,8 +83,7 @@ apiValidation { "test-app-size", "sentry-samples-netflix-dgs", "sentry-samples-console-otlp", - "sentry-test-support", - "sentry-system-test-support" + "sentry-test-support" ) ) } @@ -121,7 +120,7 @@ subprojects { } } - if (!this.name.contains("sample") && !this.name.contains("integration-tests") && this.name != "sentry-system-test-support" && this.name != "sentry-test-support") { + if (!this.name.contains("sample") && !this.name.contains("integration-tests") && this.name != "sentry-test-support") { apply() apply() diff --git a/sentry-system-test-support/build.gradle.kts b/sentry-system-test-support/build.gradle.kts deleted file mode 100644 index 7f08bf6d01b..00000000000 --- a/sentry-system-test-support/build.gradle.kts +++ /dev/null @@ -1,50 +0,0 @@ -plugins { - `java-library` - id("io.sentry.javadoc") - alias(libs.plugins.kotlin.jvm) - alias(libs.plugins.errorprone) - alias(libs.plugins.gradle.versions) - id("com.apollographql.apollo") version "4.1.1" -} - -configure { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 -} - -tasks.withType().configureEach { - compilerOptions.jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8 - compilerOptions.languageVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9 - compilerOptions.apiVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_9 -} - -dependencies { - api(projects.sentry) - api(projects.sentryTestSupport) - api(libs.apollo4.kotlin) - - compileOnly(libs.jetbrains.annotations) - compileOnly(libs.nopen.annotations) - - compileOnly(libs.springboot.starter.web) - - implementation(libs.jackson.databind) - implementation(libs.jackson.kotlin) - implementation(libs.okhttp) - - errorprone(libs.errorprone.core) - errorprone(libs.nopen.checker) - - // tests - implementation(kotlin(Config.kotlinStdLib)) - implementation(libs.kotlin.test.junit) - implementation(libs.mockito.kotlin) -} - -apollo { - service("service") { - srcDir("src/main/graphql") - packageName.set("io.sentry.samples.graphql") - outputDirConnection { connectToKotlinSourceSet("main") } - } -} diff --git a/sentry-system-test-support/src/main/graphql/greeting.graphql b/sentry-system-test-support/src/main/graphql/greeting.graphql deleted file mode 100644 index 06c866a65fa..00000000000 --- a/sentry-system-test-support/src/main/graphql/greeting.graphql +++ /dev/null @@ -1,3 +0,0 @@ -query GreetingQuery($name: String!) { - greeting(name: $name) -} diff --git a/sentry-system-test-support/src/main/graphql/project.graphql b/sentry-system-test-support/src/main/graphql/project.graphql deleted file mode 100644 index bff62ed2c2c..00000000000 --- a/sentry-system-test-support/src/main/graphql/project.graphql +++ /dev/null @@ -1,11 +0,0 @@ -query ProjectQuery($slug: ID!) { - project(slug: $slug) { - slug - name - status - } -} - -mutation AddProjectMutation($slug: ID!) { - addProject(slug: $slug) -} diff --git a/sentry-system-test-support/src/main/graphql/schema.graphqls b/sentry-system-test-support/src/main/graphql/schema.graphqls deleted file mode 100644 index d76aca4756a..00000000000 --- a/sentry-system-test-support/src/main/graphql/schema.graphqls +++ /dev/null @@ -1,70 +0,0 @@ -type Query { - greeting(name: String! = "Spring"): String! - project(slug: ID!): Project - tasks(projectSlug: ID!): [Task] -} - -type Mutation { - addProject(slug: ID!): String! -} - -type Subscription { - notifyNewTask(projectSlug: ID!): Task -} - -""" A Project in the Spring portfolio """ -type Project { - """ Unique string id used in URLs """ - slug: ID! - """ Project name """ - name: String - """ URL of the git repository """ - repositoryUrl: String! - """ Current support status """ - status: ProjectStatus! -} - -""" A task """ -type Task { - """ ID """ - id: String! - """ Name """ - name: String! - """ ID of the Assignee """ - assigneeId: String - """ Assignee """ - assignee: Assignee - """ ID of the Creator """ - creatorId: String - """ Creator """ - creator: Creator -} - -""" An Assignee """ -type Assignee { - """ ID """ - id: String! - """ Name """ - name: String! -} - -""" An Creator """ -type Creator { - """ ID """ - id: String! - """ Name """ - name: String! -} - -enum ProjectStatus { - """ Actively supported by the Spring team """ - ACTIVE - """ Supported by the community """ - COMMUNITY - """ Prototype, not officially supported yet """ - INCUBATING - """ Project being retired, in maintenance mode """ - ATTIC - """ End-Of-Lifed """ - EOL -} diff --git a/sentry-system-test-support/src/main/graphql/task.graphql b/sentry-system-test-support/src/main/graphql/task.graphql deleted file mode 100644 index 11ae18574d3..00000000000 --- a/sentry-system-test-support/src/main/graphql/task.graphql +++ /dev/null @@ -1,16 +0,0 @@ -query TasksAndAssigneesQuery($slug: ID!) { - tasks(projectSlug: $slug) { - id - name - assigneeId - assignee { - id - name - } - creatorId - creator { - id - name - } - } -} diff --git a/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/ResponseTypes.kt b/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/ResponseTypes.kt deleted file mode 100644 index 4c9a4d903ad..00000000000 --- a/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/ResponseTypes.kt +++ /dev/null @@ -1,7 +0,0 @@ -package io.sentry.systemtest - -data class Todo(val id: Long, val title: String, val completed: Boolean) - -data class Person(val firstName: String, val lastName: String) { - override fun toString(): String = "Person{firstName='$firstName', lastName='$lastName'}" -} diff --git a/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt b/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt deleted file mode 100644 index c1b0a409bda..00000000000 --- a/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt +++ /dev/null @@ -1,38 +0,0 @@ -package io.sentry.systemtest.graphql - -import com.apollographql.apollo.ApolloClient -import com.apollographql.apollo.api.ApolloResponse -import com.apollographql.apollo.api.Mutation -import com.apollographql.apollo.api.Query -import io.sentry.samples.graphql.AddProjectMutation -import io.sentry.samples.graphql.GreetingQuery -import io.sentry.samples.graphql.ProjectQuery -import io.sentry.samples.graphql.TasksAndAssigneesQuery -import kotlinx.coroutines.runBlocking - -class GraphqlTestClient(backendUrl: String) { - val apollo = - ApolloClient.Builder() - .serverUrl("$backendUrl/graphql") - .addHttpHeader("Authorization", "Basic dXNlcjpwYXNzd29yZA==") - .build() - - fun greet(name: String): ApolloResponse? = executeQuery(GreetingQuery(name)) - - fun project(slug: String): ApolloResponse? = executeQuery(ProjectQuery(slug)) - - fun tasksAndAssignees(slug: String): ApolloResponse? = - executeQuery(TasksAndAssigneesQuery(slug)) - - fun addProject(slug: String): ApolloResponse? = - executeMutation(AddProjectMutation(slug)) - - private fun executeQuery(query: Query): ApolloResponse? = runBlocking { - apollo.query(query).execute() - } - - private fun executeMutation(mutation: Mutation): ApolloResponse? = - runBlocking { - apollo.mutation(mutation).execute() - } -} diff --git a/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt b/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt deleted file mode 100644 index 8c4f27345f8..00000000000 --- a/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt +++ /dev/null @@ -1,83 +0,0 @@ -package io.sentry.systemtest.util - -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import java.util.concurrent.TimeUnit -import okhttp3.Credentials -import okhttp3.MediaType.Companion.toMediaType -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.RequestBody -import okhttp3.RequestBody.Companion.toRequestBody -import okhttp3.Response -import org.slf4j.LoggerFactory - -open class LoggingInsecureRestClient { - val logger = LoggerFactory.getLogger(LoggingInsecureRestClient::class.java) - var lastKnownStatusCode: Int? = null - - protected inline fun callTyped( - requestBuilder: Request.Builder, - useAuth: Boolean, - extraHeaders: Map? = null, - ): T? { - val response = call(requestBuilder, useAuth, extraHeaders) - val responseBody = response?.body?.string() - if (response?.isSuccessful != true) { - return null - } - if (T::class == String::class) { - return responseBody as? T - } - return responseBody?.let { objectMapper().readValue(it, T::class.java) } - } - - protected fun call( - requestBuilder: Request.Builder, - useAuth: Boolean, - extraHeaders: Map? = null, - ): Response? { - try { - val request = - requestBuilder - .also { originalRequest -> - var modifiedRequest = originalRequest - - if (useAuth) { - modifiedRequest = - modifiedRequest.header("Authorization", Credentials.basic("user", "password")) - } - - extraHeaders?.forEach { key, value -> - modifiedRequest = modifiedRequest.header(key, value) - } - - modifiedRequest - } - .build() - val call = client().newCall(request) - val response = call.execute() - lastKnownStatusCode = response.code - return response - } catch (e: Exception) { - lastKnownStatusCode = null - logger.error("Request failed", e) - return null - } - } - - protected fun client(): OkHttpClient = - OkHttpClient.Builder() - .callTimeout(60, TimeUnit.SECONDS) - .connectTimeout(60, TimeUnit.SECONDS) - .readTimeout(60, TimeUnit.SECONDS) - .writeTimeout(60, TimeUnit.SECONDS) - .build() - - protected fun objectMapper(): ObjectMapper = jacksonObjectMapper() - - protected fun toRequestBody(o: Any?): RequestBody { - val stringValue = objectMapper().writeValueAsString(o) - return stringValue.toRequestBody("application/json; charset=utf-8".toMediaType()) - } -} diff --git a/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/RestTestClient.kt b/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/RestTestClient.kt deleted file mode 100644 index ac2c69f5ed2..00000000000 --- a/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/RestTestClient.kt +++ /dev/null @@ -1,115 +0,0 @@ -package io.sentry.systemtest.util - -import io.sentry.systemtest.Person -import io.sentry.systemtest.Todo -import okhttp3.Request - -class RestTestClient(private val backendBaseUrl: String) : LoggingInsecureRestClient() { - fun getPerson(id: Long): Person? { - val request = Request.Builder().url("$backendBaseUrl/person/$id") - - return callTyped(request, true) - } - - fun createPerson(person: Person, extraHeaders: Map? = null): Person? { - val request = Request.Builder().url("$backendBaseUrl/person/").post(toRequestBody(person)) - - return callTyped(request, true, extraHeaders) - } - - fun getPersonDistributedTracing(id: Long, extraHeaders: Map? = null): Person? { - val request = Request.Builder().url("$backendBaseUrl/tracing/$id") - - return callTyped(request, true, extraHeaders) - } - - fun createPersonDistributedTracing( - person: Person, - extraHeaders: Map? = null, - ): Person? { - val request = Request.Builder().url("$backendBaseUrl/tracing/").post(toRequestBody(person)) - - return callTyped(request, true, extraHeaders) - } - - fun getTodo(id: Long): Todo? { - val request = Request.Builder().url("$backendBaseUrl/todo/$id") - - return callTyped(request, true) - } - - fun getTodoWebclient(id: Long): Todo? { - val request = Request.Builder().url("$backendBaseUrl/todo-webclient/$id") - - return callTyped(request, true) - } - - fun getTodoRestClient(id: Long): Todo? { - val request = Request.Builder().url("$backendBaseUrl/todo-restclient/$id") - - return callTyped(request, true) - } - - fun getTodoOkHttp(id: Long): Todo? { - val request = Request.Builder().url("$backendBaseUrl/todo-okhttp/$id") - - return callTyped(request, true) - } - - fun getCachedTodo(id: Long): Todo? { - val request = Request.Builder().url("$backendBaseUrl/cache/$id") - - return callTyped(request, true) - } - - fun saveCachedTodo(todo: Todo): Todo? { - val request = Request.Builder().url("$backendBaseUrl/cache/").post(toRequestBody(todo)) - - return callTyped(request, true) - } - - fun deleteCachedTodo(id: Long) { - val request = Request.Builder().url("$backendBaseUrl/cache/$id").delete() - - call(request, true) - } - - fun checkFeatureFlag(flagKey: String): FeatureFlagResponse? { - val request = Request.Builder().url("$backendBaseUrl/feature-flag/check/$flagKey") - - return callTyped(request, true) - } - - fun errorWithFeatureFlag(flagKey: String): String? { - val request = Request.Builder().url("$backendBaseUrl/feature-flag/error/$flagKey") - - val response = call(request, true) - return response?.body?.string() - } - - fun produceKafkaMessage(message: String = "hello from sentry!"): String? { - val request = Request.Builder().url("$backendBaseUrl/kafka/produce?message=$message") - - return callTyped(request, true) - } - - fun getCountMetric(): String? { - val request = Request.Builder().url("$backendBaseUrl/metric/count") - - return callTyped(request, true) - } - - fun getGaugeMetric(value: Long): String? { - val request = Request.Builder().url("$backendBaseUrl/metric/gauge/$value") - - return callTyped(request, true) - } - - fun getDistributionMetric(value: Long): String? { - val request = Request.Builder().url("$backendBaseUrl/metric/distribution/$value") - - return callTyped(request, true) - } -} - -data class FeatureFlagResponse(val flagKey: String, val value: Boolean) diff --git a/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt b/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt deleted file mode 100644 index 389f3bb5b80..00000000000 --- a/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt +++ /dev/null @@ -1,35 +0,0 @@ -package io.sentry.systemtest.util - -import okhttp3.Request - -class SentryMockServerClient(private val baseUrl: String) : LoggingInsecureRestClient() { - fun getEnvelopeCount(): EnvelopeCounts { - val request = Request.Builder().url("$baseUrl/envelope-count") - - return callTyped(request, false)!! - } - - fun reset() { - val request = Request.Builder().url("$baseUrl/reset") - - call(request, false) - } - - fun getEnvelopes(): EnvelopesReceived { - val request = Request.Builder().url("$baseUrl/envelopes-received") - - return callTyped(request, false)!! - } -} - -class EnvelopeCounts { - val envelopes: Long? = null - - override fun toString(): String = "EnvelopeCounts{envelopes=$envelopes}" -} - -class EnvelopesReceived { - val envelopes: List? = null - - override fun toString(): String = "EnvelopesReceived{envelopes=$envelopes}" -} diff --git a/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/TestHelper.kt b/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/TestHelper.kt deleted file mode 100644 index 8ef74cae3c9..00000000000 --- a/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/TestHelper.kt +++ /dev/null @@ -1,298 +0,0 @@ -package io.sentry.systemtest.util - -import com.apollographql.apollo.api.ApolloResponse -import com.apollographql.apollo.api.Operation -import io.sentry.JsonSerializer -import io.sentry.ProfileChunk -import io.sentry.SentryEnvelope -import io.sentry.SentryEnvelopeHeader -import io.sentry.SentryEvent -import io.sentry.SentryLogEvents -import io.sentry.SentryMetricsEvents -import io.sentry.SentryOptions -import io.sentry.protocol.FeatureFlag -import io.sentry.protocol.SentrySpan -import io.sentry.protocol.SentryTransaction -import io.sentry.systemtest.graphql.GraphqlTestClient -import io.sentry.test.event -import io.sentry.test.hasExceptionMessage -import io.sentry.test.hasFlag -import io.sentry.test.hasLogWithAttribute -import io.sentry.test.hasLogWithBody -import io.sentry.test.hasMetric -import io.sentry.test.hasMetricWithAttribute -import io.sentry.test.hasOp -import io.sentry.test.hasSpanWithOp -import io.sentry.test.hasSpanWithOpAndDescription -import io.sentry.test.hasTraceId -import io.sentry.test.logs -import io.sentry.test.metrics -import io.sentry.test.profileChunk -import io.sentry.test.transaction -import java.io.File -import java.io.PrintWriter -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertNotNull -import kotlin.test.assertTrue - -class TestHelper(backendUrl: String) { - val restClient: RestTestClient - val graphqlClient: GraphqlTestClient - val sentryClient: SentryMockServerClient - val jsonSerializer: JsonSerializer - val dsn = "http://502f25099c204a2fbf4cb16edc5975d1@localhost:8000/0" - - var envelopeCounts: EnvelopeCounts? = null - - init { - restClient = RestTestClient(backendUrl) - sentryClient = SentryMockServerClient("http://localhost:8000") - graphqlClient = GraphqlTestClient(backendUrl) - jsonSerializer = JsonSerializer(SentryOptions.empty()) - } - - fun snapshotEnvelopeCount() { - envelopeCounts = sentryClient.getEnvelopeCount() - } - - fun ensureEnvelopeCountIncreased() { - Thread.sleep(1000) - val envelopeCountsAfter = sentryClient.getEnvelopeCount() - assertTrue(envelopeCountsAfter!!.envelopes!! > envelopeCounts!!.envelopes!!) - } - - fun ensureEnvelopeReceived(retryCount: Int = 1, callback: ((String) -> Boolean)) { - val envelopes = sentryClient.getEnvelopes() - assertNotNull(envelopes.envelopes) - envelopes.envelopes.forEach { envelopeString -> - val didMatch = callback(envelopeString) - if (didMatch) { - return - } - } - if (retryCount <= 0) { - throw RuntimeException("Unable to find matching envelope received by relay") - } else { - Thread.sleep(10000) - ensureEnvelopeReceived(retryCount - 1, callback) - } - } - - fun ensureNoEnvelopeReceived(callback: ((String) -> Boolean)) { - Thread.sleep(10000) - val envelopes = sentryClient.getEnvelopes() - - if (envelopes.envelopes.isNullOrEmpty()) { - return - } - - envelopes.envelopes.forEach { envelopeString -> - val didMatch = callback(envelopeString) - if (didMatch) { - throw RuntimeException("Found unexpected matching envelope received by relay") - } - } - } - - fun ensureTransactionReceived(callback: ((SentryTransaction, SentryEnvelopeHeader) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> checkIfTransactionMatches(envelopeString, callback) } - } - - fun ensureProfileChunkReceived(callback: ((ProfileChunk, SentryEnvelopeHeader) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> checkIfProfileMatches(envelopeString, callback) } - } - - fun ensureNoTransactionReceived( - callback: ((SentryTransaction, SentryEnvelopeHeader) -> Boolean) - ) { - ensureNoEnvelopeReceived { envelopeString -> - checkIfTransactionMatches(envelopeString, callback) - } - } - - fun ensureLogsReceived(callback: ((SentryLogEvents, SentryEnvelopeHeader) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> checkIfLogsMatch(envelopeString, callback) } - } - - private fun checkIfLogsMatch( - envelopeString: String, - callback: ((SentryLogEvents, SentryEnvelopeHeader) -> Boolean), - ): Boolean { - val envelope = deserialize(envelopeString) ?: return false - val logs = envelope.logs() ?: return false - return callback(logs, envelope.header) - } - - fun doesContainMetric( - metrics: SentryMetricsEvents, - name: String, - type: String, - value: Double, - unit: String? = null, - ): Boolean = metrics.hasMetric(name, type, value, unit) - - fun ensureMetricsReceived(callback: ((SentryMetricsEvents, SentryEnvelopeHeader) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> checkIfMetricsMatch(envelopeString, callback) } - } - - private fun checkIfMetricsMatch( - envelopeString: String, - callback: ((SentryMetricsEvents, SentryEnvelopeHeader) -> Boolean), - ): Boolean { - val envelope = deserialize(envelopeString) ?: return false - val metrics = envelope.metrics() ?: return false - return callback(metrics, envelope.header) - } - - fun doesContainLogWithBody(logs: SentryLogEvents, body: String): Boolean = - logs.hasLogWithBody(body) - - fun doesLogWithBodyHaveAttribute( - logs: SentryLogEvents, - body: String, - attributeKey: String, - attributeValue: Any?, - ): Boolean = logs.hasLogWithAttribute(body, attributeKey, attributeValue) - - fun doesMetricHaveAttribute( - metrics: SentryMetricsEvents, - metricName: String, - attributeKey: String, - attributeValue: Any?, - ): Boolean = metrics.hasMetricWithAttribute(metricName, attributeKey, attributeValue) - - private fun checkIfTransactionMatches( - envelopeString: String, - callback: ((SentryTransaction, SentryEnvelopeHeader) -> Boolean), - ): Boolean { - val envelope = deserialize(envelopeString) ?: return false - val transaction = envelope.transaction() ?: return false - return callback(transaction, envelope.header) - } - - private fun checkIfProfileMatches( - envelopeString: String, - callback: ((ProfileChunk, SentryEnvelopeHeader) -> Boolean), - ): Boolean { - val envelope = deserialize(envelopeString) ?: return false - val chunk = envelope.profileChunk() ?: return false - return callback(chunk, envelope.header) - } - - fun ensureErrorReceived(callback: ((SentryEvent) -> Boolean)) { - ensureEnvelopeReceived(retryCount = 3) { envelopeString -> - val error = deserialize(envelopeString)?.event() ?: return@ensureEnvelopeReceived false - val callbackResult = callback(error) - if (!callbackResult) { - println("found an error event but it did not match:") - logObject(error) - } - callbackResult - } - } - - fun ensureTransactionWithSpanReceived(callback: ((SentrySpan) -> Boolean)) { - ensureTransactionReceived { transaction, envelopeHeader -> - transaction.spans.forEach { span -> - val callbackResult = callback(span) - if (callbackResult) { - return@ensureTransactionReceived true - } - } - false - } - } - - fun reset() { - sentryClient.reset() - } - - fun logObject(obj: Any?) { - obj ?: return - // Flush rather than close: closing the writer would close System.out. - PrintWriter(System.out).apply { - jsonSerializer.serialize(obj, this) - flush() - } - println() - } - - private fun deserialize(envelopeString: String): SentryEnvelope? = - jsonSerializer.deserializeEnvelope(envelopeString.byteInputStream()) - - fun ensureNoErrors(response: ApolloResponse?) { - response ?: throw RuntimeException("no response") - assertFalse(response.hasErrors()) - } - - fun ensureErrorCount(response: ApolloResponse?, errorCount: Int) { - response ?: throw RuntimeException("no response") - assertEquals(errorCount, response.errors?.size) - } - - fun doesTransactionContainSpanWithOp(transaction: SentryTransaction, op: String): Boolean = - transaction.hasSpanWithOp(op) - - fun doesTransactionContainSpanWithOpAndDescription( - transaction: SentryTransaction, - op: String, - description: String, - ): Boolean = transaction.hasSpanWithOpAndDescription(op, description) - - fun doesTransactionHaveTraceId(transaction: SentryTransaction, traceId: String): Boolean = - transaction.hasTraceId(traceId) - - fun doesTransactionHaveOp(transaction: SentryTransaction, op: String): Boolean = - transaction.hasOp(op) - - fun doesTransactionHave( - transaction: SentryTransaction, - op: String, - featureFlag: FeatureFlag? = null, - ): Boolean = transaction.hasOp(op, featureFlag) - - fun doesTransactionHaveSpanWith( - transaction: SentryTransaction, - op: String, - featureFlag: FeatureFlag? = null, - noFeatureFlags: Boolean = false, - ): Boolean = transaction.hasSpanWithOp(op, featureFlag, noFeatureFlags) - - fun doesEventHaveExceptionMessage(event: SentryEvent, expectedMessage: String): Boolean = - event.hasExceptionMessage(expectedMessage) - - fun doesEventHaveFlag(event: SentryEvent, flag: String, result: Boolean): Boolean = - event.hasFlag(flag, result) - - fun findJar(prefix: String, inDir: String = "build/libs"): File { - val buildDir = File(inDir) - val jarFiles = - buildDir.listFiles { _, name -> name.startsWith(prefix) && name.endsWith(".jar") }?.toList() - ?: emptyList() - - if (jarFiles.isEmpty()) { - throw AssertionError("No JAR found in ${buildDir.absolutePath}") - } - - return jarFiles.maxOf { it } - } - - fun launch(jar: File, env: Map, enableOtelAutoConfig: Boolean = false): Process { - val processBuilderList = mutableListOf("java", "--add-opens", "java.base/java.lang=ALL-UNNAMED") - - if (enableOtelAutoConfig) { - processBuilderList.add("-Dotel.java.global-autoconfigure.enabled=true") - } - - processBuilderList.add("-jar") - processBuilderList.add(jar.absolutePath) - - val processBuilder = - ProcessBuilder(processBuilderList).inheritIO() // forward i/o to current process - - processBuilder.environment().putAll(env) - - return processBuilder.start() - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 413ab5fd59b..5947411dd56 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -59,7 +59,6 @@ include( "sentry-apollo-3", "sentry-apollo-4", "sentry-apollo-5", - "sentry-system-test-support", "sentry-test-support", "sentry-log4j2", "sentry-logback",