diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index b0e56eb2dc4..e24edb6e3d0 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -69,12 +69,13 @@ object Config { val slf4jJdk14 = "org.slf4j:slf4j-jdk14:1.7.30" val logbackVersion = "1.2.9" val logbackClassic = "ch.qos.logback:logback-classic:$logbackVersion" + val logbackCore = "ch.qos.logback:logback-core:$logbackVersion" val log4j2Version = "2.20.0" val log4j2Api = "org.apache.logging.log4j:log4j-api:$log4j2Version" val log4j2Core = "org.apache.logging.log4j:log4j-core:$log4j2Version" - val jacksonDatabind = "com.fasterxml.jackson.core:jackson-databind" + val jacksonDatabind = "com.fasterxml.jackson.core:jackson-databind:2.18.3" val jacksonKotlin = "com.fasterxml.jackson.module:jackson-module-kotlin:2.18.3" val springBootStarter = "org.springframework.boot:spring-boot-starter:$springBootVersion" diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/build.gradle.kts index 1f31fbfc05f..24f7f422dfb 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/build.gradle.kts @@ -63,6 +63,7 @@ dependencies { testImplementation(kotlin(Config.kotlinStdLib)) testImplementation(Config.TestLibs.kotlinTestJunit) testImplementation("ch.qos.logback:logback-classic:1.5.16") + testImplementation("ch.qos.logback:logback-core:1.5.16") testImplementation(Config.Libs.slf4jApi2) testImplementation(Config.Libs.apolloKotlin) } diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/build.gradle.kts index dce546c8c4e..bbea7d9cc52 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/build.gradle.kts @@ -65,6 +65,7 @@ dependencies { testImplementation(kotlin(Config.kotlinStdLib)) testImplementation(Config.TestLibs.kotlinTestJunit) testImplementation("ch.qos.logback:logback-classic:1.5.16") + testImplementation("ch.qos.logback:logback-core:1.5.16") testImplementation(Config.Libs.slf4jApi2) testImplementation(Config.Libs.apolloKotlin) } diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot-jakarta/build.gradle.kts index 11e6b613466..d4d62a8d231 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-jakarta/build.gradle.kts @@ -63,6 +63,7 @@ dependencies { testImplementation(kotlin(Config.kotlinStdLib)) testImplementation(Config.TestLibs.kotlinTestJunit) testImplementation("ch.qos.logback:logback-classic:1.5.16") + testImplementation("ch.qos.logback:logback-core:1.5.16") testImplementation(Config.Libs.slf4jApi2) testImplementation(Config.Libs.apolloKotlin) testImplementation(projects.sentry) diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/build.gradle.kts index fa30b6d3b16..1a2f12d804d 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/build.gradle.kts @@ -63,7 +63,8 @@ dependencies { } testImplementation(kotlin(Config.kotlinStdLib)) testImplementation(Config.TestLibs.kotlinTestJunit) - testImplementation(Config.Libs.logbackClassic) + testImplementation("ch.qos.logback:logback-classic:1.5.16") + testImplementation("ch.qos.logback:logback-core:1.5.16") testImplementation(Config.Libs.slf4jApi2) testImplementation(Config.Libs.apolloKotlin) testImplementation("org.apache.httpcomponents:httpclient") diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot-opentelemetry/build.gradle.kts index 5bf0d001881..a98538eaab9 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry/build.gradle.kts @@ -64,7 +64,8 @@ dependencies { } testImplementation(kotlin(Config.kotlinStdLib)) testImplementation(Config.TestLibs.kotlinTestJunit) - testImplementation(Config.Libs.logbackClassic) + testImplementation("ch.qos.logback:logback-classic:1.5.16") + testImplementation("ch.qos.logback:logback-core:1.5.16") testImplementation(Config.Libs.slf4jApi2) testImplementation(Config.Libs.apolloKotlin) testImplementation("org.apache.httpcomponents:httpclient") diff --git a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/build.gradle.kts index 6d390ce15fa..fc7aa196cd4 100644 --- a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/build.gradle.kts @@ -36,6 +36,7 @@ dependencies { testImplementation(kotlin(Config.kotlinStdLib)) testImplementation(Config.TestLibs.kotlinTestJunit) testImplementation("ch.qos.logback:logback-classic:1.5.16") + testImplementation("ch.qos.logback:logback-core:1.5.16") testImplementation(Config.Libs.slf4jApi2) testImplementation(Config.Libs.apolloKotlin) } diff --git a/sentry-samples/sentry-samples-spring-boot-webflux/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot-webflux/build.gradle.kts index 3e50d013107..9d2ea18d2d6 100644 --- a/sentry-samples/sentry-samples-spring-boot-webflux/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-webflux/build.gradle.kts @@ -33,7 +33,8 @@ dependencies { } testImplementation(kotlin(Config.kotlinStdLib)) testImplementation(Config.TestLibs.kotlinTestJunit) - testImplementation(Config.Libs.logbackClassic) + testImplementation("ch.qos.logback:logback-classic:1.5.16") + testImplementation("ch.qos.logback:logback-core:1.5.16") testImplementation(Config.Libs.slf4jApi2) testImplementation(Config.Libs.apolloKotlin) testImplementation("org.apache.httpcomponents:httpclient") diff --git a/sentry-samples/sentry-samples-spring-boot/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot/build.gradle.kts index 3ffdcc8bef0..3e9483ae2c2 100644 --- a/sentry-samples/sentry-samples-spring-boot/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot/build.gradle.kts @@ -61,7 +61,8 @@ dependencies { } testImplementation(kotlin(Config.kotlinStdLib)) testImplementation(Config.TestLibs.kotlinTestJunit) - testImplementation(Config.Libs.logbackClassic) + testImplementation("ch.qos.logback:logback-classic:1.5.16") + testImplementation("ch.qos.logback:logback-core:1.5.16") testImplementation(Config.Libs.slf4jApi2) testImplementation(Config.Libs.apolloKotlin) testImplementation("org.apache.httpcomponents:httpclient") diff --git a/sentry-system-test-support/api/sentry-system-test-support.api b/sentry-system-test-support/api/sentry-system-test-support.api index f91725edfbf..7c7041922ba 100644 --- a/sentry-system-test-support/api/sentry-system-test-support.api +++ b/sentry-system-test-support/api/sentry-system-test-support.api @@ -488,10 +488,10 @@ public final class io/sentry/systemtest/Todo { public final fun copy (JLjava/lang/String;Z)Lio/sentry/systemtest/Todo; public static synthetic fun copy$default (Lio/sentry/systemtest/Todo;JLjava/lang/String;ZILjava/lang/Object;)Lio/sentry/systemtest/Todo; public fun equals (Ljava/lang/Object;)Z + public final fun getCompleted ()Z public final fun getId ()J public final fun getTitle ()Ljava/lang/String; public fun hashCode ()I - public final fun isCompleted ()Z public fun toString ()Ljava/lang/String; } @@ -518,7 +518,14 @@ public final class io/sentry/systemtest/util/EnvelopesReceived { public class io/sentry/systemtest/util/LoggingInsecureRestClient { public fun ()V - protected final fun restTemplate ()Lorg/springframework/web/client/RestTemplate; + protected final fun call (Lokhttp3/Request$Builder;ZLjava/util/Map;)Lokhttp3/Response; + public static synthetic fun call$default (Lio/sentry/systemtest/util/LoggingInsecureRestClient;Lokhttp3/Request$Builder;ZLjava/util/Map;ILjava/lang/Object;)Lokhttp3/Response; + protected final fun client ()Lokhttp3/OkHttpClient; + public final fun getLastKnownStatusCode ()Ljava/lang/Integer; + public final fun getLogger ()Lorg/slf4j/Logger; + protected final fun objectMapper ()Lcom/fasterxml/jackson/databind/ObjectMapper; + public final fun setLastKnownStatusCode (Ljava/lang/Integer;)V + protected final fun toRequestBody (Ljava/lang/Object;)Lokhttp3/RequestBody; } public final class io/sentry/systemtest/util/RestTestClient : io/sentry/systemtest/util/LoggingInsecureRestClient { @@ -527,14 +534,12 @@ public final class io/sentry/systemtest/util/RestTestClient : io/sentry/systemte public static synthetic fun createPerson$default (Lio/sentry/systemtest/util/RestTestClient;Lio/sentry/systemtest/Person;Ljava/util/Map;ILjava/lang/Object;)Lio/sentry/systemtest/Person; public final fun createPersonDistributedTracing (Lio/sentry/systemtest/Person;Ljava/util/Map;)Lio/sentry/systemtest/Person; public static synthetic fun createPersonDistributedTracing$default (Lio/sentry/systemtest/util/RestTestClient;Lio/sentry/systemtest/Person;Ljava/util/Map;ILjava/lang/Object;)Lio/sentry/systemtest/Person; - public final fun getLastKnownStatusCode ()Ljava/lang/Integer; public final fun getPerson (J)Lio/sentry/systemtest/Person; public final fun getPersonDistributedTracing (JLjava/util/Map;)Lio/sentry/systemtest/Person; public static synthetic fun getPersonDistributedTracing$default (Lio/sentry/systemtest/util/RestTestClient;JLjava/util/Map;ILjava/lang/Object;)Lio/sentry/systemtest/Person; public final fun getTodo (J)Lio/sentry/systemtest/Todo; public final fun getTodoRestClient (J)Lio/sentry/systemtest/Todo; public final fun getTodoWebclient (J)Lio/sentry/systemtest/Todo; - public final fun setLastKnownStatusCode (Ljava/lang/Integer;)V } public final class io/sentry/systemtest/util/SentryMockServerClient : io/sentry/systemtest/util/LoggingInsecureRestClient { diff --git a/sentry-system-test-support/build.gradle.kts b/sentry-system-test-support/build.gradle.kts index b5392694a49..6008dd10b60 100644 --- a/sentry-system-test-support/build.gradle.kts +++ b/sentry-system-test-support/build.gradle.kts @@ -24,7 +24,9 @@ dependencies { compileOnly(Config.Libs.springBoot3StarterWeb) api(Config.Libs.apolloKotlin) implementation(Config.Libs.jacksonKotlin) + implementation(Config.Libs.jacksonDatabind) api(projects.sentryTestSupport) + implementation(Config.Libs.okhttp) compileOnly(Config.CompileOnly.nopen) errorprone(Config.CompileOnly.nopenChecker) 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 index fb7721bd942..7805962118e 100644 --- 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 @@ -1,6 +1,6 @@ package io.sentry.systemtest -data class Todo(val id: Long, val title: String, val isCompleted: Boolean) +data class Todo(val id: Long, val title: String, val completed: Boolean) data class Person(val firstName: String, val lastName: String) { 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 index 17eea1a0084..e1773f1c0e7 100644 --- 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 @@ -1,13 +1,69 @@ package io.sentry.systemtest.util -import org.springframework.http.client.BufferingClientHttpRequestFactory -import org.springframework.web.client.RestTemplate +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +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 fun restTemplate(): RestTemplate { - return RestTemplate().also { - it.requestFactory = BufferingClientHttpRequestFactory(it.requestFactory) + 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 } + 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 { + return OkHttpClient.Builder() + .build() + } + + protected fun objectMapper(): ObjectMapper { + return 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 index 7a8792a13bf..2a1ce42e325 100644 --- 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 @@ -2,112 +2,58 @@ package io.sentry.systemtest.util import io.sentry.systemtest.Person import io.sentry.systemtest.Todo -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod -import org.springframework.http.ResponseEntity -import org.springframework.web.client.HttpStatusCodeException +import okhttp3.Request class RestTestClient(private val backendBaseUrl: String) : LoggingInsecureRestClient() { - var lastKnownStatusCode: Int? = null fun getPerson(id: Long): Person? { - return try { - val response = restTemplate().exchange("$backendBaseUrl/person/{id}", HttpMethod.GET, entityWithAuth(), Person::class.java, mapOf("id" to id)) - lastKnownStatusCode = statusCode(response) - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = statusCode(e) - null - } + val request = Request.Builder() + .url("$backendBaseUrl/person/$id") + + return callTyped(request, true) } fun createPerson(person: Person, extraHeaders: Map? = null): Person? { - return try { - val response = restTemplate().exchange("$backendBaseUrl/person/", HttpMethod.POST, entityWithAuth(person, extraHeaders), Person::class.java, person) - lastKnownStatusCode = statusCode(response) - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = statusCode(e) - null - } + val request = Request.Builder() + .url("$backendBaseUrl/person/") + .post(toRequestBody(person)) + + return callTyped(request, true, extraHeaders) } fun getPersonDistributedTracing(id: Long, extraHeaders: Map? = null): Person? { - return try { - val response = restTemplate().exchange("$backendBaseUrl/tracing/{id}", HttpMethod.GET, entityWithAuth(extraHeaders = extraHeaders), Person::class.java, mapOf("id" to id)) - lastKnownStatusCode = statusCode(response) - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = statusCode(e) - null - } + val request = Request.Builder() + .url("$backendBaseUrl/tracing/$id") + + return callTyped(request, true, extraHeaders) } fun createPersonDistributedTracing(person: Person, extraHeaders: Map? = null): Person? { - return try { - val response = restTemplate().exchange("$backendBaseUrl/tracing/", HttpMethod.POST, entityWithAuth(person, extraHeaders), Person::class.java, person) - lastKnownStatusCode = statusCode(response) - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = statusCode(e) - null - } - } + val request = Request.Builder() + .url("$backendBaseUrl/tracing/") + .post(toRequestBody(person)) - fun getTodo(id: Long): Todo? { - return try { - val response = restTemplate().exchange("$backendBaseUrl/todo/{id}", HttpMethod.GET, entityWithAuth(), Todo::class.java, mapOf("id" to id)) - lastKnownStatusCode = statusCode(response) - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = statusCode(e) - null - } + return callTyped(request, true, extraHeaders) } - fun getTodoWebclient(id: Long): Todo? { - return try { - val response = restTemplate().exchange("$backendBaseUrl/todo-webclient/{id}", HttpMethod.GET, entityWithAuth(), Todo::class.java, mapOf("id" to id)) - lastKnownStatusCode = statusCode(response) - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = statusCode(e) - null - } - } + fun getTodo(id: Long): Todo? { + val request = Request.Builder() + .url("$backendBaseUrl/todo/$id") - fun getTodoRestClient(id: Long): Todo? { - return try { - val response = restTemplate().exchange("$backendBaseUrl/todo-restclient/{id}", HttpMethod.GET, entityWithAuth(), Todo::class.java, mapOf("id" to id)) - lastKnownStatusCode = statusCode(response) - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = statusCode(e) - null - } + return callTyped(request, true) } - private fun entityWithAuth(request: Any? = null, extraHeaders: Map? = null): HttpEntity { - val headers = HttpHeaders().also { - it.setBasicAuth("user", "password") - } - extraHeaders?.forEach { key, value -> headers.set(key, value) } + fun getTodoWebclient(id: Long): Todo? { + val request = Request.Builder() + .url("$backendBaseUrl/todo-webclient/$id") - return HttpEntity(request, headers) + return callTyped(request, true) } - private fun statusCode(o: Any): Int? { - val statusCodeValue = (o as? ResponseEntity)?.statusCodeValue - if (statusCodeValue != null) { - return statusCodeValue - } - - val errorStatusCodeValue = (o as? HttpStatusCodeException)?.rawStatusCode - if (errorStatusCodeValue != null) { - return errorStatusCodeValue - } + fun getTodoRestClient(id: Long): Todo? { + val request = Request.Builder() + .url("$backendBaseUrl/todo-restclient/$id") - return null + return callTyped(request, true) } } 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 index 7ef1699f122..b41986656ef 100644 --- 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 @@ -1,28 +1,28 @@ package io.sentry.systemtest.util -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod +import okhttp3.Request class SentryMockServerClient(private val baseUrl: String) : LoggingInsecureRestClient() { fun getEnvelopeCount(): EnvelopeCounts { - val response = restTemplate().exchange("$baseUrl/envelope-count", HttpMethod.GET, entityWithAuth(), EnvelopeCounts::class.java) - return response.body!! + val request = Request.Builder() + .url("$baseUrl/envelope-count") + + return callTyped(request, false)!! } fun reset() { - restTemplate().exchange("$baseUrl/reset", HttpMethod.GET, entityWithAuth(), Any::class.java) + val request = Request.Builder() + .url("$baseUrl/reset") + + call(request, false) } fun getEnvelopes(): EnvelopesReceived { - val response = restTemplate().exchange("$baseUrl/envelopes-received", HttpMethod.GET, entityWithAuth(), EnvelopesReceived::class.java) - return response.body!! - } + val request = Request.Builder() + .url("$baseUrl/envelopes-received") - private fun entityWithAuth(request: Any? = null): HttpEntity { - val headers = HttpHeaders() - return HttpEntity(request, headers) + return callTyped(request, false)!! } }